Report errors on non-synthetic tokens

This updates fasta parser error reporting to find a non-synthetic token
on which to report an error. In addition, this addresses a comment in
https://dart-review.googlesource.com/c/sdk/+/56041

Change-Id: Id3415529a7b8635273221c7c2f3d36e1695a9ece
Reviewed-on: https://dart-review.googlesource.com/56540
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 cb8e089..5e92a04 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -2702,7 +2702,7 @@
     parser.parseCompilationUnit2();
     listener.assertErrors(usingFastaParser
         ? [
-            expectedError(ParserErrorCode.MISSING_IDENTIFIER, 13, 0),
+            expectedError(ParserErrorCode.MISSING_IDENTIFIER, 13, 1),
             expectedError(ParserErrorCode.EXPECTED_TOKEN, 13, 1),
             expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1),
             expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 13, 1)
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 24b5890..17da7bc 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
@@ -34,8 +34,7 @@
                 ParserErrorCode.EXPECTED_STRING_LITERAL,
                 ParserErrorCode.EXPECTED_TOKEN
               ],
-              'part of "";',
-              failing: []),
+              'part of "";'),
         ],
         nonIdentifierSuffixes);
     buildTests(
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index c8429fc..66e854b 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -97,7 +97,7 @@
         noType,
         noTypeParamOrArg;
 
-import 'util.dart' show optional;
+import 'util.dart' show findNonSyntheticToken, optional;
 
 /// An event generating parser of Dart programs. This parser expects all tokens
 /// in a linked list (aka a token stream).
@@ -6063,6 +6063,8 @@
     if (token is ErrorToken) {
       reportErrorToken(token, true);
     } else {
+      // Find a non-synthetic token on which to report the error.
+      token = findNonSyntheticToken(token);
       listener.handleRecoverableError(message, token, token);
     }
   }
@@ -6084,6 +6086,8 @@
     if (token is ErrorToken) {
       reportErrorToken(token, true);
     } else {
+      // Find a non-synthetic token on which to report the error.
+      token = findNonSyntheticToken(token);
       listener.handleRecoverableError(
           template.withArguments(token), token, token);
     }
diff --git a/pkg/front_end/lib/src/fasta/parser/util.dart b/pkg/front_end/lib/src/fasta/parser/util.dart
index bbbd361..f158cc3 100644
--- a/pkg/front_end/lib/src/fasta/parser/util.dart
+++ b/pkg/front_end/lib/src/fasta/parser/util.dart
@@ -33,6 +33,16 @@
   return token;
 }
 
+/// Return [token] if it is non-synthetic,
+/// otherwise find the next non-synthetic token.
+/// This may return EOF if there are no more non-synthetic tokens in the stream.
+Token findNonSyntheticToken(Token token) {
+  while (token.isSynthetic && !token.isEof) {
+    token = token.next;
+  }
+  return token;
+}
+
 /// A null-aware alternative to `token.offset`.  If [token] is `null`, returns
 /// `TreeNode.noOffset`.
 int offsetForToken(Token token) {