Skip to content

Commit 633ed8f

Browse files
johnniwintherCommit Queue
authored andcommitted
[parser] Handle empty class/extension type body
This is part of #61699 Change-Id: I93afc3426771c5a179fc77993433ae82aec05ff1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/459460 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Erik Ernst <eernst@google.com>
1 parent f76fa4a commit 633ed8f

32 files changed

+16068
-304
lines changed

pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,11 +2115,21 @@ class ForwardingListener implements Listener {
21152115
listener?.handleNoArguments(token);
21162116
}
21172117

2118+
@override
2119+
void handleNoClassBody(Token semicolonToken) {
2120+
listener?.handleNoClassBody(semicolonToken);
2121+
}
2122+
21182123
@override
21192124
void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) {
21202125
listener?.handleNoConstructorReferenceContinuationAfterTypeArguments(token);
21212126
}
21222127

2128+
@override
2129+
void handleNoExtensionTypeBody(Token semicolonToken) {
2130+
listener?.handleNoExtensionTypeBody(semicolonToken);
2131+
}
2132+
21232133
@override
21242134
void handleNoFieldInitializer(Token token) {
21252135
listener?.handleNoFieldInitializer(token);

pkg/_fe_analyzer_shared/lib/src/parser/listener.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,16 @@ abstract class Listener implements UnescapeErrorListener {
208208
logEvent("ClassDeclaration");
209209
}
210210

211+
/// Handle `;` as a class body.
212+
void handleNoClassBody(Token semicolonToken) {
213+
logEvent("NoClassBody");
214+
}
215+
216+
/// Handle `;` as an extension type body.
217+
void handleNoExtensionTypeBody(Token semicolonToken) {
218+
logEvent("NoExtensionTypeBody");
219+
}
220+
211221
/// Handle the beginning of a mixin declaration.
212222
void beginMixinDeclaration(
213223
Token beginToken,

pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3051,6 +3051,10 @@ class Parser {
30513051
/// typeWithParameters
30523052
/// : typeIdentifier typeParameters?
30533053
/// ;
3054+
/// classBody
3055+
/// : '{' (metadata memberDeclaration)* '}'
3056+
/// | ';'
3057+
/// ;
30543058
/// ```
30553059
Token parseClass(
30563060
Token token,
@@ -3066,16 +3070,28 @@ class Parser {
30663070
/* forExtensionType = */ false,
30673071
);
30683072
token = parseClassHeaderOpt(token, beginToken, classKeyword);
3069-
if (!token.next!.isA(TokenType.OPEN_CURLY_BRACKET)) {
3070-
// Recovery
3071-
token = parseClassHeaderRecovery(start, beginToken, classKeyword);
3072-
ensureBlock(token, BlockKind.classDeclaration);
3073+
if (token.next!.isA(TokenType.SEMICOLON)) {
3074+
Token semicolonToken = token = token.next!;
3075+
if (!_isDeclaringConstructorsFeatureEnabled) {
3076+
reportExperimentNotEnabled(
3077+
ExperimentalFlag.declaringConstructors,
3078+
semicolonToken,
3079+
semicolonToken,
3080+
);
3081+
}
3082+
listener.handleNoClassBody(semicolonToken);
3083+
} else {
3084+
if (!token.next!.isA(TokenType.OPEN_CURLY_BRACKET)) {
3085+
// Recovery
3086+
token = parseClassHeaderRecovery(start, beginToken, classKeyword);
3087+
ensureBlock(token, BlockKind.classDeclaration);
3088+
}
3089+
token = parseClassOrMixinOrExtensionBody(
3090+
token,
3091+
DeclarationKind.Class,
3092+
className,
3093+
);
30733094
}
3074-
token = parseClassOrMixinOrExtensionBody(
3075-
token,
3076-
DeclarationKind.Class,
3077-
className,
3078-
);
30793095
listener.endClassDeclaration(beginToken, token);
30803096
return token;
30813097
}
@@ -3751,19 +3767,31 @@ class Parser {
37513767
);
37523768
Token start = token;
37533769
token = parseClassOrMixinOrEnumImplementsOpt(token);
3754-
if (!token.next!.isA(TokenType.OPEN_CURLY_BRACKET)) {
3755-
// TODO(johnniwinther): Reuse logic from [parseClassHeaderRecovery] to
3756-
// handle `extends`, `with` and out-of-order/duplicate clauses.
3757-
token = parseExtensionTypeHeaderRecovery(start, extensionKeyword);
3770+
if (token.next!.isA(TokenType.SEMICOLON)) {
3771+
Token semicolonToken = token = token.next!;
3772+
if (!_isDeclaringConstructorsFeatureEnabled) {
3773+
reportExperimentNotEnabled(
3774+
ExperimentalFlag.declaringConstructors,
3775+
semicolonToken,
3776+
semicolonToken,
3777+
);
3778+
}
3779+
listener.handleNoExtensionTypeBody(semicolonToken);
3780+
} else {
3781+
if (!token.next!.isA(TokenType.OPEN_CURLY_BRACKET)) {
3782+
// TODO(johnniwinther): Reuse logic from [parseClassHeaderRecovery] to
3783+
// handle `extends`, `with` and out-of-order/duplicate clauses.
3784+
token = parseExtensionTypeHeaderRecovery(start, extensionKeyword);
37583785

3759-
// Recovery
3760-
ensureBlock(token, BlockKind.extensionTypeDeclaration);
3786+
// Recovery
3787+
ensureBlock(token, BlockKind.extensionTypeDeclaration);
3788+
}
3789+
token = parseClassOrMixinOrExtensionBody(
3790+
token,
3791+
DeclarationKind.ExtensionType,
3792+
name.lexeme,
3793+
);
37613794
}
3762-
token = parseClassOrMixinOrExtensionBody(
3763-
token,
3764-
DeclarationKind.ExtensionType,
3765-
name.lexeme,
3766-
);
37673795
listener.endExtensionTypeDeclaration(
37683796
beginToken,
37693797
augmentToken,

pkg/analyzer/lib/src/fasta/ast_builder.dart

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5356,13 +5356,37 @@ class AstBuilder extends StackListener {
53565356
}
53575357
}
53585358

5359+
@override
5360+
void handleNoClassBody(Token semicolonToken) {
5361+
debugEvent("NoClassBody");
5362+
// TODO(scheglov): Handle omitted class body.
5363+
var builder = _classLikeBuilder;
5364+
if (builder != null) {
5365+
builder
5366+
..leftBracket = semicolonToken
5367+
..rightBracket = semicolonToken;
5368+
}
5369+
}
5370+
53595371
@override
53605372
void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) {
53615373
debugEvent("NoConstructorReferenceContinuationAfterTypeArguments");
53625374

53635375
push(NullValues.ConstructorReferenceContinuationAfterTypeArguments);
53645376
}
53655377

5378+
@override
5379+
void handleNoExtensionTypeBody(Token semicolonToken) {
5380+
debugEvent("NoExtensionTypeBody");
5381+
// TODO(scheglov): Handle omitted extension type body.
5382+
var builder = _classLikeBuilder;
5383+
if (builder != null) {
5384+
builder
5385+
..leftBracket = semicolonToken
5386+
..rightBracket = semicolonToken;
5387+
}
5388+
}
5389+
53665390
@override
53675391
void handleNoFieldInitializer(Token token) {
53685392
debugEvent("NoFieldInitializer");

pkg/front_end/lib/src/source/diet_listener.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,38 @@ class DietListener extends StackListenerImpl {
10261026
_memberScope = currentDeclaration.bodyScope;
10271027
}
10281028

1029+
@override
1030+
// Coverage-ignore(suite): Not run.
1031+
void handleNoClassBody(Token semicolonToken) {
1032+
assert(
1033+
checkState(semicolonToken, [
1034+
ValueKinds.Token,
1035+
ValueKinds.IdentifierOrParserRecoveryOrNull,
1036+
ValueKinds.TokenOrNull,
1037+
]),
1038+
);
1039+
debugEvent("NoClassBody");
1040+
pop(); // Begin token
1041+
pop(); // Name
1042+
pop(); // Annotation begin token.
1043+
}
1044+
1045+
@override
1046+
// Coverage-ignore(suite): Not run.
1047+
void handleNoExtensionTypeBody(Token semicolonToken) {
1048+
assert(
1049+
checkState(semicolonToken, [
1050+
ValueKinds.Token,
1051+
ValueKinds.IdentifierOrParserRecoveryOrNull,
1052+
ValueKinds.TokenOrNull,
1053+
]),
1054+
);
1055+
debugEvent("NoExtensionTypeBody");
1056+
pop(); // Begin token
1057+
pop(); // Name
1058+
pop(); // Annotation begin token.
1059+
}
1060+
10291061
@override
10301062
void endClassOrMixinOrExtensionBody(
10311063
DeclarationKind kind,

pkg/front_end/lib/src/source/outline_builder.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4613,6 +4613,20 @@ class OutlineBuilder extends StackListenerImpl {
46134613
nativeMethodName = null;
46144614
}
46154615

4616+
@override
4617+
// Coverage-ignore(suite): Not run.
4618+
void handleNoClassBody(Token semicolonToken) {
4619+
debugEvent("NoClassBody");
4620+
_builderFactory.beginClassBody();
4621+
}
4622+
4623+
@override
4624+
// Coverage-ignore(suite): Not run.
4625+
void handleNoExtensionTypeBody(Token semicolonToken) {
4626+
debugEvent("NoExtensionTypeBody");
4627+
_builderFactory.beginExtensionTypeBody();
4628+
}
4629+
46164630
@override
46174631
void endClassOrMixinOrExtensionBody(
46184632
DeclarationKind kind,

pkg/front_end/lib/src/util/parser_ast.dart

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,13 +1167,23 @@ extension NamedMixinApplicationExtension on NamedMixinApplicationEnd {
11671167

11681168
extension ClassDeclarationExtension on ClassDeclarationEnd {
11691169
// Coverage-ignore(suite): Not run.
1170-
ClassOrMixinOrExtensionBodyEnd getClassOrMixinOrExtensionBody() {
1170+
ClassOrMixinOrExtensionBodyEnd? getClassOrMixinOrExtensionBody() {
11711171
for (ParserAstNode child in children!) {
11721172
if (child is ClassOrMixinOrExtensionBodyEnd) {
11731173
return child;
11741174
}
11751175
}
1176-
throw "Not found.";
1176+
return null;
1177+
}
1178+
1179+
// Coverage-ignore(suite): Not run.
1180+
NoClassBodyHandle? getNoClassBody() {
1181+
for (ParserAstNode child in children!) {
1182+
if (child is NoClassBodyHandle) {
1183+
return child;
1184+
}
1185+
}
1186+
return null;
11771187
}
11781188

11791189
// Coverage-ignore(suite): Not run.
@@ -1212,12 +1222,15 @@ extension ClassDeclarationExtension on ClassDeclarationEnd {
12121222
}
12131223

12141224
// Coverage-ignore(suite): Not run.
1215-
extension ClassOrMixinBodyExtension on ClassOrMixinOrExtensionBodyEnd {
1225+
extension ClassOrMixinBodyExtension on ClassOrMixinOrExtensionBodyEnd? {
12161226
List<MemberEnd> getMembers() {
12171227
List<MemberEnd> members = [];
1218-
for (ParserAstNode child in children!) {
1219-
if (child is MemberEnd) {
1220-
members.add(child);
1228+
List<ParserAstNode>? children = this?.children;
1229+
if (children != null) {
1230+
for (ParserAstNode child in children) {
1231+
if (child is MemberEnd) {
1232+
members.add(child);
1233+
}
12211234
}
12221235
}
12231236
return members;
@@ -1712,13 +1725,22 @@ extension ExtensionTypeDeclarationExtension on ExtensionTypeDeclarationEnd {
17121725
return begin.name;
17131726
}
17141727

1715-
ClassOrMixinOrExtensionBodyEnd getClassOrMixinOrExtensionBody() {
1728+
ClassOrMixinOrExtensionBodyEnd? getClassOrMixinOrExtensionBody() {
17161729
for (ParserAstNode child in children!) {
17171730
if (child is ClassOrMixinOrExtensionBodyEnd) {
17181731
return child;
17191732
}
17201733
}
1721-
throw "Not found.";
1734+
return null;
1735+
}
1736+
1737+
NoExtensionTypeBodyHandle? getNoExtensionTypeBody() {
1738+
for (ParserAstNode child in children!) {
1739+
if (child is NoExtensionTypeBodyHandle) {
1740+
return child;
1741+
}
1742+
}
1743+
return null;
17221744
}
17231745
}
17241746

0 commit comments

Comments
 (0)