diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp | 804 |
1 files changed, 556 insertions, 248 deletions
diff --git a/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp b/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp index 074e1d7..017afe1 100644 --- a/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp +++ b/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp @@ -17,6 +17,8 @@ #include "clang/Basic/SourceManager.h" #include "llvm/Support/Debug.h" +#define DEBUG_TYPE "format-token-annotator" + namespace clang { namespace format { @@ -34,16 +36,22 @@ public: : Style(Style), Line(Line), CurrentToken(Line.First), KeywordVirtualFound(false), AutoFound(false), Ident_in(Ident_in) { Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false)); + resetTokenMetadata(CurrentToken); } private: bool parseAngle() { - if (CurrentToken == NULL) + if (!CurrentToken) return false; ScopedContextCreator ContextCreator(*this, tok::less, 10); FormatToken *Left = CurrentToken->Previous; Contexts.back().IsExpression = false; - while (CurrentToken != NULL) { + // If there's a template keyword before the opening angle bracket, this is a + // template parameter, not an argument. + Contexts.back().InTemplateArgument = + Left->Previous && Left->Previous->Tok.isNot(tok::kw_template); + + while (CurrentToken) { if (CurrentToken->is(tok::greater)) { Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; @@ -61,7 +69,11 @@ 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 || + ((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) && Line.First->isNot(tok::kw_template)) return false; @@ -73,7 +85,7 @@ private: } bool parseParens(bool LookForDecls = false) { - if (CurrentToken == NULL) + if (!CurrentToken) return false; ScopedContextCreator ContextCreator(*this, tok::l_paren, 1); @@ -84,7 +96,7 @@ private: bool StartsObjCMethodExpr = false; FormatToken *Left = CurrentToken->Previous; if (CurrentToken->is(tok::caret)) { - // ^( starts a block. + // (^ can start a block type. Left->Type = TT_ObjCBlockLParen; } else if (FormatToken *MaybeSel = Left->Previous) { // @selector( starts a selector. @@ -94,15 +106,31 @@ private: } } - if (Left->Previous && Left->Previous->isOneOf(tok::kw_static_assert, - tok::kw_if, tok::kw_while)) { + 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)) { // 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))) { + 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; + } else if (Contexts[Contexts.size() - 2].CaretFound) { + // This is the parameter list of an ObjC block. + Contexts.back().IsExpression = false; + } else if (Left->Previous && Left->Previous->is(tok::kw___attribute)) { + Left->Type = TT_AttributeParen; + } else if (Left->Previous && Left->Previous->IsForEachMacro) { + // The first argument to a foreach macro is a declaration. + Contexts.back().IsForEachMacro = true; + Contexts.back().IsExpression = false; } if (StartsObjCMethodExpr) { @@ -113,7 +141,7 @@ private: bool MightBeFunctionType = CurrentToken->is(tok::star); bool HasMultipleLines = false; bool HasMultipleParametersOnALine = false; - while (CurrentToken != NULL) { + while (CurrentToken) { // 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 @@ -136,6 +164,8 @@ private: CurrentToken->Previous->Previous->isOneOf(tok::l_paren, tok::coloncolon)) MightBeFunctionType = true; + if (CurrentToken->Previous->Type == TT_BinaryOperator) + Contexts.back().IsExpression = true; if (CurrentToken->is(tok::r_paren)) { if (MightBeFunctionType && CurrentToken->Next && (CurrentToken->Next->is(tok::l_paren) || @@ -147,12 +177,15 @@ private: if (StartsObjCMethodExpr) { CurrentToken->Type = TT_ObjCMethodExpr; - if (Contexts.back().FirstObjCSelectorName != NULL) { + if (Contexts.back().FirstObjCSelectorName) { Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = Contexts.back().LongestObjCSelectorName; } } + if (Left->Type == TT_AttributeParen) + CurrentToken->Type = TT_AttributeParen; + if (!HasMultipleLines) Left->PackingKind = PPK_Inconclusive; else if (HasMultipleParametersOnALine) @@ -165,13 +198,19 @@ private: } if (CurrentToken->isOneOf(tok::r_square, tok::r_brace)) return false; - updateParameterCount(Left, CurrentToken); + else if (CurrentToken->is(tok::l_brace)) + Left->Type = TT_Unknown; // Not TT_ObjCBlockLParen if (CurrentToken->is(tok::comma) && CurrentToken->Next && !CurrentToken->Next->HasUnescapedNewline && !CurrentToken->Next->isTrailingComment()) HasMultipleParametersOnALine = true; + if (CurrentToken->isOneOf(tok::kw_const, tok::kw_auto) || + CurrentToken->isSimpleTypeSpecifier()) + Contexts.back().IsExpression = false; + FormatToken *Tok = CurrentToken; if (!consumeToken()) return false; + updateParameterCount(Left, Tok); if (CurrentToken && CurrentToken->HasUnescapedNewline) HasMultipleLines = true; } @@ -189,6 +228,7 @@ private: FormatToken *Parent = Left->getPreviousNonComment(); bool StartsObjCMethodExpr = Contexts.back().CanBeExpression && Left->Type != 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 || @@ -207,7 +247,7 @@ private: Left->Type = TT_ArraySubscriptLSquare; } - while (CurrentToken != NULL) { + while (CurrentToken) { if (CurrentToken->is(tok::r_square)) { if (CurrentToken->Next && CurrentToken->Next->is(tok::l_paren) && Left->Type == TT_ObjCMethodExpr) { @@ -216,19 +256,22 @@ private: StartsObjCMethodExpr = false; Left->Type = TT_Unknown; } - if (StartsObjCMethodExpr) { + if (StartsObjCMethodExpr && CurrentToken->Previous != Left) { CurrentToken->Type = TT_ObjCMethodExpr; // determineStarAmpUsage() thinks that '*' '[' is allocating an // array of pointers, but if '[' starts a selector then '*' is a // binary operator. - if (Parent != NULL && Parent->Type == TT_PointerOrReference) + if (Parent && Parent->Type == TT_PointerOrReference) Parent->Type = TT_BinaryOperator; } Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; - if (Contexts.back().FirstObjCSelectorName != NULL) + if (Contexts.back().FirstObjCSelectorName) { Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = Contexts.back().LongestObjCSelectorName; + if (Left->BlockParameterCount > 1) + Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 0; + } next(); return true; } @@ -237,23 +280,32 @@ private: if (CurrentToken->is(tok::colon)) ColonFound = true; if (CurrentToken->is(tok::comma) && + Style.Language != FormatStyle::LK_Proto && (Left->Type == TT_ArraySubscriptLSquare || (Left->Type == TT_ObjCMethodExpr && !ColonFound))) Left->Type = TT_ArrayInitializerLSquare; - updateParameterCount(Left, CurrentToken); + FormatToken* Tok = CurrentToken; if (!consumeToken()) return false; + updateParameterCount(Left, Tok); } return false; } bool parseBrace() { - if (CurrentToken != NULL) { + if (CurrentToken) { FormatToken *Left = CurrentToken->Previous; + + if (Contexts.back().CaretFound) + Left->Type = TT_ObjCBlockLBrace; + Contexts.back().CaretFound = false; + ScopedContextCreator ContextCreator(*this, tok::l_brace, 1); Contexts.back().ColonIsDictLiteral = true; + if (Left->BlockKind == BK_BracedInit) + Contexts.back().IsExpression = true; - while (CurrentToken != NULL) { + while (CurrentToken) { if (CurrentToken->is(tok::r_brace)) { Left->MatchingParen = CurrentToken; CurrentToken->MatchingParen = Left; @@ -263,18 +315,26 @@ private: if (CurrentToken->isOneOf(tok::r_paren, tok::r_square)) return false; updateParameterCount(Left, CurrentToken); - if (CurrentToken->is(tok::colon)) + 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 (!consumeToken()) return false; } } - // No closing "}" found, this probably starts a definition. - Line.StartsDefinition = true; return true; } void updateParameterCount(FormatToken *Left, FormatToken *Current) { + if (Current->Type == TT_LambdaLSquare || + (Current->is(tok::caret) && Current->Type == TT_UnaryOperator) || + (Style.Language == FormatStyle::LK_JavaScript && + Current->TokenText == "function")) { + ++Left->BlockParameterCount; + } if (Current->is(tok::comma)) { ++Left->ParameterCount; if (!Left->Role) @@ -286,7 +346,7 @@ private: } bool parseConditional() { - while (CurrentToken != NULL) { + while (CurrentToken) { if (CurrentToken->is(tok::colon)) { CurrentToken->Type = TT_ConditionalExpr; next(); @@ -299,12 +359,12 @@ private: } bool parseTemplateDeclaration() { - if (CurrentToken != NULL && CurrentToken->is(tok::less)) { + if (CurrentToken && CurrentToken->is(tok::less)) { CurrentToken->Type = TT_TemplateOpener; next(); if (!parseAngle()) return false; - if (CurrentToken != NULL) + if (CurrentToken) CurrentToken->Previous->ClosesTemplateDeclaration = true; return true; } @@ -317,33 +377,34 @@ private: switch (Tok->Tok.getKind()) { case tok::plus: case tok::minus: - if (Tok->Previous == NULL && Line.MustBeDeclaration) + if (!Tok->Previous && Line.MustBeDeclaration) Tok->Type = TT_ObjCMethodSpecifier; break; case tok::colon: - if (Tok->Previous == NULL) + if (!Tok->Previous) return false; // Colons from ?: are handled in parseConditional(). - if (Tok->Previous->is(tok::r_paren) && Contexts.size() == 1) { + if (Tok->Previous->is(tok::r_paren) && Contexts.size() == 1 && + Line.First->isNot(tok::kw_case)) { Tok->Type = TT_CtorInitializerColon; } else if (Contexts.back().ColonIsDictLiteral) { Tok->Type = TT_DictLiteral; } else if (Contexts.back().ColonIsObjCMethodExpr || Line.First->Type == TT_ObjCMethodSpecifier) { Tok->Type = TT_ObjCMethodExpr; - Tok->Previous->Type = TT_ObjCSelectorName; + Tok->Previous->Type = TT_SelectorName; if (Tok->Previous->ColumnWidth > Contexts.back().LongestObjCSelectorName) { Contexts.back().LongestObjCSelectorName = Tok->Previous->ColumnWidth; } - if (Contexts.back().FirstObjCSelectorName == NULL) + if (!Contexts.back().FirstObjCSelectorName) Contexts.back().FirstObjCSelectorName = Tok->Previous; } else if (Contexts.back().ColonIsForRangeExpr) { Tok->Type = TT_RangeBasedForLoopColon; - } else if (CurrentToken != NULL && - CurrentToken->is(tok::numeric_constant)) { + } else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) { Tok->Type = TT_BitFieldColon; - } else if (Contexts.size() == 1 && Line.First->isNot(tok::kw_enum)) { + } else if (Contexts.size() == 1 && + !Line.First->isOneOf(tok::kw_enum, tok::kw_case)) { Tok->Type = TT_InheritanceColon; } else if (Contexts.back().ContextKind == tok::l_paren) { Tok->Type = TT_InlineASMColon; @@ -351,7 +412,7 @@ private: break; case tok::kw_if: case tok::kw_while: - if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) { + if (CurrentToken && CurrentToken->is(tok::l_paren)) { next(); if (!parseParens(/*LookForDecls=*/true)) return false; @@ -367,7 +428,9 @@ private: if (!parseParens()) return false; if (Line.MustBeDeclaration && Contexts.size() == 1 && - !Contexts.back().IsExpression) + !Contexts.back().IsExpression && + Line.First->Type != TT_ObjCProperty && + (!Tok->Previous || Tok->Previous->isNot(tok::kw_decltype))) Line.MightBeFunctionDecl = true; break; case tok::l_square: @@ -392,7 +455,7 @@ private: return false; case tok::r_brace: // Lines can start with '}'. - if (Tok->Previous != NULL) + if (Tok->Previous) return false; break; case tok::greater: @@ -429,6 +492,8 @@ private: Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true; if (Contexts.back().InCtorInitializer) Tok->Type = TT_CtorInitializerComma; + if (Contexts.back().IsForEachMacro) + Contexts.back().IsExpression = true; break; default: break; @@ -438,15 +503,15 @@ private: void parseIncludeDirective() { next(); - if (CurrentToken != NULL && CurrentToken->is(tok::less)) { + if (CurrentToken && CurrentToken->is(tok::less)) { next(); - while (CurrentToken != NULL) { + while (CurrentToken) { if (CurrentToken->isNot(tok::comment) || CurrentToken->Next) CurrentToken->Type = TT_ImplicitStringLiteral; next(); } } else { - while (CurrentToken != NULL) { + 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. @@ -461,15 +526,27 @@ private: // We still want to format the whitespace left of the first token of the // warning or error. next(); - while (CurrentToken != NULL) { + while (CurrentToken) { CurrentToken->Type = TT_ImplicitStringLiteral; next(); } } + void parsePragma() { + next(); // Consume "pragma". + if (CurrentToken && CurrentToken->TokenText == "mark") { + next(); // Consume "mark". + next(); // Consume first token (so we fix leading whitespace). + while (CurrentToken) { + CurrentToken->Type = TT_ImplicitStringLiteral; + next(); + } + } + } + void parsePreprocessorDirective() { next(); - if (CurrentToken == NULL) + if (!CurrentToken) return; if (CurrentToken->Tok.is(tok::numeric_constant)) { CurrentToken->SpacesRequiredBefore = 1; @@ -477,7 +554,7 @@ private: } // Hashes in the middle of a line can lead to any strange token // sequence. - if (CurrentToken->Tok.getIdentifierInfo() == NULL) + if (!CurrentToken->Tok.getIdentifierInfo()) return; switch (CurrentToken->Tok.getIdentifierInfo()->getPPKeywordID()) { case tok::pp_include: @@ -488,14 +565,18 @@ private: case tok::pp_warning: parseWarningOrError(); break; + case tok::pp_pragma: + parsePragma(); + break; case tok::pp_if: case tok::pp_elif: + Contexts.back().IsExpression = true; parseLine(); break; default: break; } - while (CurrentToken != NULL) + while (CurrentToken) next(); } @@ -505,7 +586,16 @@ public: parsePreprocessorDirective(); return LT_PreprocessorDirective; } - while (CurrentToken != NULL) { + + // 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)) + parseIncludeDirective(); + + while (CurrentToken) { if (CurrentToken->is(tok::kw_virtual)) KeywordVirtualFound = true; if (!consumeToken()) @@ -515,7 +605,7 @@ public: return LT_VirtualFunctionDecl; if (Line.First->Type == TT_ObjCMethodSpecifier) { - if (Contexts.back().FirstObjCSelectorName != NULL) + if (Contexts.back().FirstObjCSelectorName) Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = Contexts.back().LongestObjCSelectorName; return LT_ObjCMethodDecl; @@ -525,26 +615,32 @@ public: } private: + 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) + CurrentToken->Type = TT_Unknown; + CurrentToken->Role.reset(); + CurrentToken->FakeLParens.clear(); + CurrentToken->FakeRParens = 0; + } + void next() { - if (CurrentToken != NULL) { + if (CurrentToken) { determineTokenType(*CurrentToken); CurrentToken->BindingStrength = Contexts.back().BindingStrength; - } - - if (CurrentToken != NULL) + CurrentToken->NestingLevel = Contexts.size() - 1; 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; } + + resetTokenMetadata(CurrentToken); } /// \brief A struct to hold information valid in a specific context, e.g. @@ -555,9 +651,10 @@ private: : ContextKind(ContextKind), BindingStrength(BindingStrength), LongestObjCSelectorName(0), ColonIsForRangeExpr(false), ColonIsDictLiteral(false), ColonIsObjCMethodExpr(false), - FirstObjCSelectorName(NULL), FirstStartOfName(NULL), + FirstObjCSelectorName(nullptr), FirstStartOfName(nullptr), IsExpression(IsExpression), CanBeExpression(true), - InCtorInitializer(false) {} + InTemplateArgument(false), InCtorInitializer(false), + CaretFound(false), IsForEachMacro(false) {} tok::TokenKind ContextKind; unsigned BindingStrength; @@ -569,7 +666,10 @@ private: FormatToken *FirstStartOfName; bool IsExpression; bool CanBeExpression; + bool InTemplateArgument; bool InCtorInitializer; + bool CaretFound; + bool IsForEachMacro; }; /// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime @@ -596,19 +696,26 @@ private: for (FormatToken *Previous = Current.Previous; Previous && !Previous->isOneOf(tok::comma, tok::semi); Previous = Previous->Previous) { - if (Previous->is(tok::r_square)) + 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; } } - } else if (Current.isOneOf(tok::kw_return, tok::kw_throw) || - (Current.is(tok::l_paren) && !Line.MustBeDeclaration && - !Line.InPPDirective && - (!Current.Previous || - !Current.Previous->isOneOf(tok::kw_for, tok::kw_catch)))) { + } else if (Current.isOneOf(tok::kw_return, tok::kw_throw)) { Contexts.back().IsExpression = true; + } else if (Current.is(tok::l_paren) && !Line.MustBeDeclaration && + !Line.InPPDirective && + (!Current.Previous || + Current.Previous->isNot(tok::kw_decltype))) { + bool ParametersOfFunctionType = + Current.Previous && Current.Previous->is(tok::r_paren) && + Current.Previous->MatchingParen && + Current.Previous->MatchingParen->Type == TT_FunctionTypeLParen; + bool IsForOrCatch = Current.Previous && + Current.Previous->isOneOf(tok::kw_for, tok::kw_catch); + Contexts.back().IsExpression = !ParametersOfFunctionType && !IsForOrCatch; } else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) { for (FormatToken *Previous = Current.Previous; Previous && Previous->isOneOf(tok::star, tok::amp); @@ -640,13 +747,18 @@ private: } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { Current.Type = determineStarAmpUsage(Current, Contexts.back().CanBeExpression && - Contexts.back().IsExpression); + 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))) { @@ -657,38 +769,7 @@ private: else Current.Type = TT_BlockComment; } else if (Current.is(tok::r_paren)) { - 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.Next && - Current.Next->isOneOf(tok::equal, tok::semi, tok::l_brace); - bool IsSizeOfOrAlignOf = - 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) + if (rParenEndsCast(Current)) Current.Type = TT_CastRParen; } else if (Current.is(tok::at) && Current.Next) { switch (Current.Next->Tok.getObjCKeywordID()) { @@ -708,6 +789,12 @@ private: 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; } } } @@ -718,15 +805,15 @@ private: /// 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) + if (Tok.isNot(tok::identifier) || !Tok.Previous) 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)) + while (PreviousNotConst && PreviousNotConst->is(tok::kw_const)) PreviousNotConst = PreviousNotConst->Previous; - if (PreviousNotConst == NULL) + if (!PreviousNotConst) return false; bool IsPPKeyword = PreviousNotConst->is(tok::identifier) && @@ -738,19 +825,84 @@ private: PreviousNotConst->MatchingParen->Previous && PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template); + if (PreviousNotConst->is(tok::r_paren) && PreviousNotConst->MatchingParen && + PreviousNotConst->MatchingParen->Previous && + PreviousNotConst->MatchingParen->Previous->is(tok::kw_decltype)) + return true; + return (!IsPPKeyword && PreviousNotConst->is(tok::identifier)) || PreviousNotConst->Type == TT_PointerOrReference || - isSimpleTypeSpecifier(*PreviousNotConst); + PreviousNotConst->isSimpleTypeSpecifier(); + } + + /// \brief Determine whether ')' is ending a cast. + bool rParenEndsCast(const FormatToken &Tok) { + FormatToken *LeftOfParens = nullptr; + if (Tok.MatchingParen) + LeftOfParens = Tok.MatchingParen->getPreviousNonComment(); + if (LeftOfParens && LeftOfParens->is(tok::r_paren)) + return false; + 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 ParensCouldEndDecl = + Tok.Next && Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace); + bool IsSizeOfOrAlignOf = + LeftOfParens && LeftOfParens->isOneOf(tok::kw_sizeof, tok::kw_alignof); + if (ParensAreType && !ParensCouldEndDecl && !IsSizeOfOrAlignOf && + ((Contexts.size() > 1 && Contexts[Contexts.size() - 2].IsExpression) || + (Tok.Next && Tok.Next->isBinaryOperator()))) + IsCast = true; + else if (Tok.Next && Tok.Next->isNot(tok::string_literal) && + (Tok.Next->Tok.isLiteral() || + Tok.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 (). + else if (LeftOfParens && + (LeftOfParens->Tok.getIdentifierInfo() == nullptr || + LeftOfParens->is(tok::kw_return)) && + LeftOfParens->Type != TT_OverloadedOperator && + LeftOfParens->isNot(tok::at) && + LeftOfParens->Type != TT_TemplateCloser && Tok.Next) { + if (Tok.Next->isOneOf(tok::identifier, tok::numeric_constant)) { + IsCast = true; + } else { + // Use heuristics to recognize c style casting. + FormatToken *Prev = Tok.Previous; + if (Prev && Prev->isOneOf(tok::amp, tok::star)) + Prev = Prev->Previous; + + 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); + } + + for (; Prev != Tok.MatchingParen; Prev = Prev->Previous) { + if (!Prev || !Prev->isOneOf(tok::kw_const, tok::identifier)) { + IsCast = false; + break; + } + } + } + } + return IsCast && !ParensAreEmpty; } /// \brief Return the type of the given token assuming it is * or &. - TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression) { + TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression, + bool InTemplateArgument) { const FormatToken *PrevToken = Tok.getPreviousNonComment(); - if (PrevToken == NULL) + if (!PrevToken) return TT_UnaryOperator; const FormatToken *NextToken = Tok.getNextNonComment(); - if (NextToken == NULL) + if (!NextToken || NextToken->is(tok::l_brace)) return TT_Unknown; if (PrevToken->is(tok::coloncolon) || @@ -761,20 +913,37 @@ private: 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) return TT_UnaryOperator; - if (NextToken->is(tok::l_square)) + if (NextToken->is(tok::l_square) && NextToken->Type != TT_LambdaLSquare) + return TT_PointerOrReference; + if (NextToken->is(tok::kw_operator)) return TT_PointerOrReference; if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen && PrevToken->MatchingParen->Previous && - PrevToken->MatchingParen->Previous->is(tok::kw_typeof)) + PrevToken->MatchingParen->Previous->isOneOf(tok::kw_typeof, + tok::kw_decltype)) return TT_PointerOrReference; if (PrevToken->Tok.isLiteral() || - PrevToken->isOneOf(tok::r_paren, tok::r_square) || - NextToken->Tok.isLiteral() || NextToken->isUnaryOperator()) + PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true, + tok::kw_false) || + NextToken->Tok.isLiteral() || + NextToken->isOneOf(tok::kw_true, tok::kw_false) || + NextToken->isUnaryOperator() || + // If we know we're in a template argument, there are no named + // declarations. Thus, having an identifier on the right-hand side + // indicates a binary operator. + (InTemplateArgument && NextToken->Tok.isAnyIdentifier())) + return TT_BinaryOperator; + + // This catches some cases where evaluation order is used as control flow: + // aaa && aaa->f(); + const FormatToken *NextNextToken = NextToken->getNextNonComment(); + if (NextNextToken && NextNextToken->is(tok::arrow)) return TT_BinaryOperator; // It is very unlikely that we are going to find a pointer or reference type @@ -787,7 +956,7 @@ private: TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) { const FormatToken *PrevToken = Tok.getPreviousNonComment(); - if (PrevToken == NULL || PrevToken->Type == TT_CastRParen) + if (!PrevToken || PrevToken->Type == TT_CastRParen) return TT_UnaryOperator; // Use heuristics to recognize unary operators. @@ -807,7 +976,7 @@ private: /// \brief Determine whether ++/-- are pre- or post-increments/-decrements. TokenType determineIncrementUsage(const FormatToken &Tok) { const FormatToken *PrevToken = Tok.getPreviousNonComment(); - if (PrevToken == NULL || PrevToken->Type == TT_CastRParen) + if (!PrevToken || PrevToken->Type == TT_CastRParen) return TT_UnaryOperator; if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier)) return TT_TrailingUnaryOperator; @@ -815,37 +984,6 @@ private: return TT_UnaryOperator; } - // 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 FormatToken &Tok) const { - switch (Tok.Tok.getKind()) { - case tok::kw_short: - case tok::kw_long: - case tok::kw___int64: - case tok::kw___int128: - case tok::kw_signed: - case tok::kw_unsigned: - case tok::kw_void: - case tok::kw_char: - case tok::kw_int: - case tok::kw_half: - case tok::kw_float: - case tok::kw_double: - case tok::kw_wchar_t: - case tok::kw_bool: - case tok::kw___underlying_type: - case tok::annot_typename: - case tok::kw_char16_t: - case tok::kw_char32_t: - case tok::kw_typeof: - case tok::kw_decltype: - return true; - default: - return false; - } - } - SmallVector<Context, 8> Contexts; const FormatStyle &Style; @@ -875,10 +1013,11 @@ public: // expression. while (Current && (Current->is(tok::kw_return) || - (Current->is(tok::colon) && Current->Type == TT_ObjCMethodExpr))) + (Current->is(tok::colon) && (Current->Type == TT_ObjCMethodExpr || + Current->Type == TT_DictLiteral)))) next(); - if (Current == NULL || Precedence > PrecedenceArrowAndPeriod) + if (!Current || Precedence > PrecedenceArrowAndPeriod) return; // Conditional expressions need to be parsed separately for proper nesting. @@ -895,7 +1034,8 @@ public: } FormatToken *Start = Current; - FormatToken *LatestOperator = NULL; + FormatToken *LatestOperator = nullptr; + unsigned OperatorIndex = 0; while (Current) { // Consume operators with higher precedence. @@ -903,17 +1043,20 @@ public: int CurrentPrecedence = getCurrentPrecedence(); - if (Current && Current->Type == TT_ObjCSelectorName && - Precedence == CurrentPrecedence) + if (Current && Current->Type == TT_SelectorName && + Precedence == CurrentPrecedence) { + if (LatestOperator) + addFakeParenthesis(Start, prec::Level(Precedence)); 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() || + if (!Current || Current->closesScope() || (CurrentPrecedence != -1 && CurrentPrecedence < Precedence)) { if (LatestOperator) { + LatestOperator->LastOperator = true; if (Precedence == PrecedenceArrowAndPeriod) { - LatestOperator->LastInChainOfCalls = true; // Call expressions don't have a binary operator precedence. addFakeParenthesis(Start, prec::Unknown); } else { @@ -932,8 +1075,11 @@ public: next(); } else { // Operator found. - if (CurrentPrecedence == Precedence) + if (CurrentPrecedence == Precedence) { LatestOperator = Current; + Current->OperatorIndex = OperatorIndex; + ++OperatorIndex; + } next(); } @@ -948,8 +1094,10 @@ private: if (Current->Type == TT_ConditionalExpr) return prec::Conditional; else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon || - Current->Type == TT_ObjCSelectorName) + Current->Type == TT_SelectorName) return 0; + else if (Current->Type == TT_RangeBasedForLoopColon) + return prec::Comma; else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma)) return Current->getPrecedence(); else if (Current->isOneOf(tok::period, tok::arrow)) @@ -972,7 +1120,7 @@ private: /// \brief Parse unary operator expressions and surround them with fake /// parentheses if appropriate. void parseUnaryOperator() { - if (Current == NULL || Current->Type != TT_UnaryOperator) { + if (!Current || Current->Type != TT_UnaryOperator) { parse(PrecedenceArrowAndPeriod); return; } @@ -991,7 +1139,7 @@ private: if (!Current || !Current->is(tok::question)) return; next(); - parse(prec::LogicalOr); + parseConditionalExpr(); if (!Current || Current->Type != TT_ConditionalExpr) return; next(); @@ -1013,15 +1161,15 @@ private: void TokenAnnotator::setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines) { - const AnnotatedLine *NextNonCommentLine = NULL; + const AnnotatedLine *NextNonCommentLine = nullptr; 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)->First->Next == nullptr) (*I)->Level = NextNonCommentLine->Level; else - NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : NULL; + NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr; setCommentLineLevels((*I)->Children); } @@ -1052,31 +1200,108 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { Line.First->CanBreakBefore = Line.First->MustBreakBefore; } +// 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) + return false; + const FormatToken *Next = Current.Next; + for (; Next; Next = Next->Next) { + if (Next->Type == TT_TemplateOpener) { + Next = Next->MatchingParen; + } else if (Next->is(tok::coloncolon)) { + Next = Next->Next; + if (!Next || !Next->is(tok::identifier)) + return false; + } else if (Next->is(tok::l_paren)) { + break; + } else { + return false; + } + } + if (!Next) + return false; + assert(Next->is(tok::l_paren)); + if (Next->Next == Next->MatchingParen) + return true; + 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) + return true; + if (Tok->isOneOf(tok::l_brace, tok::string_literal) || Tok->Tok.isLiteral()) + return false; + } + return false; +} + void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { + for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(), + E = Line.Children.end(); + I != E; ++I) { + calculateFormattingInformation(**I); + } + Line.First->TotalLength = Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth; if (!Line.First->Next) return; FormatToken *Current = Line.First->Next; bool InFunctionDecl = Line.MightBeFunctionDecl; - while (Current != NULL) { - if (Current->Type == TT_LineComment) - Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments; - else if (Current->SpacesRequiredBefore == 0 && - spaceRequiredBefore(Line, *Current)) + while (Current) { + if (isFunctionDeclarationName(*Current)) + Current->Type = TT_FunctionDeclarationName; + if (Current->Type == TT_LineComment) { + if (Current->Previous->BlockKind == BK_BracedInit && + Current->Previous->opensScope()) + Current->SpacesRequiredBefore = Style.Cpp11BracedListStyle ? 0 : 1; + else + Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments; + + // If we find a trailing comment, iterate backwards to determine whether + // it seems to relate to a specific parameter. If so, break before that + // parameter to avoid changing the comment's meaning. E.g. don't move 'b' + // to the previous line in: + // SomeFunction(a, + // b, // comment + // c); + if (!Current->HasUnescapedNewline) { + for (FormatToken *Parameter = Current->Previous; Parameter; + Parameter = Parameter->Previous) { + if (Parameter->isOneOf(tok::comment, tok::r_brace)) + break; + if (Parameter->Previous && Parameter->Previous->is(tok::comma)) { + if (Parameter->Previous->Type != TT_CtorInitializerComma && + Parameter->HasUnescapedNewline) + Parameter->MustBreakBefore = true; + break; + } + } + } + } 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->Children.empty() || + unsigned ChildSize = 0; + if (Current->Previous->Children.size() == 1) { + FormatToken &LastOfChild = *Current->Previous->Children[0]->Last; + ChildSize = LastOfChild.isTrailingComment() ? Style.ColumnLimit + : LastOfChild.TotalLength + 1; + } + if (Current->MustBreakBefore || Current->Previous->Children.size() > 1 || Current->IsMultiline) Current->TotalLength = Current->Previous->TotalLength + Style.ColumnLimit; else Current->TotalLength = Current->Previous->TotalLength + - Current->ColumnWidth + + Current->ColumnWidth + ChildSize + Current->SpacesRequiredBefore; if (Current->Type == TT_CtorInitializerColon) @@ -1092,24 +1317,18 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { } calculateUnbreakableTailLengths(Line); - for (Current = Line.First; Current != NULL; Current = Current->Next) { + for (Current = Line.First; Current != nullptr; 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) { + while (Current) { Current->UnbreakableTailLength = UnbreakableTailLength; if (Current->CanBreakBefore || Current->isOneOf(tok::comment, tok::string_literal)) { @@ -1130,18 +1349,22 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Left.is(tok::semi)) return 0; - if (Left.is(tok::comma)) + if (Left.is(tok::comma) || (Right.is(tok::identifier) && Right.Next && + Right.Next->Type == TT_DictLiteral)) return 1; - if (Right.is(tok::l_square)) - return 150; - - if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator)) { + if (Right.is(tok::l_square)) { + if (Style.Language == FormatStyle::LK_Proto) + return 1; + if (Right.Type != TT_ObjCMethodExpr && Right.Type != TT_LambdaLSquare) + return 500; + } + if (Right.Type == TT_StartOfName || + Right.Type == TT_FunctionDeclarationName || Right.is(tok::kw_operator)) { if (Line.First->is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt) return 3; if (Left.Type == TT_StartOfName) return 20; - if (InFunctionDecl && Right.BindingStrength == 1) - // FIXME: Clean up hack of using BindingStrength to find top-level names. + if (InFunctionDecl && Right.NestingLevel == 0) return Style.PenaltyReturnTypeOnItsOwnLine; return 200; } @@ -1149,7 +1372,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, return 150; if (Left.Type == TT_CastRParen) return 100; - if (Left.is(tok::coloncolon)) + if (Left.is(tok::coloncolon) || + (Right.is(tok::period) && Style.Language == FormatStyle::LK_Proto)) return 500; if (Left.isOneOf(tok::kw_class, tok::kw_struct)) return 5000; @@ -1159,17 +1383,22 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, return 2; if (Right.isMemberAccess()) { - if (Left.isOneOf(tok::r_paren, tok::r_square) && Left.MatchingParen && + if (Left.is(tok::r_paren) && 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; + if (Right.Type == TT_TrailingAnnotation && + (!Right.Next || Right.Next->isNot(tok::l_paren))) { + // 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. + // Use a slightly higher penalty after ")" so that annotations like + // "const override" are kept together. + bool is_short_annotation = Right.TokenText.size() < 10; + return (Left.is(tok::r_paren) ? 100 : 120) + (is_short_annotation ? 50 : 0); + } // In for-loops, prefer breaking at ',' and ';'. if (Line.First->is(tok::kw_for) && Left.is(tok::equal)) @@ -1177,13 +1406,15 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, // In Objective-C method expressions, prefer breaking before "param:" over // breaking after it. - if (Right.Type == TT_ObjCSelectorName) + if (Right.Type == TT_SelectorName) return 0; if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr) - return 50; + return Line.MightBeFunctionDecl ? 50 : 500; if (Left.is(tok::l_paren) && InFunctionDecl) return 100; + if (Left.is(tok::equal) && InFunctionDecl) + return 110; if (Left.opensScope()) return Left.ParameterCount > 1 ? Style.PenaltyBreakBeforeFirstCallParameter : 19; @@ -1215,6 +1446,23 @@ 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 && + Left.Tok.getObjCKeywordID() == tok::objc_property) + return true; if (Right.is(tok::hashhash)) return Left.is(tok::hash); if (Left.isOneOf(tok::hashhash, tok::hash)) @@ -1246,7 +1494,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return false; if (Left.is(tok::coloncolon)) return false; - if (Right.is(tok::coloncolon)) + 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); @@ -1259,60 +1507,64 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Right.Type == TT_PointerOrReference) return Left.Tok.isLiteral() || ((Left.Type != TT_PointerOrReference) && Left.isNot(tok::l_paren) && - !Style.PointerBindsToType); + Style.PointerAlignment != FormatStyle::PAS_Left); if (Right.Type == TT_FunctionTypeLParen && Left.isNot(tok::l_paren) && - (Left.Type != TT_PointerOrReference || Style.PointerBindsToType)) + (Left.Type != 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.PointerBindsToType && + Right.isNot(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 && - Right.isNot(tok::r_square); + Style.SpacesInContainerLiterals && Right.isNot(tok::r_square); if (Right.is(tok::r_square)) - return Right.MatchingParen && + 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)) + Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant) && + Left.Type != TT_DictLiteral) return false; if (Left.is(tok::colon)) return Left.Type != TT_ObjCMethodExpr; - if (Right.is(tok::colon)) - return Right.Type != TT_ObjCMethodExpr && !Left.is(tok::question); + if (Left.Type == TT_BlockComment) + return !Left.TokenText.endswith("=*/"); if (Right.is(tok::l_paren)) { - if (Left.is(tok::r_paren) && Left.MatchingParen && - Left.MatchingParen->Previous && - Left.MatchingParen->Previous->is(tok::kw___attribute)) + if (Left.is(tok::r_paren) && Left.Type == TT_AttributeParen) return true; return Line.Type == LT_ObjCDecl || - 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)); + Left.isOneOf(tok::kw_new, tok::kw_delete, 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) || + Left.IsForEachMacro)) || + (Style.SpaceBeforeParens == FormatStyle::SBPO_Always && + Left.isOneOf(tok::identifier, tok::kw___attribute) && + 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) || Right.is(tok::r_brace)) + 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) 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) && + if ((Left.isOneOf(tok::identifier, tok::greater, tok::r_square, + tok::r_paren) || + Left.isSimpleTypeSpecifier()) && Right.is(tok::l_brace) && Right.getNextNonComment() && Right.BlockKind != BK_Block) return false; 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; @@ -1350,11 +1602,12 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return false; if (Tok.is(tok::colon)) return !Line.First->isOneOf(tok::kw_case, tok::kw_default) && - Tok.getNextNonComment() != NULL && Tok.Type != TT_ObjCMethodExpr && - !Tok.Previous->is(tok::question); + 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 false; + 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 && @@ -1367,7 +1620,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Tok.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_BinaryOperator || + Tok.Previous->Type == TT_ConditionalExpr) return true; if (Tok.Previous->Type == TT_TemplateCloser && Tok.is(tok::l_paren)) return false; @@ -1376,16 +1630,28 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return true; if (Tok.Type == TT_TrailingUnaryOperator) return false; + if (Tok.Previous->Type == TT_RegexLiteral) + return false; return spaceRequiredBetween(Line, *Tok.Previous, Tok); } +// 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; +} + bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, const FormatToken &Right) { + const FormatToken &Left = *Right.Previous; + if (Right.NewlinesBefore > 1) + return true; if (Right.is(tok::comment)) { - return Right.NewlinesBefore > 0; + return Right.Previous->BlockKind != BK_BracedInit && + Right.Previous->Type != TT_CtorInitializerColon && + (Right.NewlinesBefore > 0 && Right.HasUnescapedNewline); } else if (Right.Previous->isTrailingComment() || - (Right.is(tok::string_literal) && - Right.Previous->is(tok::string_literal))) { + (Right.isStringLiteral() && Right.Previous->isStringLiteral())) { return true; } else if (Right.Previous->IsUnterminatedLiteral) { return true; @@ -1395,45 +1661,83 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, return true; } else if (Right.Previous->ClosesTemplateDeclaration && Right.Previous->MatchingParen && - Right.Previous->MatchingParen->BindingStrength == 1 && + Right.Previous->MatchingParen->NestingLevel == 0 && Style.AlwaysBreakTemplateDeclarations) { - // FIXME: Fix horrible hack of using BindingStrength to find top-level <>. return true; - } else if (Right.Type == TT_CtorInitializerComma && + } else if ((Right.Type == TT_CtorInitializerComma || + Right.Type == TT_CtorInitializerColon) && Style.BreakConstructorInitializersBeforeComma && !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) { return true; - } else if (Right.Previous->BlockKind == BK_Block && - Right.Previous->isNot(tok::r_brace) && Right.isNot(tok::r_brace)) { + } else 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. return true; - } else if (Right.is(tok::l_brace) && (Right.BlockKind == BK_Block)) { - return Style.BreakBeforeBraces == FormatStyle::BS_Allman; + } else 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)) + return true; + + if (Style.Language == FormatStyle::LK_JavaScript) { + // FIXME: This might apply to other languages and token kinds. + if (Right.is(tok::char_constant) && Left.is(tok::plus) && Left.Previous && + Left.Previous->is(tok::char_constant)) + return true; + } + return false; } bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right) { const FormatToken &Left = *Right.Previous; - if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator)) + 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)) return true; if (Right.isTrailingComment()) // We rely on MustBreakBefore being set correctly here as we should not // change the "binding" behavior of a comment. - return false; + // The first comment in a braced lists is always interpreted as belonging to + // the first list element. Otherwise, it should be placed outside of the + // list. + 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)) 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)) + if (Right.Type == TT_InheritanceColon) + return true; + if (Right.is(tok::colon) && (Right.Type != TT_CtorInitializerColon && + Right.Type != TT_InlineASMColon)) return false; if (Left.is(tok::colon) && (Left.Type == TT_DictLiteral || Left.Type == TT_ObjCMethodExpr)) return true; - if (Right.Type == TT_ObjCSelectorName) + if (Right.Type == TT_SelectorName) return true; if (Left.is(tok::r_paren) && Line.Type == LT_ObjCProperty) return true; @@ -1452,14 +1756,12 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, return false; if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl) return false; - 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 (Left.is(tok::l_paren) && Left.Type == 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))) + return false; if (Right.Type == TT_ImplicitStringLiteral) return false; @@ -1471,11 +1773,11 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, 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.Previous != NULL && - Left.Previous->is(tok::r_paren)) - return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal); + // Allow breaking after a trailing annotation, e.g. after a method + // declaration. + if (Left.Type == TT_TrailingAnnotation) + return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal, tok::l_paren, + tok::less, tok::coloncolon); if (Right.is(tok::kw___attribute)) return true; @@ -1483,27 +1785,32 @@ 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) + return true; + 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 (Right.Type == TT_BinaryOperator && Style.BreakBeforeBinaryOperators) + return true; if (Left.Type == TT_ArrayInitializerLSquare) return true; - return (Left.isBinaryOperator() && Left.isNot(tok::lessless) && + return (Left.isBinaryOperator() && + !Left.isOneOf(tok::arrowstar, 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, - tok::l_square, tok::at) || + Right.isMemberAccess() || + Right.isOneOf(tok::lessless, tok::colon, tok::l_square, tok::at) || (Left.is(tok::r_paren) && - Right.isOneOf(tok::identifier, tok::kw_const, tok::kw___attribute)) || + Right.isOneOf(tok::identifier, tok::kw_const)) || (Left.is(tok::l_paren) && !Right.is(tok::r_paren)); } @@ -1514,13 +1821,14 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { llvm::errs() << " M=" << Tok->MustBreakBefore << " C=" << Tok->CanBreakBefore << " T=" << Tok->Type << " S=" << Tok->SpacesRequiredBefore + << " B=" << Tok->BlockParameterCount << " 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"; - if (Tok->Next == NULL) + if (!Tok->Next) assert(Tok == Line.Last); Tok = Tok->Next; } |