summaryrefslogtreecommitdiffstats
path: root/lib/Format/UnwrappedLineParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Format/UnwrappedLineParser.cpp')
-rw-r--r--lib/Format/UnwrappedLineParser.cpp361
1 files changed, 265 insertions, 96 deletions
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
index ec04af5..939528f 100644
--- a/lib/Format/UnwrappedLineParser.cpp
+++ b/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
OpenPOWER on IntegriCloud