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;
+}