diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp')
| -rw-r--r-- | contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp | 361 | 
1 files changed, 265 insertions, 96 deletions
diff --git a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp index ec04af5231be..939528fbffe5 100644 --- a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp +++ b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp @@ -14,7 +14,9 @@  //===----------------------------------------------------------------------===//  #include "UnwrappedLineParser.h" +#include "llvm/ADT/STLExtras.h"  #include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h"  #define DEBUG_TYPE "format-parser" @@ -56,22 +58,20 @@ private:  class ScopedMacroState : public FormatTokenSource {  public:    ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource, -                   FormatToken *&ResetToken, bool &StructuralError) +                   FormatToken *&ResetToken)        : Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),          PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource), -        StructuralError(StructuralError), -        PreviousStructuralError(StructuralError), Token(nullptr) { +        Token(nullptr) {      TokenSource = this;      Line.Level = 0;      Line.InPPDirective = true;    } -  ~ScopedMacroState() { +  ~ScopedMacroState() override {      TokenSource = PreviousTokenSource;      ResetToken = Token;      Line.InPPDirective = false;      Line.Level = PreviousLineLevel; -    StructuralError = PreviousStructuralError;    }    FormatToken *getNextToken() override { @@ -110,8 +110,6 @@ private:    FormatToken *&ResetToken;    unsigned PreviousLineLevel;    FormatTokenSource *PreviousTokenSource; -  bool &StructuralError; -  bool PreviousStructuralError;    FormatToken *Token;  }; @@ -206,9 +204,8 @@ UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style,                                           ArrayRef<FormatToken *> Tokens,                                           UnwrappedLineConsumer &Callback)      : Line(new UnwrappedLine), MustBreakBeforeNextToken(false), -      CurrentLines(&Lines), StructuralError(false), Style(Style), -      Keywords(Keywords), Tokens(nullptr), Callback(Callback), -      AllTokens(Tokens), PPBranchLevel(-1) {} +      CurrentLines(&Lines), Style(Style), Keywords(Keywords), Tokens(nullptr), +      Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1) {}  void UnwrappedLineParser::reset() {    PPBranchLevel = -1; @@ -219,11 +216,10 @@ void UnwrappedLineParser::reset() {    PreprocessorDirectives.clear();    CurrentLines = &Lines;    DeclarationScopeStack.clear(); -  StructuralError = false;    PPStack.clear();  } -bool UnwrappedLineParser::parse() { +void UnwrappedLineParser::parse() {    IndexedTokenSource TokenSource(AllTokens);    do {      DEBUG(llvm::dbgs() << "----\n"); @@ -256,13 +252,15 @@ bool UnwrappedLineParser::parse() {      }    } while (!PPLevelBranchIndex.empty()); -  return StructuralError;  }  void UnwrappedLineParser::parseFile() { -  ScopedDeclarationState DeclarationState( -      *Line, DeclarationScopeStack, -      /*MustBeDeclaration=*/ !Line->InPPDirective); +  // The top-level context in a file always has declarations, except for pre- +  // processor directives and JavaScript files. +  bool MustBeDeclaration = +      !Line->InPPDirective && Style.Language != FormatStyle::LK_JavaScript; +  ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, +                                          MustBeDeclaration);    parseLevel(/*HasOpeningBrace=*/false);    // Make sure to format the remaining tokens.    flushComments(true); @@ -286,7 +284,6 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {      case tok::r_brace:        if (HasOpeningBrace)          return; -      StructuralError = true;        nextToken();        addUnwrappedLine();        break; @@ -305,7 +302,7 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {    } while (!eof());  } -void UnwrappedLineParser::calculateBraceTypes() { +void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {    // We'll parse forward through the tokens until we hit    // a closing brace or eof - note that getNextToken() will    // parse macros, so this will magically work inside macro @@ -328,6 +325,7 @@ void UnwrappedLineParser::calculateBraceTypes() {      switch (Tok->Tok.getKind()) {      case tok::l_brace: +      Tok->BlockKind = BK_Unknown;        LBraceStack.push_back(Tok);        break;      case tok::r_brace: @@ -351,9 +349,11 @@ void UnwrappedLineParser::calculateBraceTypes() {              //              // We exclude + and - as they can be ObjC visibility modifiers.              ProbablyBracedList = -                NextTok->isOneOf(tok::comma, tok::semi, tok::period, tok::colon, +                NextTok->isOneOf(tok::comma, tok::period, tok::colon,                                   tok::r_paren, tok::r_square, tok::l_brace,                                   tok::l_paren, tok::ellipsis) || +                (NextTok->is(tok::semi) && +                 (!ExpectClassBody || LBraceStack.size() != 1)) ||                  (NextTok->isBinaryOperator() && !NextIsObjCMethod);            }            if (ProbablyBracedList) { @@ -374,6 +374,7 @@ void UnwrappedLineParser::calculateBraceTypes() {      case tok::kw_for:      case tok::kw_switch:      case tok::kw_try: +    case tok::kw___try:        if (!LBraceStack.empty())          LBraceStack.back()->BlockKind = BK_Block;        break; @@ -407,7 +408,6 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,    if (!FormatTok->Tok.is(tok::r_brace)) {      Line->Level = InitialLevel; -    StructuralError = true;      return;    } @@ -417,7 +417,7 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,    Line->Level = InitialLevel;  } -static bool IsGoogScope(const UnwrappedLine &Line) { +static bool isGoogScope(const UnwrappedLine &Line) {    // FIXME: Closure-library specific stuff should not be hard-coded but be    // configurable.    if (Line.Tokens.size() < 4) @@ -453,12 +453,13 @@ void UnwrappedLineParser::parseChildBlock() {    nextToken();    {      bool GoogScope = -        Style.Language == FormatStyle::LK_JavaScript && IsGoogScope(*Line); +        Style.Language == FormatStyle::LK_JavaScript && isGoogScope(*Line);      ScopedLineState LineState(*this);      ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,                                              /*MustBeDeclaration=*/false);      Line->Level += GoogScope ? 0 : 1;      parseLevel(/*HasOpeningBrace=*/true); +    flushComments(isOnNewLine(*FormatTok));      Line->Level -= GoogScope ? 0 : 1;    }    nextToken(); @@ -466,7 +467,7 @@ void UnwrappedLineParser::parseChildBlock() {  void UnwrappedLineParser::parsePPDirective() {    assert(FormatTok->Tok.is(tok::hash) && "'#' expected"); -  ScopedMacroState MacroState(*Line, Tokens, FormatTok, StructuralError); +  ScopedMacroState MacroState(*Line, Tokens, FormatTok);    nextToken();    if (!FormatTok->Tok.getIdentifierInfo()) { @@ -549,6 +550,7 @@ void UnwrappedLineParser::conditionalCompilationEnd() {  void UnwrappedLineParser::parsePPIf(bool IfDef) {    nextToken();    bool IsLiteralFalse = (FormatTok->Tok.isLiteral() && +                         FormatTok->Tok.getLiteralData() != nullptr &&                           StringRef(FormatTok->Tok.getLiteralData(),                                     FormatTok->Tok.getLength()) == "0") ||                          FormatTok->Tok.is(tok::kw_false); @@ -602,7 +604,7 @@ void UnwrappedLineParser::parsePPUnknown() {  // Here we blacklist certain tokens that are not usually the first token in an  // unwrapped line. This is used in attempt to distinguish macro calls without  // trailing semicolons from other constructs split to several lines. -bool tokenCanStartNewLine(clang::Token Tok) { +static bool tokenCanStartNewLine(const clang::Token &Tok) {    // Semicolon can be a null-statement, l_square can be a start of a macro or    // a C++11 attribute, but this doesn't seem to be common.    return Tok.isNot(tok::semi) && Tok.isNot(tok::l_brace) && @@ -655,6 +657,11 @@ void UnwrappedLineParser::parseStructuralElement() {        nextToken();        addUnwrappedLine();        return; +    case tok::objc_try: +      // This branch isn't strictly necessary (the kw_try case below would +      // do this too after the tok::at is parsed above).  But be explicit. +      parseTryCatch(); +      return;      default:        break;      } @@ -662,10 +669,13 @@ void UnwrappedLineParser::parseStructuralElement() {    case tok::kw_asm:      nextToken();      if (FormatTok->is(tok::l_brace)) { +      FormatTok->Type = TT_InlineASMBrace;        nextToken();        while (FormatTok && FormatTok->isNot(tok::eof)) {          if (FormatTok->is(tok::r_brace)) { +          FormatTok->Type = TT_InlineASMBrace;            nextToken(); +          addUnwrappedLine();            break;          }          FormatTok->Finalized = true; @@ -686,7 +696,8 @@ void UnwrappedLineParser::parseStructuralElement() {    case tok::kw_public:    case tok::kw_protected:    case tok::kw_private: -    if (Style.Language == FormatStyle::LK_Java) +    if (Style.Language == FormatStyle::LK_Java || +        Style.Language == FormatStyle::LK_JavaScript)        nextToken();      else        parseAccessSpecifier(); @@ -712,6 +723,7 @@ void UnwrappedLineParser::parseStructuralElement() {      parseCaseLabel();      return;    case tok::kw_try: +  case tok::kw___try:      parseTryCatch();      return;    case tok::kw_extern: @@ -725,11 +737,30 @@ void UnwrappedLineParser::parseStructuralElement() {        }      }      break; +  case tok::kw_export: +    if (Style.Language == FormatStyle::LK_JavaScript) { +      parseJavaScriptEs6ImportExport(); +      return; +    } +    break;    case tok::identifier: -    if (FormatTok->IsForEachMacro) { +    if (FormatTok->is(TT_ForEachMacro)) {        parseForOrWhileLoop();        return;      } +    if (Style.Language == FormatStyle::LK_JavaScript && +        FormatTok->is(Keywords.kw_import)) { +      parseJavaScriptEs6ImportExport(); +      return; +    } +    if (FormatTok->is(Keywords.kw_signals)) { +      nextToken(); +      if (FormatTok->is(tok::colon)) { +        nextToken(); +        addUnwrappedLine(); +      } +      return; +    }      // In all other cases, parse the declaration.      break;    default: @@ -806,26 +837,42 @@ void UnwrappedLineParser::parseStructuralElement() {        parseTryCatch();        return;      case tok::identifier: { -      StringRef Text = FormatTok->TokenText;        // Parse function literal unless 'function' is the first token in a line        // in which case this should be treated as a free-standing function. -      if (Style.Language == FormatStyle::LK_JavaScript && Text == "function" && -          Line->Tokens.size() > 0) { +      if (Style.Language == FormatStyle::LK_JavaScript && +          FormatTok->is(Keywords.kw_function) && Line->Tokens.size() > 0) {          tryToParseJSFunction();          break;        } +      if ((Style.Language == FormatStyle::LK_JavaScript || +           Style.Language == FormatStyle::LK_Java) && +          FormatTok->is(Keywords.kw_interface)) { +        parseRecord(); +        break; +      } + +      StringRef Text = FormatTok->TokenText;        nextToken(); -      if (Line->Tokens.size() == 1) { -        if (FormatTok->Tok.is(tok::colon)) { +      if (Line->Tokens.size() == 1 && +          // JS doesn't have macros, and within classes colons indicate fields, +          // not labels. +          Style.Language != FormatStyle::LK_JavaScript) { +        if (FormatTok->Tok.is(tok::colon) && !Line->MustBeDeclaration) {            parseLabel();            return;          }          // Recognize function-like macro usages without trailing semicolon as -        // well as free-standing macrose like Q_OBJECT. +        // well as free-standing macros like Q_OBJECT.          bool FunctionLike = FormatTok->is(tok::l_paren);          if (FunctionLike)            parseParens(); -        if (FormatTok->NewlinesBefore > 0 && + +        bool FollowedByNewline = +            CommentsBeforeNextToken.empty() +                ? FormatTok->NewlinesBefore > 0 +                : CommentsBeforeNextToken.front()->NewlinesBefore > 0; + +        if (FollowedByNewline &&              (Text.size() >= 5 || FunctionLike) &&              tokenCanStartNewLine(FormatTok->Tok) && Text == Text.upper()) {            addUnwrappedLine(); @@ -835,6 +882,17 @@ void UnwrappedLineParser::parseStructuralElement() {        break;      }      case tok::equal: +      // Fat arrows (=>) have tok::TokenKind tok::equal but TokenType +      // TT_JsFatArrow. The always start an expression or a child block if +      // followed by a curly. +      if (FormatTok->is(TT_JsFatArrow)) { +        nextToken(); +        if (FormatTok->is(tok::l_brace)) { +          parseChildBlock(); +        } +        break; +      } +        nextToken();        if (FormatTok->Tok.is(tok::l_brace)) {          parseBracedList(); @@ -843,6 +901,9 @@ void UnwrappedLineParser::parseStructuralElement() {      case tok::l_square:        parseSquare();        break; +    case tok::kw_new: +      parseNew(); +      break;      default:        nextToken();        break; @@ -952,22 +1013,48 @@ void UnwrappedLineParser::tryToParseJSFunction() {    // Consume function name.    if (FormatTok->is(tok::identifier)) -      nextToken(); +    nextToken();    if (FormatTok->isNot(tok::l_paren))      return; -  nextToken(); -  while (FormatTok->isNot(tok::l_brace)) { -    // Err on the side of caution in order to avoid consuming the full file in -    // case of incomplete code. -    if (!FormatTok->isOneOf(tok::identifier, tok::comma, tok::r_paren, -                            tok::comment)) -      return; + +  // Parse formal parameter list. +  parseBalanced(tok::l_paren, tok::r_paren); + +  if (FormatTok->is(tok::colon)) { +    // Parse a type definition.      nextToken(); + +    // Eat the type declaration. For braced inline object types, balance braces, +    // otherwise just parse until finding an l_brace for the function body. +    if (FormatTok->is(tok::l_brace)) { +      parseBalanced(tok::l_brace, tok::r_brace); +    } else { +      while(FormatTok->isNot(tok::l_brace) && !eof()) { +        nextToken(); +      } +    }    } +    parseChildBlock();  } +void UnwrappedLineParser::parseBalanced(tok::TokenKind OpenKind, +                                        tok::TokenKind CloseKind) { +  assert(FormatTok->is(OpenKind)); +  nextToken(); +  int Depth = 1; +  while (Depth > 0 && !eof()) { +    // Parse the formal parameter list. +    if (FormatTok->is(OpenKind)) { +      ++Depth; +    } else if (FormatTok->is(CloseKind)) { +      --Depth; +    } +    nextToken(); +  } +} +  bool UnwrappedLineParser::tryToParseBracedList() {    if (FormatTok->BlockKind == BK_Unknown)      calculateBraceTypes(); @@ -985,10 +1072,19 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {    // FIXME: Once we have an expression parser in the UnwrappedLineParser,    // replace this by using parseAssigmentExpression() inside.    do { -    if (Style.Language == FormatStyle::LK_JavaScript && -        FormatTok->is(Keywords.kw_function)) { -      tryToParseJSFunction(); -      continue; +    if (Style.Language == FormatStyle::LK_JavaScript) { +      if (FormatTok->is(Keywords.kw_function)) { +        tryToParseJSFunction(); +        continue; +      } else if (FormatTok->is(TT_JsFatArrow)) { +        nextToken(); +        // Fat arrows can be followed by simple expressions or by child blocks +        // in curly braces. +        if (FormatTok->is(tok::l_brace)){ +          parseChildBlock(); +          continue; +        } +      }      }      switch (FormatTok->Tok.getKind()) {      case tok::caret: @@ -1006,6 +1102,17 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {        FormatTok->BlockKind = BK_BracedInit;        parseBracedList();        break; +    case tok::r_paren: +      // JavaScript can just have free standing methods and getters/setters in +      // object literals. Detect them by a "{" following ")". +      if (Style.Language == FormatStyle::LK_JavaScript) { +        nextToken(); +        if (FormatTok->is(tok::l_brace)) +          parseChildBlock(); +        break; +      } +      nextToken(); +      break;      case tok::r_brace:        nextToken();        return !HasError; @@ -1046,9 +1153,8 @@ void UnwrappedLineParser::parseParens() {        tryToParseLambda();        break;      case tok::l_brace: -      if (!tryToParseBracedList()) { +      if (!tryToParseBracedList())          parseChildBlock(); -      }        break;      case tok::at:        nextToken(); @@ -1088,9 +1194,8 @@ void UnwrappedLineParser::parseSquare() {        parseSquare();        break;      case tok::l_brace: { -      if (!tryToParseBracedList()) { +      if (!tryToParseBracedList())          parseChildBlock(); -      }        break;      }      case tok::at: @@ -1148,7 +1253,7 @@ void UnwrappedLineParser::parseIfThenElse() {  }  void UnwrappedLineParser::parseTryCatch() { -  assert(FormatTok->is(tok::kw_try) && "'try' expected"); +  assert(FormatTok->isOneOf(tok::kw_try, tok::kw___try) && "'try' expected");    nextToken();    bool NeedsUnwrappedLine = false;    if (FormatTok->is(tok::colon)) { @@ -1158,8 +1263,6 @@ void UnwrappedLineParser::parseTryCatch() {        nextToken();        if (FormatTok->is(tok::l_paren))          parseParens(); -      else -        StructuralError = true;        if (FormatTok->is(tok::comma))          nextToken();      } @@ -1182,23 +1285,29 @@ void UnwrappedLineParser::parseTryCatch() {      // The C++ standard requires a compound-statement after a try.      // If there's none, we try to assume there's a structuralElement      // and try to continue. -    StructuralError = true;      addUnwrappedLine();      ++Line->Level;      parseStructuralElement();      --Line->Level;    } -  while (FormatTok->is(tok::kw_catch) || -         ((Style.Language == FormatStyle::LK_Java || -           Style.Language == FormatStyle::LK_JavaScript) && -          FormatTok->is(Keywords.kw_finally))) { +  while (1) { +    if (FormatTok->is(tok::at)) +      nextToken(); +    if (!(FormatTok->isOneOf(tok::kw_catch, Keywords.kw___except, +                             tok::kw___finally) || +          ((Style.Language == FormatStyle::LK_Java || +            Style.Language == FormatStyle::LK_JavaScript) && +           FormatTok->is(Keywords.kw_finally)) || +          (FormatTok->Tok.isObjCAtKeyword(tok::objc_catch) || +           FormatTok->Tok.isObjCAtKeyword(tok::objc_finally)))) +      break;      nextToken();      while (FormatTok->isNot(tok::l_brace)) {        if (FormatTok->is(tok::l_paren)) {          parseParens();          continue;        } -      if (FormatTok->isOneOf(tok::semi, tok::r_brace)) +      if (FormatTok->isOneOf(tok::semi, tok::r_brace, tok::eof))          return;        nextToken();      } @@ -1242,9 +1351,33 @@ void UnwrappedLineParser::parseNamespace() {    // FIXME: Add error handling.  } +void UnwrappedLineParser::parseNew() { +  assert(FormatTok->is(tok::kw_new) && "'new' expected"); +  nextToken(); +  if (Style.Language != FormatStyle::LK_Java) +    return; + +  // In Java, we can parse everything up to the parens, which aren't optional. +  do { +    // There should not be a ;, { or } before the new's open paren. +    if (FormatTok->isOneOf(tok::semi, tok::l_brace, tok::r_brace)) +      return; + +    // Consume the parens. +    if (FormatTok->is(tok::l_paren)) { +      parseParens(); + +      // If there is a class body of an anonymous class, consume that as child. +      if (FormatTok->is(tok::l_brace)) +        parseChildBlock(); +      return; +    } +    nextToken(); +  } while (!eof()); +} +  void UnwrappedLineParser::parseForOrWhileLoop() { -  assert((FormatTok->Tok.is(tok::kw_for) || FormatTok->Tok.is(tok::kw_while) || -          FormatTok->IsForEachMacro) && +  assert(FormatTok->isOneOf(tok::kw_for, tok::kw_while, TT_ForEachMacro) &&           "'for', 'while' or foreach macro expected");    nextToken();    if (FormatTok->Tok.is(tok::l_paren)) @@ -1304,6 +1437,8 @@ void UnwrappedLineParser::parseLabel() {      }      addUnwrappedLine();    } else { +    if (FormatTok->is(tok::semi)) +      nextToken();      addUnwrappedLine();    }    Line->Level = OldLineLevel; @@ -1338,8 +1473,7 @@ void UnwrappedLineParser::parseSwitch() {  void UnwrappedLineParser::parseAccessSpecifier() {    nextToken();    // Understand Qt's slots. -  if (FormatTok->is(tok::identifier) && -      (FormatTok->TokenText == "slots" || FormatTok->TokenText == "Q_SLOTS")) +  if (FormatTok->isOneOf(Keywords.kw_slots, Keywords.kw_qslots))      nextToken();    // Otherwise, we don't know what it is, and we'd better keep the next token.    if (FormatTok->Tok.is(tok::colon)) @@ -1455,37 +1589,45 @@ void UnwrappedLineParser::parseJavaEnumBody() {  void UnwrappedLineParser::parseRecord() {    const FormatToken &InitialToken = *FormatTok;    nextToken(); -  if (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw___attribute, -                         tok::kw___declspec, tok::kw_alignas)) { + + +  // The actual identifier can be a nested name specifier, and in macros +  // it is often token-pasted. +  while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::hashhash, +                            tok::kw___attribute, tok::kw___declspec, +                            tok::kw_alignas) || +         ((Style.Language == FormatStyle::LK_Java || +           Style.Language == FormatStyle::LK_JavaScript) && +          FormatTok->isOneOf(tok::period, tok::comma))) { +    bool IsNonMacroIdentifier = +        FormatTok->is(tok::identifier) && +        FormatTok->TokenText != FormatTok->TokenText.upper();      nextToken();      // We can have macros or attributes in between 'class' and the class name. -    if (FormatTok->Tok.is(tok::l_paren)) { +    if (!IsNonMacroIdentifier && FormatTok->Tok.is(tok::l_paren))        parseParens(); -    } -    // The actual identifier can be a nested name specifier, and in macros -    // it is often token-pasted. -    while (FormatTok->is(tok::identifier) || FormatTok->is(tok::coloncolon) || -           FormatTok->is(tok::hashhash) || -           (Style.Language == FormatStyle::LK_Java && -            FormatTok->isOneOf(tok::period, tok::comma))) -      nextToken(); +  } -    // Note that parsing away template declarations here leads to incorrectly -    // accepting function declarations as record declarations. -    // In general, we cannot solve this problem. Consider: -    // class A<int> B() {} -    // which can be a function definition or a class definition when B() is a -    // macro. If we find enough real-world cases where this is a problem, we -    // can parse for the 'template' keyword in the beginning of the statement, -    // and thus rule out the record production in case there is no template -    // (this would still leave us with an ambiguity between template function -    // and class declarations). -    if (FormatTok->Tok.is(tok::colon) || FormatTok->Tok.is(tok::less)) { -      while (!eof() && FormatTok->Tok.isNot(tok::l_brace)) { -        if (FormatTok->Tok.is(tok::semi)) -          return; -        nextToken(); +  // Note that parsing away template declarations here leads to incorrectly +  // accepting function declarations as record declarations. +  // In general, we cannot solve this problem. Consider: +  // class A<int> B() {} +  // which can be a function definition or a class definition when B() is a +  // macro. If we find enough real-world cases where this is a problem, we +  // can parse for the 'template' keyword in the beginning of the statement, +  // and thus rule out the record production in case there is no template +  // (this would still leave us with an ambiguity between template function +  // and class declarations). +  if (FormatTok->isOneOf(tok::colon, tok::less)) { +    while (!eof()) { +      if (FormatTok->is(tok::l_brace)) { +        calculateBraceTypes(/*ExpectClassBody=*/true); +        if (!tryToParseBracedList()) +          break;        } +      if (FormatTok->Tok.is(tok::semi)) +        return; +      nextToken();      }    }    if (FormatTok->Tok.is(tok::l_brace)) { @@ -1498,8 +1640,9 @@ void UnwrappedLineParser::parseRecord() {    // We fall through to parsing a structural element afterwards, so    // class A {} n, m;    // will end up in one unwrapped line. -  // This does not apply for Java. -  if (Style.Language == FormatStyle::LK_Java) +  // This does not apply for Java and JavaScript. +  if (Style.Language == FormatStyle::LK_Java || +      Style.Language == FormatStyle::LK_JavaScript)      addUnwrappedLine();  } @@ -1578,6 +1721,35 @@ void UnwrappedLineParser::parseObjCProtocol() {    parseObjCUntilAtEnd();  } +void UnwrappedLineParser::parseJavaScriptEs6ImportExport() { +  assert(FormatTok->isOneOf(Keywords.kw_import, tok::kw_export)); +  nextToken(); + +  // Consume the "default" in "export default class/function". +  if (FormatTok->is(tok::kw_default)) +    nextToken(); + +  // Consume "function" and "default function", so that these get parsed as +  // free-standing JS functions, i.e. do not require a trailing semicolon. +  if (FormatTok->is(Keywords.kw_function)) { +    nextToken(); +    return; +  } + +  if (FormatTok->isOneOf(tok::kw_const, tok::kw_class, Keywords.kw_var)) +    return; // Fall through to parsing the corresponding structure. + +  if (FormatTok->is(tok::l_brace)) { +    FormatTok->BlockKind = BK_Block; +    parseBracedList(); +  } + +  while (!eof() && FormatTok->isNot(tok::semi) && +         FormatTok->isNot(tok::l_brace)) { +    nextToken(); +  } +} +  LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,                                                   StringRef Prefix = "") {    llvm::dbgs() << Prefix << "Line(" << Line.Level << ")" @@ -1634,14 +1806,12 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {             I = CommentsBeforeNextToken.begin(),             E = CommentsBeforeNextToken.end();         I != E; ++I) { -    if (isOnNewLine(**I) && JustComments) { +    if (isOnNewLine(**I) && JustComments)        addUnwrappedLine(); -    }      pushToken(*I);    } -  if (NewlineBeforeNext && JustComments) { +  if (NewlineBeforeNext && JustComments)      addUnwrappedLine(); -  }    CommentsBeforeNextToken.clear();  } @@ -1662,8 +1832,7 @@ void UnwrappedLineParser::readToken() {             (FormatTok->HasUnescapedNewline || FormatTok->IsFirst)) {        // If there is an unfinished unwrapped line, we flush the preprocessor        // directives only after that unwrapped line was finished later. -      bool SwitchToPreprocessorLines = -          !Line->Tokens.empty() && CurrentLines == &Lines; +      bool SwitchToPreprocessorLines = !Line->Tokens.empty();        ScopedLineState BlockState(*this, SwitchToPreprocessorLines);        // Comments stored before the preprocessor directive need to be output        // before the preprocessor directive, at the same level as the  | 
