Replace calls to parseTypeArgumentsOpt and others

* Replace several calls to parseTypeArgumentsOpt with computeTypeParamOrArg
* Replace isValidMethodTypeArguments with computeMethodTypeArguments
* Fix TokenStreamRewriter.splitGtGt to preserve preceeding comment
* Switch to using computeTypeParamOrArg and remove redundant code

Change-Id: Ic4cab3ca91de8c0c9738f43ca208cdbf2ead6057
Reviewed-on: https://dart-review.googlesource.com/54603
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index a96b872..8d228f3 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -28,6 +28,7 @@
 import 'package:front_end/src/fasta/parser/identifier_context.dart' as fasta;
 import 'package:front_end/src/fasta/parser/member_kind.dart' as fasta;
 import 'package:front_end/src/fasta/parser/parser.dart' as fasta;
+import 'package:front_end/src/fasta/parser/type_info.dart' as fasta;
 import 'package:front_end/src/fasta/scanner.dart' as fasta;
 
 export 'package:analyzer/src/dart/ast/utilities.dart' show ResolutionCopier;
diff --git a/pkg/analyzer/lib/src/generated/parser_fasta.dart b/pkg/analyzer/lib/src/generated/parser_fasta.dart
index 2a7322b..3944ae3 100644
--- a/pkg/analyzer/lib/src/generated/parser_fasta.dart
+++ b/pkg/analyzer/lib/src/generated/parser_fasta.dart
@@ -291,8 +291,10 @@
 
   @override
   TypeArgumentList parseTypeArgumentList() {
-    currentToken = fastaParser
-        .parseTypeArgumentsOpt(fastaParser.syntheticPreviousToken(currentToken))
+    Token previous = fastaParser.syntheticPreviousToken(currentToken);
+    currentToken = fasta
+        .computeTypeParamOrArg(previous)
+        .parseArguments(previous, fastaParser)
         .next;
     return astBuilder.pop();
   }
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 36baa41..f18b2ac 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
@@ -15,7 +15,7 @@
 import 'type_info.dart'
     show insertSyntheticIdentifierAfter, isValidTypeReference;
 
-import 'util.dart' show optional, skipMetadata;
+import 'util.dart' show optional;
 
 /// See [IdentifierContext.classOrNamedMixinDeclaration].
 class ClassOrNamedMixinIdentifierContext extends IdentifierContext {
@@ -517,20 +517,6 @@
     assert(next.kind != IDENTIFIER_TOKEN);
     if (isValidTypeReference(next)) {
       return next;
-    }
-
-    // Recovery: skip over any annotations
-    while (optional('@', next)) {
-      // TODO(danrubel): Improve this error message to indicate that an
-      // annotation is not allowed before type arguments.
-      parser.reportRecoverableErrorWithToken(
-          next, fasta.templateUnexpectedToken);
-      token = skipMetadata(token);
-      next = token.next;
-    }
-
-    if (isValidTypeReference(next)) {
-      return next;
     } else if (next.isKeywordOrIdentifier) {
       if (optional("void", next)) {
         parser.reportRecoverableError(next, fasta.messageInvalidVoid);
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index be5dbe0..4c176ef 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -87,6 +87,7 @@
     show
         TypeInfo,
         TypeParamOrArgInfo,
+        computeMethodTypeArguments,
         computeType,
         computeTypeParamOrArg,
         isGeneralizedFunctionType,
@@ -94,8 +95,6 @@
         noType,
         noTypeParamOrArg;
 
-import 'type_info_impl.dart' show skipTypeVariables;
-
 import 'util.dart' show optional;
 
 /// An event generating parser of Dart programs. This parser expects all tokens
@@ -1020,7 +1019,7 @@
     if (optional("<", token.next)) {
       reportRecoverableError(token.next, fasta.messageMetadataTypeArguments);
     }
-    token = parseTypeArgumentsOpt(token);
+    token = computeTypeParamOrArg(token).parseArguments(token, this);
     Token period = null;
     if (optional('.', token.next)) {
       period = token.next;
@@ -1522,22 +1521,6 @@
     return token;
   }
 
-  /// Returns `true` if [token] matches '<' type (',' type)* '>' '(', and
-  /// otherwise returns `false`. The final '(' is not part of the grammar
-  /// construct `typeArguments`, but it is required here such that type
-  /// arguments in generic method invocations can be recognized, and as few as
-  /// possible other constructs will pass (e.g., 'a < C, D > 3').
-  bool isValidMethodTypeArguments(Token token) {
-    // TODO(danrubel): Replace call with a call to computeTypeVar.
-    if (optional('<', token)) {
-      Token endGroup = skipTypeVariables(token);
-      if (endGroup != null && optional('(', endGroup.next)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
   /// ```
   /// qualified:
   ///   identifier qualifiedRest*
@@ -3583,7 +3566,7 @@
     listener.beginConstructorReference(start);
     token = parseQualifiedRestOpt(
         start, IdentifierContext.constructorReferenceContinuation);
-    token = parseTypeArgumentsOpt(token);
+    token = computeTypeParamOrArg(token).parseArguments(token, this);
     Token period = null;
     if (optional('.', token.next)) {
       period = token.next;
@@ -4126,9 +4109,8 @@
     TokenType type = next.type;
     int tokenLevel = type.precedence;
     Token typeArguments;
-    TypeParamOrArgInfo typeArg = computeTypeParamOrArg(token);
-    if (typeArg != noTypeParamOrArg &&
-        optional('(', typeArg.skip(token).next)) {
+    TypeParamOrArgInfo typeArg = computeMethodTypeArguments(token);
+    if (typeArg != noTypeParamOrArg) {
       // For example a(b)<T>(c), where token is before '<'.
       typeArguments = next;
       token = typeArg.parseArguments(token, this);
@@ -4235,10 +4217,11 @@
         listener.endBinaryExpression(period);
       }
       Token typeArguments;
-      if (isValidMethodTypeArguments(next)) {
+      TypeParamOrArgInfo typeArg = computeMethodTypeArguments(token);
+      if (typeArg != noTypeParamOrArg) {
         // For example a(b)..<T>(c), where token is '<'.
         typeArguments = next;
-        token = parseTypeArgumentsOpt(token);
+        token = typeArg.parseArguments(token, this);
         next = token.next;
         assert(optional('(', next));
       }
@@ -4338,8 +4321,9 @@
         next = token.next;
       } else if (optional('(', next)) {
         if (typeArguments == null) {
-          if (isValidMethodTypeArguments(next)) {
-            token = parseTypeArgumentsOpt(token);
+          TypeParamOrArgInfo typeArg = computeMethodTypeArguments(token);
+          if (typeArg != noTypeParamOrArg) {
+            token = typeArg.parseArguments(token, this);
             next = token.next;
           } else {
             listener.handleNoTypeArguments(next);
@@ -4657,7 +4641,7 @@
       token = parseTypeVariablesOpt(token);
       return parseLiteralFunctionSuffix(token);
     } else {
-      token = parseTypeArgumentsOpt(token);
+      token = computeTypeParamOrArg(token).parseArguments(token, this);
       Token next = token.next;
       if (optional('{', next)) {
         return parseLiteralMapSuffix(token, constKeyword);
@@ -4929,8 +4913,9 @@
 
   Token parseSend(Token token, IdentifierContext context) {
     Token beginToken = token = ensureIdentifier(token, context);
-    if (isValidMethodTypeArguments(token.next)) {
-      token = parseTypeArgumentsOpt(token);
+    TypeParamOrArgInfo typeArg = computeMethodTypeArguments(token);
+    if (typeArg != noTypeParamOrArg) {
+      token = typeArg.parseArguments(token, this);
     } else {
       listener.handleNoTypeArguments(token.next);
     }
diff --git a/pkg/front_end/lib/src/fasta/parser/token_stream_rewriter.dart b/pkg/front_end/lib/src/fasta/parser/token_stream_rewriter.dart
index b80a0a9..d5b8eae 100644
--- a/pkg/front_end/lib/src/fasta/parser/token_stream_rewriter.dart
+++ b/pkg/front_end/lib/src/fasta/parser/token_stream_rewriter.dart
@@ -83,7 +83,8 @@
 
     // A no-op rewriter could simply return `>>` here.
 
-    Token gt1 = new SimpleToken(TokenType.GT, gtgt.charOffset);
+    Token gt1 =
+        new SimpleToken(TokenType.GT, gtgt.charOffset, gtgt.precedingComments);
     Token gt2 = gt1.setNext(new SimpleToken(TokenType.GT, gt1.charOffset + 1));
     gt2.setNext(gtgt.next);
 
diff --git a/pkg/front_end/lib/src/fasta/parser/type_info.dart b/pkg/front_end/lib/src/fasta/parser/type_info.dart
index 4b33354..b70a1e2 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_info.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_info.dart
@@ -280,3 +280,15 @@
   // TODO(danrubel): Consider adding additional const for common situations.
   return new ComplexTypeParamOrArgInfo(token).compute(innerEndGroup);
 }
+
+/// Called by the parser to obtain information about a possible group of type
+/// type arguments that follow [token] and that are followed by '('.
+/// Returns the type arguments if [token] matches '<' type (',' type)* '>' '(',
+/// and otherwise returns [noTypeParamOrArg]. The final '(' is not part of the
+/// grammar construct `typeArguments`, but it is required here such that type
+/// arguments in generic method invocations can be recognized, and as few as
+/// possible other constructs will pass (e.g., 'a < C, D > 3').
+TypeParamOrArgInfo computeMethodTypeArguments(Token token) {
+  TypeParamOrArgInfo typeArg = computeTypeParamOrArg(token);
+  return optional('(', typeArg.skip(token).next) ? typeArg : noTypeParamOrArg;
+}