Improve top level const/final/var name recovery

Change-Id: Ie07ca020a5f5a6c3abbe2ee48bd83c4e3ea4075c
Reviewed-on: https://dart-review.googlesource.com/54600
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 1f39754e..5e1068a 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -2633,7 +2633,14 @@
 
   void test_constEnum() {
     parseCompilationUnit("const enum E {ONE}",
-        errors: [expectedError(ParserErrorCode.CONST_ENUM, 0, 5)]);
+        errors: usingFastaParser
+            ? [
+                // Fasta interprets the `const` as a malformed top level const
+                // and `enum` as the start of an enum declaration.
+                expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 4),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 4),
+              ]
+            : [expectedError(ParserErrorCode.CONST_ENUM, 0, 5)]);
   }
 
   void test_constFactory() {
@@ -2687,7 +2694,14 @@
 
   void test_constTypedef() {
     parseCompilationUnit("const typedef F();",
-        errors: [expectedError(ParserErrorCode.CONST_TYPEDEF, 0, 5)]);
+        errors: usingFastaParser
+            ? [
+                // Fasta interprets the `const` as a malformed top level const
+                // and `typedef` as the start of an typedef declaration.
+                expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 7),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 7),
+              ]
+            : [expectedError(ParserErrorCode.CONST_TYPEDEF, 0, 5)]);
   }
 
   void test_continueOutsideOfLoop_continueInDoStatement() {
@@ -3616,7 +3630,14 @@
 
   void test_finalEnum() {
     parseCompilationUnit("final enum E {ONE}",
-        errors: [expectedError(ParserErrorCode.FINAL_ENUM, 0, 5)]);
+        errors: usingFastaParser
+            ? [
+                // Fasta interprets the `final` as a malformed top level final
+                // and `enum` as the start of a enum declaration.
+                expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 4),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 4),
+              ]
+            : [expectedError(ParserErrorCode.FINAL_ENUM, 0, 5)]);
   }
 
   void test_finalMethod() {
@@ -3633,7 +3654,14 @@
 
   void test_finalTypedef() {
     parseCompilationUnit("final typedef F();",
-        errors: [expectedError(ParserErrorCode.FINAL_TYPEDEF, 0, 5)]);
+        errors: usingFastaParser
+            ? [
+                // Fasta interprets the `final` as a malformed top level final
+                // and `typedef` as the start of an typedef declaration.
+                expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 7),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 7),
+              ]
+            : [expectedError(ParserErrorCode.FINAL_TYPEDEF, 0, 5)]);
   }
 
   void test_functionTypedField_invalidType_abstract() {
@@ -5702,14 +5730,24 @@
   void test_varClass() {
     parseCompilationUnit("var class C {}",
         errors: usingFastaParser
-            ? [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 0, 3)]
+            ? [
+                // Fasta interprets the `var` as a malformed top level var
+                // and `class` as the start of a class declaration.
+                expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 5),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 5),
+              ]
             : [expectedError(ParserErrorCode.VAR_CLASS, 0, 3)]);
   }
 
   void test_varEnum() {
     parseCompilationUnit("var enum E {ONE}",
         errors: usingFastaParser
-            ? [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 0, 3)]
+            ? [
+                // Fasta interprets the `var` as a malformed top level var
+                // and `enum` as the start of an enum declaration.
+                expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 4),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 4),
+              ]
             : [expectedError(ParserErrorCode.VAR_ENUM, 0, 3)]);
   }
 
@@ -5724,7 +5762,12 @@
   void test_varTypedef() {
     parseCompilationUnit("var typedef F();",
         errors: usingFastaParser
-            ? [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 0, 3)]
+            ? [
+                // Fasta interprets the `var` as a malformed top level var
+                // and `typedef` as the start of an typedef declaration.
+                expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 7),
+                expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 7),
+              ]
             : [expectedError(ParserErrorCode.VAR_TYPEDEF, 0, 3)]);
   }
 
@@ -11056,17 +11099,10 @@
   }
 
   void test_incomplete_topLevelVariable_const() {
-    CompilationUnit unit = parseCompilationUnit("const ",
-        codes: usingFastaParser
-            ? [
-                ParserErrorCode.MISSING_IDENTIFIER,
-                ParserErrorCode.EXPECTED_TOKEN,
-                CompileTimeErrorCode.CONST_NOT_INITIALIZED
-              ]
-            : [
-                ParserErrorCode.MISSING_IDENTIFIER,
-                ParserErrorCode.EXPECTED_TOKEN
-              ]);
+    CompilationUnit unit = parseCompilationUnit("const ", codes: [
+      ParserErrorCode.MISSING_IDENTIFIER,
+      ParserErrorCode.EXPECTED_TOKEN
+    ]);
     NodeList<CompilationUnitMember> declarations = unit.declarations;
     expect(declarations, hasLength(1));
     CompilationUnitMember member = declarations[0];
@@ -11080,17 +11116,10 @@
   }
 
   void test_incomplete_topLevelVariable_final() {
-    CompilationUnit unit = parseCompilationUnit("final ",
-        codes: usingFastaParser
-            ? [
-                ParserErrorCode.MISSING_IDENTIFIER,
-                ParserErrorCode.EXPECTED_TOKEN,
-                StaticWarningCode.FINAL_NOT_INITIALIZED
-              ]
-            : [
-                ParserErrorCode.MISSING_IDENTIFIER,
-                ParserErrorCode.EXPECTED_TOKEN
-              ]);
+    CompilationUnit unit = parseCompilationUnit("final ", codes: [
+      ParserErrorCode.MISSING_IDENTIFIER,
+      ParserErrorCode.EXPECTED_TOKEN
+    ]);
     NodeList<CompilationUnitMember> declarations = unit.declarations;
     expect(declarations, hasLength(1));
     CompilationUnitMember member = declarations[0];
@@ -11124,17 +11153,10 @@
     CompilationUnit unit = parseCompilationUnit(r'''
 class C {
   const
-}''',
-        codes: usingFastaParser
-            ? [
-                ParserErrorCode.MISSING_IDENTIFIER,
-                ParserErrorCode.EXPECTED_TOKEN,
-                CompileTimeErrorCode.CONST_NOT_INITIALIZED
-              ]
-            : [
-                ParserErrorCode.MISSING_IDENTIFIER,
-                ParserErrorCode.EXPECTED_TOKEN
-              ]);
+}''', codes: [
+      ParserErrorCode.MISSING_IDENTIFIER,
+      ParserErrorCode.EXPECTED_TOKEN
+    ]);
     NodeList<CompilationUnitMember> declarations = unit.declarations;
     expect(declarations, hasLength(1));
     CompilationUnitMember unitMember = declarations[0];
diff --git a/pkg/analyzer/test/src/fasta/recovery/partial_code/field_declaration_test.dart b/pkg/analyzer/test/src/fasta/recovery/partial_code/field_declaration_test.dart
index d3a1af6..a4ddf6b 100644
--- a/pkg/analyzer/test/src/fasta/recovery/partial_code/field_declaration_test.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/partial_code/field_declaration_test.dart
@@ -31,11 +31,7 @@
         new TestDescriptor(
           'const_noName',
           'const',
-          [
-            ParserErrorCode.MISSING_IDENTIFIER,
-            ParserErrorCode.EXPECTED_TOKEN,
-            CompileTimeErrorCode.CONST_NOT_INITIALIZED
-          ],
+          [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN],
           'const _s_;',
           failing: allExceptEof,
           expectedErrorsInValidCode: [
@@ -166,11 +162,7 @@
         new TestDescriptor(
           'static_const_noName',
           'static const',
-          [
-            ParserErrorCode.MISSING_IDENTIFIER,
-            ParserErrorCode.EXPECTED_TOKEN,
-            CompileTimeErrorCode.CONST_NOT_INITIALIZED
-          ],
+          [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN],
           'static const _s_;',
           failing: allExceptEof,
           expectedErrorsInValidCode: [
diff --git a/pkg/analyzer/test/src/fasta/recovery/partial_code/top_level_variable_test.dart b/pkg/analyzer/test/src/fasta/recovery/partial_code/top_level_variable_test.dart
index 1d27bed..bb3264c 100644
--- a/pkg/analyzer/test/src/fasta/recovery/partial_code/top_level_variable_test.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/partial_code/top_level_variable_test.dart
@@ -33,10 +33,15 @@
             [
               ParserErrorCode.MISSING_IDENTIFIER,
               ParserErrorCode.EXPECTED_TOKEN,
-              CompileTimeErrorCode.CONST_NOT_INITIALIZED
             ],
             "const _s_;",
-            failing: allExceptEof,
+            failing: [
+              'class',
+              'functionVoid',
+              'functionNonVoid',
+              'getter',
+              'setter'
+            ],
             expectedErrorsInValidCode: [
               CompileTimeErrorCode.CONST_NOT_INITIALIZED
             ],
@@ -49,7 +54,7 @@
               CompileTimeErrorCode.CONST_NOT_INITIALIZED
             ],
             "const a;",
-            failing: ['typedef', 'functionNonVoid', 'getter', 'setter'],
+            failing: ['functionNonVoid', 'getter', 'setter'],
             expectedErrorsInValidCode: [
               CompileTimeErrorCode.CONST_NOT_INITIALIZED
             ],
@@ -72,11 +77,10 @@
             [
               ParserErrorCode.MISSING_IDENTIFIER,
               ParserErrorCode.EXPECTED_TOKEN,
-              CompileTimeErrorCode.CONST_NOT_INITIALIZED,
               CompileTimeErrorCode.CONST_NOT_INITIALIZED
             ],
             "const a, _s_;",
-            failing: ['typedef', 'functionNonVoid', 'getter', 'setter'],
+            failing: ['functionNonVoid', 'getter'],
             expectedErrorsInValidCode: [
               CompileTimeErrorCode.CONST_NOT_INITIALIZED,
               CompileTimeErrorCode.CONST_NOT_INITIALIZED
@@ -88,11 +92,10 @@
             [
               ParserErrorCode.MISSING_IDENTIFIER,
               ParserErrorCode.EXPECTED_TOKEN,
-              CompileTimeErrorCode.CONST_NOT_INITIALIZED,
               CompileTimeErrorCode.CONST_NOT_INITIALIZED
             ],
             "const int a, _s_;",
-            failing: ['typedef', 'functionNonVoid', 'getter', 'setter'],
+            failing: ['functionNonVoid', 'getter'],
             expectedErrorsInValidCode: [
               CompileTimeErrorCode.CONST_NOT_INITIALIZED,
               CompileTimeErrorCode.CONST_NOT_INITIALIZED
@@ -132,10 +135,15 @@
             [
               ParserErrorCode.MISSING_IDENTIFIER,
               ParserErrorCode.EXPECTED_TOKEN,
-              StaticWarningCode.FINAL_NOT_INITIALIZED
             ],
             "final _s_;",
-            failing: allExceptEof,
+            failing: [
+              'class',
+              'functionVoid',
+              'functionNonVoid',
+              'getter',
+              'setter'
+            ],
             expectedErrorsInValidCode: [
               StaticWarningCode.FINAL_NOT_INITIALIZED
             ],
@@ -148,7 +156,7 @@
               StaticWarningCode.FINAL_NOT_INITIALIZED
             ],
             "final a;",
-            failing: ['typedef', 'functionNonVoid', 'getter', 'setter'],
+            failing: ['functionNonVoid', 'getter', 'setter'],
             expectedErrorsInValidCode: [
               StaticWarningCode.FINAL_NOT_INITIALIZED
             ],
@@ -189,14 +197,14 @@
               ParserErrorCode.EXPECTED_TOKEN
             ],
             "var _s_;",
-            failing: allExceptEof,
+            failing: ['functionVoid', 'functionNonVoid', 'getter', 'setter'],
           ),
           new TestDescriptor(
             'varName',
             'var a',
             [ParserErrorCode.EXPECTED_TOKEN],
             "var a;",
-            failing: ['typedef', 'functionNonVoid', 'getter', 'setter'],
+            failing: ['functionNonVoid', 'getter', 'setter'],
           ),
           new TestDescriptor(
             'varNameEquals',
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 ba67f33..b9bbf76 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
@@ -120,9 +120,8 @@
       const TypeReferenceIdentifierContext.continuation();
 
   /// Identifier is a name being declared by a top level variable declaration.
-  static const topLevelVariableDeclaration = const IdentifierContext(
-      'topLevelVariableDeclaration',
-      inDeclaration: true);
+  static const topLevelVariableDeclaration =
+      const TopLevelVariableIdentifierContext();
 
   /// Identifier is a name being declared by a field declaration.
   static const fieldDeclaration = const FieldDeclarationIdentifierContext();
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 37aedf8..36baa41 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
@@ -311,10 +311,12 @@
   Token ensureIdentifier(Token token, Parser parser) {
     Token identifier = token.next;
     assert(identifier.kind != IDENTIFIER_TOKEN);
+    const followingValues = const ['.', ';'];
+
     if (identifier.isIdentifier) {
       Token next = identifier.next;
-      if (isOneOfOrEof(next, const ['.', ';']) ||
-          !looksLikeStartOfNextTopLevelDeclaration(identifier)) {
+      if (!looksLikeStartOfNextTopLevelDeclaration(identifier) ||
+          isOneOfOrEof(next, followingValues)) {
         return identifier;
       }
       // Although this is a valid library name, the library declaration
@@ -323,7 +325,7 @@
     }
 
     // Recovery
-    if (isOneOfOrEof(identifier, const ['.', ';']) ||
+    if (isOneOfOrEof(identifier, followingValues) ||
         looksLikeStartOfNextTopLevelDeclaration(identifier)) {
       identifier = parser.insertSyntheticIdentifier(token, this,
           message: fasta.templateExpectedIdentifier.withArguments(identifier));
@@ -411,6 +413,49 @@
   }
 }
 
+/// See [IdentifierContext.topLevelVariableDeclaration].
+class TopLevelVariableIdentifierContext extends IdentifierContext {
+  const TopLevelVariableIdentifierContext()
+      : super('topLevelVariableDeclaration', inDeclaration: true);
+
+  @override
+  Token ensureIdentifier(Token token, Parser parser) {
+    Token identifier = token.next;
+    assert(identifier.kind != IDENTIFIER_TOKEN);
+    const followingValues = const [';', '=', ','];
+
+    if (identifier.isIdentifier) {
+      Token next = identifier.next;
+      if (!looksLikeStartOfNextTopLevelDeclaration(identifier) ||
+          isOneOfOrEof(next, followingValues)) {
+        return identifier;
+      }
+      // Although this is a valid top level var name, the var declaration
+      // is invalid and this looks like the start of the next declaration.
+      // In this situation, fall through to insert a synthetic var name.
+    }
+
+    // Recovery
+    if (looksLikeStartOfNextTopLevelDeclaration(identifier) ||
+        isOneOfOrEof(identifier, followingValues)) {
+      identifier = parser.insertSyntheticIdentifier(token, this,
+          message: fasta.templateExpectedIdentifier.withArguments(identifier));
+    } else if (identifier.type.isBuiltIn) {
+      parser.reportRecoverableErrorWithToken(
+          identifier, fasta.templateBuiltInIdentifierInDeclaration);
+    } else {
+      parser.reportRecoverableErrorWithToken(
+          identifier, fasta.templateExpectedIdentifier);
+      if (!identifier.isKeywordOrIdentifier) {
+        // When in doubt, consume the token to ensure we make progress
+        // but insert a synthetic identifier to satisfy listeners.
+        identifier = insertSyntheticIdentifierAfter(identifier, parser);
+      }
+    }
+    return identifier;
+  }
+}
+
 /// See [IdentifierContext].typedefDeclaration
 class TypedefDeclarationIdentifierContext extends IdentifierContext {
   const TypedefDeclarationIdentifierContext()
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index 72adcc5..cbeb2c5 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -332,9 +332,12 @@
       listener.endTopLevelDeclaration(token.next);
       count++;
       if (start == token.next) {
+        // Recovery:
         // If progress has not been made reaching the end of the token stream,
         // then report an error and skip the current token.
         token = token.next;
+        listener.beginMetadataStar(token);
+        listener.endMetadataStar(0);
         reportRecoverableErrorWithToken(
             token, fasta.templateExpectedDeclaration);
         listener.handleInvalidTopLevelDeclaration(token);
@@ -443,15 +446,26 @@
       return parseScript(token);
     }
     token = parseMetadataStar(token);
-    if (token.next.isTopLevelKeyword) {
+    Token next = token.next;
+    if (next.isTopLevelKeyword) {
       return parseTopLevelKeywordDeclaration(token, null, directiveState);
     }
     Token start = token;
     // Skip modifiers to find a top level keyword or identifier
-    while (token.next.isModifier) {
-      token = token.next;
+    if (next.isModifier) {
+      if (optional('var', next) ||
+          ((optional('const', next) || optional('final', next)) &&
+              // Ignore `const class` and `final class` so that it is reported
+              // below as an invalid modifier on a class.
+              !optional('class', next.next))) {
+        directiveState?.checkDeclaration();
+        return parseTopLevelMemberImpl(token);
+      }
+      while (token.next.isModifier) {
+        token = token.next;
+      }
     }
-    Token next = token.next;
+    next = token.next;
     if (next.isTopLevelKeyword) {
       Token beforeAbstractToken;
       Token beforeModifier = start;
@@ -1934,14 +1948,7 @@
         token = next;
       } else {
         reportRecoverableErrorWithToken(next, context.recoveryTemplate);
-        if (context == IdentifierContext.topLevelVariableDeclaration) {
-          // Since the token is not a keyword or identifier, consume it to
-          // ensure forward progress in parseField.
-          token = next.next;
-          // Supply a non-empty method name so that it does not accidentally
-          // match the default constructor.
-          token = insertSyntheticIdentifier(next, context);
-        } else if (context == IdentifierContext.constructorReference) {
+        if (context == IdentifierContext.constructorReference) {
           token = insertSyntheticIdentifier(token, context);
         } else {
           token = next;
@@ -2027,8 +2034,6 @@
       followingValues = ['.', '(', '{', '=>'];
     } else if (context == IdentifierContext.topLevelFunctionDeclaration) {
       followingValues = ['(', '{', '=>'];
-    } else if (context == IdentifierContext.topLevelVariableDeclaration) {
-      followingValues = [';', '=', ','];
     } else if (context == IdentifierContext.typeVariableDeclaration) {
       followingValues = ['<', '>', ';', '}'];
     } else {
@@ -2099,8 +2104,6 @@
       initialKeywords = statementKeywords();
     } else if (context == IdentifierContext.topLevelFunctionDeclaration) {
       initialKeywords = topLevelKeywords();
-    } else if (context == IdentifierContext.topLevelVariableDeclaration) {
-      initialKeywords = topLevelKeywords();
     } else if (context == IdentifierContext.typeVariableDeclaration) {
       initialKeywords = topLevelKeywords()
         ..addAll(classMemberKeywords())
@@ -2521,14 +2524,23 @@
           next = token.next;
         }
         if (isModifier(next)) {
-          ModifierRecoveryContext context = new ModifierRecoveryContext(this);
-          token = context.parseTopLevelModifiers(token,
-              externalToken: externalToken, varFinalOrConst: varFinalOrConst);
-          next = token.next;
+          // Recovery
+          if (varFinalOrConst != null &&
+              (optional('final', next) ||
+                  optional('var', next) ||
+                  optional('const', next))) {
+            // If another `var`, `final`, or `const` then fall through
+            // to parse that as part of the next top level declaration.
+          } else {
+            ModifierRecoveryContext context = new ModifierRecoveryContext(this);
+            token = context.parseTopLevelModifiers(token,
+                externalToken: externalToken, varFinalOrConst: varFinalOrConst);
+            next = token.next;
 
-          externalToken = context.externalToken;
-          varFinalOrConst = context.varFinalOrConst;
-          context = null;
+            externalToken = context.externalToken;
+            varFinalOrConst = context.varFinalOrConst;
+            context = null;
+          }
         }
       }
     }
@@ -2745,7 +2757,7 @@
       token = parseExpression(next);
       listener.endFieldInitializer(assignment, token.next);
     } else {
-      if (varFinalOrConst != null) {
+      if (varFinalOrConst != null && !name.isSynthetic) {
         if (optional("const", varFinalOrConst)) {
           reportRecoverableError(
               name,
diff --git a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
index 4120e05..376d485 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
@@ -8,6 +8,8 @@
 
 import '../fasta_codes.dart' as fasta;
 
+import '../scanner/token_constants.dart' show IDENTIFIER_TOKEN;
+
 import '../util/link.dart' show Link;
 
 import 'identifier_context.dart' show IdentifierContext;
@@ -214,7 +216,13 @@
 }
 
 bool looksLikeName(Token token) =>
-    token.isIdentifier || optional('this', token);
+    token.kind == IDENTIFIER_TOKEN ||
+    optional('this', token) ||
+    (token.isIdentifier &&
+        // Although `typedef` is a legal identifier,
+        // type `typedef` identifier is not legal and in this situation
+        // `typedef` is probably a separate declaration.
+        (!optional('typedef', token) || !token.next.isIdentifier));
 
 Token skipTypeVariables(Token token) {
   assert(optional('<', token));
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index a4feebd..f768b5d 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -579,13 +579,9 @@
     - "external foo; main(){}"
     - "final class C {}"
     - "abstract enum foo {bar}"
-    - "const enum foo {bar}"
-    - "final enum foo {bar}"
     - "abstract void foo() {}"
     - "static void foo() {}"
     - "abstract typedef foo();"
-    - "const typedef foo();"
-    - "final typedef foo();"
     - "static typedef foo();"
 
 FinalAndCovariant: