blob: 21c4f387d4f901b44fa567f51de07b80ec16bc0e [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/error/hint_codes.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/testing/token_factory.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:front_end/src/fasta/scanner/abstract_scanner.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'test_support.dart';
main() {
// The fasta parser has a parallel set of tests in parser_fasta_test.dart
if (Parser.useFasta) return;
defineReflectiveSuite(() {
defineReflectiveTests(ClassMemberParserTest);
defineReflectiveTests(ComplexParserTest);
defineReflectiveTests(ErrorParserTest);
defineReflectiveTests(ExpressionParserTest);
defineReflectiveTests(FormalParameterParserTest);
defineReflectiveTests(NonErrorParserTest);
defineReflectiveTests(RecoveryParserTest);
defineReflectiveTests(SimpleParserTest);
defineReflectiveTests(StatementParserTest);
defineReflectiveTests(TopLevelParserTest);
});
}
/**
* Abstract base class for parser tests, which does not make assumptions about
* which parser is used.
*/
abstract class AbstractParserTestCase implements ParserTestHelpers {
bool get allowNativeClause;
void set allowNativeClause(bool value);
void set enableGenericMethodComments(bool value);
void set enableLazyAssignmentOperators(bool value);
void set enableNnbd(bool value);
/**
* Set a flag indicating whether the parser should parse instance creation
* expressions that lack either the `new` or `const` keyword.
*/
void set enableOptionalNewAndConst(bool value);
/**
* Set a flag indicating whether the parser is to parse part-of directives
* that specify a URI rather than a library name.
*/
void set enableUriInPartOf(bool value);
/**
* The error listener to which scanner and parser errors will be reported.
*
* This field is typically initialized by invoking [createParser].
*/
GatheringErrorListener get listener;
/**
* Get the parser used by the test.
*
* Caller must first invoke [createParser].
*/
Parser get parser;
/**
* Flag indicating whether the fasta parser is being used.
*/
bool get usingFastaParser;
/**
* Assert that the number and codes of errors occurred during parsing is the
* same as the [expectedErrorCodes].
*/
void assertErrorsWithCodes(List<ErrorCode> expectedErrorCodes);
/**
* Asserts that no errors occurred during parsing.
*/
void assertNoErrors();
/**
* Prepares to parse using tokens scanned from the given [content] string.
*
* [expectedEndOffset] is the expected offset of the next token to be parsed
* after the parser has finished parsing,
* or `null` (the default) if EOF is expected.
* In general, the analyzer tests do not assert that the last token is EOF,
* but the fasta parser adapter tests do assert this.
* For any analyzer test where the last token is not EOF, set this value.
* It is ignored when not using the fasta parser.
*/
void createParser(String content, {int expectedEndOffset});
ExpectedError expectedError(ErrorCode code, int offset, int length);
void expectNotNullIfNoErrors(Object result);
Expression parseAdditiveExpression(String code);
Expression parseAssignableExpression(String code, bool primaryAllowed);
Expression parseAssignableSelector(String code, bool optional,
{bool allowConditional: true});
AwaitExpression parseAwaitExpression(String code);
Expression parseBitwiseAndExpression(String code);
Expression parseBitwiseOrExpression(String code);
Expression parseBitwiseXorExpression(String code);
Expression parseCascadeSection(String code);
CompilationUnit parseCompilationUnit(String source,
{List<ErrorCode> codes, List<ExpectedError> errors});
ConditionalExpression parseConditionalExpression(String code);
Expression parseConstExpression(String code);
ConstructorInitializer parseConstructorInitializer(String code);
/**
* Parse the given source as a compilation unit.
*
* @param source the source to be parsed
* @param errorCodes the error codes of the errors that are expected to be found
* @return the compilation unit that was parsed
* @throws Exception if the source could not be parsed, if the compilation errors in the source do
* not match those that are expected, or if the result would have been `null`
*/
CompilationUnit parseDirectives(String source,
[List<ErrorCode> errorCodes = const <ErrorCode>[]]);
BinaryExpression parseEqualityExpression(String code);
Expression parseExpression(String source,
{List<ErrorCode> codes,
List<ExpectedError> errors,
int expectedEndOffset});
List<Expression> parseExpressionList(String code);
Expression parseExpressionWithoutCascade(String code);
FormalParameter parseFormalParameter(String code, ParameterKind kind,
{List<ErrorCode> errorCodes: const <ErrorCode>[]});
FormalParameterList parseFormalParameterList(String code,
{bool inFunctionType: false,
List<ErrorCode> errorCodes: const <ErrorCode>[],
List<ExpectedError> errors});
/**
* Parses a single top level member of a compilation unit (other than a
* directive), including any comment and/or metadata that precedes it.
*/
CompilationUnitMember parseFullCompilationUnitMember();
/**
* Parses a single top level directive, including any comment and/or metadata
* that precedes it.
*/
Directive parseFullDirective();
FunctionExpression parseFunctionExpression(String code);
InstanceCreationExpression parseInstanceCreationExpression(
String code, Token newToken);
ListLiteral parseListLiteral(
Token token, String typeArgumentsCode, String code);
TypedLiteral parseListOrMapLiteral(Token modifier, String code);
Expression parseLogicalAndExpression(String code);
Expression parseLogicalOrExpression(String code);
MapLiteral parseMapLiteral(
Token token, String typeArgumentsCode, String code);
MapLiteralEntry parseMapLiteralEntry(String code);
Expression parseMultiplicativeExpression(String code);
InstanceCreationExpression parseNewExpression(String code);
NormalFormalParameter parseNormalFormalParameter(String code,
{bool inFunctionType: false,
List<ErrorCode> errorCodes: const <ErrorCode>[]});
Expression parsePostfixExpression(String code);
Identifier parsePrefixedIdentifier(String code);
Expression parsePrimaryExpression(String code,
{int expectedEndOffset, List<ExpectedError> errors});
Expression parseRelationalExpression(String code);
RethrowExpression parseRethrowExpression(String code);
BinaryExpression parseShiftExpression(String code);
SimpleIdentifier parseSimpleIdentifier(String code);
Statement parseStatement(String source,
{bool enableLazyAssignmentOperators, int expectedEndOffset});
Expression parseStringLiteral(String code);
SymbolLiteral parseSymbolLiteral(String code);
Expression parseThrowExpression(String code);
Expression parseThrowExpressionWithoutCascade(String code);
PrefixExpression parseUnaryExpression(String code);
VariableDeclarationList parseVariableDeclarationList(String source);
}
/**
* Instances of the class `AstValidator` are used to validate the correct construction of an
* AST structure.
*/
class AstValidator extends UnifyingAstVisitor<Object> {
/**
* A list containing the errors found while traversing the AST structure.
*/
List<String> _errors = new List<String>();
/**
* Assert that no errors were found while traversing any of the AST structures that have been
* visited.
*/
void assertValid() {
if (!_errors.isEmpty) {
StringBuffer buffer = new StringBuffer();
buffer.write("Invalid AST structure:");
for (String message in _errors) {
buffer.write("\r\n ");
buffer.write(message);
}
fail(buffer.toString());
}
}
@override
Object visitNode(AstNode node) {
_validate(node);
return super.visitNode(node);
}
/**
* Validate that the given AST node is correctly constructed.
*
* @param node the AST node being validated
*/
void _validate(AstNode node) {
AstNode parent = node.parent;
if (node is CompilationUnit) {
if (parent != null) {
_errors.add("Compilation units should not have a parent");
}
} else {
if (parent == null) {
_errors.add("No parent for ${node.runtimeType}");
}
}
if (node.beginToken == null) {
_errors.add("No begin token for ${node.runtimeType}");
}
if (node.endToken == null) {
_errors.add("No end token for ${node.runtimeType}");
}
int nodeStart = node.offset;
int nodeLength = node.length;
if (nodeStart < 0 || nodeLength < 0) {
_errors.add("No source info for ${node.runtimeType}");
}
if (parent != null) {
int nodeEnd = nodeStart + nodeLength;
int parentStart = parent.offset;
int parentEnd = parentStart + parent.length;
if (nodeStart < parentStart) {
_errors.add("Invalid source start ($nodeStart) for ${node
.runtimeType} inside ${parent.runtimeType} ($parentStart)");
}
if (nodeEnd > parentEnd) {
_errors.add("Invalid source end ($nodeEnd) for ${node
.runtimeType} inside ${parent.runtimeType} ($parentStart)");
}
}
}
}
@reflectiveTest
class ClassMemberParserTest extends ParserTestCase
with ClassMemberParserTestMixin {
@failingTest
@override
void test_parseAwaitExpression_inSync() {
super.test_parseAwaitExpression_inSync();
}
}
/**
* Tests which exercise the parser using a class member.
*/
abstract class ClassMemberParserTestMixin implements AbstractParserTestCase {
void test_parseAwaitExpression_asStatement_inAsync() {
createParser('m() async { await x; }');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
FunctionBody body = method.body;
EngineTestCase.assertInstanceOf(
(obj) => obj is BlockFunctionBody, BlockFunctionBody, body);
Statement statement = (body as BlockFunctionBody).block.statements[0];
EngineTestCase.assertInstanceOf(
(obj) => obj is ExpressionStatement, ExpressionStatement, statement);
Expression expression = (statement as ExpressionStatement).expression;
EngineTestCase.assertInstanceOf(
(obj) => obj is AwaitExpression, AwaitExpression, expression);
expect((expression as AwaitExpression).awaitKeyword, isNotNull);
expect((expression as AwaitExpression).expression, isNotNull);
}
void test_parseAwaitExpression_asStatement_inSync() {
createParser('m() { await x; }');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
FunctionBody body = method.body;
EngineTestCase.assertInstanceOf(
(obj) => obj is BlockFunctionBody, BlockFunctionBody, body);
Statement statement = (body as BlockFunctionBody).block.statements[0];
EngineTestCase.assertInstanceOf(
(obj) => obj is VariableDeclarationStatement,
VariableDeclarationStatement,
statement);
}
void test_parseAwaitExpression_inSync() {
createParser('m() { return await x + await y; }');
MethodDeclaration method = parser.parseClassMember('C');
expect(method, isNotNull);
listener.assertErrors(usingFastaParser
? [
expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 13, 5),
expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 23, 5)
]
: [
// This test requires better error recovery than we currently have.
// In particular, we need to be able to distinguish
// between an await expression in the wrong context,
// and the use of 'await' as an identifier.
expectedError(ParserErrorCode.EXPECTED_TOKEN, 13, 5),
expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 29, 1)
]);
FunctionBody body = method.body;
EngineTestCase.assertInstanceOf(
(obj) => obj is BlockFunctionBody, BlockFunctionBody, body);
Statement statement = (body as BlockFunctionBody).block.statements[0];
EngineTestCase.assertInstanceOf(
(obj) => obj is ReturnStatement, ReturnStatement, statement);
Expression expression = (statement as ReturnStatement).expression;
EngineTestCase.assertInstanceOf(
(obj) => obj is BinaryExpression, BinaryExpression, expression);
if (!usingFastaParser) {
// TODO(danrubel): capture `await` keywords in fasta generated AST
EngineTestCase.assertInstanceOf((obj) => obj is AwaitExpression,
AwaitExpression, (expression as BinaryExpression).leftOperand);
EngineTestCase.assertInstanceOf((obj) => obj is AwaitExpression,
AwaitExpression, (expression as BinaryExpression).rightOperand);
}
}
void test_parseClassMember_constructor_withDocComment() {
createParser('/// Doc\nC();');
var constructor = parser.parseClassMember('C') as ConstructorDeclaration;
expectCommentText(constructor.documentationComment, '/// Doc');
}
void test_parseClassMember_constructor_withInitializers() {
// TODO(brianwilkerson) Test other kinds of class members: fields, getters
// and setters.
createParser('C(_, _\$, this.__) : _a = _ + _\$ {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<ConstructorDeclaration>());
ConstructorDeclaration constructor = member;
expect(constructor.body, isNotNull);
expect(constructor.separator, isNotNull);
expect(constructor.externalKeyword, isNull);
expect(constructor.constKeyword, isNull);
expect(constructor.factoryKeyword, isNull);
expect(constructor.name, isNull);
expect(constructor.parameters, isNotNull);
expect(constructor.period, isNull);
expect(constructor.returnType, isNotNull);
expect(constructor.initializers, hasLength(1));
}
void test_parseClassMember_field_covariant() {
createParser('covariant T f;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<FieldDeclaration>());
FieldDeclaration field = member;
expect(field.covariantKeyword, isNotNull);
expect(field.documentationComment, isNull);
expect(field.metadata, hasLength(0));
expect(field.staticKeyword, isNull);
VariableDeclarationList list = field.fields;
expect(list, isNotNull);
NodeList<VariableDeclaration> variables = list.variables;
expect(variables, hasLength(1));
VariableDeclaration variable = variables[0];
expect(variable.name, isNotNull);
}
void test_parseClassMember_field_generic() {
createParser('List<List<N>> _allComponents = new List<List<N>>();');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<FieldDeclaration>());
FieldDeclaration field = member;
expect(field.covariantKeyword, isNull);
expect(field.documentationComment, isNull);
expect(field.metadata, hasLength(0));
expect(field.staticKeyword, isNull);
VariableDeclarationList list = field.fields;
expect(list, isNotNull);
TypeName type = list.type;
expect(type.name.name, 'List');
NodeList typeArguments = type.typeArguments.arguments;
expect(typeArguments, hasLength(1));
TypeName type2 = typeArguments[0];
expect(type2.name.name, 'List');
NodeList typeArguments2 = type2.typeArguments.arguments;
expect(typeArguments2, hasLength(1));
TypeName type3 = typeArguments2[0];
expect(type3.name.name, 'N');
NodeList<VariableDeclaration> variables = list.variables;
expect(variables, hasLength(1));
VariableDeclaration variable = variables[0];
expect(variable.name, isNotNull);
}
void test_parseClassMember_field_gftType_gftReturnType() {
createParser('''
Function(int) Function(String) v;
''');
ClassMember member = parser.parseClassMember('C');
assertNoErrors();
expect(member, new TypeMatcher<FieldDeclaration>());
VariableDeclarationList fields = (member as FieldDeclaration).fields;
expect(fields.type, new TypeMatcher<GenericFunctionType>());
}
void test_parseClassMember_field_gftType_noReturnType() {
createParser('''
Function(int, String) v;
''');
ClassMember member = parser.parseClassMember('C');
assertNoErrors();
expect(member, new TypeMatcher<FieldDeclaration>());
VariableDeclarationList fields = (member as FieldDeclaration).fields;
expect(fields.type, new TypeMatcher<GenericFunctionType>());
}
void test_parseClassMember_field_instance_prefixedType() {
createParser('p.A f;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<FieldDeclaration>());
FieldDeclaration field = member;
expect(field.covariantKeyword, isNull);
expect(field.documentationComment, isNull);
expect(field.metadata, hasLength(0));
expect(field.staticKeyword, isNull);
VariableDeclarationList list = field.fields;
expect(list, isNotNull);
NodeList<VariableDeclaration> variables = list.variables;
expect(variables, hasLength(1));
VariableDeclaration variable = variables[0];
expect(variable.name, isNotNull);
_assertIsDeclarationName(variable.name);
}
void test_parseClassMember_field_namedGet() {
createParser('var get;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<FieldDeclaration>());
FieldDeclaration field = member;
expect(field.covariantKeyword, isNull);
expect(field.documentationComment, isNull);
expect(field.metadata, hasLength(0));
expect(field.staticKeyword, isNull);
VariableDeclarationList list = field.fields;
expect(list, isNotNull);
NodeList<VariableDeclaration> variables = list.variables;
expect(variables, hasLength(1));
VariableDeclaration variable = variables[0];
expect(variable.name, isNotNull);
}
void test_parseClassMember_field_namedOperator() {
createParser('var operator;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<FieldDeclaration>());
FieldDeclaration field = member;
expect(field.covariantKeyword, isNull);
expect(field.documentationComment, isNull);
expect(field.metadata, hasLength(0));
expect(field.staticKeyword, isNull);
VariableDeclarationList list = field.fields;
expect(list, isNotNull);
NodeList<VariableDeclaration> variables = list.variables;
expect(variables, hasLength(1));
VariableDeclaration variable = variables[0];
expect(variable.name, isNotNull);
}
void test_parseClassMember_field_namedOperator_withAssignment() {
createParser('var operator = (5);');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<FieldDeclaration>());
FieldDeclaration field = member;
expect(field.covariantKeyword, isNull);
expect(field.documentationComment, isNull);
expect(field.metadata, hasLength(0));
expect(field.staticKeyword, isNull);
VariableDeclarationList list = field.fields;
expect(list, isNotNull);
NodeList<VariableDeclaration> variables = list.variables;
expect(variables, hasLength(1));
VariableDeclaration variable = variables[0];
expect(variable.name, isNotNull);
expect(variable.initializer, isNotNull);
}
void test_parseClassMember_field_namedSet() {
createParser('var set;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<FieldDeclaration>());
FieldDeclaration field = member;
expect(field.covariantKeyword, isNull);
expect(field.documentationComment, isNull);
expect(field.metadata, hasLength(0));
expect(field.staticKeyword, isNull);
VariableDeclarationList list = field.fields;
expect(list, isNotNull);
NodeList<VariableDeclaration> variables = list.variables;
expect(variables, hasLength(1));
VariableDeclaration variable = variables[0];
expect(variable.name, isNotNull);
}
void test_parseClassMember_field_nameKeyword() {
createParser('var for;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
listener.assertErrors(usingFastaParser
? [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 3)]
: [
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 3),
expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 4, 3)
]);
}
void test_parseClassMember_field_nameMissing() {
createParser('var ;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
listener.assertErrors(
[expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 1)]);
}
void test_parseClassMember_field_nameMissing2() {
createParser('var "";');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
listener.assertErrors(usingFastaParser
? [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 2)]
: [
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 2),
expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 4, 2)
]);
}
void test_parseClassMember_field_static() {
createParser('static A f;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<FieldDeclaration>());
FieldDeclaration field = member;
expect(field.covariantKeyword, isNull);
expect(field.documentationComment, isNull);
expect(field.metadata, hasLength(0));
expect(field.staticKeyword, isNotNull);
VariableDeclarationList list = field.fields;
expect(list, isNotNull);
NodeList<VariableDeclaration> variables = list.variables;
expect(variables, hasLength(1));
VariableDeclaration variable = variables[0];
expect(variable.name, isNotNull);
}
void test_parseClassMember_getter_functionType() {
createParser('int Function(int) get g {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword, isNull);
expect(method.propertyKeyword, isNotNull);
expect(method.returnType, isNotNull);
expect(method.name, isNotNull);
expect(method.operatorKeyword, isNull);
expect(method.body, isNotNull);
expect(method.parameters, isNull);
}
void test_parseClassMember_getter_void() {
createParser('void get g {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword, isNull);
expect(method.propertyKeyword, isNotNull);
expect(method.returnType, isNotNull);
expect(method.name, isNotNull);
_assertIsDeclarationName(method.name);
expect(method.operatorKeyword, isNull);
expect(method.body, isNotNull);
expect(method.parameters, isNull);
}
void test_parseClassMember_method_external() {
createParser('external m();');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNotNull);
expect(method.modifierKeyword, isNull);
expect(method.name, isNotNull);
_assertIsDeclarationName(method.name);
expect(method.operatorKeyword, isNull);
expect(method.typeParameters, isNull);
expect(method.parameters, isNotNull);
expect(method.propertyKeyword, isNull);
expect(method.returnType, isNull);
var body = method.body as EmptyFunctionBody;
expect(body.keyword, isNull);
expect(body.star, isNull);
expect(body.semicolon.type, TokenType.SEMICOLON);
}
void test_parseClassMember_method_external_withTypeAndArgs() {
createParser('external int m(int a);');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.body, isNotNull);
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNotNull);
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_comment_noReturnType() {
enableGenericMethodComments = true;
createParser('m/*<T>*/() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
if (usingFastaParser) {
assertNoErrors();
} else {
assertErrorsWithCodes([HintCode.GENERIC_METHOD_COMMENT]);
}
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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_comment_parameterType() {
enableGenericMethodComments = true;
createParser('m/*<T>*/(dynamic /*=T*/ p) => null;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
if (usingFastaParser) {
assertNoErrors();
} else {
assertErrorsWithCodes(
[HintCode.GENERIC_METHOD_COMMENT, HintCode.GENERIC_METHOD_COMMENT]);
}
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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);
FormalParameterList parameters = method.parameters;
expect(parameters, isNotNull);
expect(parameters.parameters, hasLength(1));
var parameter = parameters.parameters[0] as SimpleFormalParameter;
var parameterType = parameter.type as TypeName;
expect(parameterType.name.name, 'T');
expect(method.body, isNotNull);
}
void test_parseClassMember_method_generic_comment_returnType() {
enableGenericMethodComments = true;
createParser('/*=T*/ m/*<T>*/() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
if (usingFastaParser) {
assertNoErrors();
} else {
assertErrorsWithCodes(
[HintCode.GENERIC_METHOD_COMMENT, HintCode.GENERIC_METHOD_COMMENT]);
}
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword, isNull);
expect(method.propertyKeyword, isNull);
expect(method.returnType, isNotNull);
expect((method.returnType as TypeName).name.name, 'T');
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_comment_returnType_bound() {
enableGenericMethodComments = true;
createParser('num/*=T*/ m/*<T extends num>*/() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
if (usingFastaParser) {
assertNoErrors();
} else {
assertErrorsWithCodes(
[HintCode.GENERIC_METHOD_COMMENT, HintCode.GENERIC_METHOD_COMMENT]);
}
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword, isNull);
expect(method.propertyKeyword, isNull);
expect((method.returnType as TypeName).name.name, 'T');
expect(method.name, isNotNull);
expect(method.operatorKeyword, isNull);
expect(method.typeParameters, isNotNull);
TypeParameter tp = method.typeParameters.typeParameters[0];
expect(tp.name.name, 'T');
expect(tp.extendsKeyword, isNotNull);
expect((tp.bound as TypeName).name.name, 'num');
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_generic_comment_returnType_complex() {
enableGenericMethodComments = true;
createParser('dynamic /*=Map<int, T>*/ m/*<T>*/() => null;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
if (usingFastaParser) {
assertNoErrors();
} else {
assertErrorsWithCodes(
[HintCode.GENERIC_METHOD_COMMENT, HintCode.GENERIC_METHOD_COMMENT]);
}
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword, isNull);
expect(method.propertyKeyword, isNull);
{
var returnType = method.returnType as TypeName;
expect(returnType, isNotNull);
expect(returnType.name.name, 'Map');
List<TypeAnnotation> typeArguments = returnType.typeArguments.arguments;
expect(typeArguments, hasLength(2));
expect((typeArguments[0] as TypeName).name.name, 'int');
expect((typeArguments[1] as TypeName).name.name, 'T');
}
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_comment_void() {
enableGenericMethodComments = true;
createParser('void m/*<T>*/() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
if (usingFastaParser) {
assertNoErrors();
} else {
assertErrorsWithCodes([HintCode.GENERIC_METHOD_COMMENT]);
}
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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_noReturnType() {
createParser('m<T>() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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_parameterType() {
createParser('m<T>(T p) => null;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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);
FormalParameterList parameters = method.parameters;
expect(parameters, isNotNull);
expect(parameters.parameters, hasLength(1));
var parameter = parameters.parameters[0] as SimpleFormalParameter;
var parameterType = parameter.type as TypeName;
expect(parameterType.name.name, 'T');
expect(method.body, isNotNull);
}
void test_parseClassMember_method_generic_returnType() {
createParser('T m<T>() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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_returnType_bound() {
createParser('T m<T extends num>() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword, isNull);
expect(method.propertyKeyword, isNull);
expect((method.returnType as TypeName).name.name, 'T');
expect(method.name, isNotNull);
expect(method.operatorKeyword, isNull);
expect(method.typeParameters, isNotNull);
TypeParameter tp = method.typeParameters.typeParameters[0];
expect(tp.name.name, 'T');
expect(tp.extendsKeyword, isNotNull);
expect((tp.bound as TypeName).name.name, 'num');
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_generic_returnType_complex() {
createParser('Map<int, T> m<T>() => null;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword, isNull);
expect(method.propertyKeyword, isNull);
{
var returnType = method.returnType as TypeName;
expect(returnType, isNotNull);
expect(returnType.name.name, 'Map');
List<TypeAnnotation> typeArguments = returnType.typeArguments.arguments;
expect(typeArguments, hasLength(2));
expect((typeArguments[0] as TypeName).name.name, 'int');
expect((typeArguments[1] as TypeName).name.name, 'T');
}
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_static() {
createParser('static T m<T>() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword, isNotNull);
expect(method.propertyKeyword, isNull);
expect(method.returnType, isNotNull);
expect((method.returnType as TypeName).name.name, 'T');
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() {
createParser('void m<T>() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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() {
createParser('get() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_get_type() {
createParser('int get() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_get_void() {
createParser('void get() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_gftReturnType_noReturnType() {
createParser('''
Function<A>(core.List<core.int> x) m() => null;
''');
ClassMember member = parser.parseClassMember('C');
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
expect((member as MethodDeclaration).body,
new TypeMatcher<ExpressionFunctionBody>());
}
void test_parseClassMember_method_gftReturnType_voidReturnType() {
createParser('''
void Function<A>(core.List<core.int> x) m() => null;
''');
ClassMember member = parser.parseClassMember('C');
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
expect((member as MethodDeclaration).body,
new TypeMatcher<ExpressionFunctionBody>());
}
void test_parseClassMember_method_native_allowed() {
allowNativeClause = true;
_parseClassMember_method_native();
assertNoErrors();
}
void test_parseClassMember_method_native_missing_literal_allowed() {
allowNativeClause = true;
_parseClassMember_method_native_missing_literal();
assertNoErrors();
}
void test_parseClassMember_method_native_missing_literal_not_allowed() {
allowNativeClause = false;
_parseClassMember_method_native_missing_literal();
if (usingFastaParser) {
listener.assertErrors([
expectedError(ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION, 4, 6),
]);
} else {
assertNoErrors();
}
}
void test_parseClassMember_method_native_not_allowed() {
allowNativeClause = false;
_parseClassMember_method_native();
if (usingFastaParser) {
listener.assertErrors([
expectedError(ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION, 4, 6),
]);
} else {
assertNoErrors();
}
}
void test_parseClassMember_method_native_with_body_allowed() {
allowNativeClause = true;
_parseClassMember_method_native_with_body();
if (usingFastaParser) {
// TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
assertErrorsWithCodes([
ParserErrorCode.EXTERNAL_METHOD_WITH_BODY,
]);
// listener.assertErrors([
// expectedError(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, 17, 2),
// ]);
} else {
assertErrorsWithCodes([
ParserErrorCode.EXPECTED_TOKEN,
]);
}
}
void test_parseClassMember_method_native_with_body_not_allowed() {
allowNativeClause = false;
_parseClassMember_method_native_with_body();
if (usingFastaParser) {
// TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
assertErrorsWithCodes([
ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION,
ParserErrorCode.EXTERNAL_METHOD_WITH_BODY,
]);
// listener.assertErrors([
// expectedError(ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION, 4, 6),
// expectedError(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, 17, 2),
// ]);
} else {
assertErrorsWithCodes([
ParserErrorCode.EXPECTED_TOKEN,
]);
}
}
void test_parseClassMember_method_operator_noType() {
createParser('operator() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_operator_type() {
createParser('int operator() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_operator_void() {
createParser('void operator() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_returnType_functionType() {
createParser('int Function(String) m() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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.name.name, 'm');
expect(method.operatorKeyword, isNull);
expect(method.typeParameters, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_returnType_parameterized() {
createParser('p.A m() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_set_noType() {
createParser('set() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_set_type() {
createParser('int set() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_set_void() {
createParser('void set() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_static_generic_comment_returnType() {
enableGenericMethodComments = true;
createParser('static /*=T*/ m/*<T>*/() {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
if (usingFastaParser) {
assertNoErrors();
} else {
assertErrorsWithCodes(
[HintCode.GENERIC_METHOD_COMMENT, HintCode.GENERIC_METHOD_COMMENT]);
}
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword, isNotNull);
expect(method.propertyKeyword, isNull);
expect(method.returnType, isNotNull);
expect((method.returnType as TypeName).name.name, 'T');
expect(method.name, isNotNull);
expect(method.operatorKeyword, isNull);
expect(method.typeParameters, isNotNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_method_trailing_commas() {
createParser('void f(int x, int y,) {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_operator_functionType() {
createParser('int Function() operator +(int Function() f) {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword, isNull);
expect(method.propertyKeyword, isNull);
expect(method.returnType, new TypeMatcher<GenericFunctionType>());
expect(method.name, isNotNull);
expect(method.operatorKeyword, isNotNull);
expect(method.typeParameters, isNull);
expect(method.parameters, isNotNull);
NodeList<FormalParameter> parameters = method.parameters.parameters;
expect(parameters, hasLength(1));
expect((parameters[0] as SimpleFormalParameter).type,
new TypeMatcher<GenericFunctionType>());
expect(method.body, isNotNull);
}
void test_parseClassMember_operator_index() {
createParser('int operator [](int i) {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNotNull);
expect(method.typeParameters, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_operator_indexAssign() {
createParser('int operator []=(int i) {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
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, isNotNull);
expect(method.typeParameters, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_operator_lessThan() {
createParser('bool operator <(other) => false;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<MethodDeclaration>());
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword, isNull);
expect(method.propertyKeyword, isNull);
expect(method.returnType, isNotNull);
expect(method.name.name, '<');
expect(method.operatorKeyword, isNotNull);
expect(method.typeParameters, isNull);
expect(method.parameters, isNotNull);
expect(method.body, isNotNull);
}
void test_parseClassMember_redirectingFactory_const() {
createParser('const factory C() = prefix.B.foo;');
var constructor = parser.parseClassMember('C') as ConstructorDeclaration;
assertNoErrors();
expect(constructor, isNotNull);
expect(constructor.externalKeyword, isNull);
expect(constructor.constKeyword.keyword, Keyword.CONST);
expect(constructor.factoryKeyword.keyword, Keyword.FACTORY);
expect(constructor.returnType.name, 'C');
expect(constructor.period, isNull);
expect(constructor.name, isNull);
_assertIsDeclarationName(constructor.returnType, false);
expect(constructor.parameters, isNotNull);
expect(constructor.parameters.parameters, isEmpty);
expect(constructor.separator.type, TokenType.EQ);
expect(constructor.initializers, isEmpty);
expect(constructor.redirectedConstructor, isNotNull);
expect(constructor.redirectedConstructor.type.name.name, 'prefix.B');
expect(constructor.redirectedConstructor.period.type, TokenType.PERIOD);
expect(constructor.redirectedConstructor.name.name, 'foo');
expect(constructor.body, new TypeMatcher<EmptyFunctionBody>());
}
void test_parseClassMember_redirectingFactory_expressionBody() {
createParser('factory C() => null;');
var constructor = parser.parseClassMember('C') as ConstructorDeclaration;
assertNoErrors();
expect(constructor, isNotNull);
expect(constructor.externalKeyword, isNull);
expect(constructor.constKeyword, isNull);
expect(constructor.factoryKeyword.keyword, Keyword.FACTORY);
expect(constructor.returnType.name, 'C');
expect(constructor.period, isNull);
expect(constructor.name, isNull);
expect(constructor.parameters, isNotNull);
expect(constructor.parameters.parameters, isEmpty);
expect(constructor.separator, isNull);
expect(constructor.initializers, isEmpty);
expect(constructor.redirectedConstructor, isNull);
var body = constructor.body as ExpressionFunctionBody;
expect(body.keyword, isNull);
expect(body.star, isNull);
expect(body.functionDefinition.type, TokenType.FUNCTION);
expect(body.expression, isNotNull);
expect(body.semicolon, isNotNull);
}
void test_parseClassMember_redirectingFactory_nonConst() {
createParser('factory C() = B;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<ConstructorDeclaration>());
ConstructorDeclaration constructor = member;
expect(constructor.externalKeyword, isNull);
expect(constructor.constKeyword, isNull);
expect(constructor.factoryKeyword.keyword, Keyword.FACTORY);
expect(constructor.returnType.name, 'C');
_assertIsDeclarationName(constructor.returnType, false);
expect(constructor.period, isNull);
expect(constructor.name, isNull);
expect(constructor.parameters, isNotNull);
expect(constructor.parameters.parameters, isEmpty);
expect(constructor.separator.type, TokenType.EQ);
expect(constructor.initializers, isEmpty);
expect(constructor.redirectedConstructor, isNotNull);
expect(constructor.redirectedConstructor.type.name.name, 'B');
expect(constructor.redirectedConstructor.period, isNull);
expect(constructor.redirectedConstructor.name, isNull);
expect(constructor.body, new TypeMatcher<EmptyFunctionBody>());
}
void test_parseConstructor_assert() {
createParser('C(x, y) : _x = x, assert (x < y), _y = y;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<ConstructorDeclaration>());
ConstructorDeclaration constructor = member as ConstructorDeclaration;
NodeList<ConstructorInitializer> initializers = constructor.initializers;
expect(initializers, hasLength(3));
ConstructorInitializer initializer = initializers[1];
expect(initializer, new TypeMatcher<AssertInitializer>());
AssertInitializer assertInitializer = initializer;
expect(assertInitializer.condition, isNotNull);
expect(assertInitializer.message, isNull);
}
void test_parseConstructor_factory_const_external() {
// Although the spec does not allow external const factory,
// there are several instances of this in the Dart SDK.
// For example `external const factory bool.fromEnvironment(...)`.
createParser('external const factory C();');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
assertNoErrors();
}
void test_parseConstructor_factory_named() {
createParser('factory C.foo() => null;');
var constructor = parser.parseClassMember('C') as ConstructorDeclaration;
assertNoErrors();
expect(constructor, isNotNull);
expect(constructor.externalKeyword, isNull);
expect(constructor.constKeyword, isNull);
expect(constructor.factoryKeyword, isNotNull);
expect(constructor.returnType.name, 'C');
_assertIsDeclarationName(constructor.returnType, false);
expect(constructor.period.type, TokenType.PERIOD);
expect(constructor.name.name, 'foo');
_assertIsDeclarationName(constructor.name);
expect(constructor.parameters, isNotNull);
expect(constructor.parameters.parameters, isEmpty);
expect(constructor.separator, isNull);
expect(constructor.initializers, isEmpty);
expect(constructor.redirectedConstructor, isNull);
expect(constructor.body, new TypeMatcher<ExpressionFunctionBody>());
}
void test_parseConstructor_initializers_field() {
createParser('C(x, y) : _x = x, this._y = y;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<ConstructorDeclaration>());
ConstructorDeclaration constructor = member as ConstructorDeclaration;
NodeList<ConstructorInitializer> initializers = constructor.initializers;
expect(initializers, hasLength(2));
{
var initializer = initializers[0] as ConstructorFieldInitializer;
expect(initializer.thisKeyword, isNull);
expect(initializer.period, isNull);
expect(initializer.fieldName.name, '_x');
expect(initializer.expression, isNotNull);
}
{
var initializer = initializers[1] as ConstructorFieldInitializer;
expect(initializer.thisKeyword, isNotNull);
expect(initializer.period, isNotNull);
expect(initializer.fieldName.name, '_y');
expect(initializer.expression, isNotNull);
}
}
void test_parseConstructor_named() {
createParser('C.foo();');
var constructor = parser.parseClassMember('C') as ConstructorDeclaration;
assertNoErrors();
expect(constructor, isNotNull);
expect(constructor.externalKeyword, isNull);
expect(constructor.constKeyword, isNull);
expect(constructor.factoryKeyword, isNull);
expect(constructor.returnType.name, 'C');
_assertIsDeclarationName(constructor.returnType, false);
expect(constructor.period.type, TokenType.PERIOD);
expect(constructor.name.name, 'foo');
_assertIsDeclarationName(constructor.name);
expect(constructor.parameters, isNotNull);
expect(constructor.parameters.parameters, isEmpty);
expect(constructor.separator, isNull);
expect(constructor.initializers, isEmpty);
expect(constructor.redirectedConstructor, isNull);
expect(constructor.body, new TypeMatcher<EmptyFunctionBody>());
}
void test_parseConstructor_unnamed() {
createParser('C();');
var constructor = parser.parseClassMember('C') as ConstructorDeclaration;
assertNoErrors();
expect(constructor, isNotNull);
expect(constructor.externalKeyword, isNull);
expect(constructor.constKeyword, isNull);
expect(constructor.factoryKeyword, isNull);
expect(constructor.returnType.name, 'C');
_assertIsDeclarationName(constructor.returnType, false);
expect(constructor.period, isNull);
expect(constructor.name, isNull);
expect(constructor.parameters, isNotNull);
expect(constructor.parameters.parameters, isEmpty);
expect(constructor.separator, isNull);
expect(constructor.initializers, isEmpty);
expect(constructor.redirectedConstructor, isNull);
expect(constructor.body, new TypeMatcher<EmptyFunctionBody>());
}
void test_parseConstructor_with_pseudo_function_literal() {
// "(b) {}" should not be misinterpreted as a function literal even though
// it looks like one.
createParser('C() : a = (b) {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
assertNoErrors();
expect(member, new TypeMatcher<ConstructorDeclaration>());
ConstructorDeclaration constructor = member as ConstructorDeclaration;
NodeList<ConstructorInitializer> initializers = constructor.initializers;
expect(initializers, hasLength(1));
ConstructorInitializer initializer = initializers[0];
EngineTestCase.assertInstanceOf((obj) => obj is ConstructorFieldInitializer,
ConstructorFieldInitializer, initializer);
EngineTestCase.assertInstanceOf(
(obj) => obj is ParenthesizedExpression,
ParenthesizedExpression,
(initializer as ConstructorFieldInitializer).expression);
EngineTestCase.assertInstanceOf(
(obj) => obj is BlockFunctionBody, BlockFunctionBody, constructor.body);
}
void test_parseConstructorFieldInitializer_qualified() {
var initializer = parseConstructorInitializer('this.a = b')
as ConstructorFieldInitializer;
expect(initializer, isNotNull);
assertNoErrors();
expect(initializer.equals, isNotNull);
expect(initializer.expression, isNotNull);
expect(initializer.fieldName, isNotNull);
expect(initializer.thisKeyword, isNotNull);
expect(initializer.period, isNotNull);
}
void test_parseConstructorFieldInitializer_unqualified() {
var initializer =
parseConstructorInitializer('a = b') as ConstructorFieldInitializer;
expect(initializer, isNotNull);
assertNoErrors();
expect(initializer.equals, isNotNull);
expect(initializer.expression, isNotNull);
expect(initializer.fieldName, isNotNull);
expect(initializer.thisKeyword, isNull);
expect(initializer.period, isNull);
}
void test_parseGetter_nonStatic() {
createParser('/// Doc\nT get a;');
MethodDeclaration method = parser.parseClassMember('C');
expect(method, isNotNull);
assertNoErrors();
expect(method.body, isNotNull);
expectCommentText(method.documentationComment, '/// Doc');
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword, isNull);
expect(method.name, isNotNull);
expect(method.operatorKeyword, isNull);
expect(method.parameters, isNull);
expect(method.propertyKeyword, isNotNull);
expect((method.returnType as TypeName).name.name, 'T');
}
void test_parseGetter_static() {
createParser('/// Doc\nstatic T get a => 42;');
MethodDeclaration method = parser.parseClassMember('C');
expect(method, isNotNull);
assertNoErrors();
expect(method.body, isNotNull);
expectCommentText(method.documentationComment, '/// Doc');
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword.lexeme, 'static');
expect(method.name, isNotNull);
expect(method.operatorKeyword, isNull);
expect(method.typeParameters, isNull);
expect(method.parameters, isNull);
expect(method.propertyKeyword, isNotNull);
expect((method.returnType as TypeName).name.name, 'T');
}
void test_parseInitializedIdentifierList_type() {
createParser("/// Doc\nstatic T a = 1, b, c = 3;");
FieldDeclaration declaration = parser.parseClassMember('C');
expect(declaration, isNotNull);
assertNoErrors();
expectCommentText(declaration.documentationComment, '/// Doc');
VariableDeclarationList fields = declaration.fields;
expect(fields, isNotNull);
expect(fields.keyword, isNull);
expect((fields.type as TypeName).name.name, 'T');
expect(fields.variables, hasLength(3));
expect(declaration.staticKeyword.lexeme, 'static');
expect(declaration.semicolon, isNotNull);
}
void test_parseInitializedIdentifierList_var() {
createParser('/// Doc\nstatic var a = 1, b, c = 3;');
FieldDeclaration declaration = parser.parseClassMember('C');
expect(declaration, isNotNull);
assertNoErrors();
expectCommentText(declaration.documentationComment, '/// Doc');
VariableDeclarationList fields = declaration.fields;
expect(fields, isNotNull);
expect(fields.keyword.lexeme, 'var');
expect(fields.type, isNull);
expect(fields.variables, hasLength(3));
expect(declaration.staticKeyword.lexeme, 'static');
expect(declaration.semicolon, isNotNull);
}
void test_parseOperator() {
createParser('/// Doc\nT operator +(A a);');
MethodDeclaration method = parser.parseClassMember('C');
expect(method, isNotNull);
assertNoErrors();
expect(method.body, isNotNull);
expectCommentText(method.documentationComment, '/// Doc');
expect(method.externalKeyword, isNull);
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 as TypeName).name.name, 'T');
}
void test_parseSetter_nonStatic() {
createParser('/// Doc\nT set a(var x);');
MethodDeclaration method = parser.parseClassMember('C');
expect(method, isNotNull);
assertNoErrors();
expect(method.body, isNotNull);
expectCommentText(method.documentationComment, '/// Doc');
expect(method.externalKeyword, isNull);
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 as TypeName).name.name, 'T');
}
void test_parseSetter_static() {
createParser('/// Doc\nstatic T set a(var x) {}');
MethodDeclaration method = parser.parseClassMember('C');
expect(method, isNotNull);
assertNoErrors();
expect(method.body, isNotNull);
expectCommentText(method.documentationComment, '/// Doc');
expect(method.externalKeyword, isNull);
expect(method.modifierKeyword.lexeme, 'static');
expect(method.name, isNotNull);
expect(method.operatorKeyword, isNull);
expect(method.typeParameters, isNull);
expect(method.parameters, isNotNull);
expect(method.propertyKeyword, isNotNull);
expect((method.returnType as TypeName).name.name, 'T');
}
void test_simpleFormalParameter_withDocComment() {
createParser('''
int f(
/// Doc
int x) {}
''');
var function = parseFullCompilationUnitMember() as FunctionDeclaration;
var parameter = function.functionExpression.parameters.parameters[0]
as NormalFormalParameter;
expectCommentText(parameter.documentationComment, '/// Doc');
}
/**
* Assert that the given [name] is in declaration context.
*/
void _assertIsDeclarationName(SimpleIdentifier name, [bool expected = true]) {
expect(name.inDeclarationContext(), expected);
}
void _parseClassMember_method_native() {
createParser('m() native "str";');
var method = parser.parseClassMember('C') as MethodDeclaration;
var body = method.body as NativeFunctionBody;
expect(body.nativeKeyword, isNotNull);
expect(body.stringLiteral, isNotNull);
expect(body.stringLiteral?.stringValue, "str");
expect(body.semicolon, isNotNull);
}
void _parseClassMember_method_native_missing_literal() {
createParser('m() native;');
var method = parser.parseClassMember('C') as MethodDeclaration;
var body = method.body as NativeFunctionBody;
expect(body.nativeKeyword, isNotNull);
expect(body.stringLiteral, isNull);
expect(body.semicolon, isNotNull);
}
void _parseClassMember_method_native_with_body() {
createParser('m() native "str" {}');
parser.parseClassMember('C') as MethodDeclaration;
}
}
/**
* Tests of the analyzer parser based on [ComplexParserTestMixin].
*/
@reflectiveTest
class ComplexParserTest extends ParserTestCase with ComplexParserTestMixin {
void test_logicalAndExpression_precedence_nullableType() {
enableNnbd = true;
BinaryExpression expression = parseExpression("x is C? && y is D");
expect(expression.leftOperand, new TypeMatcher<IsExpression>());
expect(expression.rightOperand, new TypeMatcher<IsExpression>());
}
void test_logicalOrExpression_precedence_nullableType() {
enableNnbd = true;
BinaryExpression expression = parseExpression("a is X? || (b ? c : d)");
expect(expression.leftOperand, new TypeMatcher<IsExpression>());
expect(expression.rightOperand, new TypeMatcher<ParenthesizedExpression>());
expect((expression.rightOperand as ParenthesizedExpression).expression,
new TypeMatcher<ConditionalExpression>());
}
}
/**
* The class `ComplexParserTest` defines parser tests that test the parsing of more complex
* code fragments or the interactions between multiple parsing methods. For example, tests to ensure
* that the precedence of operations is being handled correctly should be defined in this class.
*
* Simpler tests should be defined in the class [SimpleParserTest].
*/
abstract class ComplexParserTestMixin implements AbstractParserTestCase {
void test_additiveExpression_normal() {
BinaryExpression expression = parseExpression("x + y - z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_additiveExpression_noSpaces() {
BinaryExpression expression = parseExpression("i+1");
EngineTestCase.assertInstanceOf((obj) => obj is SimpleIdentifier,
SimpleIdentifier, expression.leftOperand);
EngineTestCase.assertInstanceOf((obj) => obj is IntegerLiteral,
IntegerLiteral, expression.rightOperand);
}
void test_additiveExpression_precedence_multiplicative_left() {
BinaryExpression expression = parseExpression("x * y + z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_additiveExpression_precedence_multiplicative_left_withSuper() {
BinaryExpression expression = parseExpression("super * y - z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_additiveExpression_precedence_multiplicative_right() {
BinaryExpression expression = parseExpression("x + y * z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.rightOperand);
}
void test_additiveExpression_super() {
BinaryExpression expression = parseExpression("super + y - z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_assignableExpression_arguments_normal_chain() {
PropertyAccess propertyAccess1 = parseExpression("a(b)(c).d(e).f");
expect(propertyAccess1.propertyName.name, "f");
//
// a(b)(c).d(e)
//
MethodInvocation invocation2 = EngineTestCase.assertInstanceOf(
(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));
//
// a(b)(c)
//
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));
//
// a(b)
//
MethodInvocation invocation4 = EngineTestCase.assertInstanceOf(
(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_typeArgumentComments() {
enableGenericMethodComments = true;
_validate_assignableExpression_arguments_normal_chain_typeArguments(
"a/*<E>*/(b)/*<F>*/(c).d/*<G>*/(e).f",
usingFastaParser
? []
: [
HintCode.GENERIC_METHOD_COMMENT,
HintCode.GENERIC_METHOD_COMMENT,
HintCode.GENERIC_METHOD_COMMENT
]);
}
void test_assignableExpression_arguments_normal_chain_typeArguments() {
_validate_assignableExpression_arguments_normal_chain_typeArguments(
"a<E>(b)<F>(c).d<G>(e).f");
}
void test_assignmentExpression_compound() {
AssignmentExpression expression = parseExpression("x = y = 0");
EngineTestCase.assertInstanceOf((obj) => obj is SimpleIdentifier,
SimpleIdentifier, expression.leftHandSide);
EngineTestCase.assertInstanceOf((obj) => obj is AssignmentExpression,
AssignmentExpression, expression.rightHandSide);
}
void test_assignmentExpression_indexExpression() {
AssignmentExpression expression = parseExpression("x[1] = 0");
EngineTestCase.assertInstanceOf((obj) => obj is IndexExpression,
IndexExpression, expression.leftHandSide);
EngineTestCase.assertInstanceOf((obj) => obj is IntegerLiteral,
IntegerLiteral, expression.rightHandSide);
}
void test_assignmentExpression_prefixedIdentifier() {
AssignmentExpression expression = parseExpression("x.y = 0");
EngineTestCase.assertInstanceOf((obj) => obj is PrefixedIdentifier,
PrefixedIdentifier, expression.leftHandSide);
EngineTestCase.assertInstanceOf((obj) => obj is IntegerLiteral,
IntegerLiteral, expression.rightHandSide);
}
void test_assignmentExpression_propertyAccess() {
AssignmentExpression expression = parseExpression("super.y = 0");
EngineTestCase.assertInstanceOf((obj) => obj is PropertyAccess,
PropertyAccess, expression.leftHandSide);
EngineTestCase.assertInstanceOf((obj) => obj is IntegerLiteral,
IntegerLiteral, expression.rightHandSide);
}
void test_bitwiseAndExpression_normal() {
BinaryExpression expression = parseExpression("x & y & z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_bitwiseAndExpression_precedence_equality_left() {
BinaryExpression expression = parseExpression("x == y && z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_bitwiseAndExpression_precedence_equality_right() {
BinaryExpression expression = parseExpression("x && y == z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.rightOperand);
}
void test_bitwiseAndExpression_super() {
BinaryExpression expression = parseExpression("super & y & z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_bitwiseOrExpression_normal() {
BinaryExpression expression = parseExpression("x | y | z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_bitwiseOrExpression_precedence_xor_left() {
BinaryExpression expression = parseExpression("x ^ y | z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_bitwiseOrExpression_precedence_xor_right() {
BinaryExpression expression = parseExpression("x | y ^ z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.rightOperand);
}
void test_bitwiseOrExpression_super() {
BinaryExpression expression = parseExpression("super | y | z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_bitwiseXorExpression_normal() {
BinaryExpression expression = parseExpression("x ^ y ^ z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_bitwiseXorExpression_precedence_and_left() {
BinaryExpression expression = parseExpression("x & y ^ z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_bitwiseXorExpression_precedence_and_right() {
BinaryExpression expression = parseExpression("x ^ y & z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.rightOperand);
}
void test_bitwiseXorExpression_super() {
BinaryExpression expression = parseExpression("super ^ y ^ z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_cascade_withAssignment() {
CascadeExpression cascade =
parseExpression("new Map()..[3] = 4 ..[0] = 11");
Expression target = cascade.target;
for (Expression section in cascade.cascadeSections) {
EngineTestCase.assertInstanceOf(
(obj) => obj is AssignmentExpression, AssignmentExpression, section);
Expression lhs = (section as AssignmentExpression).leftHandSide;
EngineTestCase.assertInstanceOf(
(obj) => obj is IndexExpression, IndexExpression, lhs);
IndexExpression index = lhs as IndexExpression;
expect(index.isCascaded, isTrue);
expect(index.realTarget, same(target));
}
}
void test_conditionalExpression_precedence_ifNullExpression() {
ConditionalExpression expression = parseExpression('a ?? b ? y : z');
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.condition);
}
void test_conditionalExpression_precedence_logicalOrExpression() {
ConditionalExpression expression = parseExpression("a | b ? y : z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.condition);
}
void test_conditionalExpression_precedence_nullableType_as() {
Expression expression = parseExpression('x as String ? (x + y) : z');
expect(expression, isNotNull);
expect(expression, new TypeMatcher<ConditionalExpression>());
ConditionalExpression conditional = expression;
Expression condition = conditional.condition;
expect(condition, new TypeMatcher<AsExpression>());
Expression thenExpression = conditional.thenExpression;
expect(thenExpression, new TypeMatcher<ParenthesizedExpression>());
Expression elseExpression = conditional.elseExpression;
expect(elseExpression, new TypeMatcher<SimpleIdentifier>());
}
void test_conditionalExpression_precedence_nullableType_is() {
Expression expression = parseExpression('x is String ? (x + y) : z');
expect(expression, isNotNull);
expect(expression, new TypeMatcher<ConditionalExpression>());
ConditionalExpression conditional = expression;
Expression condition = conditional.condition;
expect(condition, new TypeMatcher<IsExpression>());
Expression thenExpression = conditional.thenExpression;
expect(thenExpression, new TypeMatcher<ParenthesizedExpression>());
Expression elseExpression = conditional.elseExpression;
expect(elseExpression, new TypeMatcher<SimpleIdentifier>());
}
void test_constructor_initializer_withParenthesizedExpression() {
CompilationUnit unit = parseCompilationUnit(r'''
class C {
C() :
this.a = (b == null ? c : d) {
}
}''');
NodeList<CompilationUnitMember> declarations = unit.declarations;
expect(declarations, hasLength(1));
}
void test_equalityExpression_normal() {
BinaryExpression expression = parseExpression("x == y != z",
codes: [ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND]);
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_equalityExpression_precedence_relational_left() {
BinaryExpression expression = parseExpression("x is y == z");
EngineTestCase.assertInstanceOf(
(obj) => obj is IsExpression, IsExpression, expression.leftOperand);
}
void test_equalityExpression_precedence_relational_right() {
BinaryExpression expression = parseExpression("x == y is z");
EngineTestCase.assertInstanceOf(
(obj) => obj is IsExpression, IsExpression, expression.rightOperand);
}
void test_equalityExpression_super() {
BinaryExpression expression = parseExpression("super == y != z",
codes: [ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND]);
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_ifNullExpression() {
BinaryExpression expression = parseExpression('x ?? y ?? z');
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_ifNullExpression_precedence_logicalOr_left() {
BinaryExpression expression = parseExpression('x || y ?? z');
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_ifNullExpression_precedence_logicalOr_right() {
BinaryExpression expression = parseExpression('x ?? y || z');
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.rightOperand);
}
void test_logicalAndExpression() {
BinaryExpression expression = parseExpression("x && y && z");
expect(expression.leftOperand, new TypeMatcher<BinaryExpression>());
}
void test_logicalAndExpression_precedence_bitwiseOr_left() {
BinaryExpression expression = parseExpression("x | y < z");
expect(expression.leftOperand, new TypeMatcher<BinaryExpression>());
}
void test_logicalAndExpression_precedence_bitwiseOr_right() {
BinaryExpression expression = parseExpression("x < y | z");
expect(expression.rightOperand, new TypeMatcher<BinaryExpression>());
}
void test_logicalAndExpressionStatement() {
// Assert that `<` and `>` are not interpreted as type arguments.
ExpressionStatement statement = parseStatement("C<T && T>U;");
BinaryExpression expression = statement.expression;
expect(expression.leftOperand, new TypeMatcher<BinaryExpression>());
}
void test_logicalOrExpression() {
BinaryExpression expression = parseExpression("x || y || z");
expect(expression.leftOperand, new TypeMatcher<BinaryExpression>());
}
void test_logicalOrExpression_precedence_logicalAnd_left() {
BinaryExpression expression = parseExpression("x && y || z");
expect(expression.leftOperand, new TypeMatcher<BinaryExpression>());
}
void test_logicalOrExpression_precedence_logicalAnd_right() {
BinaryExpression expression = parseExpression("x || y && z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.rightOperand);
}
void test_methodInvocation1() {
// Assert that `<` and `>` are not interpreted as type arguments.
ExpressionStatement statement = parseStatement("f(a < b, c > 3);");
assertNoErrors();
MethodInvocation method = statement.expression;
expect(method.argumentList.arguments, hasLength(2));
}
void test_methodInvocation2() {
// Assert that `<` and `>` are not interpreted as type arguments.
ExpressionStatement statement = parseStatement("f(a < b, c >> 3);");
assertNoErrors();
MethodInvocation method = statement.expression;
expect(method.argumentList.arguments, hasLength(2));
}
void test_methodInvocation3() {
// Assert that `<` and `>` are not interpreted as type arguments.
ExpressionStatement statement = parseStatement("f(a < b, c < d >> 3);");
assertNoErrors();
MethodInvocation method = statement.expression;
expect(method.argumentList.arguments, hasLength(2));
}
void test_multipleLabels_statement() {
LabeledStatement statement = parseStatement("a: b: c: return x;");
expect(statement.labels, hasLength(3));
EngineTestCase.assertInstanceOf(
(obj) => obj is ReturnStatement, ReturnStatement, statement.statement);
}
void test_multiplicativeExpression_normal() {
BinaryExpression expression = parseExpression("x * y / z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_multiplicativeExpression_precedence_unary_left() {
BinaryExpression expression = parseExpression("-x * y");
EngineTestCase.assertInstanceOf((obj) => obj is PrefixExpression,
PrefixExpression, expression.leftOperand);
}
void test_multiplicativeExpression_precedence_unary_right() {
BinaryExpression expression = parseExpression("x * -y");
EngineTestCase.assertInstanceOf((obj) => obj is PrefixExpression,
PrefixExpression, expression.rightOperand);
}
void test_multiplicativeExpression_super() {
BinaryExpression expression = parseExpression("super * y / z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_relationalExpression_precedence_shift_right() {
IsExpression expression = parseExpression("x << y is z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.expression);
}
void test_shiftExpression_normal() {
BinaryExpression expression = parseExpression("x >> 4 << 3");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_shiftExpression_precedence_additive_left() {
BinaryExpression expression = parseExpression("x + y << z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_shiftExpression_precedence_additive_right() {
BinaryExpression expression = parseExpression("x << y + z");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.rightOperand);
}
void test_shiftExpression_super() {
BinaryExpression expression = parseExpression("super >> 4 << 3");
EngineTestCase.assertInstanceOf((obj) => obj is BinaryExpression,
BinaryExpression, expression.leftOperand);
}
void test_topLevelFunction_nestedGenericFunction() {
parseCompilationUnit('''
void f() {
void g<T>() {
}
}
''');
}
void _validate_assignableExpression_arguments_normal_chain_typeArguments(
String code,
[List<ErrorCode> errorCodes = const <ErrorCode>[]]) {
PropertyAccess propertyAccess1 = parseExpression(code, codes: errorCodes);
expect(propertyAccess1.propertyName.name, "f");
//
// a<E>(b)<F>(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<E>(b)<F>(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));
}
}
/**
* The class `ErrorParserTest` defines parser tests that test the parsing
* of code to ensure that errors are correctly reported,
* and in some cases, not reported.
*/
@reflectiveTest
class ErrorParserTest extends ParserTestCase with ErrorParserTestMixin {
void test_missingIdentifier_number() {
createParser('1');
SimpleIdentifier expression = parser.parseSimpleIdentifier();
expectNotNullIfNoErrors(expression);
listener.assertErrors(
[expectedError(ParserErrorCode.MISSING_IDENTIFIER, 0, 1)]);
expect(expression.isSynthetic, isTrue);
}
void test_nullableTypeInExtends() {
enableNnbd = true;
createParser('extends B?');
ExtendsClause clause = parser.parseExtendsClause();
expectNotNullIfNoErrors(clause);
listener.assertErrors(
[expectedError(ParserErrorCode.NULLABLE_TYPE_IN_EXTENDS, 9, 1)]);
}
void test_nullableTypeInImplements() {
enableNnbd = true;
createParser('implements I?');
ImplementsClause clause = parser.parseImplementsClause();
expectNotNullIfNoErrors(clause);
listener.assertErrors(
[expectedError(ParserErrorCode.NULLABLE_TYPE_IN_IMPLEMENTS, 12, 1)]);
}
void test_nullableTypeInWith() {
enableNnbd = true;
createParser('with M?');
WithClause clause = parser.parseWithClause();
expectNotNullIfNoErrors(clause);
listener.assertErrors(
[expectedError(ParserErrorCode.NULLABLE_TYPE_IN_WITH, 6, 1)]);
}
void test_nullableTypeParameter() {
enableNnbd = true;
createParser('T?');
TypeParameter parameter = parser.parseTypeParameter();
expectNotNullIfNoErrors(parameter);
listener.assertErrors(
[expectedError(ParserErrorCode.NULLABLE_TYPE_PARAMETER, 1, 1)]);
}
}
abstract class ErrorParserTestMixin implements AbstractParserTestCase {
void test_abstractClassMember_constructor() {
createParser('abstract C.c();');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
listener.assertErrors(
[expectedError(ParserErrorCode.ABSTRACT_CLASS_MEMBER, 0, 8)]);
}
void test_abstractClassMember_field() {
createParser('abstract C f;');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
listener.assertErrors(
[expectedError(ParserErrorCode.ABSTRACT_CLASS_MEMBER, 0, 8)]);
}
void test_abstractClassMember_getter() {
createParser('abstract get m;');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
listener.assertErrors(
[expectedError(ParserErrorCode.ABSTRACT_CLASS_MEMBER, 0, 8)]);
}
void test_abstractClassMember_method() {
createParser('abstract m();');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
listener.assertErrors(
[expectedError(ParserErrorCode.ABSTRACT_CLASS_MEMBER, 0, 8)]);
}
void test_abstractClassMember_setter() {
createParser('abstract set m(v);');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
listener.assertErrors(
[expectedError(ParserErrorCode.ABSTRACT_CLASS_MEMBER, 0, 8)]);
}
void test_abstractEnum() {
parseCompilationUnit("abstract enum E {ONE}",
errors: [expectedError(ParserErrorCode.ABSTRACT_ENUM, 0, 8)]);
}
void test_abstractTopLevelFunction_function() {
parseCompilationUnit("abstract f(v) {}", errors: [
expectedError(ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION, 0, 8)
]);
}
void test_abstractTopLevelFunction_getter() {
parseCompilationUnit("abstract get m {}", errors: [
expectedError(ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION, 0, 8)
]);
}
void test_abstractTopLevelFunction_setter() {
parseCompilationUnit("abstract set m(v) {}", errors: [
expectedError(ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION, 0, 8)
]);
}
void test_abstractTopLevelVariable() {
parseCompilationUnit("abstract C f;", errors: [
expectedError(ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE, 0, 8)
]);
}
void test_abstractTypeDef() {
parseCompilationUnit("abstract typedef F();",
errors: [expectedError(ParserErrorCode.ABSTRACT_TYPEDEF, 0, 8)]);
}
void test_breakOutsideOfLoop_breakInDoStatement() {
DoStatement statement = parseStatement('do {break;} while (x);');
expectNotNullIfNoErrors(statement);
assertNoErrors();
}
void test_breakOutsideOfLoop_breakInForStatement() {
Statement statement = parseStatement('for (; x;) {break;}');
expectNotNullIfNoErrors(statement);
assertNoErrors();
}
void test_breakOutsideOfLoop_breakInIfStatement() {
IfStatement statement = parseStatement('if (x) {break;}');
expectNotNullIfNoErrors(statement);
listener.assertErrors(
[expectedError(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, 8, 5)]);
}
void test_breakOutsideOfLoop_breakInSwitchStatement() {
SwitchStatement statement = parseStatement('switch (x) {case 1: break;}');
expectNotNullIfNoErrors(statement);
assertNoErrors();
}
void test_breakOutsideOfLoop_breakInWhileStatement() {
WhileStatement statement = parseStatement('while (x) {break;}');
expectNotNullIfNoErrors(statement);
assertNoErrors();
}
void test_breakOutsideOfLoop_functionExpression_inALoop() {
parseStatement("for(; x;) {() {break;};}");
listener.assertErrors(
[expectedError(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, 15, 5)]);
}
void test_breakOutsideOfLoop_functionExpression_withALoop() {
parseStatement("() {for (; x;) {break;}};");
}
void test_classInClass_abstract() {
parseCompilationUnit("class C { abstract class B {} }",
errors: usingFastaParser
? [
expectedError(ParserErrorCode.ABSTRACT_CLASS_MEMBER, 10, 8),
expectedError(ParserErrorCode.CLASS_IN_CLASS, 19, 5)
]