| // 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:front_end/src/scanner/scanner.dart' as fe; |
| 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; |
| |
| /** |
| * Flag indicating whether the fasta scanner is being used. |
| */ |
| bool get usingFastaScanner; |
| |
| /** |
| * 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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<FieldDeclaration>()); |
| VariableDeclarationList fields = (member as FieldDeclaration).fields; |
| expect(fields.type, new isInstanceOf<GenericFunctionType>()); |
| } |
| |
| void test_parseClassMember_field_gftType_noReturnType() { |
| createParser(''' |
| Function(int, String) v; |
| '''); |
| ClassMember member = parser.parseClassMember('C'); |
| assertNoErrors(); |
| expect(member, new isInstanceOf<FieldDeclaration>()); |
| VariableDeclarationList fields = (member as FieldDeclaration).fields; |
| expect(fields.type, new isInstanceOf<GenericFunctionType>()); |
| } |
| |
| void test_parseClassMember_field_instance_prefixedType() { |
| createParser('p.A f;'); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertNoErrors(); |
| expect(member, new isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<MethodDeclaration>()); |
| expect((member as MethodDeclaration).body, |
| new isInstanceOf<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 isInstanceOf<MethodDeclaration>()); |
| expect((member as MethodDeclaration).body, |
| new isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<MethodDeclaration>()); |
| MethodDeclaration method = member; |
| expect(method.documentationComment, isNull); |
| expect(method.externalKeyword, isNull); |
| expect(method.modifierKeyword, isNull); |
| expect(method.propertyKeyword, isNull); |
| expect(method.returnType, new isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<ConstructorDeclaration>()); |
| ConstructorDeclaration constructor = member as ConstructorDeclaration; |
| NodeList<ConstructorInitializer> initializers = constructor.initializers; |
| expect(initializers, hasLength(3)); |
| ConstructorInitializer initializer = initializers[1]; |
| expect(initializer, new isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<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 isInstanceOf<IsExpression>()); |
| expect(expression.rightOperand, new isInstanceOf<IsExpression>()); |
| } |
| |
| void test_logicalOrExpression_precedence_nullableType() { |
| enableNnbd = true; |
| BinaryExpression expression = parseExpression("a is X? || (b ? c : d)"); |
| expect(expression.leftOperand, new isInstanceOf<IsExpression>()); |
| expect( |
| expression.rightOperand, new isInstanceOf<ParenthesizedExpression>()); |
| expect((expression.rightOperand as ParenthesizedExpression).expression, |
| new isInstanceOf<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 isInstanceOf<ConditionalExpression>()); |
| ConditionalExpression conditional = expression; |
| Expression condition = conditional.condition; |
| expect(condition, new isInstanceOf<AsExpression>()); |
| Expression thenExpression = conditional.thenExpression; |
| expect(thenExpression, new isInstanceOf<ParenthesizedExpression>()); |
| Expression elseExpression = conditional.elseExpression; |
| expect(elseExpression, new isInstanceOf<SimpleIdentifier>()); |
| } |
| |
| void test_conditionalExpression_precedence_nullableType_is() { |
| Expression expression = parseExpression('x is String ? (x + y) : z'); |
| expect(expression, isNotNull); |
| expect(expression, new isInstanceOf<ConditionalExpression>()); |
| ConditionalExpression conditional = expression; |
| Expression condition = conditional.condition; |
| expect(condition, new isInstanceOf<IsExpression>()); |
| Expression thenExpression = conditional.thenExpression; |
| expect(thenExpression, new isInstanceOf<ParenthesizedExpression>()); |
| Expression elseExpression = conditional.elseExpression; |
| expect(elseExpression, new isInstanceOf<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 isInstanceOf<BinaryExpression>()); |
| } |
| |
| void test_logicalAndExpression_precedence_bitwiseOr_left() { |
| BinaryExpression expression = parseExpression("x | y < z"); |
| expect(expression.leftOperand, new isInstanceOf<BinaryExpression>()); |
| } |
| |
| void test_logicalAndExpression_precedence_bitwiseOr_right() { |
| BinaryExpression expression = parseExpression("x < y | z"); |
| expect(expression.rightOperand, new isInstanceOf<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 isInstanceOf<BinaryExpression>()); |
| } |
| |
| void test_logicalOrExpression() { |
| BinaryExpression expression = parseExpression("x || y || z"); |
| expect(expression.leftOperand, new isInstanceOf<BinaryExpression>()); |
| } |
| |
| void test_logicalOrExpression_precedence_logicalAnd_left() { |
| BinaryExpression expression = parseExpression("x && y || z"); |
| expect(expression.leftOperand, new isInstanceOf<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) |
| ] |
| : [expectedError(ParserErrorCode.CLASS_IN_CLASS, 19, 5)]); |
| } |
| |
| void test_classInClass_nonAbstract() { |
| parseCompilationUnit("class C { class B {} }", |
| errors: [expectedError(ParserErrorCode.CLASS_IN_CLASS, 10, 5)]); |
| } |
| |
| void test_classTypeAlias_abstractAfterEq() { |
| // This syntax has been removed from the language in favor of |
| // "abstract class A = B with C;" (issue 18098). |
| createParser('class A = abstract B with C;', expectedEndOffset: 21); |
| CompilationUnitMember member = parseFullCompilationUnitMember(); |
| expectNotNullIfNoErrors(member); |
| listener.assertErrors(usingFastaParser |
| ? [ |
| expectedError( |
| CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, 10, 8), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 19, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 21, 4) |
| ] |
| : [ |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 0), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 0) |
| ]); |
| } |
| |
| void test_colonInPlaceOfIn() { |
| parseStatement("for (var x : list) {}"); |
| listener.assertErrors( |
| [expectedError(ParserErrorCode.COLON_IN_PLACE_OF_IN, 11, 1)]); |
| } |
| |
| void test_constAndCovariant() { |
| createParser('covariant const C f = null;'); |
| ClassMember member = parser.parseClassMember('C'); |
| expectNotNullIfNoErrors(member); |
| listener.assertErrors( |
| [expectedError(ParserErrorCode.CONST_AND_COVARIANT, 10, 5)]); |
| } |
| |
| void test_constAndFinal() { |
| createParser('const final int x = null;'); |
| ClassMember member = parser.parseClassMember('C'); |
| expectNotNullIfNoErrors(member); |
| listener |
| .assertErrors([expectedError(ParserErrorCode.CONST_AND_FINAL, 6, 5)]); |
| } |
| |
| void test_constAndVar() { |
| createParser('const var x = null;'); |
| ClassMember member = parser.parseClassMember('C'); |
| expectNotNullIfNoErrors(member); |
| listener.assertErrors([expectedError(ParserErrorCode.CONST_AND_VAR, 6, 3)]); |
| } |
| |
| void test_constClass() { |
| parseCompilationUnit("const class C {}", |
| errors: [expectedError(ParserErrorCode.CONST_CLASS, 0, 5)]); |
| } |
| |
| void test_constConstructorWithBody() { |
| createParser('const C() {}'); |
| ClassMember member = parser.parseClassMember('C'); |
| expectNotNullIfNoErrors(member); |
| listener.assertErrors( |
| [expectedError(ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, 10, 1)]); |
| } |
| |
| void test_constEnum() { |
| parseCompilationUnit("const enum E {ONE}", |
| errors: usingFastaParser |
| ? [ |
| // Fasta interprets the `const` as a malformed top level const |
| // and `enum` as the start of an enum declaration. |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 4), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 4), |
| ] |
| : [expectedError(ParserErrorCode.CONST_ENUM, 0, 5)]); |
| } |
| |
| void test_constFactory() { |
| createParser('const factory C() {}'); |
| ClassMember member = parser.parseClassMember('C'); |
| expectNotNullIfNoErrors(member); |
| listener.assertErrors([expectedError(ParserErrorCode.CONST_FACTORY, 0, 5)]); |
| } |
| |
| void test_constMethod() { |
| createParser('const int m() {}'); |
| ClassMember member = parser.parseClassMember('C'); |
| expectNotNullIfNoErrors(member); |
| listener.assertErrors([expectedError(ParserErrorCode.CONST_METHOD, 0, 5)]); |
| } |
| |
| void test_constructorPartial() { |
| createParser('class C { C< }'); |
| parser.parseCompilationUnit2(); |
| listener.assertErrors(usingFastaParser |
| ? [ |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 13, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 13, 1), |
| expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1), |
| expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 13, 1) |
| ] |
| : [ |
| expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 13, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 13, 1), |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 13, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 13, 1) |
| ]); |
| } |
| |
| void test_constructorPartial2() { |
| createParser('class C { C<@Foo }'); |
| parser.parseCompilationUnit2(); |
| listener.assertErrors(usingFastaParser |
| ? [ |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 17, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 17, 1), |
| expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1), |
| expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 17, 1) |
| ] |
| : [ |
| expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 1), |
| expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 12, 1), |
| expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 17, 1) |
| ]); |
| } |
| |
| void test_constructorPartial3() { |
| createParser('class C { C<@Foo @Bar() }'); |
| parser.parseCompilationUnit2(); |
| listener.assertErrors(usingFastaParser |
| ? [ |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 24, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 24, 1), |
| expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1), |
| expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 24, 1) |
| ] |
| : [ |
| expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 1), |
| expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 12, 1), |
| expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 24, 1) |
| ]); |
| } |
| |
| void test_constructorWithReturnType() { |
| createParser('C C() {}'); |
| ClassMember member = parser.parseClassMember('C'); |
| expectNotNullIfNoErrors(member); |
| listener.assertErrors( |
| [expectedError(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, 0, 1)]); |
| } |
| |
| void test_constructorWithReturnType_var() { |
| createParser('var C() {}'); |
| ClassMember member = parser.parseClassMember('C'); |
| expectNotNullIfNoErrors(member); |
| listener.assertErrors(usingFastaParser |
| ? [expectedError(ParserErrorCode.VAR_RETURN_TYPE, 0, 3)] |
| : [expectedError(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, 0, 3)]); |
| } |
| |
| void test_constTypedef() { |
| parseCompilationUnit("const typedef F();", |
| errors: usingFastaParser |
| ? [ |
| // Fasta interprets the `const` as a malformed top level const |
| // and `typedef` as the start of an typedef declaration. |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 7), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 7), |
| ] |
| : [expectedError(ParserErrorCode.CONST_TYPEDEF, 0, 5)]); |
| } |
| |
| void test_continueOutsideOfLoop_continueInDoStatement() { |
| DoStatement statement = parseStatement('do {continue;} while (x);'); |
| expectNotNullIfNoErrors(statement); |
| assertNoErrors(); |
| } |
| |
| void test_continueOutsideOfLoop_continueInForStatement() { |
| Statement statement = parseStatement('for (; x;) {continue;}'); |
| expectNotNullIfNoErrors(statement); |
| assertNoErrors(); |
| } |
| |
| void test_continueOutsideOfLoop_continueInIfStatement() { |
| IfStatement statement = parseStatement('if (x) {continue;}'); |
| expectNotNullIfNoErrors(statement); |
| listener.assertErrors( |
| [expectedError(ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, 8, 8)]); |
| } |
| |
| void test_continueOutsideOfLoop_continueInSwitchStatement() { |
| SwitchStatement statement = |
| parseStatement('switch (x) {case 1: continue a;}'); |
| expectNotNullIfNoErrors(statement); |
| assertNoErrors(); |
| } |
| |
| void test_continueOutsideOfLoop_continueInWhileStatement() { |
| WhileStatement statement = parseStatement('while (x) {continue;}'); |
| expectNotNullIfNoErrors(statement); |
| assertNoErrors(); |
| } |
| |
| void test_continueOutsideOfLoop_functionExpression_inALoop() { |
| parseStatement("for(; x;) {() {continue;};}"); |
| listener.assertErrors( |
| [expectedError(ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, 15, 8)]); |
| } |
| |
| void test_continueOutsideOfLoop_functionExpression_withALoop() { |
| parseStatement("() {for (; x;) {continue;}};"); |
| } |
| |
| void test_continueWithoutLabelInCase_error() { |
| SwitchStatement statement = |
| parseStatement('switch (x) {case 1: continue;}'); |
| expectNotNullIfNoErrors(statement); |
| listener.assertErrors( |
| [expectedError(ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, 20, 8)]); |
| } |
| |
| void test_continueWithoutLabelInCase_noError() { |
| SwitchStatement statement = |
| parseStatement('switch (x) {case 1: continue a;}'); |
| expectNotNullIfNoErrors(statement); |
| assertNoErrors(); |
| } |
| |
| void test_continueWithoutLabelInCase_noError_switchInLoop() { |
| WhileStatement statement = |
| parseStatement('while (a) { switch (b) {default: continue;}}'); |
| expectNotNullIfNoErrors(statement); |
| assertNoErrors(); |
| } |
| |
| void test_covariantAfterVar() { |
| createParser('var covariant f;'); |
| ClassMember member = parser.parseClassMember('C'); |
| expectNotNullIfNoErrors(member); |
| listener.assertErrors( |
| [expectedError(ParserErrorCode.COVARIANT_AFTER_VAR, 4, 9)]); |
| } |
| |
| void test_covariantAndFinal() { |
| createParser('covariant final f = null;'); |
| ClassMember member = parser.parseClassMember('C'); |
| expectNotNullIfNoErrors(member); |
| listener.assertErrorsWithCodes([ParserErrorCode.FINAL_AND_COVARIANT]); |
| } |
| |
| void test_covariantAndStatic() { |
| createParser('covariant static A f;'); |
| ClassMember member = parser.parseClassMember('C'); |
| expectNotNullIfNoErrors(member); |
| listener.assertErrors( |
| [expectedError(ParserErrorCode.COVARIANT_AND_STATIC, 10, 6)]); |
| } |
| |
| void test_covariantAndType_local() { |
| // This is currently reporting EXPECTED_TOKEN for a missing semicolon, but |
| // this would be a better error message. |
| parseStatement("covariant int x;"); |
| listener.assertErrors(usingFastaParser |
| ? [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 0, 9)] |
| : |