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" 18251662Sdim#include "llvm/Support/Debug.h" 19249261Sdim 20249261Sdimnamespace clang { 21249261Sdimnamespace format { 22249261Sdim 23263508Sdimnamespace { 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: 32263508Sdim AnnotatingParser(const FormatStyle &Style, AnnotatedLine &Line, 33249261Sdim IdentifierInfo &Ident_in) 34263508Sdim : Style(Style), Line(Line), CurrentToken(Line.First), 35263508Sdim KeywordVirtualFound(false), AutoFound(false), Ident_in(Ident_in) { 36263508Sdim 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); 44263508Sdim 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, 55263508Sdim tok::question, tok::colon)) 56249261Sdim return false; 57263508Sdim // If a && or || is found and interpreted as a binary operator, this set 58263508Sdim // of angles is likely part of something like "a < b && c > d". If the 59263508Sdim // angles are inside an expression, the ||/&& might also be a binary 60263508Sdim // operator that was misinterpreted because we are parsing template 61263508Sdim // parameters. 62263508Sdim // FIXME: This is getting out of hand, write a decent parser. 63263508Sdim if (CurrentToken->Previous->isOneOf(tok::pipepipe, tok::ampamp) && 64263508Sdim (CurrentToken->Previous->Type == TT_BinaryOperator || 65263508Sdim Contexts[Contexts.size() - 2].IsExpression) && 66263508Sdim Line.First->isNot(tok::kw_template)) 67263508Sdim 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; 85263508Sdim FormatToken *Left = CurrentToken->Previous; 86249261Sdim if (CurrentToken->is(tok::caret)) { 87249261Sdim // ^( starts a block. 88249261Sdim Left->Type = TT_ObjCBlockLParen; 89263508Sdim } else if (FormatToken *MaybeSel = Left->Previous) { 90249261Sdim // @selector( starts a selector. 91263508Sdim if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Previous && 92263508Sdim MaybeSel->Previous->is(tok::at)) { 93249261Sdim StartsObjCMethodExpr = true; 94249261Sdim } 95249261Sdim } 96249261Sdim 97263508Sdim if (Left->Previous && Left->Previous->isOneOf(tok::kw_static_assert, 98263508Sdim tok::kw_if, tok::kw_while)) { 99263508Sdim // static_assert, if and while usually contain expressions. 100263508Sdim Contexts.back().IsExpression = true; 101263508Sdim } else if (Left->Previous && Left->Previous->is(tok::r_square) && 102263508Sdim Left->Previous->MatchingParen && 103263508Sdim Left->Previous->MatchingParen->Type == TT_LambdaLSquare) { 104263508Sdim // This is a parameter list of a lambda expression. 105263508Sdim Contexts.back().IsExpression = false; 106263508Sdim } 107263508Sdim 108249261Sdim if (StartsObjCMethodExpr) { 109249261Sdim Contexts.back().ColonIsObjCMethodExpr = true; 110249261Sdim Left->Type = TT_ObjCMethodExpr; 111249261Sdim } 112249261Sdim 113263508Sdim bool MightBeFunctionType = CurrentToken->is(tok::star); 114263508Sdim bool HasMultipleLines = false; 115263508Sdim 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. 121263508Sdim if (LookForDecls && CurrentToken->Next) { 122263508Sdim FormatToken *Prev = CurrentToken->getPreviousNonComment(); 123263508Sdim if (Prev) { 124263508Sdim FormatToken *PrevPrev = Prev->getPreviousNonComment(); 125263508Sdim FormatToken *Next = CurrentToken->Next; 126263508Sdim if (PrevPrev && PrevPrev->is(tok::identifier) && 127263508Sdim Prev->isOneOf(tok::star, tok::amp, tok::ampamp) && 128263508Sdim CurrentToken->is(tok::identifier) && Next->isNot(tok::equal)) { 129263508Sdim Prev->Type = TT_BinaryOperator; 130263508Sdim LookForDecls = false; 131263508Sdim } 132249261Sdim } 133249261Sdim } 134249261Sdim 135263508Sdim if (CurrentToken->Previous->Type == TT_PointerOrReference && 136263508Sdim CurrentToken->Previous->Previous->isOneOf(tok::l_paren, 137263508Sdim tok::coloncolon)) 138263508Sdim MightBeFunctionType = true; 139249261Sdim if (CurrentToken->is(tok::r_paren)) { 140263508Sdim if (MightBeFunctionType && CurrentToken->Next && 141263508Sdim (CurrentToken->Next->is(tok::l_paren) || 142263508Sdim (CurrentToken->Next->is(tok::l_square) && 143263508Sdim !Contexts.back().IsExpression))) 144263508Sdim 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 156263508Sdim if (!HasMultipleLines) 157263508Sdim Left->PackingKind = PPK_Inconclusive; 158263508Sdim else if (HasMultipleParametersOnALine) 159263508Sdim Left->PackingKind = PPK_BinPacked; 160263508Sdim else 161263508Sdim Left->PackingKind = PPK_OnePerLine; 162263508Sdim 163249261Sdim next(); 164249261Sdim return true; 165249261Sdim } 166249261Sdim if (CurrentToken->isOneOf(tok::r_square, tok::r_brace)) 167249261Sdim return false; 168249261Sdim updateParameterCount(Left, CurrentToken); 169263508Sdim if (CurrentToken->is(tok::comma) && CurrentToken->Next && 170263508Sdim !CurrentToken->Next->HasUnescapedNewline && 171263508Sdim !CurrentToken->Next->isTrailingComment()) 172263508Sdim HasMultipleParametersOnALine = true; 173249261Sdim if (!consumeToken()) 174249261Sdim return false; 175263508Sdim if (CurrentToken && CurrentToken->HasUnescapedNewline) 176263508Sdim HasMultipleLines = true; 177249261Sdim } 178249261Sdim return false; 179249261Sdim } 180249261Sdim 181249261Sdim bool parseSquare() { 182249261Sdim if (!CurrentToken) 183249261Sdim return false; 184249261Sdim 185263508Sdim // 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. 188263508Sdim FormatToken *Left = CurrentToken->Previous; 189263508Sdim FormatToken *Parent = Left->getPreviousNonComment(); 190249261Sdim bool StartsObjCMethodExpr = 191263508Sdim 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) || 194251662Sdim Parent->isUnaryOperator() || Parent->Type == TT_ObjCForIn || 195249261Sdim Parent->Type == TT_CastRParen || 196263508Sdim getBinOpPrecedence(Parent->Tok.getKind(), true, true) > prec::Unknown); 197249261Sdim ScopedContextCreator ContextCreator(*this, tok::l_square, 10); 198249261Sdim Contexts.back().IsExpression = true; 199263508Sdim bool ColonFound = false; 200249261Sdim 201249261Sdim if (StartsObjCMethodExpr) { 202249261Sdim Contexts.back().ColonIsObjCMethodExpr = true; 203249261Sdim Left->Type = TT_ObjCMethodExpr; 204263508Sdim } else if (Parent && Parent->is(tok::at)) { 205263508Sdim Left->Type = TT_ArrayInitializerLSquare; 206263508Sdim } else if (Left->Type == TT_Unknown) { 207263508Sdim Left->Type = TT_ArraySubscriptLSquare; 208249261Sdim } 209249261Sdim 210249261Sdim while (CurrentToken != NULL) { 211249261Sdim if (CurrentToken->is(tok::r_square)) { 212263508Sdim if (CurrentToken->Next && CurrentToken->Next->is(tok::l_paren) && 213263508Sdim 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; 237263508Sdim if (CurrentToken->is(tok::colon)) 238263508Sdim ColonFound = true; 239263508Sdim if (CurrentToken->is(tok::comma) && 240263508Sdim (Left->Type == TT_ArraySubscriptLSquare || 241263508Sdim (Left->Type == TT_ObjCMethodExpr && !ColonFound))) 242263508Sdim Left->Type = TT_ArrayInitializerLSquare; 243249261Sdim updateParameterCount(Left, CurrentToken); 244249261Sdim if (!consumeToken()) 245249261Sdim return false; 246249261Sdim } 247249261Sdim return false; 248249261Sdim } 249249261Sdim 250249261Sdim bool parseBrace() { 251251662Sdim if (CurrentToken != NULL) { 252263508Sdim FormatToken *Left = CurrentToken->Previous; 253251662Sdim ScopedContextCreator ContextCreator(*this, tok::l_brace, 1); 254263508Sdim Contexts.back().ColonIsDictLiteral = true; 255263508Sdim 256251662Sdim while (CurrentToken != NULL) { 257251662Sdim if (CurrentToken->is(tok::r_brace)) { 258251662Sdim Left->MatchingParen = CurrentToken; 259251662Sdim CurrentToken->MatchingParen = Left; 260251662Sdim next(); 261251662Sdim return true; 262251662Sdim } 263251662Sdim if (CurrentToken->isOneOf(tok::r_paren, tok::r_square)) 264251662Sdim return false; 265251662Sdim updateParameterCount(Left, CurrentToken); 266263508Sdim if (CurrentToken->is(tok::colon)) 267263508Sdim Left->Type = TT_DictLiteral; 268251662Sdim if (!consumeToken()) 269251662Sdim return false; 270249261Sdim } 271249261Sdim } 272251662Sdim // No closing "}" found, this probably starts a definition. 273251662Sdim Line.StartsDefinition = true; 274249261Sdim return true; 275249261Sdim } 276249261Sdim 277263508Sdim void updateParameterCount(FormatToken *Left, FormatToken *Current) { 278263508Sdim if (Current->is(tok::comma)) { 279249261Sdim ++Left->ParameterCount; 280263508Sdim if (!Left->Role) 281263508Sdim Left->Role.reset(new CommaSeparatedList(Style)); 282263508Sdim Left->Role->CommaFound(Current); 283263508Sdim } else if (Left->ParameterCount == 0 && Current->isNot(tok::comment)) { 284249261Sdim Left->ParameterCount = 1; 285263508Sdim } 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) 308263508Sdim CurrentToken->Previous->ClosesTemplateDeclaration = true; 309249261Sdim return true; 310249261Sdim } 311249261Sdim return false; 312249261Sdim } 313249261Sdim 314249261Sdim bool consumeToken() { 315263508Sdim FormatToken *Tok = CurrentToken; 316249261Sdim next(); 317263508Sdim switch (Tok->Tok.getKind()) { 318249261Sdim case tok::plus: 319249261Sdim case tok::minus: 320263508Sdim if (Tok->Previous == NULL && Line.MustBeDeclaration) 321249261Sdim Tok->Type = TT_ObjCMethodSpecifier; 322249261Sdim break; 323249261Sdim case tok::colon: 324263508Sdim if (Tok->Previous == NULL) 325249261Sdim return false; 326249261Sdim // Colons from ?: are handled in parseConditional(). 327263508Sdim if (Tok->Previous->is(tok::r_paren) && Contexts.size() == 1) { 328249261Sdim Tok->Type = TT_CtorInitializerColon; 329263508Sdim } else if (Contexts.back().ColonIsDictLiteral) { 330263508Sdim Tok->Type = TT_DictLiteral; 331249261Sdim } else if (Contexts.back().ColonIsObjCMethodExpr || 332263508Sdim Line.First->Type == TT_ObjCMethodSpecifier) { 333249261Sdim Tok->Type = TT_ObjCMethodExpr; 334263508Sdim Tok->Previous->Type = TT_ObjCSelectorName; 335263508Sdim if (Tok->Previous->ColumnWidth > 336263508Sdim Contexts.back().LongestObjCSelectorName) { 337263508Sdim Contexts.back().LongestObjCSelectorName = Tok->Previous->ColumnWidth; 338263508Sdim } 339249261Sdim if (Contexts.back().FirstObjCSelectorName == NULL) 340263508Sdim Contexts.back().FirstObjCSelectorName = Tok->Previous; 341249261Sdim } else if (Contexts.back().ColonIsForRangeExpr) { 342249261Sdim Tok->Type = TT_RangeBasedForLoopColon; 343263508Sdim } else if (CurrentToken != NULL && 344263508Sdim CurrentToken->is(tok::numeric_constant)) { 345263508Sdim Tok->Type = TT_BitFieldColon; 346263508Sdim } 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(); 356263508Sdim 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; 369263508Sdim if (Line.MustBeDeclaration && Contexts.size() == 1 && 370263508Sdim !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: 382263508Sdim 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 '}'. 395263508Sdim 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: 402263508Sdim while (CurrentToken && 403263508Sdim !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(); 407263508Sdim if (CurrentToken && CurrentToken->Previous->Type == TT_BinaryOperator) 408263508Sdim CurrentToken->Previous->Type = TT_OverloadedOperator; 409249261Sdim } 410263508Sdim if (CurrentToken) { 411249261Sdim CurrentToken->Type = TT_OverloadedOperatorLParen; 412263508Sdim if (CurrentToken->Previous->Type == TT_BinaryOperator) 413263508Sdim CurrentToken->Previous->Type = TT_OverloadedOperator; 414263508Sdim } 415249261Sdim break; 416249261Sdim case tok::question: 417249261Sdim parseConditional(); 418249261Sdim break; 419249261Sdim case tok::kw_template: 420249261Sdim parseTemplateDeclaration(); 421249261Sdim break; 422249261Sdim case tok::identifier: 423263508Sdim if (Line.First->is(tok::kw_for) && 424263508Sdim 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; 430263508Sdim if (Contexts.back().InCtorInitializer) 431263508Sdim 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) { 444263508Sdim 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; 474263508Sdim if (CurrentToken->Tok.is(tok::numeric_constant)) { 475263508Sdim CurrentToken->SpacesRequiredBefore = 1; 476263508Sdim return; 477263508Sdim } 478249261Sdim // Hashes in the middle of a line can lead to any strange token 479249261Sdim // sequence. 480263508Sdim if (CurrentToken->Tok.getIdentifierInfo() == NULL) 481249261Sdim return; 482263508Sdim 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; 491251662Sdim case tok::pp_if: 492251662Sdim case tok::pp_elif: 493251662Sdim parseLine(); 494251662Sdim 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 517263508Sdim 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 534263508Sdim if (CurrentToken != NULL) 535263508Sdim CurrentToken = CurrentToken->Next; 536249261Sdim 537263508Sdim if (CurrentToken != NULL) { 538263508Sdim // Reset token type in case we have already looked at it and then 539263508Sdim // recovered from an error (e.g. failure to find the matching >). 540263508Sdim if (CurrentToken->Type != TT_LambdaLSquare && 541263508Sdim CurrentToken->Type != TT_ImplicitStringLiteral) 542263508Sdim CurrentToken->Type = TT_Unknown; 543263508Sdim if (CurrentToken->Role) 544263508Sdim CurrentToken->Role.reset(NULL); 545263508Sdim CurrentToken->FakeLParens.clear(); 546263508Sdim CurrentToken->FakeRParens = 0; 547263508Sdim } 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), 557263508Sdim ColonIsDictLiteral(false), ColonIsObjCMethodExpr(false), 558263508Sdim FirstObjCSelectorName(NULL), FirstStartOfName(NULL), 559263508Sdim IsExpression(IsExpression), CanBeExpression(true), 560263508Sdim InCtorInitializer(false) {} 561249261Sdim 562249261Sdim tok::TokenKind ContextKind; 563249261Sdim unsigned BindingStrength; 564249261Sdim unsigned LongestObjCSelectorName; 565249261Sdim bool ColonIsForRangeExpr; 566263508Sdim bool ColonIsDictLiteral; 567249261Sdim bool ColonIsObjCMethodExpr; 568263508Sdim FormatToken *FirstObjCSelectorName; 569263508Sdim FormatToken *FirstStartOfName; 570249261Sdim bool IsExpression; 571249261Sdim bool CanBeExpression; 572263508Sdim 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) { 583263508Sdim P.Contexts.push_back(Context(ContextKind, 584263508Sdim P.Contexts.back().BindingStrength + Increase, 585263508Sdim P.Contexts.back().IsExpression)); 586249261Sdim } 587249261Sdim 588249261Sdim ~ScopedContextCreator() { P.Contexts.pop_back(); } 589249261Sdim }; 590249261Sdim 591263508Sdim void determineTokenType(FormatToken &Current) { 592263508Sdim if (Current.getPrecedence() == prec::Assignment && 593263508Sdim !Line.First->isOneOf(tok::kw_template, tok::kw_using) && 594263508Sdim (!Current.Previous || Current.Previous->isNot(tok::kw_operator))) { 595249261Sdim Contexts.back().IsExpression = true; 596263508Sdim for (FormatToken *Previous = Current.Previous; 597263508Sdim Previous && !Previous->isOneOf(tok::comma, tok::semi); 598263508Sdim 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 && 608263508Sdim !Line.InPPDirective && 609263508Sdim (!Current.Previous || 610263508Sdim !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)) { 613263508Sdim for (FormatToken *Previous = Current.Previous; 614249261Sdim Previous && Previous->isOneOf(tok::star, tok::amp); 615263508Sdim Previous = Previous->Previous) 616249261Sdim Previous->Type = TT_PointerOrReference; 617263508Sdim } else if (Current.Previous && 618263508Sdim Current.Previous->Type == TT_CtorInitializerColon) { 619249261Sdim Contexts.back().IsExpression = true; 620263508Sdim Contexts.back().InCtorInitializer = true; 621249261Sdim } else if (Current.is(tok::kw_new)) { 622249261Sdim Contexts.back().CanBeExpression = false; 623263508Sdim } else if (Current.is(tok::semi) || Current.is(tok::exclaim)) { 624251662Sdim // This should be the condition or increment in a for-loop. 625251662Sdim Contexts.back().IsExpression = true; 626249261Sdim } 627249261Sdim 628249261Sdim if (Current.Type == TT_Unknown) { 629263508Sdim // Line.MightBeFunctionDecl can only be true after the parentheses of a 630263508Sdim // function declaration have been found. In this case, 'Current' is a 631263508Sdim // trailing token of this declaration and thus cannot be a name. 632263508Sdim if (isStartOfName(Current) && !Line.MightBeFunctionDecl) { 633249261Sdim Contexts.back().FirstStartOfName = &Current; 634249261Sdim Current.Type = TT_StartOfName; 635263508Sdim } else if (Current.is(tok::kw_auto)) { 636263508Sdim AutoFound = true; 637263508Sdim } else if (Current.is(tok::arrow) && AutoFound && 638263508Sdim Line.MustBeDeclaration) { 639263508Sdim Current.Type = TT_TrailingReturnArrow; 640249261Sdim } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { 641249261Sdim Current.Type = 642263508Sdim determineStarAmpUsage(Current, Contexts.back().CanBeExpression && 643263508Sdim 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; 650263508Sdim } else if (Current.isBinaryOperator() && 651263508Sdim (!Current.Previous || 652263508Sdim Current.Previous->isNot(tok::l_square))) { 653249261Sdim Current.Type = TT_BinaryOperator; 654249261Sdim } else if (Current.is(tok::comment)) { 655263508Sdim if (Current.TokenText.startswith("//")) 656249261Sdim Current.Type = TT_LineComment; 657249261Sdim else 658249261Sdim Current.Type = TT_BlockComment; 659249261Sdim } else if (Current.is(tok::r_paren)) { 660263508Sdim FormatToken *LeftOfParens = NULL; 661263508Sdim if (Current.MatchingParen) 662263508Sdim LeftOfParens = Current.MatchingParen->getPreviousNonComment(); 663263508Sdim bool IsCast = false; 664263508Sdim bool ParensAreEmpty = Current.Previous == Current.MatchingParen; 665263508Sdim bool ParensAreType = !Current.Previous || 666263508Sdim Current.Previous->Type == TT_PointerOrReference || 667263508Sdim Current.Previous->Type == TT_TemplateCloser || 668263508Sdim isSimpleTypeSpecifier(*Current.Previous); 669249261Sdim bool ParensCouldEndDecl = 670263508Sdim Current.Next && 671263508Sdim Current.Next->isOneOf(tok::equal, tok::semi, tok::l_brace); 672249261Sdim bool IsSizeOfOrAlignOf = 673263508Sdim LeftOfParens && 674263508Sdim LeftOfParens->isOneOf(tok::kw_sizeof, tok::kw_alignof); 675263508Sdim if (ParensAreType && !ParensCouldEndDecl && !IsSizeOfOrAlignOf && 676263508Sdim (Contexts.back().IsExpression || 677263508Sdim (Current.Next && Current.Next->isBinaryOperator()))) 678263508Sdim IsCast = true; 679263508Sdim if (Current.Next && Current.Next->isNot(tok::string_literal) && 680263508Sdim (Current.Next->Tok.isLiteral() || 681263508Sdim Current.Next->isOneOf(tok::kw_sizeof, tok::kw_alignof))) 682263508Sdim IsCast = true; 683263508Sdim // If there is an identifier after the (), it is likely a cast, unless 684263508Sdim // there is also an identifier before the (). 685263508Sdim if (LeftOfParens && (LeftOfParens->Tok.getIdentifierInfo() == NULL || 686263508Sdim LeftOfParens->is(tok::kw_return)) && 687263508Sdim LeftOfParens->Type != TT_OverloadedOperator && 688263508Sdim LeftOfParens->Type != TT_TemplateCloser && Current.Next && 689263508Sdim Current.Next->is(tok::identifier)) 690263508Sdim IsCast = true; 691263508Sdim if (IsCast && !ParensAreEmpty) 692249261Sdim Current.Type = TT_CastRParen; 693263508Sdim } else if (Current.is(tok::at) && Current.Next) { 694263508Sdim 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 } 706263508Sdim } else if (Current.is(tok::period)) { 707263508Sdim FormatToken *PreviousNoComment = Current.getPreviousNonComment(); 708263508Sdim if (PreviousNoComment && 709263508Sdim PreviousNoComment->isOneOf(tok::comma, tok::l_brace)) 710263508Sdim Current.Type = TT_DesignatedInitializerPeriod; 711249261Sdim } 712249261Sdim } 713249261Sdim } 714249261Sdim 715263508Sdim /// \brief Take a guess at whether \p Tok starts a name of a function or 716263508Sdim /// variable declaration. 717263508Sdim /// 718263508Sdim /// This is a heuristic based on whether \p Tok is an identifier following 719263508Sdim /// something that is likely a type. 720263508Sdim bool isStartOfName(const FormatToken &Tok) { 721263508Sdim if (Tok.isNot(tok::identifier) || Tok.Previous == NULL) 722263508Sdim return false; 723263508Sdim 724263508Sdim // Skip "const" as it does not have an influence on whether this is a name. 725263508Sdim FormatToken *PreviousNotConst = Tok.Previous; 726263508Sdim while (PreviousNotConst != NULL && PreviousNotConst->is(tok::kw_const)) 727263508Sdim PreviousNotConst = PreviousNotConst->Previous; 728263508Sdim 729263508Sdim if (PreviousNotConst == NULL) 730263508Sdim return false; 731263508Sdim 732263508Sdim bool IsPPKeyword = PreviousNotConst->is(tok::identifier) && 733263508Sdim PreviousNotConst->Previous && 734263508Sdim PreviousNotConst->Previous->is(tok::hash); 735263508Sdim 736263508Sdim if (PreviousNotConst->Type == TT_TemplateCloser) 737263508Sdim return PreviousNotConst && PreviousNotConst->MatchingParen && 738263508Sdim PreviousNotConst->MatchingParen->Previous && 739263508Sdim PreviousNotConst->MatchingParen->Previous->isNot(tok::kw_template); 740263508Sdim 741263508Sdim return (!IsPPKeyword && PreviousNotConst->is(tok::identifier)) || 742263508Sdim PreviousNotConst->Type == TT_PointerOrReference || 743263508Sdim isSimpleTypeSpecifier(*PreviousNotConst); 744263508Sdim } 745263508Sdim 746249261Sdim /// \brief Return the type of the given token assuming it is * or &. 747263508Sdim TokenType determineStarAmpUsage(const FormatToken &Tok, bool IsExpression) { 748263508Sdim const FormatToken *PrevToken = Tok.getPreviousNonComment(); 749249261Sdim if (PrevToken == NULL) 750249261Sdim return TT_UnaryOperator; 751249261Sdim 752263508Sdim const FormatToken *NextToken = Tok.getNextNonComment(); 753249261Sdim if (NextToken == NULL) 754249261Sdim return TT_Unknown; 755249261Sdim 756263508Sdim if (PrevToken->is(tok::coloncolon) || 757263508Sdim (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, 762263508Sdim 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 770263508Sdim if (PrevToken->is(tok::r_paren) && PrevToken->MatchingParen && 771263508Sdim PrevToken->MatchingParen->Previous && 772263508Sdim PrevToken->MatchingParen->Previous->is(tok::kw_typeof)) 773263508Sdim return TT_PointerOrReference; 774263508Sdim 775263508Sdim if (PrevToken->Tok.isLiteral() || 776249261Sdim PrevToken->isOneOf(tok::r_paren, tok::r_square) || 777263508Sdim 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 788263508Sdim TokenType determinePlusMinusCaretUsage(const FormatToken &Tok) { 789263508Sdim const FormatToken *PrevToken = Tok.getPreviousNonComment(); 790263508Sdim 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. 808263508Sdim TokenType determineIncrementUsage(const FormatToken &Tok) { 809263508Sdim const FormatToken *PrevToken = Tok.getPreviousNonComment(); 810263508Sdim 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. 821263508Sdim bool isSimpleTypeSpecifier(const FormatToken &Tok) const { 822263508Sdim 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: 843263508Sdim return true; 844249261Sdim default: 845263508Sdim return false; 846249261Sdim } 847249261Sdim } 848249261Sdim 849249261Sdim SmallVector<Context, 8> Contexts; 850249261Sdim 851263508Sdim const FormatStyle &Style; 852249261Sdim AnnotatedLine &Line; 853263508Sdim FormatToken *CurrentToken; 854249261Sdim bool KeywordVirtualFound; 855263508Sdim bool AutoFound; 856249261Sdim IdentifierInfo &Ident_in; 857249261Sdim}; 858249261Sdim 859263508Sdimstatic int PrecedenceUnaryOperator = prec::PointerToMember + 1; 860263508Sdimstatic int PrecedenceArrowAndPeriod = prec::PointerToMember + 2; 861263508Sdim 862249261Sdim/// \brief Parses binary expressions by inserting fake parenthesis based on 863249261Sdim/// operator precedence. 864249261Sdimclass ExpressionParser { 865249261Sdimpublic: 866263508Sdim ExpressionParser(AnnotatedLine &Line) : Current(Line.First) { 867263508Sdim // Skip leading "}", e.g. in "} else if (...) {". 868263508Sdim if (Current->is(tok::r_brace)) 869263508Sdim next(); 870263508Sdim } 871249261Sdim 872249261Sdim /// \brief Parse expressions with the given operatore precedence. 873249261Sdim void parse(int Precedence = 0) { 874263508Sdim // Skip 'return' and ObjC selector colons as they are not part of a binary 875263508Sdim // expression. 876263508Sdim while (Current && 877263508Sdim (Current->is(tok::kw_return) || 878263508Sdim (Current->is(tok::colon) && Current->Type == TT_ObjCMethodExpr))) 879263508Sdim next(); 880263508Sdim 881263508Sdim if (Current == NULL || Precedence > PrecedenceArrowAndPeriod) 882249261Sdim return; 883249261Sdim 884263508Sdim // Conditional expressions need to be parsed separately for proper nesting. 885263508Sdim if (Precedence == prec::Conditional) { 886263508Sdim parseConditionalExpr(); 887263508Sdim return; 888249261Sdim } 889249261Sdim 890263508Sdim // Parse unary operators, which all have a higher precedence than binary 891263508Sdim // operators. 892263508Sdim if (Precedence == PrecedenceUnaryOperator) { 893263508Sdim parseUnaryOperator(); 894263508Sdim return; 895263508Sdim } 896249261Sdim 897263508Sdim FormatToken *Start = Current; 898263508Sdim FormatToken *LatestOperator = NULL; 899263508Sdim 900249261Sdim while (Current) { 901249261Sdim // Consume operators with higher precedence. 902251662Sdim parse(Precedence + 1); 903249261Sdim 904263508Sdim int CurrentPrecedence = getCurrentPrecedence(); 905249261Sdim 906263508Sdim if (Current && Current->Type == TT_ObjCSelectorName && 907263508Sdim Precedence == CurrentPrecedence) 908263508Sdim Start = Current; 909263508Sdim 910249261Sdim // At the end of the line or when an operator with higher precedence is 911249261Sdim // found, insert fake parenthesis and return. 912251662Sdim if (Current == NULL || Current->closesScope() || 913263508Sdim (CurrentPrecedence != -1 && CurrentPrecedence < Precedence)) { 914263508Sdim if (LatestOperator) { 915263508Sdim if (Precedence == PrecedenceArrowAndPeriod) { 916263508Sdim LatestOperator->LastInChainOfCalls = true; 917263508Sdim // Call expressions don't have a binary operator precedence. 918263508Sdim addFakeParenthesis(Start, prec::Unknown); 919263508Sdim } else { 920263508Sdim addFakeParenthesis(Start, prec::Level(Precedence)); 921263508Sdim } 922249261Sdim } 923249261Sdim return; 924249261Sdim } 925249261Sdim 926249261Sdim // Consume scopes: (), [], <> and {} 927251662Sdim if (Current->opensScope()) { 928251662Sdim while (Current && !Current->closesScope()) { 929249261Sdim next(); 930249261Sdim parse(); 931249261Sdim } 932249261Sdim next(); 933249261Sdim } else { 934249261Sdim // Operator found. 935249261Sdim if (CurrentPrecedence == Precedence) 936263508Sdim LatestOperator = Current; 937249261Sdim 938249261Sdim next(); 939249261Sdim } 940249261Sdim } 941249261Sdim } 942249261Sdim 943249261Sdimprivate: 944263508Sdim /// \brief Gets the precedence (+1) of the given token for binary operators 945263508Sdim /// and other tokens that we treat like binary operators. 946263508Sdim int getCurrentPrecedence() { 947263508Sdim if (Current) { 948263508Sdim if (Current->Type == TT_ConditionalExpr) 949263508Sdim return prec::Conditional; 950263508Sdim else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon || 951263508Sdim Current->Type == TT_ObjCSelectorName) 952263508Sdim return 0; 953263508Sdim else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma)) 954263508Sdim return Current->getPrecedence(); 955263508Sdim else if (Current->isOneOf(tok::period, tok::arrow)) 956263508Sdim return PrecedenceArrowAndPeriod; 957263508Sdim } 958263508Sdim return -1; 959263508Sdim } 960263508Sdim 961263508Sdim void addFakeParenthesis(FormatToken *Start, prec::Level Precedence) { 962263508Sdim Start->FakeLParens.push_back(Precedence); 963263508Sdim if (Precedence > prec::Unknown) 964263508Sdim Start->StartsBinaryExpression = true; 965263508Sdim if (Current) { 966263508Sdim ++Current->Previous->FakeRParens; 967263508Sdim if (Precedence > prec::Unknown) 968263508Sdim Current->Previous->EndsBinaryExpression = true; 969263508Sdim } 970263508Sdim } 971263508Sdim 972263508Sdim /// \brief Parse unary operator expressions and surround them with fake 973263508Sdim /// parentheses if appropriate. 974263508Sdim void parseUnaryOperator() { 975263508Sdim if (Current == NULL || Current->Type != TT_UnaryOperator) { 976263508Sdim parse(PrecedenceArrowAndPeriod); 977263508Sdim return; 978263508Sdim } 979263508Sdim 980263508Sdim FormatToken *Start = Current; 981263508Sdim next(); 982263508Sdim parseUnaryOperator(); 983263508Sdim 984263508Sdim // The actual precedence doesn't matter. 985263508Sdim addFakeParenthesis(Start, prec::Unknown); 986263508Sdim } 987263508Sdim 988263508Sdim void parseConditionalExpr() { 989263508Sdim FormatToken *Start = Current; 990263508Sdim parse(prec::LogicalOr); 991263508Sdim if (!Current || !Current->is(tok::question)) 992263508Sdim return; 993263508Sdim next(); 994263508Sdim parse(prec::LogicalOr); 995263508Sdim if (!Current || Current->Type != TT_ConditionalExpr) 996263508Sdim return; 997263508Sdim next(); 998263508Sdim parseConditionalExpr(); 999263508Sdim addFakeParenthesis(Start, prec::Conditional); 1000263508Sdim } 1001263508Sdim 1002249261Sdim void next() { 1003263508Sdim if (Current) 1004263508Sdim Current = Current->Next; 1005263508Sdim while (Current && Current->isTrailingComment()) 1006263508Sdim Current = Current->Next; 1007249261Sdim } 1008249261Sdim 1009263508Sdim FormatToken *Current; 1010249261Sdim}; 1011249261Sdim 1012263508Sdim} // end anonymous namespace 1013263508Sdim 1014263508Sdimvoid 1015263508SdimTokenAnnotator::setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines) { 1016263508Sdim const AnnotatedLine *NextNonCommentLine = NULL; 1017263508Sdim for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(), 1018263508Sdim E = Lines.rend(); 1019263508Sdim I != E; ++I) { 1020263508Sdim if (NextNonCommentLine && (*I)->First->is(tok::comment) && 1021263508Sdim (*I)->First->Next == NULL) 1022263508Sdim (*I)->Level = NextNonCommentLine->Level; 1023263508Sdim else 1024263508Sdim NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : NULL; 1025263508Sdim 1026263508Sdim setCommentLineLevels((*I)->Children); 1027263508Sdim } 1028263508Sdim} 1029263508Sdim 1030249261Sdimvoid TokenAnnotator::annotate(AnnotatedLine &Line) { 1031263508Sdim for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(), 1032263508Sdim E = Line.Children.end(); 1033263508Sdim I != E; ++I) { 1034263508Sdim annotate(**I); 1035263508Sdim } 1036263508Sdim 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 1044263508Sdim if (Line.First->Type == TT_ObjCMethodSpecifier) 1045249261Sdim Line.Type = LT_ObjCMethodDecl; 1046263508Sdim else if (Line.First->Type == TT_ObjCDecl) 1047249261Sdim Line.Type = LT_ObjCDecl; 1048263508Sdim else if (Line.First->Type == TT_ObjCProperty) 1049249261Sdim Line.Type = LT_ObjCProperty; 1050249261Sdim 1051263508Sdim Line.First->SpacesRequiredBefore = 1; 1052263508Sdim Line.First->CanBreakBefore = Line.First->MustBreakBefore; 1053249261Sdim} 1054249261Sdim 1055249261Sdimvoid TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { 1056263508Sdim Line.First->TotalLength = 1057263508Sdim Line.First->IsMultiline ? Style.ColumnLimit : Line.First->ColumnWidth; 1058263508Sdim if (!Line.First->Next) 1059249261Sdim return; 1060263508Sdim FormatToken *Current = Line.First->Next; 1061263508Sdim bool InFunctionDecl = Line.MightBeFunctionDecl; 1062249261Sdim while (Current != NULL) { 1063249261Sdim if (Current->Type == TT_LineComment) 1064249261Sdim Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments; 1065263508Sdim else if (Current->SpacesRequiredBefore == 0 && 1066263508Sdim spaceRequiredBefore(Line, *Current)) 1067263508Sdim Current->SpacesRequiredBefore = 1; 1068249261Sdim 1069263508Sdim Current->MustBreakBefore = 1070263508Sdim Current->MustBreakBefore || mustBreakBefore(Line, *Current); 1071263508Sdim 1072249261Sdim Current->CanBreakBefore = 1073249261Sdim Current->MustBreakBefore || canBreakBefore(Line, *Current); 1074263508Sdim if (Current->MustBreakBefore || !Current->Children.empty() || 1075263508Sdim Current->IsMultiline) 1076263508Sdim Current->TotalLength = Current->Previous->TotalLength + Style.ColumnLimit; 1077249261Sdim else 1078263508Sdim Current->TotalLength = Current->Previous->TotalLength + 1079263508Sdim Current->ColumnWidth + 1080263508Sdim Current->SpacesRequiredBefore; 1081263508Sdim 1082263508Sdim if (Current->Type == TT_CtorInitializerColon) 1083263508Sdim InFunctionDecl = false; 1084263508Sdim 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. 1088263508Sdim Current->SplitPenalty = 20 * Current->BindingStrength + 1089263508Sdim splitPenalty(Line, *Current, InFunctionDecl); 1090249261Sdim 1091263508Sdim Current = Current->Next; 1092249261Sdim } 1093251662Sdim 1094263508Sdim calculateUnbreakableTailLengths(Line); 1095263508Sdim for (Current = Line.First; Current != NULL; Current = Current->Next) { 1096263508Sdim if (Current->Role) 1097263508Sdim Current->Role->precomputeFormattingInfos(Current); 1098263508Sdim } 1099263508Sdim 1100263508Sdim DEBUG({ printDebugInfo(Line); }); 1101263508Sdim 1102263508Sdim for (SmallVectorImpl<AnnotatedLine *>::iterator I = Line.Children.begin(), 1103263508Sdim E = Line.Children.end(); 1104263508Sdim I != E; ++I) { 1105263508Sdim calculateFormattingInformation(**I); 1106263508Sdim } 1107249261Sdim} 1108249261Sdim 1109263508Sdimvoid TokenAnnotator::calculateUnbreakableTailLengths(AnnotatedLine &Line) { 1110263508Sdim unsigned UnbreakableTailLength = 0; 1111263508Sdim FormatToken *Current = Line.Last; 1112263508Sdim while (Current != NULL) { 1113263508Sdim Current->UnbreakableTailLength = UnbreakableTailLength; 1114263508Sdim if (Current->CanBreakBefore || 1115263508Sdim Current->isOneOf(tok::comment, tok::string_literal)) { 1116263508Sdim UnbreakableTailLength = 0; 1117263508Sdim } else { 1118263508Sdim UnbreakableTailLength += 1119263508Sdim Current->ColumnWidth + Current->SpacesRequiredBefore; 1120263508Sdim } 1121263508Sdim Current = Current->Previous; 1122263508Sdim } 1123263508Sdim} 1124263508Sdim 1125249261Sdimunsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, 1126263508Sdim const FormatToken &Tok, 1127263508Sdim bool InFunctionDecl) { 1128263508Sdim const FormatToken &Left = *Tok.Previous; 1129263508Sdim const FormatToken &Right = Tok; 1130249261Sdim 1131263508Sdim if (Left.is(tok::semi)) 1132263508Sdim return 0; 1133263508Sdim if (Left.is(tok::comma)) 1134263508Sdim return 1; 1135263508Sdim if (Right.is(tok::l_square)) 1136263508Sdim return 150; 1137263508Sdim 1138263508Sdim if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator)) { 1139263508Sdim if (Line.First->is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt) 1140249261Sdim return 3; 1141263508Sdim if (Left.Type == TT_StartOfName) 1142263508Sdim return 20; 1143263508Sdim if (InFunctionDecl && Right.BindingStrength == 1) 1144249261Sdim // FIXME: Clean up hack of using BindingStrength to find top-level names. 1145249261Sdim return Style.PenaltyReturnTypeOnItsOwnLine; 1146263508Sdim return 200; 1147249261Sdim } 1148249261Sdim if (Left.is(tok::equal) && Right.is(tok::l_brace)) 1149249261Sdim return 150; 1150263508Sdim if (Left.Type == TT_CastRParen) 1151263508Sdim return 100; 1152249261Sdim if (Left.is(tok::coloncolon)) 1153249261Sdim return 500; 1154251662Sdim if (Left.isOneOf(tok::kw_class, tok::kw_struct)) 1155251662Sdim return 5000; 1156249261Sdim 1157249261Sdim if (Left.Type == TT_RangeBasedForLoopColon || 1158249261Sdim Left.Type == TT_InheritanceColon) 1159249261Sdim return 2; 1160249261Sdim 1161263508Sdim 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 1168263508Sdim // Breaking before a trailing 'const' or not-function-like annotation is bad. 1169263508Sdim if (Left.is(tok::r_paren) && Line.Type != LT_ObjCProperty && 1170263508Sdim (Right.is(tok::kw_const) || (Right.is(tok::identifier) && Right.Next && 1171263508Sdim Right.Next->isNot(tok::l_paren)))) 1172263508Sdim return 100; 1173263508Sdim 1174249261Sdim // In for-loops, prefer breaking at ',' and ';'. 1175263508Sdim 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) 1183263508Sdim return 50; 1184249261Sdim 1185263508Sdim if (Left.is(tok::l_paren) && InFunctionDecl) 1186251662Sdim return 100; 1187251662Sdim if (Left.opensScope()) 1188263508Sdim return Left.ParameterCount > 1 ? Style.PenaltyBreakBeforeFirstCallParameter 1189263508Sdim : 19; 1190249261Sdim 1191249261Sdim if (Right.is(tok::lessless)) { 1192249261Sdim if (Left.is(tok::string_literal)) { 1193263508Sdim StringRef Content = Left.TokenText; 1194263508Sdim if (Content.startswith("\"")) 1195263508Sdim Content = Content.drop_front(1); 1196263508Sdim if (Content.endswith("\"")) 1197263508Sdim Content = Content.drop_back(1); 1198263508Sdim Content = Content.trim(); 1199249261Sdim if (Content.size() > 1 && 1200249261Sdim (Content.back() == ':' || Content.back() == '=')) 1201263508Sdim return 25; 1202249261Sdim } 1203263508Sdim return 1; // Breaking at a << is really cheap. 1204249261Sdim } 1205249261Sdim if (Left.Type == TT_ConditionalExpr) 1206249261Sdim return prec::Conditional; 1207263508Sdim 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, 1216263508Sdim const FormatToken &Left, 1217263508Sdim 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); 1222263508Sdim if (Left.is(tok::l_paren) && Right.is(tok::r_paren)) 1223263508Sdim return Style.SpaceInEmptyParentheses; 1224263508Sdim if (Left.is(tok::l_paren) || Right.is(tok::r_paren)) 1225263508Sdim return (Right.Type == TT_CastRParen || 1226263508Sdim (Left.MatchingParen && Left.MatchingParen->Type == TT_CastRParen)) 1227263508Sdim ? Style.SpacesInCStyleCastParentheses 1228263508Sdim : Style.SpacesInParentheses; 1229263508Sdim if (Style.SpacesInAngles && 1230263508Sdim ((Left.Type == TT_TemplateOpener) != (Right.Type == TT_TemplateCloser))) 1231263508Sdim return true; 1232263508Sdim 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)) 1250263508Sdim return (Left.is(tok::less) && Style.Standard == FormatStyle::LS_Cpp03) || 1251263508Sdim !Left.isOneOf(tok::identifier, tok::greater, tok::l_paren, 1252263508Sdim tok::r_paren, tok::less); 1253249261Sdim if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) 1254249261Sdim return false; 1255263508Sdim if (Right.is(tok::ellipsis)) 1256263508Sdim return Left.Tok.isLiteral(); 1257263508Sdim if (Left.is(tok::l_square) && Right.is(tok::amp)) 1258263508Sdim return false; 1259249261Sdim if (Right.Type == TT_PointerOrReference) 1260263508Sdim return Left.Tok.isLiteral() || 1261249261Sdim ((Left.Type != TT_PointerOrReference) && Left.isNot(tok::l_paren) && 1262249261Sdim !Style.PointerBindsToType); 1263263508Sdim if (Right.Type == TT_FunctionTypeLParen && Left.isNot(tok::l_paren) && 1264263508Sdim (Left.Type != TT_PointerOrReference || Style.PointerBindsToType)) 1265263508Sdim return true; 1266249261Sdim if (Left.Type == TT_PointerOrReference) 1267263508Sdim return Right.Tok.isLiteral() || Right.Type == TT_BlockComment || 1268249261Sdim ((Right.Type != TT_PointerOrReference) && 1269249261Sdim Right.isNot(tok::l_paren) && Style.PointerBindsToType && 1270263508Sdim Left.Previous && 1271263508Sdim !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)) 1275263508Sdim return Left.Type == TT_ArrayInitializerLSquare && 1276263508Sdim Right.isNot(tok::r_square); 1277249261Sdim if (Right.is(tok::r_square)) 1278263508Sdim return Right.MatchingParen && 1279263508Sdim Right.MatchingParen->Type == TT_ArrayInitializerLSquare; 1280263508Sdim if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr && 1281263508Sdim 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)) 1286263508Sdim return Right.Type != TT_ObjCMethodExpr && !Left.is(tok::question); 1287249261Sdim if (Right.is(tok::l_paren)) { 1288263508Sdim if (Left.is(tok::r_paren) && Left.MatchingParen && 1289263508Sdim Left.MatchingParen->Previous && 1290263508Sdim Left.MatchingParen->Previous->is(tok::kw___attribute)) 1291263508Sdim return true; 1292249261Sdim return Line.Type == LT_ObjCDecl || 1293263508Sdim Left.isOneOf(tok::kw_return, tok::kw_new, tok::kw_delete, 1294263508Sdim tok::semi) || 1295263508Sdim (Style.SpaceAfterControlStatementKeyword && 1296263508Sdim Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, 1297263508Sdim tok::kw_catch)); 1298249261Sdim } 1299263508Sdim 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)) 1302263508Sdim return !Left.Children.empty(); // No spaces in "{}". 1303263508Sdim if (Left.is(tok::l_brace) || Right.is(tok::r_brace)) 1304263508Sdim return !Style.Cpp11BracedListStyle; 1305263508Sdim if (Right.Type == TT_UnaryOperator) 1306263508Sdim return !Left.isOneOf(tok::l_paren, tok::l_square, tok::at) && 1307263508Sdim (Left.isNot(tok::colon) || Left.Type != TT_ObjCMethodExpr); 1308263508Sdim if (Left.isOneOf(tok::identifier, tok::greater, tok::r_square) && 1309263508Sdim Right.is(tok::l_brace) && Right.getNextNonComment() && 1310263508Sdim Right.BlockKind != BK_Block) 1311249261Sdim return false; 1312263508Sdim if (Left.is(tok::period) || Right.is(tok::period)) 1313251662Sdim return false; 1314263508Sdim if (Left.Type == TT_BlockComment && Left.TokenText.endswith("=*/")) 1315263508Sdim return false; 1316263508Sdim if (Right.is(tok::hash) && Left.is(tok::identifier) && Left.TokenText == "L") 1317263508Sdim return false; 1318249261Sdim return true; 1319249261Sdim} 1320249261Sdim 1321249261Sdimbool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, 1322263508Sdim const FormatToken &Tok) { 1323263508Sdim if (Tok.Tok.getIdentifierInfo() && Tok.Previous->Tok.getIdentifierInfo()) 1324249261Sdim return true; // Never ever merge two identifiers. 1325263508Sdim if (Tok.Previous->Type == TT_ImplicitStringLiteral) 1326263508Sdim return Tok.WhitespaceRange.getBegin() != Tok.WhitespaceRange.getEnd(); 1327249261Sdim if (Line.Type == LT_ObjCMethodDecl) { 1328263508Sdim if (Tok.Previous->Type == TT_ObjCMethodSpecifier) 1329249261Sdim return true; 1330263508Sdim 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 && 1335263508Sdim (Tok.is(tok::equal) || Tok.Previous->is(tok::equal))) 1336249261Sdim return false; 1337249261Sdim 1338263508Sdim if (Tok.Type == TT_TrailingReturnArrow || 1339263508Sdim Tok.Previous->Type == TT_TrailingReturnArrow) 1340249261Sdim return true; 1341263508Sdim if (Tok.Previous->is(tok::comma)) 1342263508Sdim return true; 1343249261Sdim if (Tok.is(tok::comma)) 1344249261Sdim return false; 1345249261Sdim if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen) 1346249261Sdim return true; 1347263508Sdim if (Tok.Previous->Tok.is(tok::kw_operator)) 1348263508Sdim return Tok.is(tok::coloncolon); 1349249261Sdim if (Tok.Type == TT_OverloadedOperatorLParen) 1350249261Sdim return false; 1351249261Sdim if (Tok.is(tok::colon)) 1352263508Sdim return !Line.First->isOneOf(tok::kw_case, tok::kw_default) && 1353263508Sdim Tok.getNextNonComment() != NULL && Tok.Type != TT_ObjCMethodExpr && 1354263508Sdim !Tok.Previous->is(tok::question); 1355263508Sdim if (Tok.Previous->Type == TT_UnaryOperator || 1356263508Sdim Tok.Previous->Type == TT_CastRParen) 1357249261Sdim return false; 1358263508Sdim if (Tok.Previous->is(tok::greater) && Tok.is(tok::greater)) { 1359249261Sdim return Tok.Type == TT_TemplateCloser && 1360263508Sdim Tok.Previous->Type == TT_TemplateCloser && 1361263508Sdim (Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles); 1362249261Sdim } 1363249261Sdim if (Tok.isOneOf(tok::arrowstar, tok::periodstar) || 1364263508Sdim Tok.Previous->isOneOf(tok::arrowstar, tok::periodstar)) 1365249261Sdim return false; 1366263508Sdim if (!Style.SpaceBeforeAssignmentOperators && 1367263508Sdim Tok.getPrecedence() == prec::Assignment) 1368263508Sdim return false; 1369263508Sdim if ((Tok.Type == TT_BinaryOperator && !Tok.Previous->is(tok::l_paren)) || 1370263508Sdim Tok.Previous->Type == TT_BinaryOperator) 1371249261Sdim return true; 1372263508Sdim if (Tok.Previous->Type == TT_TemplateCloser && Tok.is(tok::l_paren)) 1373249261Sdim return false; 1374263508Sdim if (Tok.is(tok::less) && Tok.Previous->isNot(tok::l_paren) && 1375263508Sdim Line.First->is(tok::hash)) 1376249261Sdim return true; 1377249261Sdim if (Tok.Type == TT_TrailingUnaryOperator) 1378249261Sdim return false; 1379263508Sdim return spaceRequiredBetween(Line, *Tok.Previous, Tok); 1380249261Sdim} 1381249261Sdim 1382263508Sdimbool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, 1383263508Sdim const FormatToken &Right) { 1384263508Sdim if (Right.is(tok::comment)) { 1385263508Sdim return Right.NewlinesBefore > 0; 1386263508Sdim } else if (Right.Previous->isTrailingComment() || 1387263508Sdim (Right.is(tok::string_literal) && 1388263508Sdim Right.Previous->is(tok::string_literal))) { 1389263508Sdim return true; 1390263508Sdim } else if (Right.Previous->IsUnterminatedLiteral) { 1391263508Sdim return true; 1392263508Sdim } else if (Right.is(tok::lessless) && Right.Next && 1393263508Sdim Right.Previous->is(tok::string_literal) && 1394263508Sdim Right.Next->is(tok::string_literal)) { 1395263508Sdim return true; 1396263508Sdim } else if (Right.Previous->ClosesTemplateDeclaration && 1397263508Sdim Right.Previous->MatchingParen && 1398263508Sdim Right.Previous->MatchingParen->BindingStrength == 1 && 1399263508Sdim Style.AlwaysBreakTemplateDeclarations) { 1400263508Sdim // FIXME: Fix horrible hack of using BindingStrength to find top-level <>. 1401263508Sdim return true; 1402263508Sdim } else if (Right.Type == TT_CtorInitializerComma && 1403263508Sdim Style.BreakConstructorInitializersBeforeComma && 1404263508Sdim !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) { 1405263508Sdim return true; 1406263508Sdim } else if (Right.Previous->BlockKind == BK_Block && 1407263508Sdim Right.Previous->isNot(tok::r_brace) && Right.isNot(tok::r_brace)) { 1408263508Sdim return true; 1409263508Sdim } else if (Right.is(tok::l_brace) && (Right.BlockKind == BK_Block)) { 1410263508Sdim return Style.BreakBeforeBraces == FormatStyle::BS_Allman; 1411263508Sdim } 1412263508Sdim return false; 1413263508Sdim} 1414263508Sdim 1415249261Sdimbool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, 1416263508Sdim const FormatToken &Right) { 1417263508Sdim const FormatToken &Left = *Right.Previous; 1418263508Sdim if (Right.Type == TT_StartOfName || Right.is(tok::kw_operator)) 1419249261Sdim return true; 1420263508Sdim if (Right.isTrailingComment()) 1421263508Sdim // We rely on MustBreakBefore being set correctly here as we should not 1422263508Sdim // change the "binding" behavior of a comment. 1423249261Sdim return false; 1424263508Sdim if (Left.is(tok::question) && Right.is(tok::colon)) 1425263508Sdim return false; 1426263508Sdim if (Right.Type == TT_ConditionalExpr || Right.is(tok::question)) 1427263508Sdim return Style.BreakBeforeTernaryOperators; 1428263508Sdim if (Left.Type == TT_ConditionalExpr || Left.is(tok::question)) 1429263508Sdim return !Style.BreakBeforeTernaryOperators; 1430263508Sdim if (Right.is(tok::colon) && 1431263508Sdim (Right.Type == TT_DictLiteral || Right.Type == TT_ObjCMethodExpr)) 1432263508Sdim return false; 1433263508Sdim if (Left.is(tok::colon) && 1434263508Sdim (Left.Type == TT_DictLiteral || Left.Type == TT_ObjCMethodExpr)) 1435249261Sdim return true; 1436249261Sdim if (Right.Type == TT_ObjCSelectorName) 1437249261Sdim return true; 1438263508Sdim if (Left.is(tok::r_paren) && Line.Type == LT_ObjCProperty) 1439263508Sdim return true; 1440249261Sdim if (Left.ClosesTemplateDeclaration) 1441249261Sdim return true; 1442249261Sdim if (Right.Type == TT_RangeBasedForLoopColon || 1443263508Sdim Right.Type == TT_OverloadedOperatorLParen || 1444263508Sdim Right.Type == TT_OverloadedOperator) 1445249261Sdim return false; 1446251662Sdim 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 || 1451263508Sdim 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; 1455263508Sdim if (Left.Previous) { 1456263508Sdim if (Left.is(tok::l_paren) && Right.is(tok::l_paren) && 1457263508Sdim Left.Previous->is(tok::kw___attribute)) 1458263508Sdim return false; 1459263508Sdim if (Left.is(tok::l_paren) && (Left.Previous->Type == TT_BinaryOperator || 1460263508Sdim Left.Previous->Type == TT_CastRParen)) 1461263508Sdim return false; 1462263508Sdim } 1463263508Sdim if (Right.Type == TT_ImplicitStringLiteral) 1464249261Sdim return false; 1465249261Sdim 1466263508Sdim if (Right.is(tok::r_paren) || Right.Type == TT_TemplateCloser) 1467249261Sdim return false; 1468249261Sdim 1469263508Sdim // We only break before r_brace if there was a corresponding break before 1470263508Sdim // the l_brace, which is tracked by BreakBeforeClosingBrace. 1471263508Sdim if (Right.is(tok::r_brace)) 1472263508Sdim return Right.MatchingParen && Right.MatchingParen->BlockKind == BK_Block; 1473263508Sdim 1474249261Sdim // Allow breaking after a trailing 'const', e.g. after a method declaration, 1475249261Sdim // unless it is follow by ';', '{' or '='. 1476263508Sdim if (Left.is(tok::kw_const) && Left.Previous != NULL && 1477263508Sdim 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; 1485263508Sdim 1486263508Sdim if (Left.Type == TT_CtorInitializerComma && 1487263508Sdim Style.BreakConstructorInitializersBeforeComma) 1488263508Sdim return false; 1489263508Sdim if (Right.Type == TT_CtorInitializerComma && 1490263508Sdim Style.BreakConstructorInitializersBeforeComma) 1491263508Sdim return true; 1492263508Sdim if (Right.isBinaryOperator() && Style.BreakBeforeBinaryOperators) 1493263508Sdim return true; 1494263508Sdim if (Left.is(tok::greater) && Right.is(tok::greater) && 1495263508Sdim Left.Type != TT_TemplateCloser) 1496263508Sdim return false; 1497263508Sdim if (Left.Type == TT_ArrayInitializerLSquare) 1498263508Sdim return true; 1499263508Sdim return (Left.isBinaryOperator() && Left.isNot(tok::lessless) && 1500263508Sdim !Style.BreakBeforeBinaryOperators) || 1501251662Sdim Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace, 1502251662Sdim tok::kw_class, tok::kw_struct) || 1503263508Sdim Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon, 1504263508Sdim tok::l_square, tok::at) || 1505263508Sdim (Left.is(tok::r_paren) && 1506263508Sdim Right.isOneOf(tok::identifier, tok::kw_const, tok::kw___attribute)) || 1507263508Sdim (Left.is(tok::l_paren) && !Right.is(tok::r_paren)); 1508249261Sdim} 1509249261Sdim 1510251662Sdimvoid TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { 1511251662Sdim llvm::errs() << "AnnotatedTokens:\n"; 1512263508Sdim const FormatToken *Tok = Line.First; 1513251662Sdim while (Tok) { 1514251662Sdim llvm::errs() << " M=" << Tok->MustBreakBefore 1515251662Sdim << " C=" << Tok->CanBreakBefore << " T=" << Tok->Type 1516251662Sdim << " S=" << Tok->SpacesRequiredBefore 1517263508Sdim << " P=" << Tok->SplitPenalty << " Name=" << Tok->Tok.getName() 1518263508Sdim << " L=" << Tok->TotalLength << " PPK=" << Tok->PackingKind 1519263508Sdim << " FakeLParens="; 1520251662Sdim for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i) 1521251662Sdim llvm::errs() << Tok->FakeLParens[i] << "/"; 1522251662Sdim llvm::errs() << " FakeRParens=" << Tok->FakeRParens << "\n"; 1523263508Sdim if (Tok->Next == NULL) 1524263508Sdim assert(Tok == Line.Last); 1525263508Sdim Tok = Tok->Next; 1526251662Sdim } 1527251662Sdim llvm::errs() << "----\n"; 1528251662Sdim} 1529251662Sdim 1530249261Sdim} // namespace format 1531249261Sdim} // namespace clang 1532