1249261Sdim//===--- TokenAnnotator.cpp - Format C++ code -----------------------------===// 2249261Sdim// 3249261Sdim// The LLVM Compiler Infrastructure 4249261Sdim// 5249261Sdim// This file is distributed under the University of Illinois Open Source 6249261Sdim// License. See LICENSE.TXT for details. 7249261Sdim// 8249261Sdim//===----------------------------------------------------------------------===// 9249261Sdim/// 10249261Sdim/// \file 11249261Sdim/// \brief This file implements a token annotator, i.e. creates 12249261Sdim/// \c AnnotatedTokens out of \c FormatTokens with required extra information. 13249261Sdim/// 14249261Sdim//===----------------------------------------------------------------------===// 15249261Sdim 16249261Sdim#include "TokenAnnotator.h" 17249261Sdim#include "clang/Basic/SourceManager.h" 18252723Sdim#include "llvm/Support/Debug.h" 19249261Sdim 20249261Sdimnamespace clang { 21249261Sdimnamespace format { 22249261Sdim 23263509Sdimnamespace { 24249261Sdim 25249261Sdim/// \brief A parser that gathers additional information about tokens. 26249261Sdim/// 27249261Sdim/// The \c TokenAnnotator tries to match parenthesis and square brakets and 28249261Sdim/// store a parenthesis levels. It also tries to resolve matching "<" and ">" 29249261Sdim/// into template parameter lists. 30249261Sdimclass AnnotatingParser { 31249261Sdimpublic: 32263509Sdim AnnotatingParser(const FormatStyle &Style, AnnotatedLine &Line, 33249261Sdim IdentifierInfo &Ident_in) 34263509Sdim : Style(Style), Line(Line), CurrentToken(Line.First), 35263509Sdim KeywordVirtualFound(false), AutoFound(false), Ident_in(Ident_in) { 36263509Sdim Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false)); 37249261Sdim } 38249261Sdim 39249261Sdimprivate: 40249261Sdim bool parseAngle() { 41249261Sdim if (CurrentToken == NULL) 42249261Sdim return false; 43249261Sdim ScopedContextCreator ContextCreator(*this, tok::less, 10); 44263509Sdim FormatToken *Left = CurrentToken->Previous; 45249261Sdim Contexts.back().IsExpression = false; 46249261Sdim while (CurrentToken != NULL) { 47249261Sdim if (CurrentToken->is(tok::greater)) { 48249261Sdim Left->MatchingParen = CurrentToken; 49249261Sdim CurrentToken->MatchingParen = Left; 50249261Sdim CurrentToken->Type = TT_TemplateCloser; 51249261Sdim next(); 52249261Sdim return true; 53249261Sdim } 54249261Sdim if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace, 55263509Sdim tok::question, tok::colon)) 56249261Sdim return false; 57263509Sdim // If a && or || is found and interpreted as a binary operator, this set 58263509Sdim // of angles is likely part of something like "a < b && c > d". If the 59263509Sdim // angles are inside an expression, the ||/&& might also be a binary 60263509Sdim // operator that was misinterpreted because we are parsing template 61263509Sdim // parameters. 62263509Sdim // FIXME: This is getting out of hand, write a decent parser. 63263509Sdim if (CurrentToken->Previous->isOneOf(tok::pipepipe, tok::ampamp) && 64263509Sdim (CurrentToken->Previous->Type == TT_BinaryOperator || 65263509Sdim Contexts[Contexts.size() - 2].IsExpression) && 66263509Sdim Line.First->isNot(tok::kw_template)) 67263509Sdim return false; 68249261Sdim updateParameterCount(Left, CurrentToken); 69249261Sdim if (!consumeToken()) 70249261Sdim return false; 71249261Sdim } 72249261Sdim return false; 73249261Sdim } 74249261Sdim 75249261Sdim bool parseParens(bool LookForDecls = false) { 76249261Sdim if (CurrentToken == NULL) 77249261Sdim return false; 78249261Sdim ScopedContextCreator ContextCreator(*this, tok::l_paren, 1); 79249261Sdim 80249261Sdim // FIXME: This is a bit of a hack. Do better. 81249261Sdim Contexts.back().ColonIsForRangeExpr = 82249261Sdim Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr; 83249261Sdim 84249261Sdim bool StartsObjCMethodExpr = false; 85263509Sdim FormatToken *Left = CurrentToken->Previous; 86249261Sdim if (CurrentToken->is(tok::caret)) { 87249261Sdim // ^( starts a block. 88249261Sdim Left->Type = TT_ObjCBlockLParen; 89263509Sdim } else if (FormatToken *MaybeSel = Left->Previous) { 90249261Sdim // @selector( starts a selector. 91263509Sdim if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous && 92263509Sdim MaybeSel->Previous->is(tok::at)) { 93249261Sdim StartsObjCMethodExpr = true; 94249261Sdim } 95249261Sdim } 96249261Sdim 97263509Sdim if (Left->Previous && Left->Previous->isOneOf(tok::kw_static_assert, 98263509Sdim tok::kw_if, tok::kw_while)) { 99263509Sdim // static_assert, if and while usually contain expressions. 100263509Sdim Contexts.back().IsExpression = true; 101263509Sdim } else if (Left->Previous && Left->Previous->is(tok::r_square) && 102263509Sdim Left->Previous->MatchingParen && 103263509Sdim Left->Previous->MatchingParen->Type == TT_LambdaLSquare) { 104263509Sdim // This is a parameter list of a lambda expression. 105263509Sdim Contexts.back().IsExpression = false; 106263509Sdim } 107263509Sdim 108249261Sdim if (StartsObjCMethodExpr) { 109249261Sdim Contexts.back().ColonIsObjCMethodExpr = true; 110249261Sdim Left->Type = TT_ObjCMethodExpr; 111249261Sdim } 112249261Sdim 113263509Sdim bool MightBeFunctionType = CurrentToken->is(tok::star); 114263509Sdim bool HasMultipleLines = false; 115263509Sdim bool HasMultipleParametersOnALine = false; 116249261Sdim while (CurrentToken != NULL) { 117249261Sdim // LookForDecls is set when "if (" has been seen. Check for 118249261Sdim // 'identifier' '*' 'identifier' followed by not '=' -- this 119249261Sdim // '*' has to be a binary operator but determineStarAmpUsage() will 120249261Sdim // categorize it as an unary operator, so set the right type here. 121263509Sdim if (LookForDecls && CurrentToken->Next) { 122263509Sdim FormatToken *Prev = CurrentToken->getPreviousNonComment(); 123263509Sdim if (Prev) { 124263509Sdim FormatToken *PrevPrev = Prev->getPreviousNonComment(); 125263509Sdim FormatToken *Next = CurrentToken->Next; 126263509Sdim if (PrevPrev && PrevPrev->is(tok::identifier) && 127263509Sdim Prev->isOneOf(tok::star, tok::amp, tok::ampamp) && 128263509Sdim CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) { 129263509Sdim Prev->Type = TT_BinaryOperator; 130263509Sdim LookForDecls = false; 131263509Sdim } 132249261Sdim } 133249261Sdim } 134249261Sdim 135263509Sdim if (CurrentToken->Previous->Type == TT_PointerOrReference && 136263509Sdim CurrentToken->Previous->Previous->isOneOf(tok::l_paren, 137263509Sdim tok::coloncolon)) 138263509Sdim MightBeFunctionType = true; 139249261Sdim if (CurrentToken->is(tok::r_paren)) { 140263509Sdim if (MightBeFunctionType && CurrentToken->Next && 141263509Sdim (CurrentToken->Next->is(tok::l_paren) || 142263509Sdim (CurrentToken->Next->is(tok::l_square) && 143263509Sdim !Contexts.back().IsExpression))) 144263509Sdim Left->Type = TT_FunctionTypeLParen; 145249261Sdim Left->MatchingParen = CurrentToken; 146249261Sdim CurrentToken->MatchingParen = Left; 147249261Sdim 148249261Sdim if (StartsObjCMethodExpr) { 149249261Sdim CurrentToken->Type = TT_ObjCMethodExpr; 150249261Sdim if (Contexts.back().FirstObjCSelectorName != NULL) { 151249261Sdim Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 152249261Sdim Contexts.back().LongestObjCSelectorName; 153249261Sdim } 154249261Sdim } 155249261Sdim 156263509Sdim if (!HasMultipleLines) 157263509Sdim Left->PackingKind = PPK_Inconclusive; 158263509Sdim else if (HasMultipleParametersOnALine) 159263509Sdim Left->PackingKind = PPK_BinPacked; 160263509Sdim else 161263509Sdim Left->PackingKind = PPK_OnePerLine; 162263509Sdim 163249261Sdim next(); 164249261Sdim return true; 165249261Sdim } 166249261Sdim if (CurrentToken->isOneOf(tok::r_square, tok::r_brace)) 167249261Sdim return false; 168249261Sdim updateParameterCount(Left, CurrentToken); 169263509Sdim if (CurrentToken->is(tok::comma) && CurrentToken->Next && 170263509Sdim !CurrentToken->Next->HasUnescapedNewline && 171263509Sdim !CurrentToken->Next->isTrailingComment()) 172263509Sdim HasMultipleParametersOnALine = true; 173249261Sdim if (!consumeToken()) 174249261Sdim return false; 175263509Sdim if (CurrentToken && CurrentToken->HasUnescapedNewline) 176263509Sdim HasMultipleLines = true; 177249261Sdim } 178249261Sdim return false; 179249261Sdim } 180249261Sdim 181249261Sdim bool parseSquare() { 182249261Sdim if (!CurrentToken) 183249261Sdim return false; 184249261Sdim 185263509Sdim // A '[' could be an index subscript (after an identifier or after 186249261Sdim // ')' or ']'), it could be the start of an Objective-C method 187249261Sdim // expression, or it could the the start of an Objective-C array literal. 188263509Sdim FormatToken *Left = CurrentToken->Previous; 189263509Sdim FormatToken *Parent = Left->getPreviousNonComment(); 190249261Sdim bool StartsObjCMethodExpr = 191263509Sdim Contexts.back().CanBeExpression && Left->Type != TT_LambdaLSquare && 192249261Sdim (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren, 193249261Sdim tok::kw_return, tok::kw_throw) || 194252723Sdim Parent->isUnaryOperator() || Parent->Type == TT_ObjCForIn || 195249261Sdim Parent->Type == TT_CastRParen || 196263509Sdim getBinOpPrecedence(Parent->Tok.getKind(), true, true) > prec::Unknown); 197249261Sdim ScopedContextCreator ContextCreator(*this, tok::l_square, 10); 198249261Sdim Contexts.back().IsExpression = true; 199263509Sdim bool ColonFound = false; 200249261Sdim 201249261Sdim if (StartsObjCMethodExpr) { 202249261Sdim Contexts.back().ColonIsObjCMethodExpr = true; 203249261Sdim Left->Type = TT_ObjCMethodExpr; 204263509Sdim } else if (Parent && Parent->is(tok::at)) { 205263509Sdim Left->Type = TT_ArrayInitializerLSquare; 206263509Sdim } else if (Left->Type == TT_Unknown) { 207263509Sdim Left->Type = TT_ArraySubscriptLSquare; 208249261Sdim } 209249261Sdim 210249261Sdim while (CurrentToken != NULL) { 211249261Sdim if (CurrentToken->is(tok::r_square)) { 212263509Sdim if (CurrentToken->Next && CurrentToken->Next->is(tok::l_paren) && 213263509Sdim Left->Type == TT_ObjCMethodExpr) { 214249261Sdim // An ObjC method call is rarely followed by an open parenthesis. 215249261Sdim // FIXME: Do we incorrectly label ":" with this? 216249261Sdim StartsObjCMethodExpr = false; 217249261Sdim Left->Type = TT_Unknown; 218249261Sdim } 219249261Sdim if (StartsObjCMethodExpr) { 220249261Sdim CurrentToken->Type = TT_ObjCMethodExpr; 221249261Sdim // determineStarAmpUsage() thinks that '*' '[' is allocating an 222249261Sdim // array of pointers, but if '[' starts a selector then '*' is a 223249261Sdim // binary operator. 224249261Sdim if (Parent != NULL && Parent->Type == TT_PointerOrReference) 225249261Sdim Parent->Type = TT_BinaryOperator; 226249261Sdim } 227249261Sdim Left->MatchingParen = CurrentToken; 228249261Sdim CurrentToken->MatchingParen = Left; 229249261Sdim if (Contexts.back().FirstObjCSelectorName != NULL) 230249261Sdim Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 231249261Sdim Contexts.back().LongestObjCSelectorName; 232249261Sdim next(); 233249261Sdim return true; 234249261Sdim } 235249261Sdim if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace)) 236249261Sdim return false; 237263509Sdim if (CurrentToken->is(tok::colon)) 238263509Sdim ColonFound = true; 239263509Sdim if (CurrentToken->is(tok::comma) && 240263509Sdim (Left->Type == TT_ArraySubscriptLSquare || 241263509Sdim (Left->Type == TT_ObjCMethodExpr && !ColonFound))) 242263509Sdim Left->Type = TT_ArrayInitializerLSquare; 243249261Sdim updateParameterCount(Left, CurrentToken); 244249261Sdim if (!consumeToken()) 245249261Sdim return false; 246249261Sdim } 247249261Sdim return false; 248249261Sdim } 249249261Sdim 250249261Sdim bool parseBrace() { 251252723Sdim if (CurrentToken != NULL) { 252263509Sdim FormatToken *Left = CurrentToken->Previous; 253252723Sdim ScopedContextCreator ContextCreator(*this, tok::l_brace, 1); 254263509Sdim Contexts.back().ColonIsDictLiteral = true; 255263509Sdim 256252723Sdim while (CurrentToken != NULL) { 257252723Sdim if (CurrentToken->is(tok::r_brace)) { 258252723Sdim Left->MatchingParen = CurrentToken; 259252723Sdim CurrentToken->MatchingParen = Left; 260252723Sdim next(); 261252723Sdim return true; 262252723Sdim } 263252723Sdim if (CurrentToken->isOneOf(tok::r_paren, tok::r_square)) 264252723Sdim return false; 265252723Sdim updateParameterCount(Left, CurrentToken); 266263509Sdim if (CurrentToken->is(tok::colon)) 267263509Sdim Left->Type = TT_DictLiteral; 268252723Sdim if (!consumeToken()) 269252723Sdim return false; 270249261Sdim } 271249261Sdim } 272252723Sdim // No closing "}" found, this probably starts a definition. 273252723Sdim Line.StartsDefinition = true; 274249261Sdim return true; 275249261Sdim } 276249261Sdim 277263509Sdim void updateParameterCount(FormatToken *Left, FormatToken *Current) { 278263509Sdim if (Current->is(tok::comma)) { 279249261Sdim ++Left->ParameterCount; 280263509Sdim if (!Left->Role) 281263509Sdim Left->Role.reset(new CommaSeparatedList(Style)); 282263509Sdim Left->Role->CommaFound(Current); 283263509Sdim } else if (Left->ParameterCount == 0 && Current->isNot(tok::comment)) { 284249261Sdim Left->ParameterCount = 1; 285263509Sdim } 286249261Sdim } 287249261Sdim 288249261Sdim bool parseConditional() { 289249261Sdim while (CurrentToken != NULL) { 290249261Sdim if (CurrentToken->is(tok::colon)) { 291249261Sdim CurrentToken->Type = TT_ConditionalExpr; 292249261Sdim next(); 293249261Sdim return true; 294249261Sdim } 295249261Sdim if (!consumeToken()) 296249261Sdim return false; 297249261Sdim } 298249261Sdim return false; 299249261Sdim } 300249261Sdim 301249261Sdim bool parseTemplateDeclaration() { 302249261Sdim if (CurrentToken != NULL && CurrentToken->is(tok::less)) { 303249261Sdim CurrentToken->Type = TT_TemplateOpener; 304249261Sdim next(); 305249261Sdim if (!parseAngle()) 306249261Sdim return false; 307249261Sdim if (CurrentToken != NULL) 308263509Sdim CurrentToken->Previous->ClosesTemplateDeclaration = true; 309249261Sdim return true; 310249261Sdim } 311249261Sdim return false; 312249261Sdim } 313249261Sdim 314249261Sdim bool consumeToken() { 315263509Sdim FormatToken *Tok = CurrentToken; 316249261Sdim next(); 317263509Sdim switch (Tok->Tok.getKind()) { 318249261Sdim case tok::plus: 319249261Sdim case tok::minus: 320263509Sdim if (Tok->Previous == NULL && Line.MustBeDeclaration) 321249261Sdim Tok->Type = TT_ObjCMethodSpecifier; 322249261Sdim break; 323249261Sdim case tok::colon: 324263509Sdim if (Tok->Previous == NULL) 325249261Sdim return false; 326249261Sdim // Colons from ?: are handled in parseConditional(). 327263509Sdim if (Tok->Previous->is(tok::r_paren) && Contexts.size() == 1) { 328249261Sdim Tok->Type = TT_CtorInitializerColon; 329263509Sdim } else if (Contexts.back().ColonIsDictLiteral) { 330263509Sdim Tok->Type = TT_DictLiteral; 331249261Sdim } else if (Contexts.back().ColonIsObjCMethodExpr || 332263509Sdim Line.First->Type == TT_ObjCMethodSpecifier) { 333249261Sdim Tok->Type = TT_ObjCMethodExpr; 334263509Sdim Tok->Previous->Type = TT_ObjCSelectorName; 335263509Sdim if (Tok->Previous->ColumnWidth > 336263509Sdim Contexts.back().LongestObjCSelectorName) { 337263509Sdim Contexts.back().LongestObjCSelectorName = Tok->Previous->ColumnWidth; 338263509Sdim } 339249261Sdim if (Contexts.back().FirstObjCSelectorName == NULL) 340263509Sdim Contexts.back().FirstObjCSelectorName = Tok->Previous; 341249261Sdim } else if (Contexts.back().ColonIsForRangeExpr) { 342249261Sdim Tok->Type = TT_RangeBasedForLoopColon; 343263509Sdim } else if (CurrentToken != NULL && 344263509Sdim CurrentToken->is(tok::numeric_constant)) { 345263509Sdim Tok->Type = TT_BitFieldColon; 346263509Sdim } else if (Contexts.size() == 1 && Line.First->isNot(tok::kw_enum)) { 347249261Sdim Tok->Type = TT_InheritanceColon; 348249261Sdim } else if (Contexts.back().ContextKind == tok::l_paren) { 349249261Sdim Tok->Type = TT_InlineASMColon; 350249261Sdim } 351249261Sdim break; 352249261Sdim case tok::kw_if: 353249261Sdim case tok::kw_while: 354249261Sdim if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) { 355249261Sdim next(); 356263509Sdim if (!parseParens(/*LookForDecls=*/true)) 357249261Sdim return false; 358249261Sdim } 359249261Sdim break; 360249261Sdim case tok::kw_for: 361249261Sdim Contexts.back().ColonIsForRangeExpr = true; 362249261Sdim next(); 363249261Sdim if (!parseParens()) 364249261Sdim return false; 365249261Sdim break; 366249261Sdim case tok::l_paren: 367249261Sdim if (!parseParens()) 368249261Sdim return false; 369263509Sdim if (Line.MustBeDeclaration && Contexts.size() == 1 && 370263509Sdim !Contexts.back().IsExpression) 371249261Sdim Line.MightBeFunctionDecl = true; 372249261Sdim break; 373249261Sdim case tok::l_square: 374249261Sdim if (!parseSquare()) 375249261Sdim return false; 376249261Sdim break; 377249261Sdim case tok::l_brace: 378249261Sdim if (!parseBrace()) 379249261Sdim return false; 380249261Sdim break; 381249261Sdim case tok::less: 382263509Sdim if (Tok->Previous && !Tok->Previous->Tok.isLiteral() && parseAngle()) 383249261Sdim Tok->Type = TT_TemplateOpener; 384249261Sdim else { 385249261Sdim Tok->Type = TT_BinaryOperator; 386249261Sdim CurrentToken = Tok; 387249261Sdim next(); 388249261Sdim } 389249261Sdim break; 390249261Sdim case tok::r_paren: 391249261Sdim case tok::r_square: 392249261Sdim return false; 393249261Sdim case tok::r_brace: 394249261Sdim // Lines can start with '}'. 395263509Sdim if (Tok->Previous != NULL) 396249261Sdim return false; 397249261Sdim break; 398249261Sdim case tok::greater: 399249261Sdim Tok->Type = TT_BinaryOperator; 400249261Sdim break; 401249261Sdim case tok::kw_operator: 402263509Sdim while (CurrentToken && 403263509Sdim !CurrentToken->isOneOf(tok::l_paren, tok::semi, tok::r_paren)) { 404249261Sdim if (CurrentToken->isOneOf(tok::star, tok::amp)) 405249261Sdim CurrentToken->Type = TT_PointerOrReference; 406249261Sdim consumeToken(); 407263509Sdim if (CurrentToken && CurrentToken->Previous->Type == TT_BinaryOperator) 408263509Sdim CurrentToken->Previous->Type = TT_OverloadedOperator; 409249261Sdim } 410263509Sdim if (CurrentToken) { 411249261Sdim CurrentToken->Type = TT_OverloadedOperatorLParen; 412263509Sdim if (CurrentToken->Previous->Type == TT_BinaryOperator) 413263509Sdim CurrentToken->Previous->Type = TT_OverloadedOperator; 414263509Sdim } 415249261Sdim break; 416249261Sdim case tok::question: 417249261Sdim parseConditional(); 418249261Sdim break; 419249261Sdim case tok::kw_template: 420249261Sdim parseTemplateDeclaration(); 421249261Sdim break; 422249261Sdim case tok::identifier: 423263509Sdim if (Line.First->is(tok::kw_for) && 424263509Sdim Tok->Tok.getIdentifierInfo() == &Ident_in) 425249261Sdim Tok->Type = TT_ObjCForIn; 426249261Sdim break; 427249261Sdim case tok::comma: 428249261Sdim if (Contexts.back().FirstStartOfName) 429249261Sdim Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true; 430263509Sdim if (Contexts.back().InCtorInitializer) 431263509Sdim Tok->Type = TT_CtorInitializerComma; 432249261Sdim break; 433249261Sdim default: 434249261Sdim break; 435249261Sdim } 436249261Sdim return true; 437249261Sdim } 438249261Sdim 439249261Sdim void parseIncludeDirective() { 440249261Sdim next(); 441249261Sdim if (CurrentToken != NULL && CurrentToken->is(tok::less)) { 442249261Sdim next(); 443249261Sdim while (CurrentToken != NULL) { 444263509Sdim if (CurrentToken->isNot(tok::comment) || CurrentToken->Next) 445249261Sdim CurrentToken->Type = TT_ImplicitStringLiteral; 446249261Sdim next(); 447249261Sdim } 448249261Sdim } else { 449249261Sdim while (CurrentToken != NULL) { 450249261Sdim if (CurrentToken->is(tok::string_literal)) 451249261Sdim // Mark these string literals as "implicit" literals, too, so that 452249261Sdim // they are not split or line-wrapped. 453249261Sdim CurrentToken->Type = TT_ImplicitStringLiteral; 454249261Sdim next(); 455249261Sdim } 456249261Sdim } 457249261Sdim } 458249261Sdim 459249261Sdim void parseWarningOrError() { 460249261Sdim next(); 461249261Sdim // We still want to format the whitespace left of the first token of the 462249261Sdim // warning or error. 463249261Sdim next(); 464249261Sdim while (CurrentToken != NULL) { 465249261Sdim CurrentToken->Type = TT_ImplicitStringLiteral; 466249261Sdim next(); 467249261Sdim } 468249261Sdim } 469249261Sdim 470249261Sdim void parsePreprocessorDirective() { 471249261Sdim next(); 472249261Sdim if (CurrentToken == NULL) 473249261Sdim return; 474263509Sdim if (CurrentToken->Tok.is(tok::numeric_constant)) { 475263509Sdim CurrentToken->SpacesRequiredBefore = 1; 476263509Sdim return; 477263509Sdim } 478249261Sdim // Hashes in the middle of a line can lead to any strange token 479249261Sdim // sequence. 480263509Sdim if (CurrentToken->Tok.getIdentifierInfo() == NULL) 481249261Sdim return; 482263509Sdim switch (CurrentToken->Tok.getIdentifierInfo()->getPPKeywordID()) { 483249261Sdim case tok::pp_include: 484249261Sdim case tok::pp_import: 485249261Sdim parseIncludeDirective(); 486249261Sdim break; 487249261Sdim case tok::pp_error: 488249261Sdim case tok::pp_warning: 489249261Sdim parseWarningOrError(); 490249261Sdim break; 491252723Sdim case tok::pp_if: 492252723Sdim case tok::pp_elif: 493252723Sdim parseLine(); 494252723Sdim break; 495249261Sdim default: 496249261Sdim break; 497249261Sdim } 498249261Sdim while (CurrentToken != NULL) 499249261Sdim next(); 500249261Sdim } 501249261Sdim 502249261Sdimpublic: 503249261Sdim LineType parseLine() { 504249261Sdim if (CurrentToken->is(tok::hash)) { 505249261Sdim parsePreprocessorDirective(); 506249261Sdim return LT_PreprocessorDirective; 507249261Sdim } 508249261Sdim while (CurrentToken != NULL) { 509249261Sdim if (CurrentToken->is(tok::kw_virtual)) 510249261Sdim KeywordVirtualFound = true; 511249261Sdim if (!consumeToken()) 512249261Sdim return LT_Invalid; 513249261Sdim } 514249261Sdim if (KeywordVirtualFound) 515249261Sdim return LT_VirtualFunctionDecl; 516249261Sdim 517263509Sdim if (Line.First->Type == TT_ObjCMethodSpecifier) { 518249261Sdim if (Contexts.back().FirstObjCSelectorName != NULL) 519249261Sdim Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 520249261Sdim Contexts.back().LongestObjCSelectorName; 521249261Sdim return LT_ObjCMethodDecl; 522249261Sdim } 523249261Sdim 524249261Sdim return LT_Other; 525249261Sdim } 526249261Sdim 527249261Sdimprivate: 528249261Sdim void next() { 529249261Sdim if (CurrentToken != NULL) { 530249261Sdim determineTokenType(*CurrentToken); 531249261Sdim CurrentToken->BindingStrength = Contexts.back().BindingStrength; 532249261Sdim } 533249261Sdim 534263509Sdim if (CurrentToken != NULL) 535263509Sdim CurrentToken = CurrentToken->Next; 536249261Sdim 537263509Sdim if (CurrentToken != NULL) { 538263509Sdim // Reset token type in case we have already looked at it and then 539263509Sdim // recovered from an error (e.g. failure to find the matching >). 540263509Sdim if (CurrentToken->Type != TT_LambdaLSquare && 541263509Sdim CurrentToken->Type != TT_ImplicitStringLiteral) 542263509Sdim CurrentToken->Type = TT_Unknown; 543263509Sdim if (CurrentToken->Role) 544263509Sdim CurrentToken->Role.reset(NULL); 545263509Sdim CurrentToken->FakeLParens.clear(); 546263509Sdim CurrentToken->FakeRParens = 0; 547263509Sdim } 548249261Sdim } 549249261Sdim 550249261Sdim /// \brief A struct to hold information valid in a specific context, e.g. 551249261Sdim /// a pair of parenthesis. 552249261Sdim struct Context { 553249261Sdim Context(tok::TokenKind ContextKind, unsigned BindingStrength, 554249261Sdim bool IsExpression) 555249261Sdim : ContextKind(ContextKind), BindingStrength(BindingStrength), 556249261Sdim LongestObjCSelectorName(0), ColonIsForRangeExpr(false), 557263509Sdim ColonIsDictLiteral(false), ColonIsObjCMethodExpr(false), 558263509Sdim FirstObjCSelectorName(NULL), FirstStartOfName(NULL), 559263509Sdim IsExpression(IsExpression), CanBeExpression(true), 560263509Sdim InCtorInitializer(false) {} 561249261Sdim 562249261Sdim tok::TokenKind ContextKind; 563249261Sdim unsigned BindingStrength; 564249261Sdim unsigned LongestObjCSelectorName; 565249261Sdim bool ColonIsForRangeExpr; 566263509Sdim bool ColonIsDictLiteral; 567249261Sdim bool ColonIsObjCMethodExpr; 568263509Sdim FormatToken *FirstObjCSelectorName; 569263509Sdim FormatToken *FirstStartOfName; 570249261Sdim bool IsExpression; 571249261Sdim bool CanBeExpression; 572263509Sdim bool InCtorInitializer; 573249261Sdim }; 574249261Sdim 575249261Sdim /// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime 576249261Sdim /// of each instance. 577249261Sdim struct ScopedContextCreator { 578249261Sdim AnnotatingParser &P; 579249261Sdim 580249261Sdim ScopedContextCreator(AnnotatingParser &P, tok::TokenKind ContextKind, 581249261Sdim unsigned Increase) 582249261Sdim : P(P) { 583263509Sdim P.Contexts.push_back(Context(ContextKind, 584263509Sdim P.Contexts.back().BindingStrength + Increase, 585263509Sdim P.Contexts.back().IsExpression)); 586249261Sdim } 587249261Sdim 588249261Sdim ~ScopedContextCreator() { P.Contexts.pop_back(); } 589249261Sdim }; 590249261Sdim 591263509Sdim void determineTokenType(FormatToken &Current) { 592263509Sdim if (Current.getPrecedence() == prec::Assignment && 593263509Sdim !Line.First->isOneOf(tok::kw_template, tok::kw_using) && 594263509Sdim (!Current.Previous || Current.Previous->isNot(tok::kw_operator))) { 595249261Sdim Contexts.back().IsExpression = true; 596263509Sdim for (FormatToken *Previous = Current.Previous; 597263509Sdim Previous && !Previous->isOneOf(tok::comma, tok::semi); 598263509Sdim Previous = Previous->Previous) { 599249261Sdim if (Previous->is(tok::r_square)) 600249261Sdim Previous = Previous->MatchingParen; 601249261Sdim if (Previous->Type == TT_BinaryOperator && 602249261Sdim Previous->isOneOf(tok::star, tok::amp)) { 603249261Sdim Previous->Type = TT_PointerOrReference; 604249261Sdim } 605249261Sdim } 606249261Sdim } else if (Current.isOneOf(tok::kw_return, tok::kw_throw) || 607249261Sdim (Current.is(tok::l_paren) && !Line.MustBeDeclaration && 608263509Sdim !Line.InPPDirective && 609263509Sdim (!Current.Previous || 610263509Sdim !Current.Previous->isOneOf(tok::kw_for, tok::kw_catch)))) { 611249261Sdim Contexts.back().IsExpression = true; 612249261Sdim } else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) { 613263509Sdim for (FormatToken *Previous = Current.Previous; 614249261Sdim Previous && Previous->isOneOf(tok::star, tok::amp); 615263509Sdim Previous = Previous->Previous) 616249261Sdim Previous->Type = TT_PointerOrReference; 617263509Sdim } else if (Current.Previous && 618263509Sdim Current.Previous->Type == TT_CtorInitializerColon) { 619249261Sdim Contexts.back().IsExpression = true; 620263509Sdim Contexts.back().InCtorInitializer = true; 621249261Sdim } else if (Current.is(tok::kw_new)) { 622249261Sdim Contexts.back().CanBeExpression = false; 623263509Sdim } else if (Current.is(tok::semi) || Current.is(tok::exclaim)) { 624252723Sdim // This should be the condition or increment in a for-loop. 625252723Sdim Contexts.back().IsExpression = true; 626249261Sdim } 627249261Sdim 628249261Sdim if (Current.Type == TT_Unknown) { 629263509Sdim // Line.MightBeFunctionDecl can only be true after the parentheses of a 630263509Sdim // function declaration have been found. In this case, 'Current' is a 631263509Sdim // trailing token of this declaration and thus cannot be a name. 632263509Sdim if (isStartOfName(Current) && !Line.MightBeFunctionDecl) { 633249261Sdim Contexts.back().FirstStartOfName = &Current; 634249261Sdim Current.Type = TT_StartOfName; 635263509Sdim } else if (Current.is(tok::kw_auto)) { 636263509Sdim AutoFound = true; 637263509Sdim } else if (Current.is(tok::arrow) && AutoFound && 638263509Sdim Line.MustBeDeclaration) { 639263509Sdim Current.Type = TT_TrailingReturnArrow; 640249261Sdim } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { 641249261Sdim Current.Type = 642263509Sdim determineStarAmpUsage(Current, Contexts.back().CanBeExpression && 643263509Sdim Contexts.back().IsExpression); 644249261Sdim } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) { 645249261Sdim Current.Type = determinePlusMinusCaretUsage(Current); 646249261Sdim } else if (Current.isOneOf(tok::minusminus, tok::plusplus)) { 647249261Sdim Current.Type = determineIncrementUsage(Current); 648249261Sdim } else if (Current.is(tok::exclaim)) { 649249261Sdim Current.Type = TT_UnaryOperator; 650263509Sdim } else if (Current.isBinaryOperator() && 651263509Sdim (!Current.Previous || 652263509Sdim Current.Previous->isNot(tok::l_square))) { 653249261Sdim Current.Type = TT_BinaryOperator; 654249261Sdim } else if (Current.is(tok::comment)) { 655263509Sdim if (Current.TokenText.startswith("//")) 656249261Sdim Current.Type = TT_LineComment; 657249261Sdim else 658249261Sdim Current.Type = TT_BlockComment; 659249261Sdim } else if (Current.is(tok::r_paren)) { 660263509Sdim FormatToken *LeftOfParens = NULL; 661263509Sdim if (Current.MatchingParen) 662263509Sdim LeftOfParens = Current.MatchingParen->getPreviousNonComment(); 663263509Sdim bool IsCast = false; 664263509Sdim bool ParensAreEmpty = Current.Previous == Current.MatchingParen; 665263509Sdim bool ParensAreType = !Current.Previous || 666263509Sdim Current.Previous->Type == TT_PointerOrReference || 667263509Sdim Current.Previous->Type == TT_TemplateCloser || 668263509Sdim isSimpleTypeSpecifier(*Current.Previous); 669249261Sdim bool ParensCouldEndDecl = 670263509Sdim Current.Next && 671263509Sdim Current.Next->isOneOf(tok::equal, tok::semi, tok::l_brace); 672249261Sdim bool IsSizeOfOrAlignOf = 673263509Sdim LeftOfParens && 674263509Sdim LeftOfParens->isOneOf(tok::kw_sizeof, tok::kw_alignof); 675263509Sdim if (ParensAreType && !ParensCouldEndDecl && !IsSizeOfOrAlignOf && 676263509Sdim (Contexts.back().IsExpression || 677263509Sdim (Current.Next && Current.Next->isBinaryOperator()))) 678263509Sdim IsCast = true; 679263509Sdim if (Current.Next && Current.Next->isNot(tok::string_literal) && 680263509Sdim (Current.Next->Tok.isLiteral() || 681263509Sdim Current.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof))) 682263509Sdim IsCast = true; 683263509Sdim // If there is an identifier after the (), it is likely a cast, unless 684263509Sdim // there is also an identifier before the (). 685263509Sdim if (LeftOfParens && (LeftOfParens->Tok.getIdentifierInfo() == NULL || 686263509Sdim LeftOfParens->is(tok::kw_return)) && 687263509Sdim LeftOfParens->Type != TT_OverloadedOperator && 688263509Sdim LeftOfParens->Type != TT_TemplateCloser && Current.Next && 689263509Sdim Current.Next->is(tok::identifier)) 690263509Sdim IsCast = true; 691263509Sdim if (IsCast && !ParensAreEmpty) 692249261Sdim Current.Type = TT_CastRParen; 693263509Sdim } else if (Current.is(tok::at) && Current.Next) { 694263509Sdim switch (Current.Next->Tok.getObjCKeywordID()) { 695249261Sdim case tok::objc_interface: 696249261Sdim case tok::objc_implementation: 697249261Sdim case tok::objc_protocol: 698249261Sdim Current.Type = TT_ObjCDecl; 699249261Sdim break; 700249261Sdim case tok::objc_property: 701249261Sdim Current.Type = TT_ObjCProperty; 702249261Sdim break; 703249261Sdim default: 704249261Sdim break; 705249261Sdim } 706263509Sdim } else if (Current.is(tok::period)) { 707263509Sdim FormatToken *PreviousNoComment = Current.getPreviousNonComment(); 708263509Sdim if (PreviousNoComment && 709263509Sdim PreviousNoComment->isOneOf(tok::comma, tok::l_brace)) 710263509Sdim Current.Type = TT_DesignatedInitializerPeriod; 711249261Sdim } 712249261Sdim } 713249261Sdim } 714249261Sdim 715263509Sdim /// \brief Take a guess at whether \p Tok starts a name of a function or 716263509Sdim /// variable declaration. 717263509Sdim /// 718263509Sdim /// This is a heuristic based on whether \p Tok is an identifier following 719263509Sdim /// something that is likely a type. 720263509Sdim bool isStartOfName(const FormatToken &Tok) { 721263509Sdim if (Tok.isNot(tok::identifier) || Tok.Previous == NULL) 722263509Sdim return false; 723263509Sdim 724263509Sdim // Skip "const" as it does not have an influence on whether this is a name. 725263509Sdim FormatToken *PreviousNotConst = Tok.Previous; 726263509Sdim while (PreviousNotConst != NULL && PreviousNotConst->is(tok::kw_const)) 727263509Sdim PreviousNotConst = PreviousNotConst->Previous; 728263509Sdim 729263509Sdim if (PreviousNotConst == NULL) 730263509Sdim return false; 731263509Sdim 732263509Sdim bool IsPPKeyword = PreviousNotConst->is(tok::identifier) && 733263509Sdim PreviousNotConst->Previous && 734263509Sdim PreviousNotConst->Previous->is(tok::hash); 735263509Sdim 736263509Sdim if (PreviousNotConst->Type == TT_TemplateCloser) 737263509Sdim return PreviousNotConst && PreviousNotConst->MatchingParen && 738263509Sdim PreviousNotConst->MatchingParen->Previous && 739263509Sdim PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template); 740263509Sdim 741263509Sdim return (!IsPPKeyword && PreviousNotConst->is(tok::identifier)) || 742263509Sdim PreviousNotConst->Type == TT_PointerOrReference || 743263509Sdim isSimpleTypeSpecifier(*PreviousNotConst); 744263509Sdim } 745263509Sdim 746249261Sdim /// \brief Return the type of the given token assuming it is * or &. 747263509Sdim TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression) { 748263509Sdim const FormatToken *PrevToken = Tok.getPreviousNonComment(); 749249261Sdim if (PrevToken == NULL) 750249261Sdim return TT_UnaryOperator; 751249261Sdim 752263509Sdim const FormatToken *NextToken = Tok.getNextNonComment(); 753249261Sdim if (NextToken == NULL) 754249261Sdim return TT_Unknown; 755249261Sdim 756263509Sdim if (PrevToken->is(tok::coloncolon) || 757263509Sdim (PrevToken->is(tok::l_paren) && !IsExpression)) 758249261Sdim return TT_PointerOrReference; 759249261Sdim 760249261Sdim if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace, 761249261Sdim tok::comma, tok::semi, tok::kw_return, tok::colon, 762263509Sdim tok::equal, tok::kw_delete, tok::kw_sizeof) || 763249261Sdim PrevToken->Type == TT_BinaryOperator || 764249261Sdim PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen) 765249261Sdim return TT_UnaryOperator; 766249261Sdim 767249261Sdim if (NextToken->is(tok::l_square)) 768249261Sdim return TT_PointerOrReference; 769249261Sdim 770263509Sdim if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen && 771263509Sdim PrevToken->MatchingParen->Previous && 772263509Sdim PrevToken->MatchingParen->Previous->is(tok::kw_typeof)) 773263509Sdim return TT_PointerOrReference; 774263509Sdim 775263509Sdim if (PrevToken->Tok.isLiteral() || 776249261Sdim PrevToken->isOneOf(tok::r_paren, tok::r_square) || 777263509Sdim NextToken->Tok.isLiteral() || NextToken->isUnaryOperator()) 778249261Sdim return TT_BinaryOperator; 779249261Sdim 780249261Sdim // It is very unlikely that we are going to find a pointer or reference type 781249261Sdim // definition on the RHS of an assignment. 782249261Sdim if (IsExpression) 783249261Sdim return TT_BinaryOperator; 784249261Sdim 785249261Sdim return TT_PointerOrReference; 786249261Sdim } 787249261Sdim 788263509Sdim TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) { 789263509Sdim const FormatToken *PrevToken = Tok.getPreviousNonComment(); 790263509Sdim if (PrevToken == NULL || PrevToken->Type == TT_CastRParen) 791249261Sdim return TT_UnaryOperator; 792249261Sdim 793249261Sdim // Use heuristics to recognize unary operators. 794249261Sdim if (PrevToken->isOneOf(tok::equal, tok::l_paren, tok::comma, tok::l_square, 795249261Sdim tok::question, tok::colon, tok::kw_return, 796249261Sdim tok::kw_case, tok::at, tok::l_brace)) 797249261Sdim return TT_UnaryOperator; 798249261Sdim 799249261Sdim // There can't be two consecutive binary operators. 800249261Sdim if (PrevToken->Type == TT_BinaryOperator) 801249261Sdim return TT_UnaryOperator; 802249261Sdim 803249261Sdim // Fall back to marking the token as binary operator. 804249261Sdim return TT_BinaryOperator; 805249261Sdim } 806249261Sdim 807249261Sdim /// \brief Determine whether ++/-- are pre- or post-increments/-decrements. 808263509Sdim TokenType determineIncrementUsage(const FormatToken &Tok) { 809263509Sdim const FormatToken *PrevToken = Tok.getPreviousNonComment(); 810263509Sdim if (PrevToken == NULL || PrevToken->Type == TT_CastRParen) 811249261Sdim return TT_UnaryOperator; 812249261Sdim if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier)) 813249261Sdim return TT_TrailingUnaryOperator; 814249261Sdim 815249261Sdim return TT_UnaryOperator; 816249261Sdim } 817249261Sdim 818249261Sdim // FIXME: This is copy&pasted from Sema. Put it in a common place and remove 819249261Sdim // duplication. 820249261Sdim /// \brief Determine whether the token kind starts a simple-type-specifier. 821263509Sdim bool isSimpleTypeSpecifier(const FormatToken &Tok) const { 822263509Sdim switch (Tok.Tok.getKind()) { 823249261Sdim case tok::kw_short: 824249261Sdim case tok::kw_long: 825249261Sdim case tok::kw___int64: 826249261Sdim case tok::kw___int128: 827249261Sdim case tok::kw_signed: 828249261Sdim case tok::kw_unsigned: 829249261Sdim case tok::kw_void: 830249261Sdim case tok::kw_char: 831249261Sdim case tok::kw_int: 832249261Sdim case tok::kw_half: 833249261Sdim case tok::kw_float: 834249261Sdim case tok::kw_double: 835249261Sdim case tok::kw_wchar_t: 836249261Sdim case tok::kw_bool: 837249261Sdim case tok::kw___underlying_type: 838249261Sdim case tok::annot_typename: 839249261Sdim case tok::kw_char16_t: 840249261Sdim case tok::kw_char32_t: 841249261Sdim case tok::kw_typeof: 842249261Sdim case tok::kw_decltype: 843263509Sdim return true; 844249261Sdim default: 845263509Sdim return false; 846249261Sdim } 847249261Sdim } 848249261Sdim 849249261Sdim SmallVector<Context, 8> Contexts; 850249261Sdim 851263509Sdim const FormatStyle &Style; 852249261Sdim AnnotatedLine &Line; 853263509Sdim FormatToken *CurrentToken; 854249261Sdim bool KeywordVirtualFound; 855263509Sdim bool AutoFound; 856249261Sdim IdentifierInfo &Ident_in; 857249261Sdim}; 858249261Sdim 859263509Sdimstatic int PrecedenceUnaryOperator = prec::PointerToMember + 1; 860263509Sdimstatic int PrecedenceArrowAndPeriod = prec::PointerToMember + 2; 861263509Sdim 862249261Sdim/// \brief Parses binary expressions by inserting fake parenthesis based on 863249261Sdim/// operator precedence. 864249261Sdimclass ExpressionParser { 865249261Sdimpublic: 866263509Sdim ExpressionParser(AnnotatedLine &Line) : Current(Line.First) { 867263509Sdim // Skip leading "}", e.g. in "} else if (...) {". 868263509Sdim if (Current->is(tok::r_brace)) 869263509Sdim next(); 870263509Sdim } 871249261Sdim 872249261Sdim /// \brief Parse expressions with the given operatore precedence. 873249261Sdim void parse(int Precedence = 0) { 874263509Sdim // Skip 'return' and ObjC selector colons as they are not part of a binary 875263509Sdim // expression. 876263509Sdim while (Current && 877263509Sdim (Current->is(tok::kw_return) || 878263509Sdim (Current->is(tok::colon) && Current->Type == TT_ObjCMethodExpr))) 879263509Sdim next(); 880263509Sdim 881263509Sdim if (Current == NULL || Precedence > PrecedenceArrowAndPeriod) 882249261Sdim return; 883249261Sdim 884263509Sdim // Conditional expressions need to be parsed separately for proper nesting. 885263509Sdim if (Precedence == prec::Conditional) { 886263509Sdim parseConditionalExpr(); 887263509Sdim return; 888249261Sdim } 889249261Sdim 890263509Sdim // Parse unary operators, which all have a higher precedence than binary 891263509Sdim // operators. 892263509Sdim if (Precedence == PrecedenceUnaryOperator) { 893263509Sdim parseUnaryOperator(); 894263509Sdim return; 895263509Sdim } 896249261Sdim 897263509Sdim FormatToken *Start = Current; 898263509Sdim FormatToken *LatestOperator = NULL; 899263509Sdim 900249261Sdim while (Current) { 901249261Sdim // Consume operators with higher precedence. 902252723Sdim parse(Precedence + 1); 903249261Sdim 904263509Sdim int CurrentPrecedence = getCurrentPrecedence(); 905249261Sdim 906263509Sdim if (Current && Current->Type == TT_ObjCSelectorName && 907263509Sdim Precedence == CurrentPrecedence) 908263509Sdim Start = Current; 909263509Sdim 910249261Sdim // At the end of the line or when an operator with higher precedence is 911249261Sdim // found, insert fake parenthesis and return. 912252723Sdim if (Current == NULL || Current->closesScope() || 913263509Sdim (CurrentPrecedence != -1 && CurrentPrecedence < Precedence)) { 914263509Sdim if (LatestOperator) { 915263509Sdim if (Precedence == PrecedenceArrowAndPeriod) { 916263509Sdim LatestOperator->LastInChainOfCalls = true; 917263509Sdim // Call expressions don't have a binary operator precedence. 918263509Sdim addFakeParenthesis(Start, prec::Unknown); 919263509Sdim } else { 920263509Sdim addFakeParenthesis(Start, prec::Level(Precedence)); 921263509Sdim } 922249261Sdim } 923249261Sdim return; 924249261Sdim } 925249261Sdim 926249261Sdim // Consume scopes: (), [], <> and {} 927252723Sdim if (Current->opensScope()) { 928252723Sdim while (Current && !Current->closesScope()) { 929249261Sdim next(); 930249261Sdim parse(); 931249261Sdim } 932249261Sdim next(); 933249261Sdim } else { 934249261Sdim // Operator found. 935249261Sdim if (CurrentPrecedence == Precedence) 936263509Sdim LatestOperator = Current; 937249261Sdim 938249261Sdim next(); 939249261Sdim } 940249261Sdim } 941249261Sdim } 942249261Sdim 943249261Sdimprivate: 944263509Sdim /// \brief Gets the precedence (+1) of the given token for binary operators 945263509Sdim /// and other tokens that we treat like binary operators. 946263509Sdim int getCurrentPrecedence() { 947263509Sdim if (Current) { 948263509Sdim if (Current->Type == TT_ConditionalExpr) 949263509Sdim return prec::Conditional; 950263509Sdim else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon || 951263509Sdim Current->Type == TT_ObjCSelectorName) 952263509Sdim return 0; 953263509Sdim else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma)) 954263509Sdim return Current->getPrecedence(); 955263509Sdim else if (Current->isOneOf(tok::period, tok::arrow)) 956263509Sdim return PrecedenceArrowAndPeriod; 957263509Sdim } 958263509Sdim return -1; 959263509Sdim } 960263509Sdim 961263509Sdim void addFakeParenthesis(FormatToken *Start, prec::Level Precedence) { 962263509Sdim Start->FakeLParens.push_back(Precedence); 963263509Sdim if (Precedence > prec::Unknown) 964263509Sdim Start->StartsBinaryExpression = true; 965263509Sdim if (Current) { 966263509Sdim ++Current->Previous->FakeRParens; 967263509Sdim if (Precedence > prec::Unknown) 968263509Sdim Current->Previous->EndsBinaryExpression = true; 969263509Sdim } 970263509Sdim } 971263509Sdim 972263509Sdim /// \brief Parse unary operator expressions and surround them with fake 973263509Sdim /// parentheses if appropriate. 974263509Sdim void parseUnaryOperator() { 975263509Sdim if (Current == NULL || Current->Type != TT_UnaryOperator) { 976263509Sdim parse(PrecedenceArrowAndPeriod); 977263509Sdim return; 978263509Sdim } 979263509Sdim 980263509Sdim FormatToken *Start = Current; 981263509Sdim next(); 982263509Sdim parseUnaryOperator(); 983263509Sdim 984263509Sdim // The actual precedence doesn't matter. 985263509Sdim addFakeParenthesis(Start, prec::Unknown); 986263509Sdim } 987263509Sdim 988263509Sdim void parseConditionalExpr() { 989263509Sdim FormatToken *Start = Current; 990263509Sdim parse(prec::LogicalOr); 991263509Sdim if (!Current || !Current->is(tok::question)) 992263509Sdim return; 993263509Sdim next(); 994263509Sdim parse(prec::LogicalOr); 995263509Sdim if (!Current || Current->Type != TT_ConditionalExpr) 996263509Sdim return; 997263509Sdim next(); 998263509Sdim parseConditionalExpr(); 999263509Sdim addFakeParenthesis(Start, prec::Conditional); 1000263509Sdim } 1001263509Sdim 1002249261Sdim void next() { 1003263509Sdim if (Current) 1004263509Sdim Current = Current->Next; 1005263509Sdim while (Current && Current->isTrailingComment()) 1006263509Sdim Current = Current->Next; 1007249261Sdim } 1008249261Sdim 1009263509Sdim FormatToken *Current; 1010249261Sdim}; 1011249261Sdim 1012263509Sdim} // end anonymous namespace 1013263509Sdim 1014263509Sdimvoid 1015263509SdimTokenAnnotator::setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines) { 1016263509Sdim const AnnotatedLine *NextNonCommentLine = NULL; 1017263509Sdim for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(), 1018263509Sdim E = Lines.rend(); 1019263509Sdim I != E; ++I) { 1020263509Sdim if (NextNonCommentLine && (*I)->First->is(tok::comment) && 1021263509Sdim (*I)->First->Next == NULL) 1022263509Sdim (*I)->Level = NextNonCommentLine->Level; 1023263509Sdim else 1024263509Sdim NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : NULL; 1025263509Sdim 1026263509Sdim setCommentLineLevels((*I)->Children); 1027263509Sdim } 1028263509Sdim} 1029263509Sdim 1030249261Sdimvoid TokenAnnotator::annotate(AnnotatedLine &Line) { 1031263509Sdim for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(), 1032263509Sdim E = Line.Children.end(); 1033263509Sdim I != E; ++I) { 1034263509Sdim annotate(**I); 1035263509Sdim } 1036263509Sdim AnnotatingParser Parser(Style, Line, Ident_in); 1037249261Sdim Line.Type = Parser.parseLine(); 1038249261Sdim if (Line.Type == LT_Invalid) 1039249261Sdim return; 1040249261Sdim 1041249261Sdim ExpressionParser ExprParser(Line); 1042249261Sdim ExprParser.parse(); 1043249261Sdim 1044263509Sdim if (Line.First->Type == TT_ObjCMethodSpecifier) 1045249261Sdim Line.Type = LT_ObjCMethodDecl; 1046263509Sdim else if (Line.First->Type == TT_ObjCDecl) 1047249261Sdim Line.Type = LT_ObjCDecl; 1048263509Sdim else if (Line.First->Type == TT_ObjCProperty) 1049249261Sdim Line.Type = LT_ObjCProperty; 1050249261Sdim 1051263509Sdim Line.First->SpacesRequiredBefore = 1; 1052263509Sdim Line.First->CanBreakBefore = Line.First->MustBreakBefore; 1053249261Sdim} 1054249261Sdim 1055249261Sdimvoid TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { 1056263509Sdim Line.First->TotalLength = 1057263509Sdim Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth; 1058263509Sdim if (!Line.First->Next) 1059249261Sdim return; 1060263509Sdim FormatToken *Current = Line.First->Next; 1061263509Sdim bool InFunctionDecl = Line.MightBeFunctionDecl; 1062249261Sdim while (Current != NULL) { 1063249261Sdim if (Current->Type == TT_LineComment) 1064249261Sdim Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments; 1065263509Sdim else if (Current->SpacesRequiredBefore == 0 && 1066263509Sdim spaceRequiredBefore(Line, *Current)) 1067263509Sdim Current->SpacesRequiredBefore = 1; 1068249261Sdim 1069263509Sdim Current->MustBreakBefore = 1070263509Sdim Current->MustBreakBefore || mustBreakBefore(Line, *Current); 1071263509Sdim 1072249261Sdim Current->CanBreakBefore = 1073249261Sdim Current->MustBreakBefore || canBreakBefore(Line, *Current); 1074263509Sdim if (Current->MustBreakBefore || !Current->Children.empty() || 1075263509Sdim Current->IsMultiline) 1076263509Sdim Current->TotalLength = Current->Previous->TotalLength + Style.ColumnLimit; 1077249261Sdim else 1078263509Sdim Current->TotalLength = Current->Previous->TotalLength + 1079263509Sdim Current->ColumnWidth + 1080263509Sdim Current->SpacesRequiredBefore; 1081263509Sdim 1082263509Sdim if (Current->Type == TT_CtorInitializerColon) 1083263509Sdim InFunctionDecl = false; 1084263509Sdim 1085249261Sdim // FIXME: Only calculate this if CanBreakBefore is true once static 1086249261Sdim // initializers etc. are sorted out. 1087249261Sdim // FIXME: Move magic numbers to a better place. 1088263509Sdim Current->SplitPenalty = 20 * Current->BindingStrength + 1089263509Sdim splitPenalty(Line, *Current, InFunctionDecl); 1090249261Sdim 1091263509Sdim Current = Current->Next; 1092249261Sdim } 1093252723Sdim 1094263509Sdim calculateUnbreakableTailLengths(Line); 1095263509Sdim for (Current = Line.First; Current != NULL; Current = Current->Next) { 1096263509Sdim if (Current->Role) 1097263509Sdim Current->Role->precomputeFormattingInfos(Current); 1098263509Sdim } 1099263509Sdim 1100263509Sdim DEBUG({ printDebugInfo(Line); }); 1101263509Sdim 1102263509Sdim for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(), 1103263509Sdim E = Line.Children.end(); 1104263509Sdim I != E; ++I) { 1105263509Sdim calculateFormattingInformation(**I); 1106263509Sdim } 1107249261Sdim} 1108249261Sdim 1109263509Sdimvoid TokenAnnotator::calculateUnbreakableTailLengths(AnnotatedLine &Line) { 1110263509Sdim unsigned UnbreakableTailLength = 0; 1111263509Sdim FormatToken *Current = Line.Last; 1112263509Sdim while (Current != NULL) { 1113263509Sdim Current->UnbreakableTailLength = UnbreakableTailLength; 1114263509Sdim if (Current->CanBreakBefore || 1115263509Sdim Current->isOneOf(tok::comment, tok::string_literal)) { 1116263509Sdim UnbreakableTailLength = 0; 1117263509Sdim } else { 1118263509Sdim UnbreakableTailLength += 1119263509Sdim Current->ColumnWidth + Current->SpacesRequiredBefore; 1120263509Sdim } 1121263509Sdim Current = Current->Previous; 1122263509Sdim } 1123263509Sdim} 1124263509Sdim 1125249261Sdimunsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, 1126263509Sdim const FormatToken &Tok, 1127263509Sdim bool InFunctionDecl) { 1128263509Sdim const FormatToken &Left = *Tok.Previous; 1129263509Sdim const FormatToken &Right = Tok; 1130249261Sdim 1131263509Sdim if (Left.is(tok::semi)) 1132263509Sdim return 0; 1133263509Sdim if (Left.is(tok::comma)) 1134263509Sdim return 1; 1135263509Sdim if (Right.is(tok::l_square)) 1136263509Sdim return 150; 1137263509Sdim 1138263509Sdim if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator)) { 1139263509Sdim if (Line.First->is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt) 1140249261Sdim return 3; 1141263509Sdim if (Left.Type == TT_StartOfName) 1142263509Sdim return 20; 1143263509Sdim if (InFunctionDecl && Right.BindingStrength == 1) 1144249261Sdim // FIXME: Clean up hack of using BindingStrength to find top-level names. 1145249261Sdim return Style.PenaltyReturnTypeOnItsOwnLine; 1146263509Sdim return 200; 1147249261Sdim } 1148249261Sdim if (Left.is(tok::equal) && Right.is(tok::l_brace)) 1149249261Sdim return 150; 1150263509Sdim if (Left.Type == TT_CastRParen) 1151263509Sdim return 100; 1152249261Sdim if (Left.is(tok::coloncolon)) 1153249261Sdim return 500; 1154252723Sdim if (Left.isOneOf(tok::kw_class, tok::kw_struct)) 1155252723Sdim return 5000; 1156249261Sdim 1157249261Sdim if (Left.Type == TT_RangeBasedForLoopColon || 1158249261Sdim Left.Type == TT_InheritanceColon) 1159249261Sdim return 2; 1160249261Sdim 1161263509Sdim if (Right.isMemberAccess()) { 1162249261Sdim if (Left.isOneOf(tok::r_paren, tok::r_square) && Left.MatchingParen && 1163249261Sdim Left.MatchingParen->ParameterCount > 0) 1164249261Sdim return 20; // Should be smaller than breaking at a nested comma. 1165249261Sdim return 150; 1166249261Sdim } 1167249261Sdim 1168263509Sdim // Breaking before a trailing 'const' or not-function-like annotation is bad. 1169263509Sdim if (Left.is(tok::r_paren) && Line.Type != LT_ObjCProperty && 1170263509Sdim (Right.is(tok::kw_const) || (Right.is(tok::identifier) && Right.Next && 1171263509Sdim Right.Next->isNot(tok::l_paren)))) 1172263509Sdim return 100; 1173263509Sdim 1174249261Sdim // In for-loops, prefer breaking at ',' and ';'. 1175263509Sdim if (Line.First->is(tok::kw_for) && Left.is(tok::equal)) 1176249261Sdim return 4; 1177249261Sdim 1178249261Sdim // In Objective-C method expressions, prefer breaking before "param:" over 1179249261Sdim // breaking after it. 1180249261Sdim if (Right.Type == TT_ObjCSelectorName) 1181249261Sdim return 0; 1182249261Sdim if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr) 1183263509Sdim return 50; 1184249261Sdim 1185263509Sdim if (Left.is(tok::l_paren) && InFunctionDecl) 1186252723Sdim return 100; 1187252723Sdim if (Left.opensScope()) 1188263509Sdim return Left.ParameterCount > 1 ? Style.PenaltyBreakBeforeFirstCallParameter 1189263509Sdim : 19; 1190249261Sdim 1191249261Sdim if (Right.is(tok::lessless)) { 1192249261Sdim if (Left.is(tok::string_literal)) { 1193263509Sdim StringRef Content = Left.TokenText; 1194263509Sdim if (Content.startswith("\"")) 1195263509Sdim Content = Content.drop_front(1); 1196263509Sdim if (Content.endswith("\"")) 1197263509Sdim Content = Content.drop_back(1); 1198263509Sdim Content = Content.trim(); 1199249261Sdim if (Content.size() > 1 && 1200249261Sdim (Content.back() == ':' || Content.back() == '=')) 1201263509Sdim return 25; 1202249261Sdim } 1203263509Sdim return 1; // Breaking at a << is really cheap. 1204249261Sdim } 1205249261Sdim if (Left.Type == TT_ConditionalExpr) 1206249261Sdim return prec::Conditional; 1207263509Sdim prec::Level Level = Left.getPrecedence(); 1208249261Sdim 1209249261Sdim if (Level != prec::Unknown) 1210249261Sdim return Level; 1211249261Sdim 1212249261Sdim return 3; 1213249261Sdim} 1214249261Sdim 1215249261Sdimbool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, 1216263509Sdim const FormatToken &Left, 1217263509Sdim const FormatToken &Right) { 1218249261Sdim if (Right.is(tok::hashhash)) 1219249261Sdim return Left.is(tok::hash); 1220249261Sdim if (Left.isOneOf(tok::hashhash, tok::hash)) 1221249261Sdim return Right.is(tok::hash); 1222263509Sdim if (Left.is(tok::l_paren) && Right.is(tok::r_paren)) 1223263509Sdim return Style.SpaceInEmptyParentheses; 1224263509Sdim if (Left.is(tok::l_paren) || Right.is(tok::r_paren)) 1225263509Sdim return (Right.Type == TT_CastRParen || 1226263509Sdim (Left.MatchingParen && Left.MatchingParen->Type == TT_CastRParen)) 1227263509Sdim ? Style.SpacesInCStyleCastParentheses 1228263509Sdim : Style.SpacesInParentheses; 1229263509Sdim if (Style.SpacesInAngles && 1230263509Sdim ((Left.Type == TT_TemplateOpener) != (Right.Type == TT_TemplateCloser))) 1231263509Sdim return true; 1232263509Sdim if (Right.isOneOf(tok::semi, tok::comma)) 1233249261Sdim return false; 1234249261Sdim if (Right.is(tok::less) && 1235249261Sdim (Left.is(tok::kw_template) || 1236249261Sdim (Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList))) 1237249261Sdim return true; 1238249261Sdim if (Left.is(tok::arrow) || Right.is(tok::arrow)) 1239249261Sdim return false; 1240249261Sdim if (Left.isOneOf(tok::exclaim, tok::tilde)) 1241249261Sdim return false; 1242249261Sdim if (Left.is(tok::at) && 1243249261Sdim Right.isOneOf(tok::identifier, tok::string_literal, tok::char_constant, 1244249261Sdim tok::numeric_constant, tok::l_paren, tok::l_brace, 1245249261Sdim tok::kw_true, tok::kw_false)) 1246249261Sdim return false; 1247249261Sdim if (Left.is(tok::coloncolon)) 1248249261Sdim return false; 1249249261Sdim if (Right.is(tok::coloncolon)) 1250263509Sdim return (Left.is(tok::less) && Style.Standard == FormatStyle::LS_Cpp03) || 1251263509Sdim !Left.isOneOf(tok::identifier, tok::greater, tok::l_paren, 1252263509Sdim tok::r_paren, tok::less); 1253249261Sdim if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) 1254249261Sdim return false; 1255263509Sdim if (Right.is(tok::ellipsis)) 1256263509Sdim return Left.Tok.isLiteral(); 1257263509Sdim if (Left.is(tok::l_square) && Right.is(tok::amp)) 1258263509Sdim return false; 1259249261Sdim if (Right.Type == TT_PointerOrReference) 1260263509Sdim return Left.Tok.isLiteral() || 1261249261Sdim ((Left.Type != TT_PointerOrReference) && Left.isNot(tok::l_paren) && 1262249261Sdim !Style.PointerBindsToType); 1263263509Sdim if (Right.Type == TT_FunctionTypeLParen && Left.isNot(tok::l_paren) && 1264263509Sdim (Left.Type != TT_PointerOrReference || Style.PointerBindsToType)) 1265263509Sdim return true; 1266249261Sdim if (Left.Type == TT_PointerOrReference) 1267263509Sdim return Right.Tok.isLiteral() || Right.Type == TT_BlockComment || 1268249261Sdim ((Right.Type != TT_PointerOrReference) && 1269249261Sdim Right.isNot(tok::l_paren) && Style.PointerBindsToType && 1270263509Sdim Left.Previous && 1271263509Sdim !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon)); 1272249261Sdim if (Right.is(tok::star) && Left.is(tok::l_paren)) 1273249261Sdim return false; 1274249261Sdim if (Left.is(tok::l_square)) 1275263509Sdim return Left.Type == TT_ArrayInitializerLSquare && 1276263509Sdim Right.isNot(tok::r_square); 1277249261Sdim if (Right.is(tok::r_square)) 1278263509Sdim return Right.MatchingParen && 1279263509Sdim Right.MatchingParen->Type == TT_ArrayInitializerLSquare; 1280263509Sdim if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr && 1281263509Sdim Right.Type != TT_LambdaLSquare && Left.isNot(tok::numeric_constant)) 1282249261Sdim return false; 1283249261Sdim if (Left.is(tok::colon)) 1284249261Sdim return Left.Type != TT_ObjCMethodExpr; 1285249261Sdim if (Right.is(tok::colon)) 1286263509Sdim return Right.Type != TT_ObjCMethodExpr && !Left.is(tok::question); 1287249261Sdim if (Right.is(tok::l_paren)) { 1288263509Sdim if (Left.is(tok::r_paren) && Left.MatchingParen && 1289263509Sdim Left.MatchingParen->Previous && 1290263509Sdim Left.MatchingParen->Previous->is(tok::kw___attribute)) 1291263509Sdim return true; 1292249261Sdim return Line.Type == LT_ObjCDecl || 1293263509Sdim Left.isOneOf(tok::kw_return, tok::kw_new, tok::kw_delete, 1294263509Sdim tok::semi) || 1295263509Sdim (Style.SpaceAfterControlStatementKeyword && 1296263509Sdim Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, 1297263509Sdim tok::kw_catch)); 1298249261Sdim } 1299263509Sdim if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword) 1300249261Sdim return false; 1301249261Sdim if (Left.is(tok::l_brace) && Right.is(tok::r_brace)) 1302263509Sdim return !Left.Children.empty(); // No spaces in "{}". 1303263509Sdim if (Left.is(tok::l_brace) || Right.is(tok::r_brace)) 1304263509Sdim return !Style.Cpp11BracedListStyle; 1305263509Sdim if (Right.Type == TT_UnaryOperator) 1306263509Sdim return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) && 1307263509Sdim (Left.isNot(tok::colon) || Left.Type != TT_ObjCMethodExpr); 1308263509Sdim if (Left.isOneOf(tok::identifier, tok::greater, tok::r_square) && 1309263509Sdim Right.is(tok::l_brace) && Right.getNextNonComment() && 1310263509Sdim Right.BlockKind != BK_Block) 1311249261Sdim return false; 1312263509Sdim if (Left.is(tok::period) || Right.is(tok::period)) 1313252723Sdim return false; 1314263509Sdim if (Left.Type == TT_BlockComment && Left.TokenText.endswith("=*/")) 1315263509Sdim return false; 1316263509Sdim if (Right.is(tok::hash) && Left.is(tok::identifier) && Left.TokenText == "L") 1317263509Sdim return false; 1318249261Sdim return true; 1319249261Sdim} 1320249261Sdim 1321249261Sdimbool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, 1322263509Sdim const FormatToken &Tok) { 1323263509Sdim if (Tok.Tok.getIdentifierInfo() && Tok.Previous->Tok.getIdentifierInfo()) 1324249261Sdim return true; // Never ever merge two identifiers. 1325263509Sdim if (Tok.Previous->Type == TT_ImplicitStringLiteral) 1326263509Sdim return Tok.WhitespaceRange.getBegin() != Tok.WhitespaceRange.getEnd(); 1327249261Sdim if (Line.Type == LT_ObjCMethodDecl) { 1328263509Sdim if (Tok.Previous->Type == TT_ObjCMethodSpecifier) 1329249261Sdim return true; 1330263509Sdim if (Tok.Previous->is(tok::r_paren) && Tok.is(tok::identifier)) 1331249261Sdim // Don't space between ')' and <id> 1332249261Sdim return false; 1333249261Sdim } 1334249261Sdim if (Line.Type == LT_ObjCProperty && 1335263509Sdim (Tok.is(tok::equal) || Tok.Previous->is(tok::equal))) 1336249261Sdim return false; 1337249261Sdim 1338263509Sdim if (Tok.Type == TT_TrailingReturnArrow || 1339263509Sdim Tok.Previous->Type == TT_TrailingReturnArrow) 1340249261Sdim return true; 1341263509Sdim if (Tok.Previous->is(tok::comma)) 1342263509Sdim return true; 1343249261Sdim if (Tok.is(tok::comma)) 1344249261Sdim return false; 1345249261Sdim if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen) 1346249261Sdim return true; 1347263509Sdim if (Tok.Previous->Tok.is(tok::kw_operator)) 1348263509Sdim return Tok.is(tok::coloncolon); 1349249261Sdim if (Tok.Type == TT_OverloadedOperatorLParen) 1350249261Sdim return false; 1351249261Sdim if (Tok.is(tok::colon)) 1352263509Sdim return !Line.First->isOneOf(tok::kw_case, tok::kw_default) && 1353263509Sdim Tok.getNextNonComment() != NULL && Tok.Type != TT_ObjCMethodExpr && 1354263509Sdim !Tok.Previous->is(tok::question); 1355263509Sdim if (Tok.Previous->Type == TT_UnaryOperator || 1356263509Sdim Tok.Previous->Type == TT_CastRParen) 1357249261Sdim return false; 1358263509Sdim if (Tok.Previous->is(tok::greater) && Tok.is(tok::greater)) { 1359249261Sdim return Tok.Type == TT_TemplateCloser && 1360263509Sdim Tok.Previous->Type == TT_TemplateCloser && 1361263509Sdim (Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles); 1362249261Sdim } 1363249261Sdim if (Tok.isOneOf(tok::arrowstar, tok::periodstar) || 1364263509Sdim Tok.Previous->isOneOf(tok::arrowstar, tok::periodstar)) 1365249261Sdim return false; 1366263509Sdim if (!Style.SpaceBeforeAssignmentOperators && 1367263509Sdim Tok.getPrecedence() == prec::Assignment) 1368263509Sdim return false; 1369263509Sdim if ((Tok.Type == TT_BinaryOperator && !Tok.Previous->is(tok::l_paren)) || 1370263509Sdim Tok.Previous->Type == TT_BinaryOperator) 1371249261Sdim return true; 1372263509Sdim if (Tok.Previous->Type == TT_TemplateCloser && Tok.is(tok::l_paren)) 1373249261Sdim return false; 1374263509Sdim if (Tok.is(tok::less) && Tok.Previous->isNot(tok::l_paren) && 1375263509Sdim Line.First->is(tok::hash)) 1376249261Sdim return true; 1377249261Sdim if (Tok.Type == TT_TrailingUnaryOperator) 1378249261Sdim return false; 1379263509Sdim return spaceRequiredBetween(Line, *Tok.Previous, Tok); 1380249261Sdim} 1381249261Sdim 1382263509Sdimbool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, 1383263509Sdim const FormatToken &Right) { 1384263509Sdim if (Right.is(tok::comment)) { 1385263509Sdim return Right.NewlinesBefore > 0; 1386263509Sdim } else if (Right.Previous->isTrailingComment() || 1387263509Sdim (Right.is(tok::string_literal) && 1388263509Sdim Right.Previous->is(tok::string_literal))) { 1389263509Sdim return true; 1390263509Sdim } else if (Right.Previous->IsUnterminatedLiteral) { 1391263509Sdim return true; 1392263509Sdim } else if (Right.is(tok::lessless) && Right.Next && 1393263509Sdim Right.Previous->is(tok::string_literal) && 1394263509Sdim Right.Next->is(tok::string_literal)) { 1395263509Sdim return true; 1396263509Sdim } else if (Right.Previous->ClosesTemplateDeclaration && 1397263509Sdim Right.Previous->MatchingParen && 1398263509Sdim Right.Previous->MatchingParen->BindingStrength == 1 && 1399263509Sdim Style.AlwaysBreakTemplateDeclarations) { 1400263509Sdim // FIXME: Fix horrible hack of using BindingStrength to find top-level <>. 1401263509Sdim return true; 1402263509Sdim } else if (Right.Type == TT_CtorInitializerComma && 1403263509Sdim Style.BreakConstructorInitializersBeforeComma && 1404263509Sdim !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) { 1405263509Sdim return true; 1406263509Sdim } else if (Right.Previous->BlockKind == BK_Block && 1407263509Sdim Right.Previous->isNot(tok::r_brace) && Right.isNot(tok::r_brace)) { 1408263509Sdim return true; 1409263509Sdim } else if (Right.is(tok::l_brace) && (Right.BlockKind == BK_Block)) { 1410263509Sdim return Style.BreakBeforeBraces == FormatStyle::BS_Allman; 1411263509Sdim } 1412263509Sdim return false; 1413263509Sdim} 1414263509Sdim 1415249261Sdimbool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, 1416263509Sdim const FormatToken &Right) { 1417263509Sdim const FormatToken &Left = *Right.Previous; 1418263509Sdim if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator)) 1419249261Sdim return true; 1420263509Sdim if (Right.isTrailingComment()) 1421263509Sdim // We rely on MustBreakBefore being set correctly here as we should not 1422263509Sdim // change the "binding" behavior of a comment. 1423249261Sdim return false; 1424263509Sdim if (Left.is(tok::question) && Right.is(tok::colon)) 1425263509Sdim return false; 1426263509Sdim if (Right.Type == TT_ConditionalExpr || Right.is(tok::question)) 1427263509Sdim return Style.BreakBeforeTernaryOperators; 1428263509Sdim if (Left.Type == TT_ConditionalExpr || Left.is(tok::question)) 1429263509Sdim return !Style.BreakBeforeTernaryOperators; 1430263509Sdim if (Right.is(tok::colon) && 1431263509Sdim (Right.Type == TT_DictLiteral || Right.Type == TT_ObjCMethodExpr)) 1432263509Sdim return false; 1433263509Sdim if (Left.is(tok::colon) && 1434263509Sdim (Left.Type == TT_DictLiteral || Left.Type == TT_ObjCMethodExpr)) 1435249261Sdim return true; 1436249261Sdim if (Right.Type == TT_ObjCSelectorName) 1437249261Sdim return true; 1438263509Sdim if (Left.is(tok::r_paren) && Line.Type == LT_ObjCProperty) 1439263509Sdim return true; 1440249261Sdim if (Left.ClosesTemplateDeclaration) 1441249261Sdim return true; 1442249261Sdim if (Right.Type == TT_RangeBasedForLoopColon || 1443263509Sdim Right.Type == TT_OverloadedOperatorLParen || 1444263509Sdim Right.Type == TT_OverloadedOperator) 1445249261Sdim return false; 1446252723Sdim if (Left.Type == TT_RangeBasedForLoopColon) 1447249261Sdim return true; 1448249261Sdim if (Right.Type == TT_RangeBasedForLoopColon) 1449249261Sdim return false; 1450249261Sdim if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser || 1451263509Sdim Left.Type == TT_UnaryOperator || Left.is(tok::kw_operator)) 1452249261Sdim return false; 1453249261Sdim if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl) 1454249261Sdim return false; 1455263509Sdim if (Left.Previous) { 1456263509Sdim if (Left.is(tok::l_paren) && Right.is(tok::l_paren) && 1457263509Sdim Left.Previous->is(tok::kw___attribute)) 1458263509Sdim return false; 1459263509Sdim if (Left.is(tok::l_paren) && (Left.Previous->Type == TT_BinaryOperator || 1460263509Sdim Left.Previous->Type == TT_CastRParen)) 1461263509Sdim return false; 1462263509Sdim } 1463263509Sdim if (Right.Type == TT_ImplicitStringLiteral) 1464249261Sdim return false; 1465249261Sdim 1466263509Sdim if (Right.is(tok::r_paren) || Right.Type == TT_TemplateCloser) 1467249261Sdim return false; 1468249261Sdim 1469263509Sdim // We only break before r_brace if there was a corresponding break before 1470263509Sdim // the l_brace, which is tracked by BreakBeforeClosingBrace. 1471263509Sdim if (Right.is(tok::r_brace)) 1472263509Sdim return Right.MatchingParen && Right.MatchingParen->BlockKind == BK_Block; 1473263509Sdim 1474249261Sdim // Allow breaking after a trailing 'const', e.g. after a method declaration, 1475249261Sdim // unless it is follow by ';', '{' or '='. 1476263509Sdim if (Left.is(tok::kw_const) && Left.Previous != NULL && 1477263509Sdim Left.Previous->is(tok::r_paren)) 1478249261Sdim return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal); 1479249261Sdim 1480249261Sdim if (Right.is(tok::kw___attribute)) 1481249261Sdim return true; 1482249261Sdim 1483249261Sdim if (Left.is(tok::identifier) && Right.is(tok::string_literal)) 1484249261Sdim return true; 1485263509Sdim 1486263509Sdim if (Left.Type == TT_CtorInitializerComma && 1487263509Sdim Style.BreakConstructorInitializersBeforeComma) 1488263509Sdim return false; 1489263509Sdim if (Right.Type == TT_CtorInitializerComma && 1490263509Sdim Style.BreakConstructorInitializersBeforeComma) 1491263509Sdim return true; 1492263509Sdim if (Right.isBinaryOperator() && Style.BreakBeforeBinaryOperators) 1493263509Sdim return true; 1494263509Sdim if (Left.is(tok::greater) && Right.is(tok::greater) && 1495263509Sdim Left.Type != TT_TemplateCloser) 1496263509Sdim return false; 1497263509Sdim if (Left.Type == TT_ArrayInitializerLSquare) 1498263509Sdim return true; 1499263509Sdim return (Left.isBinaryOperator() && Left.isNot(tok::lessless) && 1500263509Sdim !Style.BreakBeforeBinaryOperators) || 1501252723Sdim Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace, 1502252723Sdim tok::kw_class, tok::kw_struct) || 1503263509Sdim Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon, 1504263509Sdim tok::l_square, tok::at) || 1505263509Sdim (Left.is(tok::r_paren) && 1506263509Sdim Right.isOneOf(tok::identifier, tok::kw_const, tok::kw___attribute)) || 1507263509Sdim (Left.is(tok::l_paren) && !Right.is(tok::r_paren)); 1508249261Sdim} 1509249261Sdim 1510252723Sdimvoid TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { 1511252723Sdim llvm::errs() << "AnnotatedTokens:\n"; 1512263509Sdim const FormatToken *Tok = Line.First; 1513252723Sdim while (Tok) { 1514252723Sdim llvm::errs() << " M=" << Tok->MustBreakBefore 1515252723Sdim << " C=" << Tok->CanBreakBefore << " T=" << Tok->Type 1516252723Sdim << " S=" << Tok->SpacesRequiredBefore 1517263509Sdim << " P=" << Tok->SplitPenalty << " Name=" << Tok->Tok.getName() 1518263509Sdim << " L=" << Tok->TotalLength << " PPK=" << Tok->PackingKind 1519263509Sdim << " FakeLParens="; 1520252723Sdim for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i) 1521252723Sdim llvm::errs() << Tok->FakeLParens[i] << "/"; 1522252723Sdim llvm::errs() << " FakeRParens=" << Tok->FakeRParens << "\n"; 1523263509Sdim if (Tok->Next == NULL) 1524263509Sdim assert(Tok == Line.Last); 1525263509Sdim Tok = Tok->Next; 1526252723Sdim } 1527252723Sdim llvm::errs() << "----\n"; 1528252723Sdim} 1529252723Sdim 1530249261Sdim} // namespace format 1531249261Sdim} // namespace clang 1532