diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 34c0c8380729..94b849881941 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -818,7 +818,8 @@ void UnwrappedLineParser::parseStructuralElement() { case tok::kw_enum: // parseEnum falls through and does not yet add an unwrapped line as an // enum definition can start a structural element. - parseEnum(); + if (!parseEnum()) + break; // This only applies for C++. if (Style.Language != FormatStyle::LK_Cpp) { addUnwrappedLine(); @@ -1524,11 +1525,17 @@ void UnwrappedLineParser::parseAccessSpecifier() { addUnwrappedLine(); } -void UnwrappedLineParser::parseEnum() { +bool UnwrappedLineParser::parseEnum() { // Won't be 'enum' for NS_ENUMs. if (FormatTok->Tok.is(tok::kw_enum)) nextToken(); + // In TypeScript, "enum" can also be used as property name, e.g. in interface + // declarations. An "enum" keyword followed by a colon would be a syntax + // error and thus assume it is just an identifier. + if (Style.Language == FormatStyle::LK_JavaScript && FormatTok->is(tok::colon)) + return false; + // Eat up enum class ... if (FormatTok->Tok.is(tok::kw_class) || FormatTok->Tok.is(tok::kw_struct)) nextToken(); @@ -1546,22 +1553,23 @@ void UnwrappedLineParser::parseEnum() { // return type. In Java, this can be "implements", etc. if (Style.Language == FormatStyle::LK_Cpp && FormatTok->is(tok::identifier)) - return; + return false; } } // Just a declaration or something is wrong. if (FormatTok->isNot(tok::l_brace)) - return; + return true; FormatTok->BlockKind = BK_Block; if (Style.Language == FormatStyle::LK_Java) { // Java enums are different. parseJavaEnumBody(); - return; - } else if (Style.Language == FormatStyle::LK_Proto) { + return true; + } + if (Style.Language == FormatStyle::LK_Proto) { parseBlock(/*MustBeDeclaration=*/true); - return; + return true; } // Parse enum body. @@ -1571,6 +1579,7 @@ void UnwrappedLineParser::parseEnum() { nextToken(); addUnwrappedLine(); } + return true; // There is no addUnwrappedLine() here so that we fall through to parsing a // structural element afterwards. Thus, in "enum A {} n, m;", diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index c2fa02957685..a13c03f94086 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -96,7 +96,7 @@ private: void parseNamespace(); void parseNew(); void parseAccessSpecifier(); - void parseEnum(); + bool parseEnum(); void parseJavaEnumBody(); void parseRecord(); void parseObjCProtocolList(); diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp index 9bfd587412d3..56b493dae1c1 100644 --- a/clang/unittests/Format/FormatTestJS.cpp +++ b/clang/unittests/Format/FormatTestJS.cpp @@ -762,6 +762,7 @@ TEST_F(FormatTestJS, ClassDeclarations) { TEST_F(FormatTestJS, InterfaceDeclarations) { verifyFormat("interface I {\n" " x: string;\n" + " enum: string[];\n" "}\n" "var y;"); // Ensure that state is reset after parsing the interface.