Improve part of identifier recovery

Change-Id: I16b5799e883ed0a04445809e329d9e7fba5afff4
Reviewed-on: https://dart-review.googlesource.com/56041
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/analyzer/test/src/fasta/recovery/partial_code/part_of_directive_test.dart b/pkg/analyzer/test/src/fasta/recovery/partial_code/part_of_directive_test.dart
index 7432c7f..24b5890 100644
--- a/pkg/analyzer/test/src/fasta/recovery/partial_code/part_of_directive_test.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/partial_code/part_of_directive_test.dart
@@ -12,17 +12,18 @@
 
 class PartOfDirectivesTest extends PartialCodeTest {
   buildAll() {
-    List<String> allExceptEof = <String>[
-      'class',
+    List<String> identifiers = const [
       'typedef',
-      'functionVoid',
       'functionNonVoid',
-      'var',
-      'const',
-      'final',
       'getter',
       'setter'
     ];
+    List<TestSuffix> identifierSuffixes = PartialCodeTest.declarationSuffixes
+        .where((t) => identifiers.contains(t.name))
+        .toList();
+    List<TestSuffix> nonIdentifierSuffixes = PartialCodeTest.declarationSuffixes
+        .where((t) => !identifiers.contains(t.name))
+        .toList();
     buildTests(
         'part_of_directive',
         [
@@ -30,11 +31,31 @@
               'keyword',
               'part of',
               [
-                ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE,
+                ParserErrorCode.EXPECTED_STRING_LITERAL,
+                ParserErrorCode.EXPECTED_TOKEN
+              ],
+              'part of "";',
+              failing: []),
+        ],
+        nonIdentifierSuffixes);
+    buildTests(
+        'part_of_directive',
+        [
+          new TestDescriptor(
+              'keyword',
+              'part of',
+              [
+                ParserErrorCode.MISSING_IDENTIFIER,
                 ParserErrorCode.EXPECTED_TOKEN
               ],
               'part of _s_;',
-              allFailing: true),
+              failing: ['functionNonVoid', 'getter']),
+        ],
+        identifierSuffixes,
+        includeEof: false);
+    buildTests(
+        'part_of_directive',
+        [
           new TestDescriptor('name', 'part of lib',
               [ParserErrorCode.EXPECTED_TOKEN], 'library lib;',
               allFailing: true),
@@ -46,7 +67,7 @@
                 ParserErrorCode.EXPECTED_TOKEN
               ],
               'part of lib._s_;',
-              failing: allExceptEof),
+              failing: ['functionNonVoid', 'getter']),
           new TestDescriptor('nameDotName', 'part of lib.a',
               [ParserErrorCode.EXPECTED_TOKEN], 'part of lib.a;'),
           new TestDescriptor('emptyUri', "part of ''",
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 a4d6a9e..9c65f14 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
@@ -77,15 +77,12 @@
 
   /// Identifier is the start of a library name referenced by a `part of`
   /// directive (e.g. `foo` in the directive `part of foo;`).
-  static const partName =
-      const IdentifierContext('partName', inLibraryOrPartOfDeclaration: true);
+  static const partName = const LibraryIdentifierContext.partName();
 
   /// Identifier is part of a library name referenced by a `part of` directive,
   /// but it's not the first identifier in the name.
-  static const partNameContinuation = const IdentifierContext(
-      'partNameContinuation',
-      inLibraryOrPartOfDeclaration: true,
-      isContinuation: true);
+  static const partNameContinuation =
+      const LibraryIdentifierContext.partNameContinuation();
 
   /// Identifier is the type name being declared by an enum declaration.
   static const enumDeclaration = const EnumDeclarationIdentifierContext();
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 23e03bf..ab54ca0 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
@@ -372,7 +372,10 @@
   }
 }
 
-/// See [IdentifierContext.libraryName].
+/// See [IdentifierContext.libraryName],
+/// and [IdentifierContext.libraryNameContinuation]
+/// and [IdentifierContext.partName],
+/// and [IdentifierContext.partNameContinuation].
 class LibraryIdentifierContext extends IdentifierContext {
   const LibraryIdentifierContext()
       : super('libraryName', inLibraryOrPartOfDeclaration: true);
@@ -381,6 +384,13 @@
       : super('libraryNameContinuation',
             inLibraryOrPartOfDeclaration: true, isContinuation: true);
 
+  const LibraryIdentifierContext.partName()
+      : super('partName', inLibraryOrPartOfDeclaration: true);
+
+  const LibraryIdentifierContext.partNameContinuation()
+      : super('partNameContinuation',
+            inLibraryOrPartOfDeclaration: true, isContinuation: true);
+
   @override
   Token ensureIdentifier(Token token, Parser parser) {
     Token identifier = token.next;