Skip to content

Commit 77d63cf

Browse files
krasimirggowenca
andauthored
[clang-format] js handle anonymous classes (#106242)
Addresses a regression in JavaScript when formatting anonymous classes. --------- Co-authored-by: Owen Pan <[email protected]>
1 parent f7a74ec commit 77d63cf

File tree

3 files changed

+20
-2
lines changed

3 files changed

+20
-2
lines changed

clang/lib/Format/UnwrappedLineParser.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -3992,6 +3992,9 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
39923992
auto IsNonMacroIdentifier = [](const FormatToken *Tok) {
39933993
return Tok->is(tok::identifier) && Tok->TokenText != Tok->TokenText.upper();
39943994
};
3995+
// JavaScript/TypeScript supports anonymous classes like:
3996+
// a = class extends foo { }
3997+
bool JSPastExtendsOrImplements = false;
39953998
// The actual identifier can be a nested name specifier, and in macros
39963999
// it is often token-pasted.
39974000
// An [[attribute]] can be before the identifier.
@@ -4002,6 +4005,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
40024005
FormatTok->isOneOf(tok::period, tok::comma))) {
40034006
if (Style.isJavaScript() &&
40044007
FormatTok->isOneOf(Keywords.kw_extends, Keywords.kw_implements)) {
4008+
JSPastExtendsOrImplements = true;
40054009
// JavaScript/TypeScript supports inline object types in
40064010
// extends/implements positions:
40074011
// class Foo implements {bar: number} { }
@@ -4027,8 +4031,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
40274031
case tok::coloncolon:
40284032
break;
40294033
default:
4030-
if (!ClassName && Previous->is(tok::identifier) &&
4031-
Previous->isNot(TT_AttributeMacro)) {
4034+
if (!JSPastExtendsOrImplements && !ClassName &&
4035+
Previous->is(tok::identifier) && Previous->isNot(TT_AttributeMacro)) {
40324036
ClassName = Previous;
40334037
}
40344038
}

clang/unittests/Format/FormatTestJS.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,14 @@ TEST_F(FormatTestJS, GoogScopes) {
579579
"});");
580580
}
581581

582+
TEST_F(FormatTestJS, GoogAnonymousClass) {
583+
verifyFormat("a = class extends goog.structs.a {\n"
584+
" a() {\n"
585+
" return 0;\n"
586+
" }\n"
587+
"};");
588+
}
589+
582590
TEST_F(FormatTestJS, IIFEs) {
583591
// Internal calling parens; no semi.
584592
verifyFormat("(function() {\n"

clang/unittests/Format/TokenAnnotatorTest.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -3238,6 +3238,12 @@ TEST_F(TokenAnnotatorTest, BraceKind) {
32383238
EXPECT_BRACE_KIND(Tokens[8], BK_BracedInit);
32393239
EXPECT_BRACE_KIND(Tokens[11], BK_BracedInit);
32403240
EXPECT_BRACE_KIND(Tokens[13], BK_Block);
3241+
3242+
Tokens = annotate("a = class extends goog.a {};",
3243+
getGoogleStyle(FormatStyle::LK_JavaScript));
3244+
ASSERT_EQ(Tokens.size(), 11u) << Tokens;
3245+
EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_ClassLBrace);
3246+
EXPECT_BRACE_KIND(Tokens[7], BK_Block);
32413247
}
32423248

32433249
TEST_F(TokenAnnotatorTest, UnderstandsElaboratedTypeSpecifier) {

0 commit comments

Comments
 (0)