// Copyright (c) 2017, 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/analysis/features.dart'; import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/ast/token.dart' as analyzer; import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; import 'package:analyzer/error/error.dart'; import 'package:analyzer/error/listener.dart' show ErrorReporter; import 'package:analyzer/src/dart/ast/ast.dart'; import 'package:analyzer/src/dart/ast/token.dart'; import 'package:analyzer/src/dart/scanner/scanner.dart'; import 'package:analyzer/src/error/codes.dart'; import 'package:analyzer/src/fasta/ast_builder.dart'; import 'package:analyzer/src/generated/parser.dart' as analyzer; import 'package:analyzer/src/generated/utilities_dart.dart'; import 'package:analyzer/src/string_source.dart'; import 'package:front_end/src/fasta/parser/async_modifier.dart'; import 'package:front_end/src/fasta/parser/forwarding_listener.dart' as fasta; import 'package:front_end/src/fasta/parser/parser.dart' as fasta; import 'package:front_end/src/fasta/scanner.dart' as fasta; import 'package:front_end/src/fasta/scanner.dart' show LanguageVersionToken, ScannerConfiguration, ScannerResult, scanString; import 'package:front_end/src/fasta/scanner/error_token.dart' show ErrorToken; import 'package:pub_semver/src/version.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; import '../util/ast_type_matchers.dart'; import 'parser_fasta_listener.dart'; import 'parser_test.dart'; import 'test_support.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(ClassMemberParserTest_Fasta); defineReflectiveTests(ExtensionMethodsParserTest_Fasta); defineReflectiveTests(CollectionLiteralParserTest); defineReflectiveTests(ComplexParserTest_Fasta); defineReflectiveTests(ErrorParserTest_Fasta); defineReflectiveTests(ExpressionParserTest_Fasta); defineReflectiveTests(FormalParameterParserTest_Fasta); defineReflectiveTests(NNBDParserTest_Fasta); defineReflectiveTests(RecoveryParserTest_Fasta); defineReflectiveTests(SimpleParserTest_Fasta); defineReflectiveTests(StatementParserTest_Fasta); defineReflectiveTests(TopLevelParserTest_Fasta); }); } /** * Type of the "parse..." methods defined in the Fasta parser. */ typedef analyzer.Token ParseFunction(analyzer.Token token); @reflectiveTest class ClassMemberParserTest_Fasta extends FastaParserTestCase with ClassMemberParserTestMixin { final tripleShift = FeatureSet.forTesting( sdkVersion: '2.0.0', additionalFeatures: [Feature.triple_shift]); void test_parseClassMember_operator_gtgtgt() { CompilationUnitImpl unit = parseCompilationUnit( 'class C { bool operator >>>(other) => false; }', featureSet: tripleShift); ClassDeclaration declaration = unit.declarations[0]; MethodDeclaration method = declaration.members[0]; 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_operator_gtgtgteq() { CompilationUnitImpl unit = parseCompilationUnit( 'class C { foo(int value) { x >>>= value; } }', featureSet: tripleShift); ClassDeclaration declaration = unit.declarations[0]; MethodDeclaration method = declaration.members[0]; BlockFunctionBody blockFunctionBody = method.body; NodeList statements = blockFunctionBody.block.statements; expect(statements, hasLength(1)); ExpressionStatement statement = statements[0]; AssignmentExpression assignment = statement.expression; SimpleIdentifier leftHandSide = assignment.leftHandSide; expect(leftHandSide.name, 'x'); expect(assignment.operator.lexeme, '>>>='); SimpleIdentifier rightHandSide = assignment.rightHandSide; expect(rightHandSide.name, 'value'); } void test_parseField_const_late() { createParser('const late T f = 0;', featureSet: nonNullable); ClassMember member = parser.parseClassMember('C'); expect(member, isNotNull); assertErrors(errors: [ expectedError(ParserErrorCode.CONFLICTING_MODIFIERS, 6, 4), ]); expect(member, isFieldDeclaration); 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); expect(list.keyword, isNotNull); expect(list.isConst, isTrue); expect(list.isFinal, isFalse); expect(list.isLate, isTrue); expect(list.lateKeyword, isNotNull); NodeList variables = list.variables; expect(variables, hasLength(1)); VariableDeclaration variable = variables[0]; expect(variable.name, isNotNull); } void test_parseField_final_late() { createParser('final late T f;', featureSet: nonNullable); ClassMember member = parser.parseClassMember('C'); assertErrors(errors: [ expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 6, 4), ]); expect(member, isNotNull); expect(member, isFieldDeclaration); 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); expect(list.keyword, isNotNull); expect(list.isConst, isFalse); expect(list.isFinal, isTrue); expect(list.isLate, isTrue); expect(list.lateKeyword, isNotNull); NodeList variables = list.variables; expect(variables, hasLength(1)); VariableDeclaration variable = variables[0]; expect(variable.name, isNotNull); } void test_parseField_late() { createParser('late T f;', featureSet: nonNullable); ClassMember member = parser.parseClassMember('C'); expect(member, isNotNull); assertNoErrors(); expect(member, isFieldDeclaration); 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); expect(list.keyword, isNull); expect(list.isConst, isFalse); expect(list.isFinal, isFalse); expect(list.isLate, isTrue); expect(list.lateKeyword, isNotNull); NodeList variables = list.variables; expect(variables, hasLength(1)); VariableDeclaration variable = variables[0]; expect(variable.name, isNotNull); } void test_parseField_late_const() { createParser('late const T f = 0;', featureSet: nonNullable); ClassMember member = parser.parseClassMember('C'); expect(member, isNotNull); assertErrors(errors: [ expectedError(ParserErrorCode.CONFLICTING_MODIFIERS, 5, 5), ]); expect(member, isFieldDeclaration); 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); expect(list.keyword, isNotNull); expect(list.isConst, isTrue); expect(list.isFinal, isFalse); expect(list.isLate, isTrue); expect(list.lateKeyword, isNotNull); NodeList variables = list.variables; expect(variables, hasLength(1)); VariableDeclaration variable = variables[0]; expect(variable.name, isNotNull); } void test_parseField_late_final() { createParser('late final T f;', featureSet: nonNullable); ClassMember member = parser.parseClassMember('C'); expect(member, isNotNull); assertNoErrors(); expect(member, isFieldDeclaration); 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); expect(list.keyword, isNotNull); expect(list.isConst, isFalse); expect(list.isFinal, isTrue); expect(list.isLate, isTrue); expect(list.lateKeyword, isNotNull); NodeList variables = list.variables; expect(variables, hasLength(1)); VariableDeclaration variable = variables[0]; expect(variable.name, isNotNull); } void test_parseField_late_var() { createParser('late var f;', featureSet: nonNullable); ClassMember member = parser.parseClassMember('C'); expect(member, isNotNull); assertErrors(errors: [ expectedError(ParserErrorCode.CONFLICTING_MODIFIERS, 5, 3), ]); expect(member, isFieldDeclaration); 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); expect(list.keyword, isNotNull); expect(list.isConst, isFalse); expect(list.isFinal, isFalse); expect(list.isLate, isTrue); expect(list.lateKeyword, isNotNull); NodeList variables = list.variables; expect(variables, hasLength(1)); VariableDeclaration variable = variables[0]; expect(variable.name, isNotNull); } void test_parseField_var_late() { createParser('var late f;', featureSet: nonNullable); ClassMember member = parser.parseClassMember('C'); expect(member, isNotNull); assertErrors(errors: [ expectedError(ParserErrorCode.CONFLICTING_MODIFIERS, 4, 4), ]); expect(member, isFieldDeclaration); 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); expect(list.keyword, isNotNull); expect(list.isConst, isFalse); expect(list.isFinal, isFalse); expect(list.isLate, isTrue); expect(list.lateKeyword, isNotNull); NodeList variables = list.variables; expect(variables, hasLength(1)); VariableDeclaration variable = variables[0]; expect(variable.name, isNotNull); } } /** * Tests of the fasta parser based on [ExpressionParserTestMixin]. */ @reflectiveTest class CollectionLiteralParserTest extends FastaParserTestCase { Expression parseCollectionLiteral(String source, {List codes, List errors, int expectedEndOffset, bool inAsync = false}) { return parseExpression(source, codes: codes, errors: errors, expectedEndOffset: expectedEndOffset, inAsync: inAsync, featureSet: FeatureSet.forTesting( sdkVersion: '2.0.0', additionalFeatures: [ Feature.spread_collections, Feature.control_flow_collections ])); } void test_listLiteral_for() { ListLiteral list = parseCollectionLiteral( '[1, await for (var x in list) 2]', inAsync: true, ); expect(list.elements, hasLength(2)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); ForElement second = list.elements[1]; expect(second.awaitKeyword, isNotNull); expect(second.forKeyword.isKeyword, isTrue); expect(second.leftParenthesis.lexeme, '('); expect(second.rightParenthesis.lexeme, ')'); ForEachPartsWithDeclaration forLoopParts = second.forLoopParts; DeclaredIdentifier forLoopVar = forLoopParts.loopVariable; expect(forLoopVar.identifier.name, 'x'); expect(forLoopParts.inKeyword, isNotNull); SimpleIdentifier iterable = forLoopParts.iterable; expect(iterable.name, 'list'); } void test_listLiteral_forIf() { ListLiteral list = parseCollectionLiteral( '[1, await for (var x in list) if (c) 2]', inAsync: true, ); expect(list.elements, hasLength(2)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); ForElement second = list.elements[1]; expect(second.awaitKeyword, isNotNull); expect(second.forKeyword.isKeyword, isTrue); expect(second.leftParenthesis.lexeme, '('); expect(second.rightParenthesis.lexeme, ')'); ForEachPartsWithDeclaration forLoopParts = second.forLoopParts; DeclaredIdentifier forLoopVar = forLoopParts.loopVariable; expect(forLoopVar.identifier.name, 'x'); expect(forLoopParts.inKeyword, isNotNull); SimpleIdentifier iterable = forLoopParts.iterable; expect(iterable.name, 'list'); IfElement body = second.body; SimpleIdentifier condition = body.condition; expect(condition.name, 'c'); IntegerLiteral thenElement = body.thenElement; expect(thenElement.value, 2); } void test_listLiteral_forSpread() { ListLiteral list = parseCollectionLiteral('[1, for (int x = 0; x < 10; ++x) ...[2]]'); expect(list.elements, hasLength(2)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); ForElement second = list.elements[1]; expect(second.awaitKeyword, isNull); expect(second.forKeyword.isKeyword, isTrue); expect(second.leftParenthesis.lexeme, '('); expect(second.rightParenthesis.lexeme, ')'); ForPartsWithDeclarations forLoopParts = second.forLoopParts; VariableDeclaration forLoopVar = forLoopParts.variables.variables[0]; expect(forLoopVar.name.name, 'x'); BinaryExpression condition = forLoopParts.condition; IntegerLiteral rightOperand = condition.rightOperand; expect(rightOperand.value, 10); PrefixExpression updater = forLoopParts.updaters[0]; SimpleIdentifier updaterOperand = updater.operand; expect(updaterOperand.name, 'x'); } void test_listLiteral_if() { ListLiteral list = parseCollectionLiteral('[1, if (true) 2]'); expect(list.elements, hasLength(2)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); IfElement second = list.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); IntegerLiteral thenElement = second.thenElement; expect(thenElement.value, 2); expect(second.elseElement, isNull); } void test_listLiteral_ifElse() { ListLiteral list = parseCollectionLiteral('[1, if (true) 2 else 5]'); expect(list.elements, hasLength(2)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); IfElement second = list.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); IntegerLiteral thenElement = second.thenElement; expect(thenElement.value, 2); IntegerLiteral elseElement = second.elseElement; expect(elseElement.value, 5); } void test_listLiteral_ifElseFor() { ListLiteral list = parseCollectionLiteral('[1, if (true) 2 else for (a in b) 5]'); expect(list.elements, hasLength(2)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); IfElement second = list.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); IntegerLiteral thenElement = second.thenElement; expect(thenElement.value, 2); ForElement elseElement = second.elseElement; ForEachPartsWithIdentifier forLoopParts = elseElement.forLoopParts; expect(forLoopParts.identifier.name, 'a'); IntegerLiteral forValue = elseElement.body; expect(forValue.value, 5); } void test_listLiteral_ifElseSpread() { ListLiteral list = parseCollectionLiteral('[1, if (true) ...[2] else ...?[5]]'); expect(list.elements, hasLength(2)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); IfElement second = list.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); SpreadElement thenElement = second.thenElement; expect(thenElement.spreadOperator.lexeme, '...'); SpreadElement elseElement = second.elseElement; expect(elseElement.spreadOperator.lexeme, '...?'); } void test_listLiteral_ifFor() { ListLiteral list = parseCollectionLiteral('[1, if (true) for (a in b) 2]'); expect(list.elements, hasLength(2)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); IfElement second = list.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); ForElement thenElement = second.thenElement; ForEachPartsWithIdentifier forLoopParts = thenElement.forLoopParts; expect(forLoopParts.identifier.name, 'a'); IntegerLiteral forValue = thenElement.body; expect(forValue.value, 2); expect(second.elseElement, isNull); } void test_listLiteral_ifSpread() { ListLiteral list = parseCollectionLiteral('[1, if (true) ...[2]]'); expect(list.elements, hasLength(2)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); IfElement second = list.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); SpreadElement thenElement = second.thenElement; expect(thenElement.spreadOperator.lexeme, '...'); expect(second.elseElement, isNull); } void test_listLiteral_spread() { ListLiteral list = parseCollectionLiteral('[1, ...[2]]'); expect(list.elements, hasLength(2)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); SpreadElement element = list.elements[1]; expect(element.spreadOperator.lexeme, '...'); ListLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_listLiteral_spreadQ() { ListLiteral list = parseCollectionLiteral('[1, ...?[2]]'); expect(list.elements, hasLength(2)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); SpreadElement element = list.elements[1]; expect(element.spreadOperator.lexeme, '...?'); ListLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_mapLiteral_for() { SetOrMapLiteral map = parseCollectionLiteral( '{1:7, await for (y in list) 2:3}', inAsync: true); expect(map.elements, hasLength(2)); MapLiteralEntry first = map.elements[0]; IntegerLiteral firstValue = first.value; expect(firstValue.value, 7); ForElement second = map.elements[1]; expect(second.awaitKeyword, isNotNull); expect(second.forKeyword.isKeyword, isTrue); expect(second.leftParenthesis.lexeme, '('); expect(second.rightParenthesis.lexeme, ')'); ForEachPartsWithIdentifier forLoopParts = second.forLoopParts; SimpleIdentifier forLoopVar = forLoopParts.identifier; expect(forLoopVar.name, 'y'); expect(forLoopParts.inKeyword, isNotNull); SimpleIdentifier iterable = forLoopParts.iterable; expect(iterable.name, 'list'); } void test_mapLiteral_forIf() { SetOrMapLiteral map = parseCollectionLiteral( '{1:7, await for (y in list) if (c) 2:3}', inAsync: true); expect(map.elements, hasLength(2)); MapLiteralEntry first = map.elements[0]; IntegerLiteral firstValue = first.value; expect(firstValue.value, 7); ForElement second = map.elements[1]; expect(second.awaitKeyword, isNotNull); expect(second.forKeyword.isKeyword, isTrue); expect(second.leftParenthesis.lexeme, '('); expect(second.rightParenthesis.lexeme, ')'); ForEachPartsWithIdentifier forLoopParts = second.forLoopParts; SimpleIdentifier forLoopVar = forLoopParts.identifier; expect(forLoopVar.name, 'y'); expect(forLoopParts.inKeyword, isNotNull); SimpleIdentifier iterable = forLoopParts.iterable; expect(iterable.name, 'list'); IfElement body = second.body; SimpleIdentifier condition = body.condition; expect(condition.name, 'c'); MapLiteralEntry thenElement = body.thenElement; IntegerLiteral thenValue = thenElement.value; expect(thenValue.value, 3); } void test_mapLiteral_forSpread() { SetOrMapLiteral map = parseCollectionLiteral('{1:7, for (x = 0; x < 10; ++x) ...{2:3}}'); expect(map.elements, hasLength(2)); MapLiteralEntry first = map.elements[0]; IntegerLiteral firstValue = first.value; expect(firstValue.value, 7); ForElement second = map.elements[1]; expect(second.awaitKeyword, isNull); expect(second.forKeyword.isKeyword, isTrue); expect(second.leftParenthesis.lexeme, '('); expect(second.rightParenthesis.lexeme, ')'); ForPartsWithExpression forLoopParts = second.forLoopParts; AssignmentExpression forLoopInit = forLoopParts.initialization; SimpleIdentifier forLoopVar = forLoopInit.leftHandSide; expect(forLoopVar.name, 'x'); BinaryExpression condition = forLoopParts.condition; IntegerLiteral rightOperand = condition.rightOperand; expect(rightOperand.value, 10); PrefixExpression updater = forLoopParts.updaters[0]; SimpleIdentifier updaterOperand = updater.operand; expect(updaterOperand.name, 'x'); } void test_mapLiteral_if() { SetOrMapLiteral map = parseCollectionLiteral('{1:1, if (true) 2:4}'); expect(map.elements, hasLength(2)); MapLiteralEntry first = map.elements[0]; IntegerLiteral firstValue = first.value; expect(firstValue.value, 1); IfElement second = map.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); MapLiteralEntry thenElement = second.thenElement; IntegerLiteral thenElementValue = thenElement.value; expect(thenElementValue.value, 4); expect(second.elseElement, isNull); } void test_mapLiteral_ifElse() { SetOrMapLiteral map = parseCollectionLiteral('{1:1, if (true) 2:4 else 5:6}'); expect(map.elements, hasLength(2)); MapLiteralEntry first = map.elements[0]; IntegerLiteral firstValue = first.value; expect(firstValue.value, 1); IfElement second = map.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); MapLiteralEntry thenElement = second.thenElement; IntegerLiteral thenElementValue = thenElement.value; expect(thenElementValue.value, 4); MapLiteralEntry elseElement = second.elseElement; IntegerLiteral elseElementValue = elseElement.value; expect(elseElementValue.value, 6); } void test_mapLiteral_ifElseFor() { SetOrMapLiteral map = parseCollectionLiteral('{1:1, if (true) 2:4 else for (c in d) 5:6}'); expect(map.elements, hasLength(2)); MapLiteralEntry first = map.elements[0]; IntegerLiteral firstValue = first.value; expect(firstValue.value, 1); IfElement second = map.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); MapLiteralEntry thenElement = second.thenElement; IntegerLiteral thenElementValue = thenElement.value; expect(thenElementValue.value, 4); ForElement elseElement = second.elseElement; ForEachPartsWithIdentifier forLoopParts = elseElement.forLoopParts; expect(forLoopParts.identifier.name, 'c'); MapLiteralEntry body = elseElement.body; IntegerLiteral bodyValue = body.value; expect(bodyValue.value, 6); } void test_mapLiteral_ifElseSpread() { SetOrMapLiteral map = parseCollectionLiteral('{1:7, if (true) ...{2:4} else ...?{5:6}}'); expect(map.elements, hasLength(2)); MapLiteralEntry first = map.elements[0]; IntegerLiteral firstValue = first.value; expect(firstValue.value, 7); IfElement second = map.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); SpreadElement thenElement = second.thenElement; expect(thenElement.spreadOperator.lexeme, '...'); SpreadElement elseElement = second.elseElement; expect(elseElement.spreadOperator.lexeme, '...?'); SetOrMapLiteral elseElementExpression = elseElement.expression; expect(elseElementExpression.elements, hasLength(1)); MapLiteralEntry entry = elseElementExpression.elements[0]; IntegerLiteral entryValue = entry.value; expect(entryValue.value, 6); } void test_mapLiteral_ifFor() { SetOrMapLiteral map = parseCollectionLiteral('{1:1, if (true) for (a in b) 2:4}'); expect(map.elements, hasLength(2)); MapLiteralEntry first = map.elements[0]; IntegerLiteral firstValue = first.value; expect(firstValue.value, 1); IfElement second = map.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); ForElement thenElement = second.thenElement; ForEachPartsWithIdentifier forLoopParts = thenElement.forLoopParts; expect(forLoopParts.identifier.name, 'a'); MapLiteralEntry body = thenElement.body; IntegerLiteral thenElementValue = body.value; expect(thenElementValue.value, 4); expect(second.elseElement, isNull); } void test_mapLiteral_ifSpread() { SetOrMapLiteral map = parseCollectionLiteral('{1:1, if (true) ...{2:4}}'); expect(map.elements, hasLength(2)); MapLiteralEntry first = map.elements[0]; IntegerLiteral firstValue = first.value; expect(firstValue.value, 1); IfElement second = map.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); SpreadElement thenElement = second.thenElement; expect(thenElement.spreadOperator.lexeme, '...'); expect(second.elseElement, isNull); } void test_mapLiteral_spread() { SetOrMapLiteral map = parseCollectionLiteral('{1: 2, ...{3: 4}}'); expect(map.constKeyword, isNull); expect(map.typeArguments, isNull); expect(map.elements, hasLength(2)); SpreadElement element = map.elements[1]; expect(element.spreadOperator.lexeme, '...'); SetOrMapLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_mapLiteral_spread2_typed() { SetOrMapLiteral map = parseCollectionLiteral('{1: 2, ...{3: 4}}'); expect(map.constKeyword, isNull); expect(map.typeArguments.arguments, hasLength(2)); expect(map.elements, hasLength(2)); SpreadElement element = map.elements[1]; expect(element.spreadOperator.lexeme, '...'); SetOrMapLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_mapLiteral_spread_typed() { SetOrMapLiteral map = parseCollectionLiteral('{...{3: 4}}'); expect(map.constKeyword, isNull); expect(map.typeArguments.arguments, hasLength(2)); expect(map.elements, hasLength(1)); SpreadElement element = map.elements[0]; expect(element.spreadOperator.lexeme, '...'); SetOrMapLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_mapLiteral_spreadQ() { SetOrMapLiteral map = parseCollectionLiteral('{1: 2, ...?{3: 4}}'); expect(map.constKeyword, isNull); expect(map.typeArguments, isNull); expect(map.elements, hasLength(2)); SpreadElement element = map.elements[1]; expect(element.spreadOperator.lexeme, '...?'); SetOrMapLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_mapLiteral_spreadQ2_typed() { SetOrMapLiteral map = parseCollectionLiteral('{1: 2, ...?{3: 4}}'); expect(map.constKeyword, isNull); expect(map.typeArguments.arguments, hasLength(2)); expect(map.elements, hasLength(2)); SpreadElement element = map.elements[1]; expect(element.spreadOperator.lexeme, '...?'); SetOrMapLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_mapLiteral_spreadQ_typed() { SetOrMapLiteral map = parseCollectionLiteral('{...?{3: 4}}'); expect(map.constKeyword, isNull); expect(map.typeArguments.arguments, hasLength(2)); expect(map.elements, hasLength(1)); SpreadElement element = map.elements[0]; expect(element.spreadOperator.lexeme, '...?'); SetOrMapLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_setLiteral_if() { SetOrMapLiteral setLiteral = parseCollectionLiteral('{1, if (true) 2}'); expect(setLiteral.elements, hasLength(2)); IntegerLiteral first = setLiteral.elements[0]; expect(first.value, 1); IfElement second = setLiteral.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); IntegerLiteral thenElement = second.thenElement; expect(thenElement.value, 2); expect(second.elseElement, isNull); } void test_setLiteral_ifElse() { SetOrMapLiteral setLiteral = parseCollectionLiteral('{1, if (true) 2 else 5}'); expect(setLiteral.elements, hasLength(2)); IntegerLiteral first = setLiteral.elements[0]; expect(first.value, 1); IfElement second = setLiteral.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); IntegerLiteral thenElement = second.thenElement; expect(thenElement.value, 2); IntegerLiteral elseElement = second.elseElement; expect(elseElement.value, 5); } void test_setLiteral_ifElseSpread() { SetOrMapLiteral setLiteral = parseCollectionLiteral('{1, if (true) ...{2} else ...?[5]}'); expect(setLiteral.elements, hasLength(2)); IntegerLiteral first = setLiteral.elements[0]; expect(first.value, 1); IfElement second = setLiteral.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); SpreadElement thenElement = second.thenElement; expect(thenElement.spreadOperator.lexeme, '...'); SetOrMapLiteral theExpression = thenElement.expression; expect(theExpression.elements, hasLength(1)); SpreadElement elseElement = second.elseElement; expect(elseElement.spreadOperator.lexeme, '...?'); ListLiteral elseExpression = elseElement.expression; expect(elseExpression.elements, hasLength(1)); } void test_setLiteral_ifSpread() { SetOrMapLiteral setLiteral = parseCollectionLiteral('{1, if (true) ...[2]}'); expect(setLiteral.elements, hasLength(2)); IntegerLiteral first = setLiteral.elements[0]; expect(first.value, 1); IfElement second = setLiteral.elements[1]; BooleanLiteral condition = second.condition; expect(condition.value, isTrue); SpreadElement thenElement = second.thenElement; expect(thenElement.spreadOperator.lexeme, '...'); expect(second.elseElement, isNull); } void test_setLiteral_spread2() { SetOrMapLiteral set = parseCollectionLiteral('{3, ...[4]}'); expect(set.constKeyword, isNull); expect(set.typeArguments, isNull); expect(set.elements, hasLength(2)); IntegerLiteral value = set.elements[0]; expect(value.value, 3); SpreadElement element = set.elements[1]; expect(element.spreadOperator.lexeme, '...'); ListLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_setLiteral_spread2Q() { SetOrMapLiteral set = parseCollectionLiteral('{3, ...?[4]}'); expect(set.constKeyword, isNull); expect(set.typeArguments, isNull); expect(set.elements, hasLength(2)); IntegerLiteral value = set.elements[0]; expect(value.value, 3); SpreadElement element = set.elements[1]; expect(element.spreadOperator.lexeme, '...?'); ListLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_setLiteral_spread_typed() { SetOrMapLiteral set = parseCollectionLiteral('{...[3]}'); expect(set.constKeyword, isNull); expect(set.typeArguments, isNotNull); expect(set.elements, hasLength(1)); SpreadElement element = set.elements[0]; expect(element.spreadOperator.lexeme, '...'); ListLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_setLiteral_spreadQ_typed() { SetOrMapLiteral set = parseCollectionLiteral('{...?[3]}'); expect(set.constKeyword, isNull); expect(set.typeArguments, isNotNull); expect(set.elements, hasLength(1)); SpreadElement element = set.elements[0]; expect(element.spreadOperator.lexeme, '...?'); ListLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_setOrMapLiteral_spread() { SetOrMapLiteral map = parseCollectionLiteral('{...{3: 4}}'); expect(map.constKeyword, isNull); expect(map.typeArguments, isNull); expect(map.elements, hasLength(1)); SpreadElement element = map.elements[0]; expect(element.spreadOperator.lexeme, '...'); SetOrMapLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } void test_setOrMapLiteral_spreadQ() { SetOrMapLiteral map = parseCollectionLiteral('{...?{3: 4}}'); expect(map.constKeyword, isNull); expect(map.typeArguments, isNull); expect(map.elements, hasLength(1)); SpreadElement element = map.elements[0]; expect(element.spreadOperator.lexeme, '...?'); SetOrMapLiteral spreadExpression = element.expression; expect(spreadExpression.elements, hasLength(1)); } } /** * Tests of the fasta parser based on [ComplexParserTestMixin]. */ @reflectiveTest class ComplexParserTest_Fasta extends FastaParserTestCase with ComplexParserTestMixin { void test_conditionalExpression_precedence_nullableType_as2() { ExpressionStatement statement = parseStatement('x as bool? ? (x + y) : z;'); ConditionalExpression expression = statement.expression; AsExpression asExpression = expression.condition; TypeName type = asExpression.type; expect(type.question.lexeme, '?'); Expression thenExpression = expression.thenExpression; expect(thenExpression, isParenthesizedExpression); Expression elseExpression = expression.elseExpression; expect(elseExpression, isSimpleIdentifier); assertErrors( errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 9, 1)]); } void test_conditionalExpression_precedence_nullableType_as3() { ExpressionStatement statement = parseStatement('(x as bool?) ? (x + y) : z;'); ConditionalExpression expression = statement.expression; ParenthesizedExpression condition = expression.condition; AsExpression asExpression = condition.expression; TypeName type = asExpression.type; expect(type.question.lexeme, '?'); Expression thenExpression = expression.thenExpression; expect(thenExpression, isParenthesizedExpression); Expression elseExpression = expression.elseExpression; expect(elseExpression, isSimpleIdentifier); assertErrors( errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 10, 1)]); } void test_conditionalExpression_precedence_nullableType_is2() { ExpressionStatement statement = parseStatement('x is String? ? (x + y) : z;'); ConditionalExpression expression = statement.expression; IsExpression isExpression = expression.condition; TypeName type = isExpression.type; expect(type.question.lexeme, '?'); Expression thenExpression = expression.thenExpression; expect(thenExpression, isParenthesizedExpression); Expression elseExpression = expression.elseExpression; expect(elseExpression, isSimpleIdentifier); assertErrors( errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 11, 1)]); } void test_conditionalExpression_precedence_nullableType_is3() { ExpressionStatement statement = parseStatement('(x is String?) ? (x + y) : z;'); ConditionalExpression expression = statement.expression; ParenthesizedExpression condition = expression.condition; IsExpression isExpression = condition.expression; TypeName type = isExpression.type; expect(type.question.lexeme, '?'); Expression thenExpression = expression.thenExpression; expect(thenExpression, isParenthesizedExpression); Expression elseExpression = expression.elseExpression; expect(elseExpression, isSimpleIdentifier); assertErrors( errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 12, 1)]); } } /** * Tests of the fasta parser based on [ErrorParserTest]. */ @reflectiveTest class ErrorParserTest_Fasta extends FastaParserTestCase with ErrorParserTestMixin { void test_await_missing_async2_issue36048() { parseCompilationUnit(''' main() { // missing async await foo.bar(); } ''', errors: [ expectedError(CompileTimeErrorCode.AWAIT_IN_WRONG_CONTEXT, 28, 5) ]); } void test_await_missing_async3_issue36048() { parseCompilationUnit(''' main() { // missing async (await foo); } ''', errors: [ expectedError(CompileTimeErrorCode.AWAIT_IN_WRONG_CONTEXT, 29, 5) ]); } void test_await_missing_async4_issue36048() { parseCompilationUnit(''' main() { // missing async [await foo]; } ''', errors: [ expectedError(CompileTimeErrorCode.AWAIT_IN_WRONG_CONTEXT, 29, 5) ]); } void test_await_missing_async_issue36048() { parseCompilationUnit(''' main() { // missing async await foo(); } ''', errors: [ expectedError(CompileTimeErrorCode.AWAIT_IN_WRONG_CONTEXT, 28, 5) ]); } void test_constructor_super_field() { // https://github.com/dart-lang/sdk/issues/36262 // https://github.com/dart-lang/sdk/issues/31198 parseCompilationUnit('class B extends A { B(): super().foo {} }', errors: [ expectedError(ParserErrorCode.INVALID_SUPER_IN_INITIALIZER, 25, 5), ]); } void test_constructor_super_method() { // https://github.com/dart-lang/sdk/issues/36262 // https://github.com/dart-lang/sdk/issues/31198 parseCompilationUnit('class B extends A { B(): super().foo() {} }', errors: [ expectedError(ParserErrorCode.INVALID_SUPER_IN_INITIALIZER, 25, 5), ]); } void test_constructor_this_field() { // https://github.com/dart-lang/sdk/issues/36262 // https://github.com/dart-lang/sdk/issues/31198 parseCompilationUnit('class B extends A { B(): this().foo; }', errors: [ expectedError(ParserErrorCode.INVALID_THIS_IN_INITIALIZER, 25, 4), ]); } void test_constructor_this_method() { // https://github.com/dart-lang/sdk/issues/36262 // https://github.com/dart-lang/sdk/issues/31198 parseCompilationUnit('class B extends A { B(): this().foo(); }', errors: [ expectedError(ParserErrorCode.INVALID_THIS_IN_INITIALIZER, 25, 4), ]); } @override void test_expectedListOrMapLiteral() { // The fasta parser returns an 'IntegerLiteralImpl' when parsing '1'. // This test is not expected to ever pass. //super.test_expectedListOrMapLiteral(); } @override void test_expectedStringLiteral() { // The fasta parser returns an 'IntegerLiteralImpl' when parsing '1'. // This test is not expected to ever pass. //super.test_expectedStringLiteral(); } void test_factory_issue_36400() { parseCompilationUnit('class T { T factory T() { return null; } }', errors: [expectedError(ParserErrorCode.TYPE_BEFORE_FACTORY, 10, 1)]); } void test_getterNativeWithBody() { createParser('String get m native "str" => 0;'); parser.parseClassMember('C') as MethodDeclaration; if (!allowNativeClause) { assertErrorsWithCodes([ ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION, ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, ]); } else { assertErrorsWithCodes([ ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, ]); } } void test_invalidOperatorAfterSuper_constructorInitializer2() { parseCompilationUnit('class C { C() : super?.namedConstructor(); }', errors: [ expectedError( ParserErrorCode.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER, 21, 2) ]); } void test_partialNamedConstructor() { parseCompilationUnit('class C { C. }', errors: [ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 13, 1), expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1), expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 13, 1), ]); } void test_staticOperatorNamedMethod() { // operator can be used as a method name parseCompilationUnit('class C { static operator(x) => x; }'); } void test_yieldAsLabel() { // yield can be used as a label parseCompilationUnit('main() { yield: break yield; }'); } } /** * Tests of the fasta parser based on [ExpressionParserTestMixin]. */ @reflectiveTest class ExpressionParserTest_Fasta extends FastaParserTestCase with ExpressionParserTestMixin { final beforeUiAsCode = FeatureSet.forTesting(sdkVersion: '2.2.0'); void test_binaryExpression_allOperators() { // https://github.com/dart-lang/sdk/issues/36255 for (TokenType type in TokenType.all) { if (type.precedence > 0) { var source = 'a ${type.lexeme} b'; try { parseExpression(source); } on TestFailure { // Ensure that there are no infinite loops or exceptions thrown // by the parser. Test failures are fine. } } } } void test_listLiteral_spread_disabled() { ListLiteral list = parseExpression('[1, ...[2]]', featureSet: beforeUiAsCode, errors: [ expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 4, 3), ]); expect(list.elements, hasLength(1)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); } void test_listLiteral_spreadQ_disabled() { ListLiteral list = parseExpression('[1, ...?[2]]', featureSet: beforeUiAsCode, errors: [ expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 4, 4), ]); expect(list.elements, hasLength(1)); IntegerLiteral first = list.elements[0]; expect(first.value, 1); } void test_mapLiteral() { SetOrMapLiteral map = parseExpression('{3: 6}'); expect(map.constKeyword, isNull); expect(map.typeArguments, isNull); expect(map.elements, hasLength(1)); MapLiteralEntry entry = map.elements[0]; IntegerLiteral key = entry.key; expect(key.value, 3); IntegerLiteral value = entry.value; expect(value.value, 6); } void test_mapLiteral_const() { SetOrMapLiteral map = parseExpression('const {3: 6}'); expect(map.constKeyword, isNotNull); expect(map.typeArguments, isNull); expect(map.elements, hasLength(1)); MapLiteralEntry entry = map.elements[0]; IntegerLiteral key = entry.key; expect(key.value, 3); IntegerLiteral value = entry.value; expect(value.value, 6); } void test_mapLiteral_invalid_set_entry_uiAsCodeDisabled() { SetOrMapLiteral map = parseExpression('{1}', featureSet: beforeUiAsCode, errors: [ expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 1), expectedError(ParserErrorCode.MISSING_IDENTIFIER, 12, 1), ]); expect(map.constKeyword, isNull); expect(map.typeArguments.arguments, hasLength(2)); expect(map.elements, hasLength(1)); } @failingTest void test_mapLiteral_invalid_too_many_type_arguments1() { SetOrMapLiteral map = parseExpression('{}', errors: [ // TODO(danrubel): Currently the resolver reports invalid number of // type arguments, but the parser could report this. expectedError( /* ParserErrorCode.EXPECTED_ONE_OR_TWO_TYPE_VARIABLES */ ParserErrorCode.EXPECTED_TOKEN, 11, 3), ]); expect(map.constKeyword, isNull); expect(map.elements, hasLength(0)); } @failingTest void test_mapLiteral_invalid_too_many_type_arguments2() { SetOrMapLiteral map = parseExpression('{1}', errors: [ // TODO(danrubel): Currently the resolver reports invalid number of // type arguments, but the parser could report this. expectedError( /* ParserErrorCode.EXPECTED_ONE_OR_TWO_TYPE_VARIABLES */ ParserErrorCode.EXPECTED_TOKEN, 11, 3), ]); expect(map.constKeyword, isNull); expect(map.elements, hasLength(0)); } void test_mapLiteral_spread2_typed_disabled() { SetOrMapLiteral map = parseExpression('{1: 2, ...{3: 4}}', featureSet: beforeUiAsCode, errors: [ expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 17, 3), ]); expect(map.constKeyword, isNull); expect(map.typeArguments.arguments, hasLength(2)); expect(map.elements, hasLength(1)); } void test_mapLiteral_spread_disabled() { SetOrMapLiteral map = parseExpression('{1: 2, ...{3: 4}}', featureSet: beforeUiAsCode, errors: [ expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 7, 3), ]); expect(map.constKeyword, isNull); expect(map.typeArguments, isNull); expect(map.elements, hasLength(1)); } void test_mapLiteral_spread_typed_disabled() { SetOrMapLiteral map = parseExpression('{...{3: 4}}', featureSet: beforeUiAsCode, errors: [ expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 11, 3), ]); expect(map.constKeyword, isNull); expect(map.typeArguments.arguments, hasLength(2)); expect(map.elements, hasLength(0)); } void test_mapLiteral_spreadQ2_typed_disabled() { SetOrMapLiteral map = parseExpression('{1: 2, ...?{3: 4}}', featureSet: beforeUiAsCode, errors: [ expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 17, 4), ]); expect(map.constKeyword, isNull); expect(map.typeArguments.arguments, hasLength(2)); expect(map.elements, hasLength(1)); } void test_mapLiteral_spreadQ_disabled() { SetOrMapLiteral map = parseExpression('{1: 2, ...?{3: 4}}', featureSet: beforeUiAsCode, errors: [ expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 7, 4), ]); expect(map.constKeyword, isNull); expect(map.typeArguments, isNull); expect(map.elements, hasLength(1)); } void test_mapLiteral_spreadQ_typed_disabled() { SetOrMapLiteral map = parseExpression('{...?{3: 4}}', featureSet: beforeUiAsCode, errors: [ expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 11, 4), ]); expect(map.constKeyword, isNull); expect(map.typeArguments.arguments, hasLength(2)); expect(map.elements, hasLength(0)); } @override @failingTest void test_parseUnaryExpression_decrement_super() { // TODO(danrubel) Reports a different error and different token stream. // Expected: TokenType: // Actual: TokenType: super.test_parseUnaryExpression_decrement_super(); } @override @failingTest void test_parseUnaryExpression_decrement_super_withComment() { // TODO(danrubel) Reports a different error and different token stream. // Expected: TokenType: // Actual: TokenType: super.test_parseUnaryExpression_decrement_super_withComment(); } void test_setLiteral() { SetOrMapLiteral set = parseExpression('{3}'); expect(set.constKeyword, isNull); expect(set.typeArguments, isNull); expect(set.elements, hasLength(1)); IntegerLiteral value = set.elements[0]; expect(value.value, 3); } void test_setLiteral_const() { SetOrMapLiteral set = parseExpression('const {3, 6}'); expect(set.constKeyword, isNotNull); expect(set.typeArguments, isNull); expect(set.elements, hasLength(2)); IntegerLiteral value1 = set.elements[0]; expect(value1.value, 3); IntegerLiteral value2 = set.elements[1]; expect(value2.value, 6); } void test_setLiteral_const_typed() { SetOrMapLiteral set = parseExpression('const {3}'); expect(set.constKeyword, isNotNull); expect(set.typeArguments.arguments, hasLength(1)); NamedType typeArg = set.typeArguments.arguments[0]; expect(typeArg.name.name, 'int'); expect(set.elements.length, 1); IntegerLiteral value = set.elements[0]; expect(value.value, 3); } void test_setLiteral_invalid_map_entry_beforeUiAsCode() { SetOrMapLiteral set = parseExpression('{1: 1}', featureSet: beforeUiAsCode, errors: [ expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 7, 1), ]); expect(set.constKeyword, isNull); expect(set.typeArguments.arguments, hasLength(1)); NamedType typeArg = set.typeArguments.arguments[0]; expect(typeArg.name.name, 'int'); expect(set.elements.length, 1); } void test_setLiteral_nested_typeArgument() { SetOrMapLiteral set = parseExpression('>{{3}}'); expect(set.constKeyword, isNull); expect(set.typeArguments.arguments, hasLength(1)); NamedType typeArg1 = set.typeArguments.arguments[0]; expect(typeArg1.name.name, 'Set'); expect(typeArg1.typeArguments.arguments, hasLength(1)); NamedType typeArg2 = typeArg1.typeArguments.arguments[0]; expect(typeArg2.name.name, 'int'); expect(set.elements.length, 1); SetOrMapLiteral intSet = set.elements[0]; expect(intSet.elements, hasLength(1)); IntegerLiteral value = intSet.elements[0]; expect(value.value, 3); } void test_setLiteral_spread2_disabled() { SetOrMapLiteral set = parseExpression('{3, ...[4]}', featureSet: beforeUiAsCode, errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 4, 3)]); expect(set.constKeyword, isNull); expect(set.typeArguments, isNull); expect(set.elements, hasLength(1)); IntegerLiteral value = set.elements[0]; expect(value.value, 3); } void test_setLiteral_spread2Q_disabled() { SetOrMapLiteral set = parseExpression('{3, ...?[4]}', featureSet: beforeUiAsCode, errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 4, 4)]); expect(set.constKeyword, isNull); expect(set.typeArguments, isNull); expect(set.elements, hasLength(1)); IntegerLiteral value = set.elements[0]; expect(value.value, 3); } void test_setLiteral_spread_typed_disabled() { SetOrMapLiteral set = parseExpression('{...[3]}', featureSet: beforeUiAsCode, errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 6, 3)]); expect(set.constKeyword, isNull); expect(set.typeArguments, isNotNull); expect(set.elements, hasLength(0)); } void test_setLiteral_spreadQ_typed_disabled() { SetOrMapLiteral set = parseExpression('{...?[3]}', featureSet: beforeUiAsCode, errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 6, 4)]); expect(set.constKeyword, isNull); expect(set.typeArguments, isNotNull); expect(set.elements, hasLength(0)); } void test_setLiteral_typed() { SetOrMapLiteral set = parseExpression('{3}'); expect(set.constKeyword, isNull); expect(set.typeArguments.arguments, hasLength(1)); NamedType typeArg = set.typeArguments.arguments[0]; expect(typeArg.name.name, 'int'); expect(set.elements.length, 1); IntegerLiteral value = set.elements[0]; expect(value.value, 3); } void test_setOrMapLiteral_spread_disabled() { SetOrMapLiteral map = parseExpression('{...{3: 4}}', featureSet: beforeUiAsCode, errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 1, 3)]); expect(map.constKeyword, isNull); expect(map.typeArguments, isNull); expect(map.elements, hasLength(0)); } void test_setOrMapLiteral_spreadQ_disabled() { SetOrMapLiteral map = parseExpression('{...?{3: 4}}', featureSet: beforeUiAsCode, errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 1, 4)]); expect(map.constKeyword, isNull); expect(map.typeArguments, isNull); expect(map.elements, hasLength(0)); } } @reflectiveTest class ExtensionMethodsParserTest_Fasta extends FastaParserTestCase { @override CompilationUnit parseCompilationUnit(String content, {List codes, List errors, FeatureSet featureSet}) { return super.parseCompilationUnit(content, codes: codes, errors: errors, featureSet: featureSet ?? FeatureSet.forTesting( sdkVersion: '2.3.0', additionalFeatures: [Feature.extension_methods], )); } void test_complex_extends() { var unit = parseCompilationUnit( 'extension E extends A with B, C implements D { }', errors: [ expectedError(ParserErrorCode.EXPECTED_INSTEAD, 12, 7), expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 22, 4), expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 28, 1), expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 32, 10), ]); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name.name, 'E'); expect(extension.onKeyword.lexeme, 'extends'); expect((extension.extendedType as NamedType).name.name, 'A'); expect(extension.members, hasLength(0)); } void test_complex_implements() { var unit = parseCompilationUnit('extension E implements C, D { }', errors: [ expectedError(ParserErrorCode.EXPECTED_INSTEAD, 12, 10), expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 24, 1), ]); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name.name, 'E'); expect(extension.onKeyword.lexeme, 'implements'); expect((extension.extendedType as NamedType).name.name, 'C'); expect(extension.members, hasLength(0)); } void test_complex_type() { var unit = parseCompilationUnit('extension E on C { }'); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name.name, 'E'); expect(extension.onKeyword.lexeme, 'on'); var namedType = (extension.extendedType as NamedType); expect(namedType.name.name, 'C'); expect(namedType.typeArguments.arguments, hasLength(1)); expect(extension.members, hasLength(0)); } void test_complex_type2() { var unit = parseCompilationUnit('extension E on C { }'); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name.name, 'E'); expect(extension.onKeyword.lexeme, 'on'); var namedType = (extension.extendedType as NamedType); expect(namedType.name.name, 'C'); expect(namedType.typeArguments.arguments, hasLength(1)); expect(extension.members, hasLength(0)); } void test_complex_type2_no_name() { var unit = parseCompilationUnit('extension on C { }'); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name, isNull); expect(extension.onKeyword.lexeme, 'on'); var namedType = (extension.extendedType as NamedType); expect(namedType.name.name, 'C'); expect(namedType.typeArguments.arguments, hasLength(1)); expect(extension.members, hasLength(0)); } void test_missing_on() { var unit = parseCompilationUnit('extension E', errors: [ expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 1), expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 11, 0), expectedError(ParserErrorCode.MISSING_CLASS_BODY, 11, 0), ]); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name.name, 'E'); expect(extension.onKeyword.lexeme, 'on'); expect((extension.extendedType as NamedType).name.name, ''); expect(extension.members, hasLength(0)); } void test_missing_on_withBlock() { var unit = parseCompilationUnit('extension E {}', errors: [ expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 1), expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 1), ]); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name.name, 'E'); expect(extension.onKeyword.lexeme, 'on'); expect((extension.extendedType as NamedType).name.name, ''); expect(extension.members, hasLength(0)); } void test_missing_on_withClassAndBlock() { var unit = parseCompilationUnit('extension E C {}', errors: [ expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 1), ]); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name.name, 'E'); expect(extension.onKeyword.lexeme, 'on'); expect((extension.extendedType as NamedType).name.name, 'C'); expect(extension.members, hasLength(0)); } void test_simple() { var unit = parseCompilationUnit('extension E on C { }'); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name.name, 'E'); expect(extension.onKeyword.lexeme, 'on'); expect((extension.extendedType as NamedType).name.name, 'C'); var namedType = (extension.extendedType as NamedType); expect(namedType.name.name, 'C'); expect(namedType.typeArguments, isNull); expect(extension.members, hasLength(0)); } void test_simple_extends() { var unit = parseCompilationUnit('extension E extends C { }', errors: [ expectedError(ParserErrorCode.EXPECTED_INSTEAD, 12, 7), ]); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name.name, 'E'); expect(extension.onKeyword.lexeme, 'extends'); expect((extension.extendedType as NamedType).name.name, 'C'); expect(extension.members, hasLength(0)); } void test_simple_implements() { var unit = parseCompilationUnit('extension E implements C { }', errors: [ expectedError(ParserErrorCode.EXPECTED_INSTEAD, 12, 10), ]); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name.name, 'E'); expect(extension.onKeyword.lexeme, 'implements'); expect((extension.extendedType as NamedType).name.name, 'C'); expect(extension.members, hasLength(0)); } void test_simple_no_name() { var unit = parseCompilationUnit('extension on C { }'); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name, isNull); expect(extension.onKeyword.lexeme, 'on'); expect((extension.extendedType as NamedType).name.name, 'C'); var namedType = (extension.extendedType as NamedType); expect(namedType.name.name, 'C'); expect(namedType.typeArguments, isNull); expect(extension.members, hasLength(0)); } void test_simple_not_enabled() { parseCompilationUnit('extension E on C { }', errors: [ expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 0, 9), expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 15, 1) ], featureSet: FeatureSet.forTesting(sdkVersion: '2.3.0')); } void test_simple_with() { var unit = parseCompilationUnit('extension E with C { }', errors: [ expectedError(ParserErrorCode.EXPECTED_INSTEAD, 12, 4), ]); expect(unit.declarations, hasLength(1)); var extension = unit.declarations[0] as ExtensionDeclaration; expect(extension.name.name, 'E'); expect(extension.onKeyword.lexeme, 'with'); expect((extension.extendedType as NamedType).name.name, 'C'); expect(extension.members, hasLength(0)); } } /** * Implementation of [AbstractParserTestCase] specialized for testing the * Fasta parser. */ class FastaParserTestCase with ParserTestHelpers implements AbstractParserTestCase { static final List NO_ERROR_COMPARISON = []; final controlFlow = FeatureSet.forTesting( sdkVersion: '2.0.0', additionalFeatures: [Feature.control_flow_collections]); final spread = FeatureSet.forTesting( sdkVersion: '2.0.0', additionalFeatures: [Feature.spread_collections]); final nonNullable = FeatureSet.forTesting( sdkVersion: '2.2.2', additionalFeatures: [Feature.non_nullable]); final preNonNullable = FeatureSet.forTesting(sdkVersion: '2.2.2'); ParserProxy _parserProxy; analyzer.Token _fastaTokens; @override bool allowNativeClause = false; set enableOptionalNewAndConst(bool enable) { // ignored } @override set enableUriInPartOf(bool value) { if (value == false) { throw new UnimplementedError( 'URIs in "part of" declarations cannot be disabled in Fasta.'); } } @override GatheringErrorListener get listener => _parserProxy._errorListener; @override analyzer.Parser get parser => _parserProxy; @override bool get usingFastaParser => true; void assertErrors({List codes, List errors}) { if (codes != null) { if (!identical(codes, NO_ERROR_COMPARISON)) { assertErrorsWithCodes(codes); } } else if (errors != null) { listener.assertErrors(errors); } else { assertNoErrors(); } } @override void assertErrorsWithCodes(List expectedErrorCodes) { _parserProxy._errorListener.assertErrorsWithCodes( _toFastaGeneratedAnalyzerErrorCodes(expectedErrorCodes)); } @override void assertNoErrors() { _parserProxy._errorListener.assertNoErrors(); } @override void createParser(String content, {int expectedEndOffset, FeatureSet featureSet}) { featureSet ??= FeatureSet.forTesting(); var result = scanString(content, configuration: featureSet.isEnabled(Feature.non_nullable) ? ScannerConfiguration.nonNullable : ScannerConfiguration.classic, includeComments: true); _fastaTokens = result.tokens; _parserProxy = new ParserProxy(_fastaTokens, featureSet, allowNativeClause: allowNativeClause, expectedEndOffset: expectedEndOffset); } @override ExpectedError expectedError(ErrorCode code, int offset, int length) => new ExpectedError( _toFastaGeneratedAnalyzerErrorCode(code), offset, length); @override void expectNotNullIfNoErrors(Object result) { if (!listener.hasErrors) { expect(result, isNotNull); } } @override Expression parseAdditiveExpression(String code) { return _parseExpression(code); } Expression parseArgument(String source) { createParser(source); return _parserProxy.parseArgument(); } @override Expression parseAssignableExpression(String code, bool primaryAllowed) { return _parseExpression(code); } @override Expression parseAssignableSelector(String code, bool optional, {bool allowConditional: true}) { if (optional) { if (code.isEmpty) { return _parseExpression('foo'); } return _parseExpression('(foo)$code'); } return _parseExpression('foo$code'); } @override AwaitExpression parseAwaitExpression(String code) { var function = _parseExpression('() async => $code') as FunctionExpression; return (function.body as ExpressionFunctionBody).expression; } @override Expression parseBitwiseAndExpression(String code) { return _parseExpression(code); } @override Expression parseBitwiseOrExpression(String code) { return _parseExpression(code); } @override Expression parseBitwiseXorExpression(String code) { return _parseExpression(code); } @override Expression parseCascadeSection(String code) { var cascadeExpression = _parseExpression('null$code') as CascadeExpression; return cascadeExpression.cascadeSections.first; } CommentReference parseCommentReference( String referenceSource, int sourceOffset) { String padding = ' '.padLeft(sourceOffset - 4, 'a'); String source = '/**$padding[$referenceSource] */ class C { }'; CompilationUnit unit = parseCompilationUnit(source); ClassDeclaration clazz = unit.declarations[0]; Comment comment = clazz.documentationComment; List references = comment.references; if (references.isEmpty) { return null; } else { expect(references, hasLength(1)); return references[0]; } } @override CompilationUnit parseCompilationUnit(String content, {List codes, List errors, FeatureSet featureSet}) { GatheringErrorListener listener = new GatheringErrorListener(checkRanges: true); CompilationUnit unit = parseCompilationUnit2(content, listener, featureSet: featureSet); // Assert and return result if (codes != null) { listener .assertErrorsWithCodes(_toFastaGeneratedAnalyzerErrorCodes(codes)); } else if (errors != null) { listener.assertErrors(errors); } else { listener.assertNoErrors(); } return unit; } CompilationUnit parseCompilationUnit2( String content, GatheringErrorListener listener, {FeatureSet featureSet}) { featureSet ??= FeatureSet.forTesting(); var source = new StringSource(content, 'parser_test_StringSource.dart'); // Adjust the feature set based on language version comment. void languageVersionChanged( fasta.Scanner scanner, LanguageVersionToken languageVersion) { featureSet = featureSet.restrictToVersion( Version(languageVersion.major, languageVersion.minor, 0)); scanner.configuration = Scanner.buildConfig(featureSet); } // Scan tokens ScannerResult result = scanString(content, includeComments: true, configuration: Scanner.buildConfig(featureSet), languageVersionChanged: languageVersionChanged); _fastaTokens = result.tokens; // Run parser ErrorReporter errorReporter = new ErrorReporter(listener, source); fasta.Parser parser = new fasta.Parser(null); AstBuilder astBuilder = new AstBuilder(errorReporter, source.uri, true) ..configureFeatures(featureSet); parser.listener = astBuilder; astBuilder.parser = parser; astBuilder.allowNativeClause = allowNativeClause; parser.parseUnit(_fastaTokens); CompilationUnitImpl unit = astBuilder.pop(); unit.localDeclarations = astBuilder.localDeclarations; expect(unit, isNotNull); return unit; } @override ConditionalExpression parseConditionalExpression(String code) { return _parseExpression(code); } @override Expression parseConstExpression(String code) { return _parseExpression(code); } @override ConstructorInitializer parseConstructorInitializer(String code) { createParser('class __Test { __Test() : $code; }'); CompilationUnit unit = _parserProxy.parseCompilationUnit2(); assertNoErrors(); var clazz = unit.declarations[0] as ClassDeclaration; var constructor = clazz.members[0] as ConstructorDeclaration; return constructor.initializers.single; } @override CompilationUnit parseDirectives(String source, [List errorCodes = const []]) { createParser(source); CompilationUnit unit = _parserProxy.parseDirectives(_parserProxy.currentToken); expect(unit, isNotNull); expect(unit.declarations, hasLength(0)); listener.assertErrorsWithCodes(errorCodes); return unit; } @override BinaryExpression parseEqualityExpression(String code) { return _parseExpression(code); } @override Expression parseExpression(String source, {List codes, List errors, int expectedEndOffset, bool inAsync = false, FeatureSet featureSet}) { createParser(source, expectedEndOffset: expectedEndOffset, featureSet: featureSet); if (inAsync) { _parserProxy.fastaParser.asyncState = AsyncModifier.Async; } Expression result = _parserProxy.parseExpression2(); assertErrors(codes: codes, errors: errors); return result; } @override List parseExpressionList(String code) { return (_parseExpression('[$code]') as ListLiteral) .elements .toList() .cast(); } @override Expression parseExpressionWithoutCascade(String code) { return _parseExpression(code); } @override FormalParameter parseFormalParameter(String code, ParameterKind kind, {List errorCodes: const []}) { String parametersCode; if (kind == ParameterKind.REQUIRED) { parametersCode = '($code)'; } else if (kind == ParameterKind.POSITIONAL) { parametersCode = '([$code])'; } else if (kind == ParameterKind.NAMED) { parametersCode = '({$code})'; } else { fail('$kind'); } FormalParameterList list = parseFormalParameterList(parametersCode, inFunctionType: false, errorCodes: errorCodes); return list.parameters.single; } @override FormalParameterList parseFormalParameterList(String code, {bool inFunctionType: false, List errorCodes: const [], List errors}) { createParser(code); FormalParameterList result = _parserProxy.parseFormalParameterList(inFunctionType: inFunctionType); assertErrors(codes: errors != null ? null : errorCodes, errors: errors); return result; } @override CompilationUnitMember parseFullCompilationUnitMember() { return _parserProxy.parseTopLevelDeclaration(false); } @override Directive parseFullDirective() { return _parserProxy.parseTopLevelDeclaration(true); } @override FunctionExpression parseFunctionExpression(String code) { return _parseExpression(code); } @override InstanceCreationExpression parseInstanceCreationExpression( String code, analyzer.Token newToken) { return _parseExpression('$newToken $code'); } @override ListLiteral parseListLiteral( analyzer.Token token, String typeArgumentsCode, String code) { String sc = ''; if (token != null) { sc += token.lexeme + ' '; } if (typeArgumentsCode != null) { sc += typeArgumentsCode; } sc += code; return _parseExpression(sc); } @override TypedLiteral parseListOrMapLiteral(analyzer.Token modifier, String code) { String literalCode = modifier != null ? '$modifier $code' : code; return parsePrimaryExpression(literalCode) as TypedLiteral; } @override Expression parseLogicalAndExpression(String code) { return _parseExpression(code); } @override Expression parseLogicalOrExpression(String code) { return _parseExpression(code); } @override SetOrMapLiteral parseMapLiteral( analyzer.Token token, String typeArgumentsCode, String code) { String sc = ''; if (token != null) { sc += token.lexeme + ' '; } if (typeArgumentsCode != null) { sc += typeArgumentsCode; } sc += code; return parsePrimaryExpression(sc) as SetOrMapLiteral; } @override MapLiteralEntry parseMapLiteralEntry(String code) { var mapLiteral = parseMapLiteral(null, null, '{ $code }'); return mapLiteral.elements.single; } @override Expression parseMultiplicativeExpression(String code) { return _parseExpression(code); } @override InstanceCreationExpression parseNewExpression(String code) { return _parseExpression(code); } @override NormalFormalParameter parseNormalFormalParameter(String code, {bool inFunctionType: false, List errorCodes: const []}) { FormalParameterList list = parseFormalParameterList('($code)', inFunctionType: inFunctionType, errorCodes: errorCodes); return list.parameters.single; } @override Expression parsePostfixExpression(String code) { return _parseExpression(code); } @override Identifier parsePrefixedIdentifier(String code) { return _parseExpression(code); } @override Expression parsePrimaryExpression(String code, {int expectedEndOffset, List errors}) { createParser(code, expectedEndOffset: expectedEndOffset); Expression result = _parserProxy.parsePrimaryExpression(); assertErrors(codes: null, errors: errors); return result; } @override Expression parseRelationalExpression(String code) { return _parseExpression(code); } @override RethrowExpression parseRethrowExpression(String code) { return _parseExpression(code); } @override BinaryExpression parseShiftExpression(String code) { return _parseExpression(code); } @override SimpleIdentifier parseSimpleIdentifier(String code) { return _parseExpression(code); } @override Statement parseStatement(String source, {int expectedEndOffset, FeatureSet featureSet, bool inAsync = false}) { createParser(source, expectedEndOffset: expectedEndOffset, featureSet: featureSet); if (inAsync) { _parserProxy.fastaParser.asyncState = AsyncModifier.Async; } Statement statement = _parserProxy.parseStatement2(); assertErrors(codes: NO_ERROR_COMPARISON); return statement; } @override Expression parseStringLiteral(String code) { return _parseExpression(code); } @override SymbolLiteral parseSymbolLiteral(String code) { return _parseExpression(code); } @override Expression parseThrowExpression(String code) { return _parseExpression(code); } @override Expression parseThrowExpressionWithoutCascade(String code) { return _parseExpression(code); } @override PrefixExpression parseUnaryExpression(String code) { return _parseExpression(code); } @override VariableDeclarationList parseVariableDeclarationList(String code) { var statement = parseStatement('$code;') as VariableDeclarationStatement; return statement.variables; } Expression _parseExpression(String code) { var statement = parseStatement('$code;') as ExpressionStatement; return statement.expression; } ErrorCode _toFastaGeneratedAnalyzerErrorCode(ErrorCode code) { if (code == ParserErrorCode.ABSTRACT_ENUM || code == ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION || code == ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE || code == ParserErrorCode.ABSTRACT_TYPEDEF || code == ParserErrorCode.CONST_ENUM || code == ParserErrorCode.CONST_TYPEDEF || code == ParserErrorCode.COVARIANT_TOP_LEVEL_DECLARATION || code == ParserErrorCode.FINAL_CLASS || code == ParserErrorCode.FINAL_ENUM || code == ParserErrorCode.FINAL_TYPEDEF || code == ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION) return ParserErrorCode.EXTRANEOUS_MODIFIER; return code; } List _toFastaGeneratedAnalyzerErrorCodes( List expectedErrorCodes) => expectedErrorCodes.map(_toFastaGeneratedAnalyzerErrorCode).toList(); } /** * Tests of the fasta parser based on [FormalParameterParserTestMixin]. */ @reflectiveTest class FormalParameterParserTest_Fasta extends FastaParserTestCase with FormalParameterParserTestMixin { FormalParameter parseNNBDFormalParameter(String code, ParameterKind kind, {List errors}) { String parametersCode; if (kind == ParameterKind.REQUIRED) { parametersCode = '($code)'; } else if (kind == ParameterKind.POSITIONAL) { parametersCode = '([$code])'; } else if (kind == ParameterKind.NAMED) { parametersCode = '({$code})'; } else { fail('$kind'); } createParser(parametersCode, featureSet: nonNullable); FormalParameterList list = _parserProxy.parseFormalParameterList(inFunctionType: false); assertErrors(errors: errors); return list.parameters.single; } void test_parseFormalParameter_covariant_required_named() { ParameterKind kind = ParameterKind.NAMED; FormalParameter parameter = parseNNBDFormalParameter( 'covariant required A a : null', kind, errors: [expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 12, 8)]); expect(parameter, isNotNull); expect(parameter, isDefaultFormalParameter); DefaultFormalParameter defaultParameter = parameter; SimpleFormalParameter simpleParameter = defaultParameter.parameter as SimpleFormalParameter; expect(simpleParameter.covariantKeyword, isNotNull); expect(simpleParameter.requiredKeyword, isNotNull); expect(simpleParameter.identifier, isNotNull); expect(simpleParameter.keyword, isNull); expect(simpleParameter.type, isNotNull); expect(simpleParameter.isNamed, isTrue); expect(defaultParameter.separator, isNotNull); expect(defaultParameter.defaultValue, isNotNull); expect(defaultParameter.isNamed, isTrue); } void test_parseFormalParameter_final_required_named() { ParameterKind kind = ParameterKind.NAMED; FormalParameter parameter = parseNNBDFormalParameter( 'final required a : null', kind, errors: [expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 8, 8)]); expect(parameter, isNotNull); expect(parameter, isDefaultFormalParameter); DefaultFormalParameter defaultParameter = parameter; SimpleFormalParameter simpleParameter = defaultParameter.parameter as SimpleFormalParameter; expect(simpleParameter.covariantKeyword, isNull); expect(simpleParameter.requiredKeyword, isNotNull); expect(simpleParameter.identifier, isNotNull); expect(simpleParameter.keyword, isNotNull); expect(simpleParameter.type, isNull); expect(simpleParameter.isNamed, isTrue); expect(defaultParameter.separator, isNotNull); expect(defaultParameter.defaultValue, isNotNull); expect(defaultParameter.isNamed, isTrue); } void test_parseFormalParameter_required_covariant_named() { ParameterKind kind = ParameterKind.NAMED; FormalParameter parameter = parseNNBDFormalParameter('required covariant A a : null', kind); expect(parameter, isNotNull); expect(parameter, isDefaultFormalParameter); DefaultFormalParameter defaultParameter = parameter; SimpleFormalParameter simpleParameter = defaultParameter.parameter as SimpleFormalParameter; expect(simpleParameter.covariantKeyword, isNotNull); expect(simpleParameter.requiredKeyword, isNotNull); expect(simpleParameter.identifier, isNotNull); expect(simpleParameter.keyword, isNull); expect(simpleParameter.type, isNotNull); expect(simpleParameter.isNamed, isTrue); expect(defaultParameter.separator, isNotNull); expect(defaultParameter.defaultValue, isNotNull); expect(defaultParameter.isNamed, isTrue); } void test_parseFormalParameter_required_final_named() { ParameterKind kind = ParameterKind.NAMED; FormalParameter parameter = parseNNBDFormalParameter('required final a : null', kind); expect(parameter, isNotNull); expect(parameter, isDefaultFormalParameter); DefaultFormalParameter defaultParameter = parameter; SimpleFormalParameter simpleParameter = defaultParameter.parameter as SimpleFormalParameter; expect(simpleParameter.covariantKeyword, isNull); expect(simpleParameter.requiredKeyword, isNotNull); expect(simpleParameter.identifier, isNotNull); expect(simpleParameter.keyword, isNotNull); expect(simpleParameter.type, isNull); expect(simpleParameter.isNamed, isTrue); expect(defaultParameter.separator, isNotNull); expect(defaultParameter.defaultValue, isNotNull); expect(defaultParameter.isNamed, isTrue); } void test_parseFormalParameter_required_type_named() { ParameterKind kind = ParameterKind.NAMED; FormalParameter parameter = parseNNBDFormalParameter('required A a : null', kind); expect(parameter, isNotNull); expect(parameter, isDefaultFormalParameter); DefaultFormalParameter defaultParameter = parameter; SimpleFormalParameter simpleParameter = defaultParameter.parameter as SimpleFormalParameter; expect(simpleParameter.covariantKeyword, isNull); expect(simpleParameter.requiredKeyword, isNotNull); expect(simpleParameter.identifier, isNotNull); expect(simpleParameter.keyword, isNull); expect(simpleParameter.type, isNotNull); expect(simpleParameter.isNamed, isTrue); expect(defaultParameter.separator, isNotNull); expect(defaultParameter.defaultValue, isNotNull); expect(defaultParameter.isNamed, isTrue); } void test_parseFormalParameter_required_var_named() { ParameterKind kind = ParameterKind.NAMED; FormalParameter parameter = parseNNBDFormalParameter('required var a : null', kind); expect(parameter, isNotNull); expect(parameter, isDefaultFormalParameter); DefaultFormalParameter defaultParameter = parameter; SimpleFormalParameter simpleParameter = defaultParameter.parameter as SimpleFormalParameter; expect(simpleParameter.covariantKeyword, isNull); expect(simpleParameter.requiredKeyword, isNotNull); expect(simpleParameter.identifier, isNotNull); expect(simpleParameter.keyword, isNotNull); expect(simpleParameter.type, isNull); expect(simpleParameter.isNamed, isTrue); expect(defaultParameter.separator, isNotNull); expect(defaultParameter.defaultValue, isNotNull); expect(defaultParameter.isNamed, isTrue); } void test_parseFormalParameter_var_required_named() { ParameterKind kind = ParameterKind.NAMED; FormalParameter parameter = parseNNBDFormalParameter( 'var required a : null', kind, errors: [expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 6, 8)]); expect(parameter, isNotNull); expect(parameter, isDefaultFormalParameter); DefaultFormalParameter defaultParameter = parameter; SimpleFormalParameter simpleParameter = defaultParameter.parameter as SimpleFormalParameter; expect(simpleParameter.covariantKeyword, isNull); expect(simpleParameter.requiredKeyword, isNotNull); expect(simpleParameter.identifier, isNotNull); expect(simpleParameter.keyword, isNotNull); expect(simpleParameter.type, isNull); expect(simpleParameter.isNamed, isTrue); expect(defaultParameter.separator, isNotNull); expect(defaultParameter.defaultValue, isNotNull); expect(defaultParameter.isNamed, isTrue); } void test_parseNormalFormalParameter_function_named_nullable() { ParameterKind kind = ParameterKind.NAMED; var defaultParameter = parseFormalParameter('a()? : null', kind) as DefaultFormalParameter; var functionParameter = defaultParameter.parameter as FunctionTypedFormalParameter; assertNoErrors(); expect(functionParameter.returnType, isNull); expect(functionParameter.identifier, isNotNull); expect(functionParameter.typeParameters, isNull); expect(functionParameter.parameters, isNotNull); expect(functionParameter.isNamed, isTrue); expect(functionParameter.question, isNotNull); expect(defaultParameter.separator, isNotNull); expect(defaultParameter.defaultValue, isNotNull); expect(defaultParameter.isNamed, isTrue); } void test_parseNormalFormalParameter_function_noType_nullable() { NormalFormalParameter parameter = parseNNBDFormalParameter('a()?', ParameterKind.REQUIRED); expect(parameter, isNotNull); assertNoErrors(); expect(parameter, isFunctionTypedFormalParameter); FunctionTypedFormalParameter functionParameter = parameter; expect(functionParameter.returnType, isNull); expect(functionParameter.identifier, isNotNull); expect(functionParameter.typeParameters, isNull); expect(functionParameter.parameters, isNotNull); expect(functionParameter.question, isNotNull); } } /** * Tests of the fasta parser based on [ComplexParserTestMixin]. */ @reflectiveTest class NNBDParserTest_Fasta extends FastaParserTestCase { @override CompilationUnit parseCompilationUnit(String content, {List codes, List errors, FeatureSet featureSet}) => super.parseCompilationUnit(content, codes: codes, errors: errors, featureSet: featureSet ?? nonNullable); void test_assignment_complex() { parseCompilationUnit('D? foo(X? x) { X? x1; X? x2 = x + bar(7); }'); } void test_assignment_simple() { parseCompilationUnit('D? foo(X? x) { X? x1; X? x2 = x; }'); } void test_binary_expression_statement() { final unit = parseCompilationUnit('D? foo(X? x) { X ?? x2; }'); FunctionDeclaration funct = unit.declarations[0]; BlockFunctionBody body = funct.functionExpression.body; ExpressionStatement statement = body.block.statements[0]; BinaryExpression expression = statement.expression; SimpleIdentifier lhs = expression.leftOperand; expect(lhs.name, 'X'); expect(expression.operator.lexeme, '??'); SimpleIdentifier rhs = expression.rightOperand; expect(rhs.name, 'x2'); } void test_conditional() { parseCompilationUnit('D? foo(X? x) { X ? 7 : y; }'); } void test_conditional_complex() { parseCompilationUnit('D? foo(X? x) { X ? x2 = x + bar(7) : y; }'); } void test_conditional_error() { parseCompilationUnit('D? foo(X? x) { X ? ? x2 = x + bar(7) : y; }', errors: [ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 19, 1), expectedError(ParserErrorCode.EXPECTED_TOKEN, 40, 1), expectedError(ParserErrorCode.MISSING_IDENTIFIER, 40, 1), ]); } void test_conditional_simple() { parseCompilationUnit('D? foo(X? x) { X ? x2 = x : y; }'); } void test_enableNonNullable_false() { parseCompilationUnit('main() { x is String? ? (x + y) : z; }', errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 20, 1)], featureSet: preNonNullable); } void test_for() { parseCompilationUnit('main() { for(int x = 0; x < 7; ++x) { } }'); } void test_for_conditional() { parseCompilationUnit('main() { for(x ? y = 7 : y = 8; y < 10; ++y) { } }'); } void test_for_nullable() { parseCompilationUnit('main() { for(int? x = 0; x < 7; ++x) { } }'); } void test_foreach() { parseCompilationUnit('main() { for(int x in [7]) { } }'); } void test_foreach_nullable() { parseCompilationUnit('main() { for(int? x in [7, null]) { } }'); } void test_gft_nullable() { parseCompilationUnit('main() { C? Function() x = 7; }'); } void test_gft_nullable_1() { parseCompilationUnit('main() { C Function()? x = 7; }'); } void test_gft_nullable_2() { parseCompilationUnit('main() { C? Function()? x = 7; }'); } void test_gft_nullable_3() { parseCompilationUnit('main() { C? Function()? Function()? x = 7; }'); } void test_gft_nullable_prefixed() { parseCompilationUnit('main() { C.a? Function()? x = 7; }'); } void test_indexed() { CompilationUnit unit = parseCompilationUnit('main() { a[7]; }'); FunctionDeclaration method = unit.declarations[0]; BlockFunctionBody body = method.functionExpression.body; ExpressionStatement statement = body.block.statements[0]; IndexExpression expression = statement.expression; expect(expression.leftBracket.lexeme, '['); } void test_indexed_nullAware() { CompilationUnit unit = parseCompilationUnit('main() { a?.[7]; }'); FunctionDeclaration method = unit.declarations[0]; BlockFunctionBody body = method.functionExpression.body; ExpressionStatement statement = body.block.statements[0]; IndexExpression expression = statement.expression; expect(expression.leftBracket.lexeme, '?.['); expect(expression.rightBracket.lexeme, ']'); expect(expression.leftBracket.endGroup, expression.rightBracket); } void test_indexed_nullAware_optOut() { CompilationUnit unit = parseCompilationUnit(''' // @dart = 2.2 main() { a?.[7]; }''', errors: [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 27, 1)]); FunctionDeclaration method = unit.declarations[0]; BlockFunctionBody body = method.functionExpression.body; ExpressionStatement statement = body.block.statements[0]; PropertyAccess expression = statement.expression; expect(expression.target.toSource(), 'a'); expect(expression.operator.lexeme, '?.'); } void test_is_nullable() { CompilationUnit unit = parseCompilationUnit('main() { x is String? ? (x + y) : z; }'); FunctionDeclaration function = unit.declarations[0]; BlockFunctionBody body = function.functionExpression.body; ExpressionStatement statement = body.block.statements[0]; ConditionalExpression expression = statement.expression; IsExpression condition = expression.condition; expect((condition.type as NamedType).question, isNotNull); Expression thenExpression = expression.thenExpression; expect(thenExpression, isParenthesizedExpression); Expression elseExpression = expression.elseExpression; expect(elseExpression, isSimpleIdentifier); } void test_is_nullable_parenthesis() { CompilationUnit unit = parseCompilationUnit('main() { (x is String?) ? (x + y) : z; }'); FunctionDeclaration function = unit.declarations[0]; BlockFunctionBody body = function.functionExpression.body; ExpressionStatement statement = body.block.statements[0]; ConditionalExpression expression = statement.expression; ParenthesizedExpression condition = expression.condition; IsExpression isExpression = condition.expression; expect((isExpression.type as NamedType).question, isNotNull); Expression thenExpression = expression.thenExpression; expect(thenExpression, isParenthesizedExpression); Expression elseExpression = expression.elseExpression; expect(elseExpression, isSimpleIdentifier); } void test_is_nullable_parenthesis_optOut() { parseCompilationUnit(''' // @dart = 2.2 main() { (x is String?) ? (x + y) : z; } ''', errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 36, 1)]); } void test_late_as_identifier() { parseCompilationUnit(''' class C { int late; } void f(C c) { print(c.late); } main() { f(new C()); } ''', featureSet: preNonNullable); } void test_late_as_identifier_optOut() { parseCompilationUnit(''' // @dart = 2.2 class C { int late; } void f(C c) { print(c.late); } main() { f(new C()); } '''); } void test_nullCheck() { var unit = parseCompilationUnit('f(int? y) { var x = y!; }'); FunctionDeclaration function = unit.declarations[0]; BlockFunctionBody body = function.functionExpression.body; VariableDeclarationStatement statement = body.block.statements[0]; PostfixExpression expression = statement.variables.variables[0].initializer; SimpleIdentifier identifier = expression.operand; expect(identifier.name, 'y'); expect(expression.operator.lexeme, '!'); } void test_nullCheck_disabled() { var unit = parseCompilationUnit('f(int? y) { var x = y!; }', errors: [ expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 5, 1), expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 21, 1), ], featureSet: preNonNullable); FunctionDeclaration function = unit.declarations[0]; BlockFunctionBody body = function.functionExpression.body; VariableDeclarationStatement statement = body.block.statements[0]; SimpleIdentifier identifier = statement.variables.variables[0].initializer; expect(identifier.name, 'y'); } void test_nullCheckAfterGetterAccess() { parseCompilationUnit('f() { var x = g.x!.y + 7; }'); } void test_nullCheckAfterMethodCall() { parseCompilationUnit('f() { var x = g.m()!.y + 7; }'); } void test_nullCheckBeforeGetterAccess() { parseCompilationUnit('f() { var x = g!.x + 7; }'); } void test_nullCheckBeforeMethodCall() { parseCompilationUnit('f() { var x = g!.m() + 7; }'); } void test_nullCheckFunctionResult() { parseCompilationUnit('f() { var x = g()! + 7; }'); } void test_nullCheckIndexedValue() { parseCompilationUnit('f(int? y) { var x = y[0]! + 7; }'); } void test_nullCheckIndexedValue2() { parseCompilationUnit('f(int? y) { var x = super.y[0]! + 7; }'); } void test_nullCheckInExpression() { parseCompilationUnit('f(int? y) { var x = y! + 7; }'); } void test_nullCheckInExpression_disabled() { parseCompilationUnit('f(int? y) { var x = y! + 7; }', errors: [ expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 5, 1), expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 21, 1), ], featureSet: preNonNullable); } void test_nullCheckMethodResult() { parseCompilationUnit('f() { var x = g.m()! + 7; }'); } void test_nullCheckMethodResult2() { parseCompilationUnit('f() { var x = g?.m()! + 7; }'); } void test_nullCheckMethodResult3() { parseCompilationUnit('f() { var x = super.m()! + 7; }'); } void test_nullCheckOnConstConstructor() { parseCompilationUnit('f() { var x = const Foo()!; }'); } void test_nullCheckOnConstructor() { parseCompilationUnit('f() { var x = new Foo()!; }'); } void test_nullCheckOnLiteral_disabled() { parseCompilationUnit('f() { var x = 0!; }', errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 15, 1)], featureSet: preNonNullable); } void test_nullCheckOnLiteralDouble() { // Issues like this should be caught during later analysis parseCompilationUnit('f() { var x = 1.2!; }'); } void test_nullCheckOnLiteralInt() { // Issues like this should be caught during later analysis parseCompilationUnit('f() { var x = 0!; }'); } void test_nullCheckOnLiteralList() { // Issues like this should be caught during later analysis parseCompilationUnit('f() { var x = [1,2]!; }'); } void test_nullCheckOnLiteralMap() { // Issues like this should be caught during later analysis parseCompilationUnit('f() { var x = {1:2}!; }'); } void test_nullCheckOnLiteralSet() { // Issues like this should be caught during later analysis parseCompilationUnit('f() { var x = {1,2}!; }'); } void test_nullCheckOnLiteralString() { // Issues like this should be caught during later analysis parseCompilationUnit('f() { var x = "seven"!; }'); } void test_nullCheckOnNull() { // Issues like this should be caught during later analysis parseCompilationUnit('f() { var x = null!; }'); } void test_nullCheckOnSymbol() { // Issues like this should be caught during later analysis parseCompilationUnit('f() { var x = #seven!; }'); } void test_nullCheckOnValue() { parseCompilationUnit('f(Point p) { var x = p.y! + 7; }'); } void test_nullCheckOnValue_disabled() { parseCompilationUnit('f(Point p) { var x = p.y! + 7; }', errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 24, 1)], featureSet: preNonNullable); } void test_nullCheckParenthesizedExpression() { parseCompilationUnit('f(int? y) { var x = (y)! + 7; }'); } void test_nullCheckPropertyAccess() { parseCompilationUnit('f() { var x = g.p! + 7; }'); } void test_nullCheckPropertyAccess2() { parseCompilationUnit('f() { var x = g?.p! + 7; }'); } void test_nullCheckPropertyAccess3() { parseCompilationUnit('f() { var x = super.p! + 7; }'); } void test_postfix_null_assertion_and_unary_prefix_operator_precedence() { // -x! is parsed as -(x!). var unit = parseCompilationUnit('void main() { -x!; }'); var function = unit.declarations[0] as FunctionDeclaration; var body = function.functionExpression.body as BlockFunctionBody; var statement = body.block.statements[0] as ExpressionStatement; var outerExpression = statement.expression as PrefixExpression; expect(outerExpression.operator.type, TokenType.MINUS); var innerExpression = outerExpression.operand as PostfixExpression; expect(innerExpression.operator.type, TokenType.BANG); } void test_postfix_null_assertion_of_postfix_expression() { // x++! is parsed as (x++)!. var unit = parseCompilationUnit('void main() { x++!; }'); var function = unit.declarations[0] as FunctionDeclaration; var body = function.functionExpression.body as BlockFunctionBody; var statement = body.block.statements[0] as ExpressionStatement; var outerExpression = statement.expression as PostfixExpression; expect(outerExpression.operator.type, TokenType.BANG); var innerExpression = outerExpression.operand as PostfixExpression; expect(innerExpression.operator.type, TokenType.PLUS_PLUS); } } /** * Proxy implementation of the analyzer parser, implemented in terms of the * Fasta parser. * * This allows many of the analyzer parser tests to be run on Fasta, even if * they call into the analyzer parser class directly. */ class ParserProxy extends analyzer.ParserAdapter { /** * The error listener to which scanner and parser errors will be reported. */ final GatheringErrorListener _errorListener; ForwardingTestListener _eventListener; final int expectedEndOffset; /** * Creates a [ParserProxy] which is prepared to begin parsing at the given * Fasta token. */ factory ParserProxy(analyzer.Token firstToken, FeatureSet featureSet, {bool allowNativeClause: false, int expectedEndOffset}) { TestSource source = new TestSource(); var errorListener = new GatheringErrorListener(checkRanges: true); var errorReporter = new ErrorReporter(errorListener, source); return new ParserProxy._( firstToken, errorReporter, null, errorListener, featureSet, allowNativeClause: allowNativeClause, expectedEndOffset: expectedEndOffset); } ParserProxy._(analyzer.Token firstToken, ErrorReporter errorReporter, Uri fileUri, this._errorListener, FeatureSet featureSet, {bool allowNativeClause: false, this.expectedEndOffset}) : super(firstToken, errorReporter, fileUri, allowNativeClause: allowNativeClause) { configureFeatures(featureSet); _eventListener = new ForwardingTestListener(astBuilder); fastaParser.listener = _eventListener; } noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); @override Annotation parseAnnotation() { return _run('MetadataStar', () => super.parseAnnotation()); } @override ArgumentList parseArgumentList() { return _run('unspecified', () => super.parseArgumentList()); } @override ClassMember parseClassMember(String className) { return _run('ClassOrMixinBody', () => super.parseClassMember(className)); } List parseCombinators() { return _run('Import', () => super.parseCombinators()); } @override List parseCommentReferences( List tokens) { for (int index = 0; index < tokens.length - 1; ++index) { analyzer.Token next = tokens[index].next; if (next == null) { tokens[index].setNext(tokens[index + 1]); } else { expect(next, tokens[index + 1]); } } expect(tokens[tokens.length - 1].next, isNull); List references = astBuilder.parseCommentReferences(tokens.first); if (astBuilder.stack.isNotEmpty) { throw 'Expected empty stack, but found:' '\n ${astBuilder.stack.values.join('\n ')}'; } return references; } @override CompilationUnit parseCompilationUnit2() { CompilationUnit result = super.parseCompilationUnit2(); expect(currentToken.isEof, isTrue, reason: currentToken.lexeme); expect(astBuilder.stack, hasLength(0)); _eventListener.expectEmpty(); return result; } @override Configuration parseConfiguration() { return _run('ConditionalUris', () => super.parseConfiguration()); } @override DottedName parseDottedName() { return _run('unspecified', () => super.parseDottedName()); } @override Expression parseExpression2() { return _run('unspecified', () => super.parseExpression2()); } @override FormalParameterList parseFormalParameterList({bool inFunctionType: false}) { return _run('unspecified', () => super.parseFormalParameterList(inFunctionType: inFunctionType)); } @override FunctionBody parseFunctionBody( bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) { Token lastToken; FunctionBody body = _run('unspecified', () { FunctionBody body = super.parseFunctionBody(mayBeEmpty, emptyErrorCode, inExpression); lastToken = currentToken; currentToken = currentToken.next; return body; }); if (!inExpression) { if (![';', '}'].contains(lastToken.lexeme)) { fail('Expected ";" or "}", but found: ${lastToken.lexeme}'); } } return body; } @override Expression parsePrimaryExpression() { return _run('unspecified', () => super.parsePrimaryExpression()); } @override Statement parseStatement(Token token) { return _run('unspecified', () => super.parseStatement(token)); } @override Statement parseStatement2() { return _run('unspecified', () => super.parseStatement2()); } @override AnnotatedNode parseTopLevelDeclaration(bool isDirective) { return _run( 'CompilationUnit', () => super.parseTopLevelDeclaration(isDirective)); } @override TypeAnnotation parseTypeAnnotation(bool inExpression) { return _run('unspecified', () => super.parseTypeAnnotation(inExpression)); } @override TypeArgumentList parseTypeArgumentList() { return _run('unspecified', () => super.parseTypeArgumentList()); } @override TypeName parseTypeName(bool inExpression) { return _run('unspecified', () => super.parseTypeName(inExpression)); } @override TypeParameter parseTypeParameter() { return _run('unspecified', () => super.parseTypeParameter()); } @override TypeParameterList parseTypeParameterList() { return _run('unspecified', () => super.parseTypeParameterList()); } /** * Runs the specified function and returns the result. * It checks the enclosing listener events, * that the parse consumed all of the tokens, * and that the result stack is empty. */ _run(String enclosingEvent, f()) { _eventListener.begin(enclosingEvent); // Simulate error handling of parseUnit by skipping error tokens // before parsing and reporting them after parsing is complete. Token errorToken = currentToken; currentToken = fastaParser.skipErrorTokens(currentToken); var result = f(); fastaParser.reportAllErrorTokens(errorToken); _eventListener.end(enclosingEvent); String lexeme = currentToken is ErrorToken ? currentToken.runtimeType.toString() : currentToken.lexeme; if (expectedEndOffset == null) { expect(currentToken.isEof, isTrue, reason: lexeme); } else { expect(currentToken.offset, expectedEndOffset, reason: lexeme); } expect(astBuilder.stack, hasLength(0)); expect(astBuilder.directives, hasLength(0)); expect(astBuilder.declarations, hasLength(0)); return result; } } @reflectiveTest class RecoveryParserTest_Fasta extends FastaParserTestCase with RecoveryParserTestMixin { @override void test_equalityExpression_precedence_relational_right() { parseExpression("== is", codes: [ ParserErrorCode.EXPECTED_TYPE_NAME, ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.MISSING_IDENTIFIER ]); } void test_incompleteForEach2() { ForStatement statement = parseStatement('for (String item i) {}', featureSet: controlFlow); listener.assertErrors([ expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 4), expectedError(ParserErrorCode.EXPECTED_TOKEN, 17, 1) ]); expect(statement.toSource(), 'for (String item; i;) {}'); ForPartsWithDeclarations forLoopParts = statement.forLoopParts; expect(forLoopParts.leftSeparator, isNotNull); expect(forLoopParts.leftSeparator.type, TokenType.SEMICOLON); expect(forLoopParts.rightSeparator, isNotNull); expect(forLoopParts.rightSeparator.type, TokenType.SEMICOLON); } void test_invalidTypeParameters_super() { parseCompilationUnit('class C {}', errors: [ // TODO(danrubel): Improve recovery. expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 1), expectedError(ParserErrorCode.MISSING_CLASS_BODY, 10, 5), expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 10, 5), expectedError(ParserErrorCode.MISSING_IDENTIFIER, 10, 5), expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 5), expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 16, 1), expectedError(ParserErrorCode.EXPECTED_TOKEN, 16, 1), expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 17, 1), expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 19, 1), ]); } @override void test_relationalExpression_missing_LHS_RHS() { parseExpression("is", codes: [ ParserErrorCode.EXPECTED_TYPE_NAME, ParserErrorCode.MISSING_IDENTIFIER ]); } @override void test_relationalExpression_precedence_shift_right() { parseExpression("<< is", codes: [ ParserErrorCode.EXPECTED_TYPE_NAME, ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.MISSING_IDENTIFIER ]); } } @reflectiveTest class SimpleParserTest_Fasta extends FastaParserTestCase with SimpleParserTestMixin { test_parseArgument() { Expression result = parseArgument('3'); expect(result, const TypeMatcher()); IntegerLiteral literal = result; expect(literal.value, 3); } test_parseArgument_named() { Expression result = parseArgument('foo: "a"'); expect(result, const TypeMatcher()); NamedExpression expression = result; StringLiteral literal = expression.expression; expect(literal.stringValue, 'a'); } @failingTest @override void test_parseCommentReferences_skipLink_direct_multiLine() => super.test_parseCommentReferences_skipLink_direct_multiLine(); @failingTest @override void test_parseCommentReferences_skipLink_reference_multiLine() => super.test_parseCommentReferences_skipLink_reference_multiLine(); void test_parseVariableDeclaration_final_late() { var statement = parseStatement('final late a;', featureSet: nonNullable) as VariableDeclarationStatement; var declarationList = statement.variables; assertErrors( errors: [expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 6, 4)]); expect(declarationList.keyword.lexeme, 'final'); expect(declarationList.type, isNull); expect(declarationList.variables, hasLength(1)); } void test_parseVariableDeclaration_late() { var statement = parseStatement('late a;', featureSet: nonNullable) as VariableDeclarationStatement; var declarationList = statement.variables; assertNoErrors(); expect(declarationList.keyword, isNull); expect(declarationList.type, isNull); expect(declarationList.variables, hasLength(1)); } void test_parseVariableDeclaration_late_final() { var statement = parseStatement('late final a;', featureSet: nonNullable) as VariableDeclarationStatement; var declarationList = statement.variables; assertNoErrors(); expect(declarationList.keyword.lexeme, 'final'); expect(declarationList.type, isNull); expect(declarationList.variables, hasLength(1)); } void test_parseVariableDeclaration_late_init() { var statement = parseStatement('late a = 0;', featureSet: nonNullable) as VariableDeclarationStatement; var declarationList = statement.variables; assertNoErrors(); expect(declarationList.keyword, isNull); expect(declarationList.type, isNull); expect(declarationList.variables, hasLength(1)); } void test_parseVariableDeclaration_late_type() { var statement = parseStatement('late A a;', featureSet: nonNullable) as VariableDeclarationStatement; var declarationList = statement.variables; assertNoErrors(); expect(declarationList.lateKeyword, isNotNull); expect(declarationList.keyword, isNull); expect(declarationList.type, isNotNull); expect(declarationList.variables, hasLength(1)); } } /** * Tests of the fasta parser based on [StatementParserTestMixin]. */ @reflectiveTest class StatementParserTest_Fasta extends FastaParserTestCase with StatementParserTestMixin { void test_35177() { ExpressionStatement statement = parseStatement('(f)()();'); FunctionExpressionInvocation funct1 = statement.expression; NodeList typeArgs = funct1.typeArguments.arguments; expect(typeArgs, hasLength(1)); TypeName typeName = typeArgs[0]; expect(typeName.name.name, 'int'); expect(funct1.argumentList.arguments, hasLength(0)); FunctionExpressionInvocation funct2 = funct1.function; expect(funct2.typeArguments, isNull); expect(funct2.argumentList.arguments, hasLength(0)); ParenthesizedExpression expression = funct2.function; SimpleIdentifier identifier = expression.expression; expect(identifier.name, 'f'); } void test_invalid_typeArg_34850() { var unit = parseCompilationUnit('foo Future> bar() {}', errors: [ expectedError(ParserErrorCode.EXPECTED_TOKEN, 11, 4), expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 4, 6), expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 22, 3), ]); // Validate that recovery has properly updated the token stream. analyzer.Token token = unit.beginToken; while (!token.isEof) { expect(token.type, isNot(TokenType.GT_GT)); analyzer.Token next = token.next; expect(next.previous, token); token = next; } } void test_parseForStatement_each_await2() { ForStatement forStatement = parseStatement( 'await for (element in list) {}', inAsync: true, featureSet: controlFlow, ); assertNoErrors(); expect(forStatement.awaitKeyword, isNotNull); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForEachPartsWithIdentifier forLoopParts = forStatement.forLoopParts; expect(forLoopParts.identifier, isNotNull); expect(forLoopParts.inKeyword, isNotNull); expect(forLoopParts.iterable, isNotNull); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_each_finalExternal() { ForStatement forStatement = parseStatement( 'for (final external in list) {}', featureSet: controlFlow, ); assertNoErrors(); expect(forStatement.awaitKeyword, isNull); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForEachPartsWithDeclaration forLoopParts = forStatement.forLoopParts; expect(forLoopParts.loopVariable.identifier.name, 'external'); expect(forLoopParts.inKeyword, isNotNull); expect(forLoopParts.iterable, isNotNull); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_each_finalRequired() { ForStatement forStatement = parseStatement( 'for (final required in list) {}', featureSet: controlFlow, ); assertNoErrors(); expect(forStatement.awaitKeyword, isNull); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForEachPartsWithDeclaration forLoopParts = forStatement.forLoopParts; expect(forLoopParts.loopVariable.identifier.name, 'required'); expect(forLoopParts.inKeyword, isNotNull); expect(forLoopParts.iterable, isNotNull); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_each_genericFunctionType2() { ForStatement forStatement = parseStatement( 'for (void Function(T) element in list) {}', featureSet: controlFlow, ); assertNoErrors(); expect(forStatement.awaitKeyword, isNull); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForEachPartsWithDeclaration forLoopParts = forStatement.forLoopParts; expect(forLoopParts.loopVariable, isNotNull); expect(forLoopParts.inKeyword, isNotNull); expect(forLoopParts.iterable, isNotNull); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_each_identifier2() { ForStatement forStatement = parseStatement( 'for (element in list) {}', featureSet: controlFlow, ); assertNoErrors(); expect(forStatement.awaitKeyword, isNull); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForEachPartsWithIdentifier forLoopParts = forStatement.forLoopParts; expect(forLoopParts.identifier, isNotNull); expect(forLoopParts.inKeyword, isNotNull); expect(forLoopParts.iterable, isNotNull); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_each_noType_metadata2() { ForStatement forStatement = parseStatement( 'for (@A var element in list) {}', featureSet: controlFlow, ); assertNoErrors(); expect(forStatement.awaitKeyword, isNull); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForEachPartsWithDeclaration forLoopParts = forStatement.forLoopParts; expect(forLoopParts.loopVariable, isNotNull); expect(forLoopParts.loopVariable.metadata, hasLength(1)); expect(forLoopParts.inKeyword, isNotNull); expect(forLoopParts.iterable, isNotNull); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_each_type2() { ForStatement forStatement = parseStatement( 'for (A element in list) {}', featureSet: controlFlow, ); assertNoErrors(); expect(forStatement.awaitKeyword, isNull); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForEachPartsWithDeclaration forLoopParts = forStatement.forLoopParts; expect(forLoopParts.loopVariable, isNotNull); expect(forLoopParts.inKeyword, isNotNull); expect(forLoopParts.iterable, isNotNull); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_each_var2() { ForStatement forStatement = parseStatement( 'for (var element in list) {}', featureSet: controlFlow, ); assertNoErrors(); expect(forStatement.awaitKeyword, isNull); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForEachPartsWithDeclaration forLoopParts = forStatement.forLoopParts; expect(forLoopParts.loopVariable, isNotNull); expect(forLoopParts.inKeyword, isNotNull); expect(forLoopParts.iterable, isNotNull); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_loop_c2() { ForStatement forStatement = parseStatement( 'for (; i < count;) {}', featureSet: controlFlow, ); assertNoErrors(); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForPartsWithExpression forLoopParts = forStatement.forLoopParts; expect(forLoopParts.initialization, isNull); expect(forLoopParts.leftSeparator, isNotNull); expect(forLoopParts.condition, isNotNull); expect(forLoopParts.rightSeparator, isNotNull); expect(forLoopParts.updaters, hasLength(0)); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_loop_cu2() { ForStatement forStatement = parseStatement( 'for (; i < count; i++) {}', featureSet: controlFlow, ); assertNoErrors(); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForPartsWithExpression forLoopParts = forStatement.forLoopParts; expect(forLoopParts.initialization, isNull); expect(forLoopParts.leftSeparator, isNotNull); expect(forLoopParts.condition, isNotNull); expect(forLoopParts.rightSeparator, isNotNull); expect(forLoopParts.updaters, hasLength(1)); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_loop_ecu2() { ForStatement forStatement = parseStatement( 'for (i--; i < count; i++) {}', featureSet: spread, ); assertNoErrors(); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForPartsWithExpression forLoopParts = forStatement.forLoopParts; expect(forLoopParts.initialization, isNotNull); expect(forLoopParts.leftSeparator, isNotNull); expect(forLoopParts.condition, isNotNull); expect(forLoopParts.rightSeparator, isNotNull); expect(forLoopParts.updaters, hasLength(1)); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_loop_i2() { ForStatement forStatement = parseStatement( 'for (var i = 0;;) {}', featureSet: spread, ); assertNoErrors(); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForPartsWithDeclarations forLoopParts = forStatement.forLoopParts; VariableDeclarationList variables = forLoopParts.variables; expect(variables, isNotNull); expect(variables.metadata, hasLength(0)); expect(variables.variables, hasLength(1)); expect(forLoopParts.leftSeparator, isNotNull); expect(forLoopParts.condition, isNull); expect(forLoopParts.rightSeparator, isNotNull); expect(forLoopParts.updaters, hasLength(0)); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_loop_i_withMetadata2() { ForStatement forStatement = parseStatement( 'for (@A var i = 0;;) {}', featureSet: spread, ); assertNoErrors(); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForPartsWithDeclarations forLoopParts = forStatement.forLoopParts; VariableDeclarationList variables = forLoopParts.variables; expect(variables, isNotNull); expect(variables.metadata, hasLength(1)); expect(variables.variables, hasLength(1)); expect(forLoopParts.leftSeparator, isNotNull); expect(forLoopParts.condition, isNull); expect(forLoopParts.rightSeparator, isNotNull); expect(forLoopParts.updaters, hasLength(0)); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_loop_ic2() { ForStatement forStatement = parseStatement( 'for (var i = 0; i < count;) {}', featureSet: spread, ); assertNoErrors(); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForPartsWithDeclarations forLoopParts = forStatement.forLoopParts; VariableDeclarationList variables = forLoopParts.variables; expect(variables, isNotNull); expect(variables.variables, hasLength(1)); expect(forLoopParts.leftSeparator, isNotNull); expect(forLoopParts.condition, isNotNull); expect(forLoopParts.rightSeparator, isNotNull); expect(forLoopParts.updaters, hasLength(0)); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_loop_icu2() { ForStatement forStatement = parseStatement( 'for (var i = 0; i < count; i++) {}', featureSet: spread, ); assertNoErrors(); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForPartsWithDeclarations forLoopParts = forStatement.forLoopParts; VariableDeclarationList variables = forLoopParts.variables; expect(variables, isNotNull); expect(variables.variables, hasLength(1)); expect(forLoopParts.leftSeparator, isNotNull); expect(forLoopParts.condition, isNotNull); expect(forLoopParts.rightSeparator, isNotNull); expect(forLoopParts.updaters, hasLength(1)); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_loop_iicuu2() { ForStatement forStatement = parseStatement( 'for (int i = 0, j = count; i < j; i++, j--) {}', featureSet: spread, ); assertNoErrors(); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForPartsWithDeclarations forLoopParts = forStatement.forLoopParts; VariableDeclarationList variables = forLoopParts.variables; expect(variables, isNotNull); expect(variables.variables, hasLength(2)); expect(forLoopParts.leftSeparator, isNotNull); expect(forLoopParts.condition, isNotNull); expect(forLoopParts.rightSeparator, isNotNull); expect(forLoopParts.updaters, hasLength(2)); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_loop_iu2() { ForStatement forStatement = parseStatement( 'for (var i = 0;; i++) {}', featureSet: spread, ); assertNoErrors(); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForPartsWithDeclarations forLoopParts = forStatement.forLoopParts; VariableDeclarationList variables = forLoopParts.variables; expect(variables, isNotNull); expect(variables.variables, hasLength(1)); expect(forLoopParts.leftSeparator, isNotNull); expect(forLoopParts.condition, isNull); expect(forLoopParts.rightSeparator, isNotNull); expect(forLoopParts.updaters, hasLength(1)); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_parseForStatement_loop_u2() { ForStatement forStatement = parseStatement( 'for (;; i++) {}', featureSet: spread, ); assertNoErrors(); expect(forStatement.forKeyword, isNotNull); expect(forStatement.leftParenthesis, isNotNull); ForPartsWithExpression forLoopParts = forStatement.forLoopParts; expect(forLoopParts.initialization, isNull); expect(forLoopParts.leftSeparator, isNotNull); expect(forLoopParts.condition, isNull); expect(forLoopParts.rightSeparator, isNotNull); expect(forLoopParts.updaters, hasLength(1)); expect(forStatement.rightParenthesis, isNotNull); expect(forStatement.body, isNotNull); } void test_partial_typeArg1_34850() { var unit = parseCompilationUnit('()); ClassDeclaration declaration = member; expect(declaration.nativeClause, isNotNull); expect(declaration.nativeClause.nativeKeyword, isNotNull); expect(declaration.nativeClause.name, isNull); expect(declaration.endToken.type, TokenType.CLOSE_CURLY_BRACKET); } void test_parseClassDeclaration_native_missing_literal_allowed() { allowNativeClause = true; test_parseClassDeclaration_native_missing_literal(); } void test_parseClassDeclaration_native_missing_literal_not_allowed() { allowNativeClause = false; test_parseClassDeclaration_native_missing_literal(); } void test_parseClassDeclaration_native_not_allowed() { allowNativeClause = false; test_parseClassDeclaration_native(); } void test_parseMixinDeclaration_empty() { createParser('mixin A {}'); MixinDeclaration declaration = parseFullCompilationUnitMember(); expect(declaration, isNotNull); assertNoErrors(); expect(declaration.metadata, isEmpty); expect(declaration.documentationComment, isNull); expect(declaration.onClause, isNull); expect(declaration.implementsClause, isNull); expect(declaration.mixinKeyword, isNotNull); expect(declaration.leftBracket, isNotNull); expect(declaration.name.name, 'A'); expect(declaration.members, hasLength(0)); expect(declaration.rightBracket, isNotNull); expect(declaration.typeParameters, isNull); } void test_parseMixinDeclaration_implements() { createParser('mixin A implements B {}'); MixinDeclaration declaration = parseFullCompilationUnitMember(); expect(declaration, isNotNull); assertNoErrors(); expect(declaration.metadata, isEmpty); expect(declaration.documentationComment, isNull); expect(declaration.onClause, isNull); ImplementsClause implementsClause = declaration.implementsClause; expect(implementsClause.implementsKeyword, isNotNull); NodeList interfaces = implementsClause.interfaces; expect(interfaces, hasLength(1)); expect(interfaces[0].name.name, 'B'); expect(interfaces[0].typeArguments, isNull); expect(declaration.mixinKeyword, isNotNull); expect(declaration.leftBracket, isNotNull); expect(declaration.name.name, 'A'); expect(declaration.members, hasLength(0)); expect(declaration.rightBracket, isNotNull); expect(declaration.typeParameters, isNull); } void test_parseMixinDeclaration_implements2() { createParser('mixin A implements B, C {}'); MixinDeclaration declaration = parseFullCompilationUnitMember(); expect(declaration, isNotNull); assertNoErrors(); expect(declaration.metadata, isEmpty); expect(declaration.documentationComment, isNull); expect(declaration.onClause, isNull); ImplementsClause implementsClause = declaration.implementsClause; expect(implementsClause.implementsKeyword, isNotNull); NodeList interfaces = implementsClause.interfaces; expect(interfaces, hasLength(2)); expect(interfaces[0].name.name, 'B'); expect(interfaces[0].typeArguments.arguments, hasLength(1)); expect(interfaces[1].name.name, 'C'); expect(interfaces[1].typeArguments, isNull); expect(declaration.mixinKeyword, isNotNull); expect(declaration.leftBracket, isNotNull); expect(declaration.name.name, 'A'); expect(declaration.members, hasLength(0)); expect(declaration.rightBracket, isNotNull); expect(declaration.typeParameters, isNull); } void test_parseMixinDeclaration_metadata() { createParser('@Z mixin A {}'); MixinDeclaration declaration = parseFullCompilationUnitMember(); expect(declaration, isNotNull); assertNoErrors(); NodeList metadata = declaration.metadata; expect(metadata, hasLength(1)); expect(metadata[0].name.name, 'Z'); expect(declaration.documentationComment, isNull); expect(declaration.onClause, isNull); expect(declaration.implementsClause, isNull); expect(declaration.mixinKeyword, isNotNull); expect(declaration.leftBracket, isNotNull); expect(declaration.name.name, 'A'); expect(declaration.members, hasLength(0)); expect(declaration.rightBracket, isNotNull); expect(declaration.typeParameters, isNull); } void test_parseMixinDeclaration_on() { createParser('mixin A on B {}'); MixinDeclaration declaration = parseFullCompilationUnitMember(); expect(declaration, isNotNull); assertNoErrors(); expect(declaration.metadata, isEmpty); expect(declaration.documentationComment, isNull); OnClause onClause = declaration.onClause; expect(onClause.onKeyword, isNotNull); NodeList constraints = onClause.superclassConstraints; expect(constraints, hasLength(1)); expect(constraints[0].name.name, 'B'); expect(constraints[0].typeArguments, isNull); expect(declaration.implementsClause, isNull); expect(declaration.mixinKeyword, isNotNull); expect(declaration.leftBracket, isNotNull); expect(declaration.name.name, 'A'); expect(declaration.members, hasLength(0)); expect(declaration.rightBracket, isNotNull); expect(declaration.typeParameters, isNull); } void test_parseMixinDeclaration_on2() { createParser('mixin A on B, C {}'); MixinDeclaration declaration = parseFullCompilationUnitMember(); expect(declaration, isNotNull); assertNoErrors(); expect(declaration.metadata, isEmpty); expect(declaration.documentationComment, isNull); OnClause onClause = declaration.onClause; expect(onClause.onKeyword, isNotNull); NodeList constraints = onClause.superclassConstraints; expect(constraints, hasLength(2)); expect(constraints[0].name.name, 'B'); expect(constraints[0].typeArguments, isNull); expect(constraints[1].name.name, 'C'); expect(constraints[1].typeArguments.arguments, hasLength(1)); expect(declaration.implementsClause, isNull); expect(declaration.mixinKeyword, isNotNull); expect(declaration.leftBracket, isNotNull); expect(declaration.name.name, 'A'); expect(declaration.members, hasLength(0)); expect(declaration.rightBracket, isNotNull); expect(declaration.typeParameters, isNull); } void test_parseMixinDeclaration_onAndImplements() { createParser('mixin A on B implements C {}'); MixinDeclaration declaration = parseFullCompilationUnitMember(); expect(declaration, isNotNull); assertNoErrors(); expect(declaration.metadata, isEmpty); expect(declaration.documentationComment, isNull); OnClause onClause = declaration.onClause; expect(onClause.onKeyword, isNotNull); NodeList constraints = onClause.superclassConstraints; expect(constraints, hasLength(1)); expect(constraints[0].name.name, 'B'); expect(constraints[0].typeArguments, isNull); ImplementsClause implementsClause = declaration.implementsClause; expect(implementsClause.implementsKeyword, isNotNull); NodeList interfaces = implementsClause.interfaces; expect(interfaces, hasLength(1)); expect(interfaces[0].name.name, 'C'); expect(interfaces[0].typeArguments, isNull); expect(declaration.mixinKeyword, isNotNull); expect(declaration.leftBracket, isNotNull); expect(declaration.name.name, 'A'); expect(declaration.members, hasLength(0)); expect(declaration.rightBracket, isNotNull); expect(declaration.typeParameters, isNull); } void test_parseMixinDeclaration_simple() { createParser(''' mixin A { int f; int get g => f; set s(int v) {f = v;} int add(int v) => f = f + v; }'''); MixinDeclaration declaration = parseFullCompilationUnitMember(); expect(declaration, isNotNull); assertNoErrors(); expect(declaration.metadata, isEmpty); expect(declaration.documentationComment, isNull); expect(declaration.onClause, isNull); expect(declaration.implementsClause, isNull); expect(declaration.mixinKeyword, isNotNull); expect(declaration.leftBracket, isNotNull); expect(declaration.name.name, 'A'); expect(declaration.members, hasLength(4)); expect(declaration.rightBracket, isNotNull); expect(declaration.typeParameters, isNull); } void test_parseMixinDeclaration_withDocumentationComment() { createParser('/// Doc\nmixin M {}'); MixinDeclaration declaration = parseFullCompilationUnitMember(); expectCommentText(declaration.documentationComment, '/// Doc'); } void test_parseTopLevelVariable_final_late() { var unit = parseCompilationUnit('final late a;', featureSet: nonNullable, errors: [expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 6, 4)]); var declaration = unit.declarations[0] as TopLevelVariableDeclaration; var declarationList = declaration.variables; expect(declarationList.keyword.lexeme, 'final'); expect(declarationList.type, isNull); expect(declarationList.variables, hasLength(1)); } void test_parseTopLevelVariable_late() { var unit = parseCompilationUnit('late a;', featureSet: nonNullable); var declaration = unit.declarations[0] as TopLevelVariableDeclaration; var declarationList = declaration.variables; expect(declarationList.keyword, isNull); expect(declarationList.type, isNull); expect(declarationList.variables, hasLength(1)); } void test_parseTopLevelVariable_late_final() { var unit = parseCompilationUnit('late final a;', featureSet: nonNullable); var declaration = unit.declarations[0] as TopLevelVariableDeclaration; var declarationList = declaration.variables; expect(declarationList.keyword.lexeme, 'final'); expect(declarationList.type, isNull); expect(declarationList.variables, hasLength(1)); } void test_parseTopLevelVariable_late_init() { var unit = parseCompilationUnit('late a = 0;', featureSet: nonNullable); var declaration = unit.declarations[0] as TopLevelVariableDeclaration; var declarationList = declaration.variables; expect(declarationList.keyword, isNull); expect(declarationList.type, isNull); expect(declarationList.variables, hasLength(1)); } void test_parseTopLevelVariable_late_type() { var unit = parseCompilationUnit('late A a;', featureSet: nonNullable); var declaration = unit.declarations[0] as TopLevelVariableDeclaration; var declarationList = declaration.variables; expect(declarationList.lateKeyword, isNotNull); expect(declarationList.keyword, isNull); expect(declarationList.type, isNotNull); expect(declarationList.variables, hasLength(1)); } }