diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart index af4bd8dc24b..8581fa44f54 100644 --- a/pkg/analyzer/lib/src/generated/parser.dart +++ b/pkg/analyzer/lib/src/generated/parser.dart @@ -2333,7 +2333,8 @@ class Parser { _peek().matchesAny([ TokenType.OPEN_PAREN, TokenType.OPEN_CURLY_BRACKET, - TokenType.FUNCTION + TokenType.FUNCTION, + TokenType.LT ])) { _validateModifiersForGetterOrSetterOrMethod(modifiers); return _parseMethodDeclarationAfterReturnType(commentAndMetadata, @@ -2488,6 +2489,12 @@ class Parser { // function type alias that was parsed. _parseFunctionTypeAlias(commentAndMetadata, getAndAdvance()); return null; + } else if (parseGenericMethods) { + Token token = _skipTypeParameterList(_peek()); + if (token != null && _tokenMatches(token, TokenType.OPEN_PAREN)) { + return _parseMethodDeclarationAfterReturnType(commentAndMetadata, + modifiers.externalKeyword, modifiers.staticKeyword, null); + } } TypeName type = parseTypeName(); if (_matchesKeyword(Keyword.GET) && _tokenMatchesIdentifier(_peek())) { @@ -2552,6 +2559,9 @@ class Parser { return _parseMethodDeclarationAfterParameters(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, type, methodName, null, parameters); + } else if (parseGenericMethods && _tokenMatches(_peek(), TokenType.LT)) { + return _parseMethodDeclarationAfterReturnType(commentAndMetadata, + modifiers.externalKeyword, modifiers.staticKeyword, type); } else if (_tokenMatches(_peek(), TokenType.OPEN_CURLY_BRACKET)) { // We have found "TypeName identifier {", and are guessing that this is a // getter without the keyword 'get'. @@ -3041,14 +3051,18 @@ class Parser { * parsed. * * functionExpression ::= - * formalParameterList functionExpressionBody + * typeParameters? formalParameterList functionExpressionBody */ FunctionExpression parseFunctionExpression() { + TypeParameterList typeParameters = null; + if (parseGenericMethods && _matches(TokenType.LT)) { + typeParameters = parseTypeParameterList(); + } FormalParameterList parameters = parseFormalParameterList(); _validateFormalParameterList(parameters); FunctionBody body = _parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true); - return new FunctionExpression(null, parameters, body); + return new FunctionExpression(typeParameters, parameters, body); } /** @@ -3151,7 +3165,7 @@ class Parser { * | simpleFormalParameter * * functionSignature: - * metadata returnType? identifier formalParameterList + * metadata returnType? identifier typeParameters? formalParameterList * * fieldFormalParameter ::= * metadata finalConstVarOrType? 'this' '.' identifier @@ -3170,6 +3184,10 @@ class Parser { period = _expect(TokenType.PERIOD); } SimpleIdentifier identifier = parseSimpleIdentifier(); + TypeParameterList typeParameters = null; + if (parseGenericMethods && _matches(TokenType.LT)) { + typeParameters = parseTypeParameterList(); + } if (_matches(TokenType.OPEN_PAREN)) { FormalParameterList parameters = parseFormalParameterList(); if (thisKeyword == null) { @@ -3178,13 +3196,17 @@ class Parser { ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword); } return new FunctionTypedFormalParameter(commentAndMetadata.comment, - commentAndMetadata.metadata, holder.type, identifier, null, - parameters); + commentAndMetadata.metadata, holder.type, identifier, + typeParameters, parameters); } else { return new FieldFormalParameter(commentAndMetadata.comment, commentAndMetadata.metadata, holder.keyword, holder.type, - thisKeyword, period, identifier, null, parameters); + thisKeyword, period, identifier, typeParameters, parameters); } + } else if (typeParameters != null) { + // TODO(brianwilkerson) Report an error. It looks like a function-typed + // parameter with no parameter list. + //_reportErrorForToken(ParserErrorCode.MISSING_PARAMETERS, typeParameters.endToken); } TypeName type = holder.type; if (type != null) { @@ -3197,6 +3219,9 @@ class Parser { } } if (thisKeyword != null) { + // TODO(brianwilkerson) If there are type parameters but no parameters, + // should we create a synthetic empty parameter list here so we can + // capture the type parameters? return new FieldFormalParameter(commentAndMetadata.comment, commentAndMetadata.metadata, holder.keyword, holder.type, thisKeyword, period, identifier, null, null); @@ -3846,7 +3871,11 @@ class Parser { if (_inInitializer) { return false; } - Token afterParameters = _skipFormalParameterList(token); + Token afterTypeParameters = _skipTypeParameterList(token); + if (afterTypeParameters == null) { + afterTypeParameters = token; + } + Token afterParameters = _skipFormalParameterList(afterTypeParameters); if (afterParameters == null) { return false; } @@ -3923,6 +3952,17 @@ class Parser { _tokenMatchesKeyword(token, Keyword.IN); } + bool _isLikelyParameterList() { + if (_matches(TokenType.OPEN_PAREN)) { + return true; + } + if (!parseGenericMethods) { + return false; + } + Token token = _skipTypeArgumentList(_currentToken); + return token != null && _tokenMatches(token, TokenType.OPEN_PAREN); + } + /** * Given that we have just found bracketed text within the given [comment], * look to see whether that text is (a) followed by a parenthesized link @@ -4011,7 +4051,8 @@ class Parser { // The keyword 'void' isn't a valid identifier, so it should be assumed to // be a type name. return true; - } else if (startToken.next != token) { + } else if (startToken.next != token && + !_tokenMatches(token, TokenType.OPEN_PAREN)) { // The type is more than a simple identifier, so it should be assumed to // be a type name. return true; @@ -4184,22 +4225,27 @@ class Parser { Expression expression = _parsePrimaryExpression(); bool isOptional = primaryAllowed || expression is SimpleIdentifier; while (true) { - while (_matches(TokenType.OPEN_PAREN)) { + while (_isLikelyParameterList()) { + TypeArgumentList typeArguments = null; + if (_matches(TokenType.LT)) { + typeArguments = parseTypeArgumentList(); + } ArgumentList argumentList = parseArgumentList(); if (expression is SimpleIdentifier) { - expression = new MethodInvocation( - null, null, expression as SimpleIdentifier, null, argumentList); + expression = new MethodInvocation(null, null, + expression as SimpleIdentifier, typeArguments, argumentList); } else if (expression is PrefixedIdentifier) { PrefixedIdentifier identifier = expression as PrefixedIdentifier; expression = new MethodInvocation(identifier.prefix, - identifier.period, identifier.identifier, null, argumentList); + identifier.period, identifier.identifier, typeArguments, + argumentList); } else if (expression is PropertyAccess) { PropertyAccess access = expression as PropertyAccess; expression = new MethodInvocation(access.target, access.operator, - access.propertyName, null, argumentList); + access.propertyName, typeArguments, argumentList); } else { - expression = - new FunctionExpressionInvocation(expression, null, argumentList); + expression = new FunctionExpressionInvocation( + expression, typeArguments, argumentList); } if (!primaryAllowed) { isOptional = false; @@ -4351,7 +4397,8 @@ class Parser { * method invocation. * * cascadeSection ::= - * '..' (cascadeSelector arguments*) (assignableSelector arguments*)* cascadeAssignment? + * '..' (cascadeSelector typeArguments? arguments*) + * (assignableSelector typeArguments? arguments*)* cascadeAssignment? * * cascadeSelector ::= * '[' expression ']' @@ -4386,20 +4433,24 @@ class Parser { } assert((expression == null && functionName != null) || (expression != null && functionName == null)); - if (_currentToken.type == TokenType.OPEN_PAREN) { - while (_currentToken.type == TokenType.OPEN_PAREN) { + if (_isLikelyParameterList()) { + while (_isLikelyParameterList()) { + TypeArgumentList typeArguments = null; + if (_matches(TokenType.LT)) { + typeArguments = parseTypeArgumentList(); + } if (functionName != null) { - expression = new MethodInvocation( - expression, period, functionName, null, parseArgumentList()); + expression = new MethodInvocation(expression, period, functionName, + typeArguments, parseArgumentList()); period = null; functionName = null; } else if (expression == null) { // It should not be possible to get here. expression = new MethodInvocation(expression, period, - _createSyntheticIdentifier(), null, parseArgumentList()); + _createSyntheticIdentifier(), typeArguments, parseArgumentList()); } else { expression = new FunctionExpressionInvocation( - expression, null, parseArgumentList()); + expression, typeArguments, parseArgumentList()); } } } else if (functionName != null) { @@ -4414,15 +4465,19 @@ class Parser { if (!identical(selector, expression)) { expression = selector; progress = true; - while (_currentToken.type == TokenType.OPEN_PAREN) { + while (_isLikelyParameterList()) { + TypeArgumentList typeArguments = null; + if (_matches(TokenType.LT)) { + typeArguments = parseTypeArgumentList(); + } if (expression is PropertyAccess) { PropertyAccess propertyAccess = expression as PropertyAccess; expression = new MethodInvocation(propertyAccess.target, - propertyAccess.operator, propertyAccess.propertyName, null, - parseArgumentList()); + propertyAccess.operator, propertyAccess.propertyName, + typeArguments, parseArgumentList()); } else { expression = new FunctionExpressionInvocation( - expression, null, parseArgumentList()); + expression, typeArguments, parseArgumentList()); } } } @@ -5758,6 +5813,10 @@ class Parser { keyword = getAndAdvance(); } SimpleIdentifier name = parseSimpleIdentifier(); + TypeParameterList typeParameters = null; + if (parseGenericMethods && _matches(TokenType.LT)) { + typeParameters = parseTypeParameterList(); + } FormalParameterList parameters = null; if (!isGetter) { if (_matches(TokenType.OPEN_PAREN)) { @@ -5788,7 +5847,7 @@ class Parser { // } return new FunctionDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, returnType, keyword, name, - new FunctionExpression(null, parameters, body)); + new FunctionExpression(typeParameters, parameters, body)); } /** @@ -6270,6 +6329,10 @@ class Parser { CommentAndMetadata commentAndMetadata, Token externalKeyword, Token staticKeyword, TypeName returnType) { SimpleIdentifier methodName = parseSimpleIdentifier(); + TypeParameterList typeParameters = null; + if (parseGenericMethods && _matches(TokenType.LT)) { + typeParameters = parseTypeParameterList(); + } FormalParameterList parameters; if (!_matches(TokenType.OPEN_PAREN) && (_matches(TokenType.OPEN_CURLY_BRACKET) || @@ -6284,7 +6347,7 @@ class Parser { } _validateFormalParameterList(parameters); return _parseMethodDeclarationAfterParameters(commentAndMetadata, - externalKeyword, staticKeyword, returnType, methodName, null, + externalKeyword, staticKeyword, returnType, methodName, typeParameters, parameters); } @@ -6712,17 +6775,22 @@ class Parser { if (_matches(TokenType.OPEN_SQUARE_BRACKET) || _matches(TokenType.PERIOD) || _matches(TokenType.QUESTION_PERIOD) || - _matches(TokenType.OPEN_PAREN)) { + _matches(TokenType.OPEN_PAREN) || + (parseGenericMethods && _matches(TokenType.LT))) { do { - if (_matches(TokenType.OPEN_PAREN)) { + if (_isLikelyParameterList()) { + TypeArgumentList typeArguments = null; + if (_matches(TokenType.LT)) { + typeArguments = parseTypeArgumentList(); + } ArgumentList argumentList = parseArgumentList(); if (operand is PropertyAccess) { PropertyAccess access = operand as PropertyAccess; operand = new MethodInvocation(access.target, access.operator, - access.propertyName, null, argumentList); + access.propertyName, typeArguments, argumentList); } else { - operand = - new FunctionExpressionInvocation(operand, null, argumentList); + operand = new FunctionExpressionInvocation( + operand, typeArguments, argumentList); } } else { operand = _parseAssignableSelector(operand, true); diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart index 89de72cb334..5816ab8882a 100644 --- a/pkg/analyzer/test/generated/parser_test.dart +++ b/pkg/analyzer/test/generated/parser_test.dart @@ -173,6 +173,7 @@ class ComplexParserTest extends ParserTestCase { (obj) => obj is MethodInvocation, MethodInvocation, propertyAccess1.target); expect(invocation2.methodName.name, "d"); + expect(invocation2.typeArguments, isNull); ArgumentList argumentList2 = invocation2.argumentList; expect(argumentList2, isNotNull); expect(argumentList2.arguments, hasLength(1)); @@ -182,6 +183,7 @@ class ComplexParserTest extends ParserTestCase { FunctionExpressionInvocation invocation3 = EngineTestCase.assertInstanceOf( (obj) => obj is FunctionExpressionInvocation, FunctionExpressionInvocation, invocation2.target); + expect(invocation3.typeArguments, isNull); ArgumentList argumentList3 = invocation3.argumentList; expect(argumentList3, isNotNull); expect(argumentList3.arguments, hasLength(1)); @@ -192,6 +194,45 @@ class ComplexParserTest extends ParserTestCase { (obj) => obj is MethodInvocation, MethodInvocation, invocation3.function); expect(invocation4.methodName.name, "a"); + expect(invocation4.typeArguments, isNull); + ArgumentList argumentList4 = invocation4.argumentList; + expect(argumentList4, isNotNull); + expect(argumentList4.arguments, hasLength(1)); + } + + void test_assignableExpression_arguments_normal_chain_typeArguments() { + enableGenericMethods = true; + PropertyAccess propertyAccess1 = parseExpression("a(b)(c).d(e).f"); + expect(propertyAccess1.propertyName.name, "f"); + // + // a(b)(c).d>G?(e) + // + MethodInvocation invocation2 = EngineTestCase.assertInstanceOf( + (obj) => obj is MethodInvocation, MethodInvocation, + propertyAccess1.target); + expect(invocation2.methodName.name, "d"); + expect(invocation2.typeArguments, isNotNull); + ArgumentList argumentList2 = invocation2.argumentList; + expect(argumentList2, isNotNull); + expect(argumentList2.arguments, hasLength(1)); + // + // a(b)(c) + // + FunctionExpressionInvocation invocation3 = EngineTestCase.assertInstanceOf( + (obj) => obj is FunctionExpressionInvocation, + FunctionExpressionInvocation, invocation2.target); + expect(invocation3.typeArguments, isNotNull); + ArgumentList argumentList3 = invocation3.argumentList; + expect(argumentList3, isNotNull); + expect(argumentList3.arguments, hasLength(1)); + // + // a(b) + // + MethodInvocation invocation4 = EngineTestCase.assertInstanceOf( + (obj) => obj is MethodInvocation, MethodInvocation, + invocation3.function); + expect(invocation4.methodName.name, "a"); + expect(invocation4.typeArguments, isNotNull); ArgumentList argumentList4 = invocation4.argumentList; expect(argumentList4, isNotNull); expect(argumentList4.arguments, hasLength(1)); @@ -1750,6 +1791,17 @@ class Foo { "parseCascadeSection", "..()", [ParserErrorCode.MISSING_IDENTIFIER]); expect(methodInvocation.target, isNull); expect(methodInvocation.methodName.name, ""); + expect(methodInvocation.typeArguments, isNull); + expect(methodInvocation.argumentList.arguments, hasLength(0)); + } + + void test_parseCascadeSection_missingIdentifier_typeArguments() { + enableGenericMethods = true; + MethodInvocation methodInvocation = parse4( + "parseCascadeSection", "..()", [ParserErrorCode.MISSING_IDENTIFIER]); + expect(methodInvocation.target, isNull); + expect(methodInvocation.methodName.name, ""); + expect(methodInvocation.typeArguments, isNotNull); expect(methodInvocation.argumentList.arguments, hasLength(0)); } @@ -2527,6 +2579,12 @@ class ParserTestCase extends EngineTestCase { */ static bool parseFunctionBodies = true; + /** + * A flag indicating whether generic method support should be enabled for a + * specific test. + */ + bool enableGenericMethods = false; + /** * If non-null, this value is used to override the default value of * [Scanner.enableNullAwareOperators] before scanning. @@ -2585,6 +2643,7 @@ class ParserTestCase extends EngineTestCase { // Parse the source. // Parser parser = createParser(listener); + parser.parseGenericMethods = enableGenericMethods; parser.parseFunctionBodies = parseFunctionBodies; Object result = invokeParserMethodImpl(parser, methodName, objects, tokenStream); @@ -2718,6 +2777,7 @@ class ParserTestCase extends EngineTestCase { listener.setLineInfo(new TestSource(), scanner.lineStarts); Token token = scanner.tokenize(); Parser parser = createParser(listener); + parser.parseGenericMethods = enableGenericMethods; Expression expression = parser.parseExpression(token); expect(expression, isNotNull); listener.assertErrorsWithCodes(errorCodes); @@ -4654,6 +4714,16 @@ class SimpleParserTest extends ParserTestCase { expect(_isFunctionDeclaration("f() => e"), isTrue); } + void test_isFunctionDeclaration_nameButNoReturn_typeParameters_block() { + enableGenericMethods = true; + expect(_isFunctionDeclaration("f() {}"), isTrue); + } + + void test_isFunctionDeclaration_nameButNoReturn_typeParameters_expression() { + enableGenericMethods = true; + expect(_isFunctionDeclaration("f() => e"), isTrue); + } + void test_isFunctionDeclaration_normalReturn_block() { expect(_isFunctionDeclaration("C f() {}"), isTrue); } @@ -4662,6 +4732,16 @@ class SimpleParserTest extends ParserTestCase { expect(_isFunctionDeclaration("C f() => e"), isTrue); } + void test_isFunctionDeclaration_normalReturn_typeParameters_block() { + enableGenericMethods = true; + expect(_isFunctionDeclaration("C f() {}"), isTrue); + } + + void test_isFunctionDeclaration_normalReturn_typeParameters_expression() { + enableGenericMethods = true; + expect(_isFunctionDeclaration("C f() => e"), isTrue); + } + void test_isFunctionDeclaration_voidReturn_block() { expect(_isFunctionDeclaration("void f() {}"), isTrue); } @@ -4670,6 +4750,16 @@ class SimpleParserTest extends ParserTestCase { expect(_isFunctionDeclaration("void f() => e"), isTrue); } + void test_isFunctionDeclaration_voidReturn_typeParameters_block() { + enableGenericMethods = true; + expect(_isFunctionDeclaration("void f() {}"), isTrue); + } + + void test_isFunctionDeclaration_voidReturn_typeParameters_expression() { + enableGenericMethods = true; + expect(_isFunctionDeclaration("void f() => e"), isTrue); + } + void test_isFunctionExpression_false_noBody() { expect(_isFunctionExpression("f();"), isFalse); } @@ -4678,14 +4768,24 @@ class SimpleParserTest extends ParserTestCase { expect(_isFunctionExpression("(a + b) {"), isFalse); } - void test_isFunctionExpression_noName_block() { + void test_isFunctionExpression_noParameters_block() { expect(_isFunctionExpression("() {}"), isTrue); } - void test_isFunctionExpression_noName_expression() { + void test_isFunctionExpression_noParameters_expression() { expect(_isFunctionExpression("() => e"), isTrue); } + void test_isFunctionExpression_noParameters_typeParameters_block() { + enableGenericMethods = true; + expect(_isFunctionExpression("() {}"), isTrue); + } + + void test_isFunctionExpression_noParameters_typeParameters_expression() { + enableGenericMethods = true; + expect(_isFunctionExpression("() => e"), isTrue); + } + void test_isFunctionExpression_parameter_final() { expect(_isFunctionExpression("(final a) {}"), isTrue); expect(_isFunctionExpression("(final a, b) {}"), isTrue); @@ -4935,6 +5035,22 @@ class SimpleParserTest extends ParserTestCase { FunctionExpressionInvocation invocation = propertyAccess.target as FunctionExpressionInvocation; expect(invocation.function, isNotNull); + expect(invocation.typeArguments, isNull); + ArgumentList argumentList = invocation.argumentList; + expect(argumentList, isNotNull); + expect(argumentList.arguments, hasLength(1)); + expect(propertyAccess.operator, isNotNull); + expect(propertyAccess.propertyName, isNotNull); + } + + void test_parseAssignableExpression_expression_args_dot_typeParameters() { + enableGenericMethods = true; + PropertyAccess propertyAccess = + parse("parseAssignableExpression", [false], "(x)(y).z"); + FunctionExpressionInvocation invocation = + propertyAccess.target as FunctionExpressionInvocation; + expect(invocation.function, isNotNull); + expect(invocation.typeArguments, isNotNull); ArgumentList argumentList = invocation.argumentList; expect(argumentList, isNotNull); expect(argumentList.arguments, hasLength(1)); @@ -4979,6 +5095,21 @@ class SimpleParserTest extends ParserTestCase { parse("parseAssignableExpression", [false], "x(y).z"); MethodInvocation invocation = propertyAccess.target as MethodInvocation; expect(invocation.methodName.name, "x"); + expect(invocation.typeArguments, isNull); + ArgumentList argumentList = invocation.argumentList; + expect(argumentList, isNotNull); + expect(argumentList.arguments, hasLength(1)); + expect(propertyAccess.operator, isNotNull); + expect(propertyAccess.propertyName, isNotNull); + } + + void test_parseAssignableExpression_identifier_args_dot_typeParameters() { + enableGenericMethods = true; + PropertyAccess propertyAccess = + parse("parseAssignableExpression", [false], "x(y).z"); + MethodInvocation invocation = propertyAccess.target as MethodInvocation; + expect(invocation.methodName.name, "x"); + expect(invocation.typeArguments, isNotNull); ArgumentList argumentList = invocation.argumentList; expect(argumentList, isNotNull); expect(argumentList.arguments, hasLength(1)); @@ -5193,6 +5324,17 @@ class SimpleParserTest extends ParserTestCase { parse4("parseCascadeSection", "..[i](b)"); EngineTestCase.assertInstanceOf( (obj) => obj is IndexExpression, IndexExpression, section.function); + expect(section.typeArguments, isNull); + expect(section.argumentList, isNotNull); + } + + void test_parseCascadeSection_ia_typeArguments() { + enableGenericMethods = true; + FunctionExpressionInvocation section = + parse4("parseCascadeSection", "..[i](b)"); + EngineTestCase.assertInstanceOf( + (obj) => obj is IndexExpression, IndexExpression, section.function); + expect(section.typeArguments, isNotNull); expect(section.argumentList, isNotNull); } @@ -5202,6 +5344,20 @@ class SimpleParserTest extends ParserTestCase { (obj) => obj is MethodInvocation, MethodInvocation, section.target); expect(section.operator, isNotNull); expect(section.methodName, isNotNull); + expect(section.typeArguments, isNull); + expect(section.argumentList, isNotNull); + expect(section.argumentList.arguments, hasLength(1)); + } + + void test_parseCascadeSection_ii_typeArguments() { + enableGenericMethods = true; + MethodInvocation section = + parse4("parseCascadeSection", "..a(b).c(d)"); + EngineTestCase.assertInstanceOf( + (obj) => obj is MethodInvocation, MethodInvocation, section.target); + expect(section.operator, isNotNull); + expect(section.methodName, isNotNull); + expect(section.typeArguments, isNotNull); expect(section.argumentList, isNotNull); expect(section.argumentList.arguments, hasLength(1)); } @@ -5231,6 +5387,17 @@ class SimpleParserTest extends ParserTestCase { (obj) => obj is IntegerLiteral, IntegerLiteral, rhs); } + void test_parseCascadeSection_p_assign_withCascade_typeArguments() { + enableGenericMethods = true; + AssignmentExpression section = + parse4("parseCascadeSection", "..a = 3..m()"); + expect(section.leftHandSide, isNotNull); + expect(section.operator, isNotNull); + Expression rhs = section.rightHandSide; + EngineTestCase.assertInstanceOf( + (obj) => obj is IntegerLiteral, IntegerLiteral, rhs); + } + void test_parseCascadeSection_p_builtIn() { PropertyAccess section = parse4("parseCascadeSection", "..as"); expect(section.target, isNull); @@ -5243,6 +5410,18 @@ class SimpleParserTest extends ParserTestCase { expect(section.target, isNull); expect(section.operator, isNotNull); expect(section.methodName, isNotNull); + expect(section.typeArguments, isNull); + expect(section.argumentList, isNotNull); + expect(section.argumentList.arguments, hasLength(1)); + } + + void test_parseCascadeSection_pa_typeArguments() { + enableGenericMethods = true; + MethodInvocation section = parse4("parseCascadeSection", "..a(b)"); + expect(section.target, isNull); + expect(section.operator, isNotNull); + expect(section.methodName, isNotNull); + expect(section.typeArguments, isNotNull); expect(section.argumentList, isNotNull); expect(section.argumentList.arguments, hasLength(1)); } @@ -5252,6 +5431,18 @@ class SimpleParserTest extends ParserTestCase { parse4("parseCascadeSection", "..a(b)(c)"); EngineTestCase.assertInstanceOf( (obj) => obj is MethodInvocation, MethodInvocation, section.function); + expect(section.typeArguments, isNull); + expect(section.argumentList, isNotNull); + expect(section.argumentList.arguments, hasLength(1)); + } + + void test_parseCascadeSection_paa_typeArguments() { + enableGenericMethods = true; + FunctionExpressionInvocation section = + parse4("parseCascadeSection", "..a(b)(c)"); + EngineTestCase.assertInstanceOf( + (obj) => obj is MethodInvocation, MethodInvocation, section.function); + expect(section.typeArguments, isNotNull); expect(section.argumentList, isNotNull); expect(section.argumentList.arguments, hasLength(1)); } @@ -5261,6 +5452,18 @@ class SimpleParserTest extends ParserTestCase { parse4("parseCascadeSection", "..a(b)(c).d(e)(f)"); EngineTestCase.assertInstanceOf( (obj) => obj is MethodInvocation, MethodInvocation, section.function); + expect(section.typeArguments, isNull); + expect(section.argumentList, isNotNull); + expect(section.argumentList.arguments, hasLength(1)); + } + + void test_parseCascadeSection_paapaa_typeArguments() { + enableGenericMethods = true; + FunctionExpressionInvocation section = + parse4("parseCascadeSection", "..a(b)(c).d(e)(f)"); + EngineTestCase.assertInstanceOf( + (obj) => obj is MethodInvocation, MethodInvocation, section.function); + expect(section.typeArguments, isNotNull); expect(section.argumentList, isNotNull); expect(section.argumentList.arguments, hasLength(1)); } @@ -5272,6 +5475,14 @@ class SimpleParserTest extends ParserTestCase { expect(section.propertyName, isNotNull); } + void test_parseCascadeSection_pap_typeArguments() { + enableGenericMethods = true; + PropertyAccess section = parse4("parseCascadeSection", "..a(b).c"); + expect(section.target, isNotNull); + expect(section.operator, isNotNull); + expect(section.propertyName, isNotNull); + } + void test_parseClassDeclaration_abstract() { ClassDeclaration declaration = parse("parseClassDeclaration", [ emptyCommentAndMetadata(), @@ -5581,6 +5792,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.modifierKeyword, isNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.propertyKeyword, isNull); expect(method.returnType, isNull); @@ -5595,11 +5807,60 @@ class SimpleParserTest extends ParserTestCase { expect(method.modifierKeyword, isNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.propertyKeyword, isNull); expect(method.returnType, isNotNull); } + void test_parseClassMember_method_generic_noReturnType() { + enableGenericMethods = true; + MethodDeclaration method = + parse("parseClassMember", ["C"], "m() {}"); + expect(method.documentationComment, isNull); + expect(method.externalKeyword, isNull); + expect(method.modifierKeyword, isNull); + expect(method.propertyKeyword, isNull); + expect(method.returnType, isNull); + expect(method.name, isNotNull); + expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNotNull); + expect(method.parameters, isNotNull); + expect(method.body, isNotNull); + } + + void test_parseClassMember_method_generic_returnType() { + enableGenericMethods = true; + MethodDeclaration method = + parse("parseClassMember", ["C"], "T m() {}"); + expect(method.documentationComment, isNull); + expect(method.externalKeyword, isNull); + expect(method.modifierKeyword, isNull); + expect(method.propertyKeyword, isNull); + expect(method.returnType, isNotNull); + expect(method.name, isNotNull); + expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNotNull); + expect(method.parameters, isNotNull); + expect(method.body, isNotNull); + } + + void test_parseClassMember_method_generic_void() { + enableGenericMethods = true; + MethodDeclaration method = + parse("parseClassMember", ["C"], "void m() {}"); + expect(method.documentationComment, isNull); + expect(method.externalKeyword, isNull); + expect(method.modifierKeyword, isNull); + expect(method.propertyKeyword, isNull); + expect(method.returnType, isNotNull); + expect(method.name, isNotNull); + expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNotNull); + expect(method.parameters, isNotNull); + expect(method.body, isNotNull); + } + void test_parseClassMember_method_get_noType() { MethodDeclaration method = parse("parseClassMember", ["C"], "get() {}"); @@ -5610,6 +5871,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.returnType, isNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.body, isNotNull); } @@ -5624,6 +5886,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.returnType, isNotNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.body, isNotNull); } @@ -5638,6 +5901,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.returnType, isNotNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.body, isNotNull); } @@ -5652,6 +5916,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.returnType, isNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.body, isNotNull); } @@ -5666,6 +5931,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.returnType, isNotNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.body, isNotNull); } @@ -5680,6 +5946,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.returnType, isNotNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.body, isNotNull); } @@ -5694,6 +5961,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.returnType, isNotNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.body, isNotNull); } @@ -5708,6 +5976,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.returnType, isNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.body, isNotNull); } @@ -5722,6 +5991,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.returnType, isNotNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.body, isNotNull); } @@ -5736,6 +6006,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.returnType, isNotNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.body, isNotNull); } @@ -5750,6 +6021,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.returnType, isNotNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNotNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.body, isNotNull); } @@ -5764,6 +6036,7 @@ class SimpleParserTest extends ParserTestCase { expect(method.returnType, isNotNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNotNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.body, isNotNull); } @@ -6978,6 +7251,7 @@ void'''); FunctionExpression expression = invocation.function as FunctionExpression; expect(expression.parameters, isNotNull); expect(expression.body, isNotNull); + expect(invocation.typeArguments, isNull); ArgumentList list = invocation.argumentList; expect(list, isNotNull); expect(list.arguments, hasLength(1)); @@ -6986,12 +7260,24 @@ void'''); void test_parseExpression_nonAwait() { MethodInvocation expression = parseExpression("await()"); expect(expression.methodName.name, 'await'); + expect(expression.typeArguments, isNull); + expect(expression.argumentList, isNotNull); } void test_parseExpression_superMethodInvocation() { MethodInvocation invocation = parse4("parseExpression", "super.m()"); expect(invocation.target, isNotNull); expect(invocation.methodName, isNotNull); + expect(invocation.typeArguments, isNull); + expect(invocation.argumentList, isNotNull); + } + + void test_parseExpression_superMethodInvocation_typeArguments() { + enableGenericMethods = true; + MethodInvocation invocation = parse4("parseExpression", "super.m()"); + expect(invocation.target, isNotNull); + expect(invocation.methodName, isNotNull); + expect(invocation.typeArguments, isNotNull); expect(invocation.argumentList, isNotNull); } @@ -7029,6 +7315,17 @@ void'''); parse4("parseExpressionWithoutCascade", "super.m()"); expect(invocation.target, isNotNull); expect(invocation.methodName, isNotNull); + expect(invocation.typeArguments, isNull); + expect(invocation.argumentList, isNotNull); + } + + void test_parseExpressionWithoutCascade_superMethodInvocation_typeArguments() { + enableGenericMethods = true; + MethodInvocation invocation = + parse4("parseExpressionWithoutCascade", "super.m()"); + expect(invocation.target, isNotNull); + expect(invocation.methodName, isNotNull); + expect(invocation.typeArguments, isNotNull); expect(invocation.argumentList, isNotNull); } @@ -7765,6 +8062,24 @@ void'''); FunctionExpression expression = declaration.functionExpression; expect(expression, isNotNull); expect(expression.body, isNotNull); + expect(expression.typeParameters, isNull); + expect(expression.parameters, isNotNull); + expect(declaration.propertyKeyword, isNull); + } + + void test_parseFunctionDeclaration_functionWithTypeParameters() { + enableGenericMethods = true; + Comment comment = Comment.createDocumentationComment(new List(0)); + TypeName returnType = new TypeName(new SimpleIdentifier(null), null); + FunctionDeclaration declaration = parse("parseFunctionDeclaration", + [commentAndMetadata(comment), null, returnType], "f() {}"); + expect(declaration.documentationComment, comment); + expect(declaration.returnType, returnType); + expect(declaration.name, isNotNull); + FunctionExpression expression = declaration.functionExpression; + expect(expression, isNotNull); + expect(expression.body, isNotNull); + expect(expression.typeParameters, isNotNull); expect(expression.parameters, isNotNull); expect(declaration.propertyKeyword, isNull); } @@ -7780,6 +8095,7 @@ void'''); FunctionExpression expression = declaration.functionExpression; expect(expression, isNotNull); expect(expression.body, isNotNull); + expect(expression.typeParameters, isNull); expect(expression.parameters, isNull); expect(declaration.propertyKeyword, isNotNull); } @@ -7795,6 +8111,7 @@ void'''); FunctionExpression expression = declaration.functionExpression; expect(expression, isNotNull); expect(expression.body, isNotNull); + expect(expression.typeParameters, isNull); expect(expression.parameters, isNotNull); expect(declaration.propertyKeyword, isNotNull); } @@ -7805,10 +8122,28 @@ void'''); expect(statement.functionDeclaration, isNotNull); } + void test_parseFunctionDeclarationStatement_typeParameters() { + enableGenericMethods = true; + FunctionDeclarationStatement statement = + parse4("parseFunctionDeclarationStatement", "E f(E p) => p * 2;"); + expect(statement.functionDeclaration, isNotNull); + } + void test_parseFunctionExpression_body_inExpression() { FunctionExpression expression = parse4("parseFunctionExpression", "(int i) => i++"); expect(expression.body, isNotNull); + expect(expression.typeParameters, isNull); + expect(expression.parameters, isNotNull); + expect((expression.body as ExpressionFunctionBody).semicolon, isNull); + } + + void test_parseFunctionExpression_typeParameters() { + enableGenericMethods = true; + FunctionExpression expression = + parse4("parseFunctionExpression", "(E i) => i++"); + expect(expression.body, isNotNull); + expect(expression.typeParameters, isNotNull); expect(expression.parameters, isNotNull); expect((expression.body as ExpressionFunctionBody).semicolon, isNull); } @@ -7849,6 +8184,7 @@ void'''); expect(method.modifierKeyword, staticKeyword); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNull); expect(method.propertyKeyword, isNotNull); expect(method.returnType, returnType); @@ -8433,6 +8769,7 @@ void'''); FunctionExpression expression = invocation.function as FunctionExpression; expect(expression.parameters, isNotNull); expect(expression.body, isNotNull); + expect(invocation.typeArguments, isNull); ArgumentList list = invocation.argumentList; expect(list, isNotNull); expect(list.arguments, hasLength(1)); @@ -8550,6 +8887,17 @@ void'''); parse4("parseNormalFormalParameter", "a())"); expect(parameter.returnType, isNull); expect(parameter.identifier, isNotNull); + expect(parameter.typeParameters, isNull); + expect(parameter.parameters, isNotNull); + } + + void test_parseNormalFormalParameter_function_noType_typeParameters() { + enableGenericMethods = true; + FunctionTypedFormalParameter parameter = + parse4("parseNormalFormalParameter", "a())"); + expect(parameter.returnType, isNull); + expect(parameter.identifier, isNotNull); + expect(parameter.typeParameters, isNotNull); expect(parameter.parameters, isNotNull); } @@ -8558,6 +8906,17 @@ void'''); parse4("parseNormalFormalParameter", "A a())"); expect(parameter.returnType, isNotNull); expect(parameter.identifier, isNotNull); + expect(parameter.typeParameters, isNull); + expect(parameter.parameters, isNotNull); + } + + void test_parseNormalFormalParameter_function_type_typeParameters() { + enableGenericMethods = true; + FunctionTypedFormalParameter parameter = + parse4("parseNormalFormalParameter", "A a())"); + expect(parameter.returnType, isNotNull); + expect(parameter.identifier, isNotNull); + expect(parameter.typeParameters, isNotNull); expect(parameter.parameters, isNotNull); } @@ -8566,6 +8925,17 @@ void'''); parse4("parseNormalFormalParameter", "void a())"); expect(parameter.returnType, isNotNull); expect(parameter.identifier, isNotNull); + expect(parameter.typeParameters, isNull); + expect(parameter.parameters, isNotNull); + } + + void test_parseNormalFormalParameter_function_void_typeParameters() { + enableGenericMethods = true; + FunctionTypedFormalParameter parameter = + parse4("parseNormalFormalParameter", "void a())"); + expect(parameter.returnType, isNotNull); + expect(parameter.identifier, isNotNull); + expect(parameter.typeParameters, isNotNull); expect(parameter.parameters, isNotNull); } @@ -8631,6 +9001,7 @@ void'''); expect(method.modifierKeyword, isNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNotNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.propertyKeyword, isNull); expect(method.returnType, returnType); @@ -8682,6 +9053,7 @@ void'''); expect(expression.target, isNotNull); expect(expression.operator.type, TokenType.PERIOD); expect(expression.methodName, isNotNull); + expect(expression.typeArguments, isNull); expect(expression.argumentList, isNotNull); } @@ -8691,6 +9063,28 @@ void'''); expect(expression.target, isNotNull); expect(expression.operator.type, TokenType.QUESTION_PERIOD); expect(expression.methodName, isNotNull); + expect(expression.typeArguments, isNull); + expect(expression.argumentList, isNotNull); + } + + void test_parsePostfixExpression_none_methodInvocation_question_dot_typeArguments() { + enableGenericMethods = true; + _enableNullAwareOperators = true; + MethodInvocation expression = parse4('parsePostfixExpression', 'a?.m()'); + expect(expression.target, isNotNull); + expect(expression.operator.type, TokenType.QUESTION_PERIOD); + expect(expression.methodName, isNotNull); + expect(expression.typeArguments, isNotNull); + expect(expression.argumentList, isNotNull); + } + + void test_parsePostfixExpression_none_methodInvocation_typeArguments() { + enableGenericMethods = true; + MethodInvocation expression = parse4("parsePostfixExpression", "a.m()"); + expect(expression.target, isNotNull); + expect(expression.operator.type, TokenType.PERIOD); + expect(expression.methodName, isNotNull); + expect(expression.typeArguments, isNotNull); expect(expression.argumentList, isNotNull); } @@ -8961,6 +9355,7 @@ void'''); expect(method.modifierKeyword, isNull); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.propertyKeyword, isNotNull); expect(method.returnType, returnType); @@ -8982,6 +9377,7 @@ void'''); expect(method.modifierKeyword, staticKeyword); expect(method.name, isNotNull); expect(method.operatorKeyword, isNull); + expect(method.typeParameters, isNull); expect(method.parameters, isNotNull); expect(method.propertyKeyword, isNotNull); expect(method.returnType, returnType); @@ -9033,13 +9429,33 @@ void'''); expect(argumentList.rightBracket, isNotNull); } - void test_parseStatement_functionDeclaration() { + void test_parseStatement_functionDeclaration_noReturnType() { + FunctionDeclarationStatement statement = + parse4("parseStatement", "f(a, b) {};"); + expect(statement.functionDeclaration, isNotNull); + } + + void test_parseStatement_functionDeclaration_noReturnType_typeParameters() { + enableGenericMethods = true; + FunctionDeclarationStatement statement = + parse4("parseStatement", "f(a, b) {};"); + expect(statement.functionDeclaration, isNotNull); + } + + void test_parseStatement_functionDeclaration_returnType() { // TODO(brianwilkerson) Implement more tests for this method. FunctionDeclarationStatement statement = parse4("parseStatement", "int f(a, b) {};"); expect(statement.functionDeclaration, isNotNull); } + void test_parseStatement_functionDeclaration_returnType_typeParameters() { + enableGenericMethods = true; + FunctionDeclarationStatement statement = + parse4("parseStatement", "int f(a, b) {};"); + expect(statement.functionDeclaration, isNotNull); + } + void test_parseStatement_mulipleLabels() { LabeledStatement statement = parse4("parseStatement", "l: m: return x;"); expect(statement.labels, hasLength(2));