Parser refactoring in preparation for mixin declaration support

This is a bunch of renames and cleanup in preparation for
my next CL with basic mixin declaration support.

Rename listener events:
* handleClassImplements to handleClassOrMixinImplements
* beginClassBody to beginClassOrMixinBody
* endClassBody to endClassOrMixinBody

Rename parser methods:
* parseClassMember to parseClassOrMixinMember
* parseClassBody to parseClassOrMixinBody
* skipClassBody to skipClassOrMixinBody

Also:
* Change test expect from "ClassBody" to "ClassOrMixinBody"
* Rename message ExpectedClassBody to ExpectedClassOrMixinBody
* Update text of MISSING_CLASS_BODY to include mixin
* Rename IdentifierContext.classOrNamedMixinDeclaration to classOrMixinDeclaration
Change-Id: Iaa554cc859e1e665475c0eb544895a311c06395a
Reviewed-on: https://dart-review.googlesource.com/70881
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
index ac0dd3e..9ca8202 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
@@ -527,8 +527,8 @@
 
   static const ParserErrorCode MISSING_CLASS_BODY = const ParserErrorCode(
       'MISSING_CLASS_BODY',
-      "A class definition must have a body, even if it is empty.",
-      correction: "Try adding a class body.");
+      "A class or mixin definition must have a body, even if it is empty.",
+      correction: "Try adding a body to your class or mixin.");
 
   static const ParserErrorCode MISSING_CLOSING_PARENTHESIS =
       const ParserErrorCode(
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index f52171a..2fde37f 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -1739,10 +1739,11 @@
   }
 
   @override
-  void endClassBody(int memberCount, Token leftBracket, Token rightBracket) {
+  void endClassOrMixinBody(
+      int memberCount, Token leftBracket, Token rightBracket) {
     assert(optional('{', leftBracket));
     assert(optional('}', rightBracket));
-    debugEvent("ClassBody");
+    debugEvent("ClassOrMixinBody");
 
     classDeclaration.leftBracket = leftBracket;
     classDeclaration.rightBracket = rightBracket;
@@ -1778,7 +1779,8 @@
   }
 
   @override
-  void handleClassImplements(Token implementsKeyword, int interfacesCount) {
+  void handleClassOrMixinImplements(
+      Token implementsKeyword, int interfacesCount) {
     assert(optionalOrNull('implements', implementsKeyword));
     debugEvent("ClassImplements");
 
@@ -1810,7 +1812,8 @@
     Token abstractKeyword = modifiers?.abstractKeyword;
     List<Annotation> metadata = pop();
     Comment comment = _findComment(metadata, begin);
-    // leftBracket, members, and rightBracket are set in [endClassBody].
+    // leftBracket, members, and rightBracket
+    // are set in [endClassOrMixinBody].
     classDeclaration = ast.classDeclaration(
       comment,
       metadata,
diff --git a/pkg/analyzer/lib/src/generated/parser_fasta.dart b/pkg/analyzer/lib/src/generated/parser_fasta.dart
index d6079cf..82e23f4 100644
--- a/pkg/analyzer/lib/src/generated/parser_fasta.dart
+++ b/pkg/analyzer/lib/src/generated/parser_fasta.dart
@@ -134,7 +134,7 @@
       <ClassMember>[],
       null /* rightBracket */,
     );
-    currentToken = fastaParser.parseClassMember(currentToken);
+    currentToken = fastaParser.parseClassOrMixinMember(currentToken);
     ClassDeclaration declaration = astBuilder.classDeclaration;
     astBuilder.classDeclaration = null;
     return declaration.members.isNotEmpty ? declaration.members[0] : null;
diff --git a/pkg/analyzer/test/generated/parser_fasta_listener.dart b/pkg/analyzer/test/generated/parser_fasta_listener.dart
index b489cf5a..40f2c23 100644
--- a/pkg/analyzer/test/generated/parser_fasta_listener.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_listener.dart
@@ -108,9 +108,9 @@
   }
 
   @override
-  void beginClassBody(Token token) {
-    super.beginClassBody(token);
-    begin('ClassBody');
+  void beginClassOrMixinBody(Token token) {
+    super.beginClassOrMixinBody(token);
+    begin('ClassOrMixinBody');
   }
 
   @override
@@ -360,7 +360,7 @@
 
   @override
   void beginMember() {
-    expectIn('ClassBody');
+    expectIn('ClassOrMixinBody');
     super.beginMember();
     begin('Member');
   }
@@ -600,9 +600,9 @@
   }
 
   @override
-  void endClassBody(int memberCount, Token beginToken, Token endToken) {
-    end('ClassBody');
-    super.endClassBody(memberCount, beginToken, endToken);
+  void endClassOrMixinBody(int memberCount, Token beginToken, Token endToken) {
+    end('ClassOrMixinBody');
+    super.endClassOrMixinBody(memberCount, beginToken, endToken);
   }
 
   @override
@@ -1096,9 +1096,10 @@
   }
 
   @override
-  void handleClassImplements(Token implementsKeyword, int interfacesCount) {
-    expectIn('ClassDeclaration');
-    listener.handleClassImplements(implementsKeyword, interfacesCount);
+  void handleClassOrMixinImplements(
+      Token implementsKeyword, int interfacesCount) {
+    expectInOneOf(['ClassDeclaration', 'MixinDeclaration']);
+    listener.handleClassOrMixinImplements(implementsKeyword, interfacesCount);
   }
 
   @override
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index bb251fe..db49d52 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -843,7 +843,7 @@
 
   @override
   ClassMember parseClassMember(String className) {
-    return _run('ClassBody', () => super.parseClassMember(className));
+    return _run('ClassOrMixinBody', () => super.parseClassMember(className));
   }
 
   List<Combinator> parseCombinators() {
diff --git a/pkg/analyzer/tool/summary/mini_ast.dart b/pkg/analyzer/tool/summary/mini_ast.dart
index dce0c1c..4c4eb38 100644
--- a/pkg/analyzer/tool/summary/mini_ast.dart
+++ b/pkg/analyzer/tool/summary/mini_ast.dart
@@ -173,8 +173,8 @@
   }
 
   @override
-  void endClassBody(int memberCount, Token beginToken, Token endToken) {
-    debugEvent("ClassBody");
+  void endClassOrMixinBody(int memberCount, Token beginToken, Token endToken) {
+    debugEvent("ClassOrMixinBody");
     push(popList(memberCount,
         new List<ClassMember>.filled(memberCount, null, growable: true)));
   }
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index c9c7c7b..537c775 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -2357,29 +2357,10 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<Message Function(Token token)> templateExpectedClassBody =
-    const Template<Message Function(Token token)>(
-        messageTemplate: r"""Expected a class body, but got '#lexeme'.""",
-        withArguments: _withArgumentsExpectedClassBody);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(Token token)> codeExpectedClassBody =
-    const Code<Message Function(Token token)>(
-        "ExpectedClassBody", templateExpectedClassBody,
-        analyzerCode: "MISSING_CLASS_BODY", dart2jsCode: "*fatal*");
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsExpectedClassBody(Token token) {
-  String lexeme = token.lexeme;
-  return new Message(codeExpectedClassBody,
-      message: """Expected a class body, but got '${lexeme}'.""",
-      arguments: {'token': token});
-}
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(Token token)> templateExpectedClassBodyToSkip =
     const Template<Message Function(Token token)>(
-        messageTemplate: r"""Expected a class body, but got '#lexeme'.""",
+        messageTemplate:
+            r"""Expected a class or mixin body, but got '#lexeme'.""",
         withArguments: _withArgumentsExpectedClassBodyToSkip);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2392,7 +2373,7 @@
 Message _withArgumentsExpectedClassBodyToSkip(Token token) {
   String lexeme = token.lexeme;
   return new Message(codeExpectedClassBodyToSkip,
-      message: """Expected a class body, but got '${lexeme}'.""",
+      message: """Expected a class or mixin body, but got '${lexeme}'.""",
       arguments: {'token': token});
 }
 
@@ -2417,6 +2398,27 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(Token token)> templateExpectedClassOrMixinBody =
+    const Template<Message Function(Token token)>(
+        messageTemplate:
+            r"""Expected a class or mixin body, but got '#lexeme'.""",
+        withArguments: _withArgumentsExpectedClassOrMixinBody);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(Token token)> codeExpectedClassOrMixinBody =
+    const Code<Message Function(Token token)>(
+        "ExpectedClassOrMixinBody", templateExpectedClassOrMixinBody,
+        analyzerCode: "MISSING_CLASS_BODY", dart2jsCode: "*fatal*");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsExpectedClassOrMixinBody(Token token) {
+  String lexeme = token.lexeme;
+  return new Message(codeExpectedClassOrMixinBody,
+      message: """Expected a class or mixin body, but got '${lexeme}'.""",
+      arguments: {'token': token});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(Token token)> templateExpectedDeclaration =
     const Template<Message Function(Token token)>(
         messageTemplate: r"""Expected a declaration, but got '#lexeme'.""",
diff --git a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
index 12d5c37..49bf6ab 100644
--- a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
@@ -61,8 +61,8 @@
   }
 
   @override
-  void beginClassBody(Token token) {
-    listener?.beginClassBody(token);
+  void beginClassOrMixinBody(Token token) {
+    listener?.beginClassOrMixinBody(token);
   }
 
   @override
@@ -479,8 +479,8 @@
   }
 
   @override
-  void endClassBody(int memberCount, Token beginToken, Token endToken) {
-    listener?.endClassBody(memberCount, beginToken, endToken);
+  void endClassOrMixinBody(int memberCount, Token beginToken, Token endToken) {
+    listener?.endClassOrMixinBody(memberCount, beginToken, endToken);
   }
 
   @override
@@ -923,8 +923,9 @@
   }
 
   @override
-  void handleClassImplements(Token implementsKeyword, int interfacesCount) {
-    listener?.handleClassImplements(implementsKeyword, interfacesCount);
+  void handleClassOrMixinImplements(
+      Token implementsKeyword, int interfacesCount) {
+    listener?.handleClassOrMixinImplements(implementsKeyword, interfacesCount);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/parser/identifier_context.dart b/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
index c064669..460fec9 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
@@ -95,10 +95,10 @@
   static const enumValueDeclaration =
       const EnumValueDeclarationIdentifierContext();
 
-  /// Identifier is the name being declared by a class declaration or a named
-  /// mixin application, for example, `Foo` in `class Foo = X with Y;`.
-  static const classOrNamedMixinDeclaration =
-      const ClassOrNamedMixinIdentifierContext();
+  /// Identifier is the name being declared by a class declaration, a mixin
+  /// declaration, or a named mixin application, for example,
+  /// `Foo` in `class Foo = X with Y;`.
+  static const classOrMixinDeclaration = const ClassOrMixinIdentifierContext();
 
   /// Identifier is the name of a type variable being declared (e.g. `Foo` in
   /// `class C<Foo extends num> {}`).
diff --git a/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart b/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
index 16cf689..9814c3b 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
@@ -43,10 +43,10 @@
   }
 }
 
-/// See [IdentifierContext.classOrNamedMixinDeclaration].
-class ClassOrNamedMixinIdentifierContext extends IdentifierContext {
-  const ClassOrNamedMixinIdentifierContext()
-      : super('classOrNamedMixinDeclaration',
+/// See [IdentifierContext.classOrMixinDeclaration].
+class ClassOrMixinIdentifierContext extends IdentifierContext {
+  const ClassOrMixinIdentifierContext()
+      : super('classOrMixinDeclaration',
             inDeclaration: true, isBuiltInIdentifierAllowed: false);
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/parser/listener.dart b/pkg/front_end/lib/src/fasta/parser/listener.dart
index e3d96f9..d4fa7d9 100644
--- a/pkg/front_end/lib/src/fasta/parser/listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/listener.dart
@@ -76,19 +76,19 @@
     logEvent("CaseExpression");
   }
 
-  void beginClassBody(Token token) {}
+  void beginClassOrMixinBody(Token token) {}
 
-  /// Handle the end of the body of a class declaration.  The only substructures
-  /// are the class members.
-  void endClassBody(int memberCount, Token beginToken, Token endToken) {
-    logEvent("ClassBody");
+  /// Handle the end of the body of a class or mixin declaration.
+  /// The only substructures are the class or mixin members.
+  void endClassOrMixinBody(int memberCount, Token beginToken, Token endToken) {
+    logEvent("ClassOrMixinBody");
   }
 
   /// Called before parsing a class or named mixin application.
   void beginClassOrNamedMixinApplication(Token token) {}
 
   /// Handle the beginning of a class declaration.
-  /// [beginToken] may be the same as [name], or may point to modifiers
+  /// [begin] may be the same as [name], or may point to modifiers
   /// (or extraneous modifiers in the case of recovery) preceding [name].
   void beginClassDeclaration(Token begin, Token abstractToken, Token name) {}
 
@@ -98,9 +98,11 @@
     logEvent("ClassExtends");
   }
 
-  /// Handle an implements clause in a class declaration. Substructures:
+  /// Handle an implements clause in a class or mixin declaration.
+  /// Substructures:
   /// - implemented types
-  void handleClassImplements(Token implementsKeyword, int interfacesCount) {
+  void handleClassOrMixinImplements(
+      Token implementsKeyword, int interfacesCount) {
     logEvent("ClassImplements");
   }
 
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index 80c8118..40b3b4e 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -112,7 +112,7 @@
 /// Parse methods all have the prefix `parse`, generate events
 /// (by calling methods on [listener]), and return the next token to parse.
 /// Some exceptions to this last point are methods such as [parseFunctionBody]
-/// and [parseClassBody] which return the last token parsed
+/// and [parseClassOrMixinBody] which return the last token parsed
 /// rather than the next token to be parsed.
 /// Parse methods are generally named `parseGrammarProductionSuffix`.
 /// The suffix can be one of `opt`, or `star`.
@@ -1643,7 +1643,7 @@
     Token begin = abstractToken ?? classKeyword;
     listener.beginClassOrNamedMixinApplication(begin);
     Token name = ensureIdentifier(
-        classKeyword, IdentifierContext.classOrNamedMixinDeclaration);
+        classKeyword, IdentifierContext.classOrMixinDeclaration);
     Token token = computeTypeParamOrArg(name, true).parseVariables(name, this);
     if (optional('=', token.next)) {
       listener.beginNamedMixinApplication(begin, abstractToken, name);
@@ -1688,16 +1688,16 @@
     if (!optional('{', token.next)) {
       // Recovery
       token = parseClassHeaderRecovery(start, begin, classKeyword);
-      ensureBlock(token, fasta.templateExpectedClassBody);
+      ensureBlock(token, fasta.templateExpectedClassOrMixinBody);
     }
-    token = parseClassBody(token);
+    token = parseClassOrMixinBody(token);
     listener.endClassDeclaration(begin, token);
     return token;
   }
 
   Token parseClassHeaderOpt(Token token, Token begin, Token classKeyword) {
     token = parseClassExtendsOpt(token);
-    token = parseClassImplementsOpt(token);
+    token = parseClassOrMixinImplementsOpt(token);
     Token nativeToken;
     if (optional('native', token.next)) {
       nativeToken = token.next;
@@ -1783,7 +1783,7 @@
         }
       }
 
-      token = parseClassImplementsOpt(token);
+      token = parseClassOrMixinImplementsOpt(token);
 
       if (recoveryListener.implementsKeyword != null) {
         if (hasImplements) {
@@ -1830,7 +1830,7 @@
   ///   'implements' typeName (',' typeName)*
   /// ;
   /// ```
-  Token parseClassImplementsOpt(Token token) {
+  Token parseClassOrMixinImplementsOpt(Token token) {
     Token implementsKeyword;
     int interfacesCount = 0;
     if (optional('implements', token.next)) {
@@ -1841,7 +1841,7 @@
         ++interfacesCount;
       } while (optional(',', token.next));
     }
-    listener.handleClassImplements(implementsKeyword, interfacesCount);
+    listener.handleClassOrMixinImplements(implementsKeyword, interfacesCount);
     return token;
   }
 
@@ -2515,9 +2515,9 @@
     return token;
   }
 
-  Token skipClassBody(Token token) {
+  Token skipClassOrMixinBody(Token token) {
     // The scanner ensures that `{` always has a closing `}`.
-    return ensureBlock(token, fasta.templateExpectedClassBody);
+    return ensureBlock(token, fasta.templateExpectedClassOrMixinBody);
   }
 
   /// ```
@@ -2525,18 +2525,18 @@
   ///   '{' classMember* '}'
   /// ;
   /// ```
-  Token parseClassBody(Token token) {
+  Token parseClassOrMixinBody(Token token) {
     Token begin = token = token.next;
     assert(optional('{', token));
-    listener.beginClassBody(token);
+    listener.beginClassOrMixinBody(token);
     int count = 0;
     while (notEofOrValue('}', token.next)) {
-      token = parseClassMemberImpl(token);
+      token = parseClassOrMixinMemberImpl(token);
       ++count;
     }
     token = token.next;
     assert(optional('}', token));
-    listener.endClassBody(count, begin, token);
+    listener.endClassOrMixinBody(count, begin, token);
     return token;
   }
 
@@ -2545,14 +2545,14 @@
       token.lexeme == 'unary' &&
       optional('-', token.next);
 
-  /// Parse a class member.
+  /// Parse a class or mixin member.
   ///
   /// This method is only invoked from outside the parser. As a result, this
   /// method takes the next token to be consumed rather than the last consumed
   /// token and returns the token after the last consumed token rather than the
   /// last consumed token.
-  Token parseClassMember(Token token) {
-    return parseClassMemberImpl(syntheticPreviousToken(token)).next;
+  Token parseClassOrMixinMember(Token token) {
+    return parseClassOrMixinMemberImpl(syntheticPreviousToken(token)).next;
   }
 
   /// ```
@@ -2561,8 +2561,13 @@
   ///   constructorDeclaration |
   ///   methodDeclaration
   /// ;
+  ///
+  /// mixinMember:
+  ///   fieldDeclaration |
+  ///   methodDeclaration
+  /// ;
   /// ```
-  Token parseClassMemberImpl(Token token) {
+  Token parseClassOrMixinMemberImpl(Token token) {
     Token beforeStart = token = parseMetadataStar(token);
 
     Token covariantToken;
diff --git a/pkg/front_end/lib/src/fasta/parser/recovery_listeners.dart b/pkg/front_end/lib/src/fasta/parser/recovery_listeners.dart
index 05159cd..9ffcb3e 100644
--- a/pkg/front_end/lib/src/fasta/parser/recovery_listeners.dart
+++ b/pkg/front_end/lib/src/fasta/parser/recovery_listeners.dart
@@ -30,9 +30,10 @@
   }
 
   @override
-  void handleClassImplements(Token implementsKeyword, int interfacesCount) {
+  void handleClassOrMixinImplements(
+      Token implementsKeyword, int interfacesCount) {
     this.implementsKeyword = implementsKeyword;
-    super.handleClassImplements(implementsKeyword, interfacesCount);
+    super.handleClassOrMixinImplements(implementsKeyword, interfacesCount);
   }
 }
 
diff --git a/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart b/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart
index 98dc6fb..cf47b09 100644
--- a/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/top_level_parser.dart
@@ -15,5 +15,5 @@
 class TopLevelParser extends ClassMemberParser {
   TopLevelParser(Listener listener) : super(listener);
 
-  Token parseClassBody(Token token) => skipClassBody(token);
+  Token parseClassOrMixinBody(Token token) => skipClassOrMixinBody(token);
 }
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index 54ac074..fcab286 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -653,7 +653,7 @@
   }
 
   @override
-  void beginClassBody(Token token) {
+  void beginClassOrMixinBody(Token token) {
     debugEvent("beginClassBody");
     String name = pop();
     Token metadata = pop();
@@ -668,8 +668,8 @@
   }
 
   @override
-  void endClassBody(int memberCount, Token beginToken, Token endToken) {
-    debugEvent("ClassBody");
+  void endClassOrMixinBody(int memberCount, Token beginToken, Token endToken) {
+    debugEvent("ClassOrMixinBody");
     currentClass = null;
     memberScope = library.scope;
   }
@@ -785,7 +785,7 @@
     if (isTopLevel) {
       token = parser.parseTopLevelMember(metadata ?? token);
     } else {
-      token = parser.parseClassMember(metadata ?? token).next;
+      token = parser.parseClassOrMixinMember(metadata ?? token).next;
     }
     listenerFinishFields(listener, startToken, metadata, isTopLevel);
     listener.checkEmpty(token.charOffset);
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index 682a025..d487929 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -442,7 +442,8 @@
   }
 
   @override
-  void handleClassImplements(Token implementsKeyword, int interfacesCount) {
+  void handleClassOrMixinImplements(
+      Token implementsKeyword, int interfacesCount) {
     debugEvent("handleClassImplements");
     push(popList(
             interfacesCount,
@@ -1370,8 +1371,8 @@
   }
 
   @override
-  void endClassBody(int memberCount, Token beginToken, Token endToken) {
-    debugEvent("ClassBody");
+  void endClassOrMixinBody(int memberCount, Token beginToken, Token endToken) {
+    debugEvent("ClassOrMixinBody");
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/source/stack_listener.dart b/pkg/front_end/lib/src/fasta/source/stack_listener.dart
index a6d853c..154b20a 100644
--- a/pkg/front_end/lib/src/fasta/source/stack_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/stack_listener.dart
@@ -205,7 +205,8 @@
   }
 
   @override
-  void handleClassImplements(Token implementsKeyword, int interfacesCount) {
+  void handleClassOrMixinImplements(
+      Token implementsKeyword, int interfacesCount) {
     debugEvent("ClassImplements");
   }
 
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 87d2bb0..2b6a9a5 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -122,8 +122,8 @@
 ExpectedBlockToSkip/script: Fail
 ExpectedButGot/script1: Fail
 ExpectedButGot/script2: Fail
-ExpectedClassBody/example: Fail
 ExpectedClassMember/example: Fail
+ExpectedClassOrMixinBody/example: Fail
 ExpectedDeclaration/example: Fail
 ExpectedFunctionBody/example: Fail
 ExpectedNamedArgument/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 2124b1e..e240cc0 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -310,12 +310,12 @@
   dart2jsCode: "GENERIC"
   script: "class A implements B implements C, D {}"
 
-ExpectedClassBody:
-  template: "Expected a class body, but got '#lexeme'."
+ExpectedClassOrMixinBody:
+  template: "Expected a class or mixin body, but got '#lexeme'."
   analyzerCode: MISSING_CLASS_BODY
   dart2jsCode: "*fatal*"
 
-ExpectedClassBodyToSkip: ExpectedClassBody
+ExpectedClassBodyToSkip: ExpectedClassOrMixinBody
 
 ExpectedDeclaration:
   template: "Expected a declaration, but got '#lexeme'."