| // 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:_fe_analyzer_shared/src/parser/async_modifier.dart'; |
| import 'package:_fe_analyzer_shared/src/parser/parser.dart' as fasta; |
| import 'package:_fe_analyzer_shared/src/scanner/error_token.dart' |
| show ErrorToken; |
| import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' as fasta; |
| import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' |
| show ScannerConfiguration, ScannerResult, scanString; |
| 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, LanguageVersionToken; |
| 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: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); |
| defineReflectiveTests(VarianceParserTest_Fasta); |
| }); |
| } |
| |
| /// Type of the "parse..." methods defined in the Fasta parser. |
| typedef ParseFunction = analyzer.Token Function(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_parse_member_called_late() { |
| CompilationUnitImpl unit = parseCompilationUnit( |
| 'class C { void late() { new C().late(); } }', |
| featureSet: nonNullable); |
| 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, 'late'); |
| expect(method.operatorKeyword, isNull); |
| expect(method.typeParameters, isNull); |
| expect(method.parameters, isNotNull); |
| expect(method.body, isNotNull); |
| |
| BlockFunctionBody body = method.body; |
| ExpressionStatement statement = body.block.statements[0]; |
| MethodInvocation invocation = statement.expression; |
| expect(invocation.operator.lexeme, '.'); |
| expect(invocation.toSource(), 'new C().late()'); |
| } |
| |
| void test_parseClassMember_finalAndCovariantLateWithInitializer() { |
| createParser( |
| 'covariant late final int f = 0;', |
| featureSet: nonNullable, |
| ); |
| parser.parseClassMember('C'); |
| assertErrors(errors: [ |
| expectedError( |
| ParserErrorCode.FINAL_AND_COVARIANT_LATE_WITH_INITIALIZER, 0, 9) |
| ]); |
| } |
| |
| 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<Statement> 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_parseConstructor_invalidInitializer() { |
| // https://github.com/dart-lang/sdk/issues/37693 |
| parseCompilationUnit('class C{ C() : super() * (); }', errors: [ |
| expectedError(ParserErrorCode.INVALID_INITIALIZER, 15, 12), |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 26, 1), |
| ]); |
| } |
| |
| void test_parseConstructor_nullSuperArgList_openBrace_37735() { |
| // https://github.com/dart-lang/sdk/issues/37735 |
| var unit = parseCompilationUnit('class{const():super.{n', errors: [ |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 5, 1), |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 11, 1), |
| expectedError(ParserErrorCode.INVALID_CONSTRUCTOR_NAME, 11, 1), |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 20, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 20, 1), |
| expectedError(ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, 20, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 21, 1), |
| expectedError(ScannerErrorCode.EXPECTED_TOKEN, 22, 1), |
| expectedError(ScannerErrorCode.EXPECTED_TOKEN, 22, 1), |
| ]); |
| var classDeclaration = unit.declarations[0] as ClassDeclaration; |
| var constructor = classDeclaration.members[0] as ConstructorDeclaration; |
| var invocation = constructor.initializers[0] as SuperConstructorInvocation; |
| expect(invocation.argumentList.arguments, hasLength(0)); |
| } |
| |
| void test_parseConstructor_operator_name() { |
| var unit = parseCompilationUnit('class A { operator/() : super(); }', |
| errors: [ |
| expectedError(ParserErrorCode.INVALID_CONSTRUCTOR_NAME, 10, 8) |
| ]); |
| var classDeclaration = unit.declarations[0] as ClassDeclaration; |
| var constructor = classDeclaration.members[0] as ConstructorDeclaration; |
| var invocation = constructor.initializers[0] as SuperConstructorInvocation; |
| expect(invocation.argumentList.arguments, hasLength(0)); |
| } |
| |
| void test_parseField_abstract() { |
| createParser('abstract int i;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertNoErrors(); |
| expect(member, isFieldDeclaration); |
| FieldDeclaration field = member; |
| expect(field.abstractKeyword, isNotNull); |
| } |
| |
| void test_parseField_abstract_external() { |
| createParser('abstract external int i;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertErrors(errors: [ |
| expectedError(ParserErrorCode.ABSTRACT_EXTERNAL_FIELD, 0, 8), |
| ]); |
| expect(member, isFieldDeclaration); |
| FieldDeclaration field = member; |
| expect(field.abstractKeyword, isNotNull); |
| expect(field.externalKeyword, isNotNull); |
| } |
| |
| void test_parseField_abstract_late() { |
| createParser('abstract late int? i;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertErrors(errors: [ |
| expectedError(ParserErrorCode.ABSTRACT_LATE_FIELD, 0, 8), |
| ]); |
| expect(member, isFieldDeclaration); |
| FieldDeclaration field = member; |
| expect(field.abstractKeyword, isNotNull); |
| } |
| |
| void test_parseField_abstract_late_final() { |
| createParser('abstract late final int? i;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertErrors(errors: [ |
| expectedError(ParserErrorCode.ABSTRACT_LATE_FIELD, 0, 8), |
| ]); |
| expect(member, isFieldDeclaration); |
| FieldDeclaration field = member; |
| expect(field.abstractKeyword, isNotNull); |
| } |
| |
| void test_parseField_abstract_static() { |
| createParser('abstract static int? i;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertErrors(errors: [ |
| expectedError(ParserErrorCode.ABSTRACT_STATIC_FIELD, 0, 8), |
| ]); |
| expect(member, isFieldDeclaration); |
| FieldDeclaration field = member; |
| expect(field.abstractKeyword, isNotNull); |
| } |
| |
| 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<VariableDeclaration> variables = list.variables; |
| expect(variables, hasLength(1)); |
| VariableDeclaration variable = variables[0]; |
| expect(variable.name, isNotNull); |
| } |
| |
| void test_parseField_external() { |
| createParser('external int i;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertNoErrors(); |
| expect(member, isFieldDeclaration); |
| FieldDeclaration field = member; |
| expect(field.externalKeyword, isNotNull); |
| } |
| |
| void test_parseField_external_abstract() { |
| createParser('external abstract int i;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertErrors(errors: [ |
| expectedError(ParserErrorCode.ABSTRACT_EXTERNAL_FIELD, 9, 8), |
| ]); |
| expect(member, isFieldDeclaration); |
| FieldDeclaration field = member; |
| expect(field.abstractKeyword, isNotNull); |
| expect(field.externalKeyword, isNotNull); |
| } |
| |
| void test_parseField_external_late() { |
| createParser('external late int? i;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertErrors(errors: [ |
| expectedError(ParserErrorCode.EXTERNAL_LATE_FIELD, 0, 8), |
| ]); |
| expect(member, isFieldDeclaration); |
| FieldDeclaration field = member; |
| expect(field.externalKeyword, isNotNull); |
| } |
| |
| void test_parseField_external_late_final() { |
| createParser('external late final int? i;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertErrors(errors: [ |
| expectedError(ParserErrorCode.EXTERNAL_LATE_FIELD, 0, 8), |
| ]); |
| expect(member, isFieldDeclaration); |
| FieldDeclaration field = member; |
| expect(field.externalKeyword, isNotNull); |
| } |
| |
| void test_parseField_external_static() { |
| createParser('external static int? i;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertNoErrors(); |
| expect(member, isFieldDeclaration); |
| FieldDeclaration field = member; |
| expect(field.externalKeyword, 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<VariableDeclaration> 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<VariableDeclaration> 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<VariableDeclaration> 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<VariableDeclaration> 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); |
| 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<VariableDeclaration> variables = list.variables; |
| expect(variables, hasLength(1)); |
| VariableDeclaration variable = variables[0]; |
| expect(variable.name, isNotNull); |
| } |
| |
| void test_parseField_non_abstract() { |
| createParser('int i;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertNoErrors(); |
| expect(member, isFieldDeclaration); |
| FieldDeclaration field = member; |
| expect(field.abstractKeyword, isNull); |
| } |
| |
| void test_parseField_non_external() { |
| createParser('int i;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertNoErrors(); |
| expect(member, isFieldDeclaration); |
| FieldDeclaration field = member; |
| expect(field.externalKeyword, isNull); |
| } |
| |
| void test_parseField_var_late() { |
| createParser('var late f;', featureSet: nonNullable); |
| ClassMember member = parser.parseClassMember('C'); |
| expect(member, isNotNull); |
| assertErrors(errors: [ |
| expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 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<VariableDeclaration> 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<ErrorCode> codes, |
| List<ExpectedError> 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('<int, int>{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('<int, int>{...{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('<int, int>{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('<int, int>{...?{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('<int>{...[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('<int>{...?[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_cascade_synthetic() { |
| // https://github.com/dart-lang/sdk/issues/37110 |
| parseCompilationUnit('class B extends A { B(): super.. {} }', errors: [ |
| expectedError(ParserErrorCode.INVALID_SUPER_IN_INITIALIZER, 25, 5), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 30, 2), |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 33, 1), |
| ]); |
| } |
| |
| 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_super_named_method() { |
| // https://github.com/dart-lang/sdk/issues/37600 |
| parseCompilationUnit('class B extends A { B(): super.c().create() {} }', |
| errors: [ |
| expectedError(ParserErrorCode.INVALID_SUPER_IN_INITIALIZER, 25, 5), |
| ]); |
| } |
| |
| void test_constructor_super_named_method_method() { |
| // https://github.com/dart-lang/sdk/issues/37600 |
| parseCompilationUnit('class B extends A { B(): super.c().create().x() {} }', |
| errors: [ |
| expectedError(ParserErrorCode.INVALID_SUPER_IN_INITIALIZER, 25, 5), |
| ]); |
| } |
| |
| void test_constructor_this_cascade_synthetic() { |
| // https://github.com/dart-lang/sdk/issues/37110 |
| parseCompilationUnit('class B extends A { B(): this.. {} }', errors: [ |
| expectedError(ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER, 25, 4), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 29, 2), |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 32, 1), |
| ]); |
| } |
| |
| 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), |
| ]); |
| } |
| |
| void test_constructor_this_named_method() { |
| // https://github.com/dart-lang/sdk/issues/37600 |
| parseCompilationUnit('class B extends A { B(): super.c().create() {} }', |
| errors: [ |
| expectedError(ParserErrorCode.INVALID_SUPER_IN_INITIALIZER, 25, 5), |
| ]); |
| } |
| |
| void test_constructor_this_named_method_field() { |
| // https://github.com/dart-lang/sdk/issues/37600 |
| parseCompilationUnit('class B extends A { B(): super.c().create().x {} }', |
| errors: [ |
| expectedError(ParserErrorCode.INVALID_SUPER_IN_INITIALIZER, 25, 5), |
| ]); |
| } |
| |
| @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_missing_closing_bracket_issue37528() { |
| final code = '\${foo'; |
| createParser(code); |
| final result = fasta.scanString(code); |
| expect(result.hasErrors, isTrue); |
| var token = _parserProxy.fastaParser.syntheticPreviousToken(result.tokens); |
| try { |
| _parserProxy.fastaParser.parseExpression(token); |
| // TODO(danrubel): Replace this test once root cause is found |
| fail('exception expected'); |
| } catch (e) { |
| var msg = e.toString(); |
| expect(msg.contains('test_missing_closing_bracket_issue37528'), isTrue); |
| } |
| } |
| |
| 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.fromEnableFlags2( |
| sdkLanguageVersion: Version.parse('2.2.0'), |
| flags: [], |
| ); |
| |
| 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_invalidExpression_37706() { |
| // https://github.com/dart-lang/sdk/issues/37706 |
| parseExpression('<b?c>()', errors: [ |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 1, 1), |
| expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 7, 0), |
| expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 7, 0), |
| ]); |
| } |
| |
| void test_listLiteral_invalid_assert() { |
| // https://github.com/dart-lang/sdk/issues/37674 |
| parseExpression('n=<.["\$assert', errors: [ |
| expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 3, 1), |
| expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 4, 1), |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 7, 6), |
| expectedError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 12, 1), |
| expectedError(ScannerErrorCode.EXPECTED_TOKEN, 13, 1), |
| ]); |
| } |
| |
| void test_listLiteral_invalidElement_37697() { |
| // https://github.com/dart-lang/sdk/issues/37674 |
| parseExpression('[<y.<z>(){}]', errors: [ |
| expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 4, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 1), |
| ]); |
| } |
| |
| 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_lt_dot_bracket_quote() { |
| // https://github.com/dart-lang/sdk/issues/37674 |
| ListLiteral list = parseExpression('<.["', errors: [ |
| expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 1, 1), |
| expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 2, 1), |
| expectedError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 3, 1), |
| expectedError(ScannerErrorCode.EXPECTED_TOKEN, 4, 1), |
| ]); |
| expect(list.elements, hasLength(1)); |
| StringLiteral first = list.elements[0]; |
| expect(first.length, 1); |
| } |
| |
| void test_lt_dot_listLiteral() { |
| // https://github.com/dart-lang/sdk/issues/37674 |
| ListLiteral list = parseExpression('<.[]', errors: [ |
| expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 1, 1), |
| expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 2, 2), |
| ]); |
| expect(list.elements, hasLength(0)); |
| } |
| |
| 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('<int, int>{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('<int, int, int>{}', 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('<int, int, int>{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('<int, int>{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('<int, int>{...{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('<int, int>{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('<int, int>{...?{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)); |
| } |
| |
| void test_parseConstructorInitializer_functionExpression() { |
| // https://github.com/dart-lang/sdk/issues/37414 |
| parseCompilationUnit('class C { C.n() : this()(); }', errors: [ |
| expectedError(ParserErrorCode.INVALID_INITIALIZER, 18, 8), |
| ]); |
| } |
| |
| void test_parseStringLiteral_interpolated_void() { |
| Expression expression = parseStringLiteral(r"'<html>$void</html>'"); |
| expect(expression, isNotNull); |
| assertErrors( |
| errors: [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 4)]); |
| expect(expression, isStringInterpolation); |
| StringInterpolation literal = expression; |
| NodeList<InterpolationElement> elements = literal.elements; |
| expect(elements, hasLength(3)); |
| expect(elements[0] is InterpolationString, isTrue); |
| expect(elements[1] is InterpolationExpression, isTrue); |
| expect(elements[2] is InterpolationString, isTrue); |
| expect((elements[1] as InterpolationExpression).leftBracket.lexeme, '\$'); |
| expect((elements[1] as InterpolationExpression).rightBracket, isNull); |
| } |
| |
| @override |
| @failingTest |
| void test_parseUnaryExpression_decrement_super() { |
| // TODO(danrubel) Reports a different error and different token stream. |
| // Expected: TokenType:<MINUS> |
| // Actual: TokenType:<MINUS_MINUS> |
| 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:<MINUS> |
| // Actual: TokenType:<MINUS_MINUS> |
| 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 <int>{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('<int>{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('<Set<int>>{{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('<int>{...[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('<int>{...?[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('<int>{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 { |
| 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<T> { }'); |
| 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<T> on C<T> { }'); |
| 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<T> on C<T> { }'); |
| 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_constructor_named() { |
| var unit = parseCompilationUnit(''' |
| extension E on C { |
| E.named(); |
| } |
| class C {} |
| ''', errors: [ |
| expectedError(ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 21, 1), |
| ]); |
| expect(unit.declarations, hasLength(2)); |
| var extension = unit.declarations[0] as ExtensionDeclaration; |
| expect(extension.members, hasLength(0)); |
| } |
| |
| void test_constructor_unnamed() { |
| var unit = parseCompilationUnit(''' |
| extension E on C { |
| E(); |
| } |
| class C {} |
| ''', errors: [ |
| expectedError(ParserErrorCode.EXTENSION_DECLARES_CONSTRUCTOR, 21, 1), |
| ]); |
| expect(unit.declarations, hasLength(2)); |
| var extension = unit.declarations[0] as ExtensionDeclaration; |
| 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.EXPECTED_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_parse_toplevel_member_called_late_calling_self() { |
| CompilationUnitImpl unit = parseCompilationUnit('void late() { late(); }', |
| featureSet: nonNullable); |
| FunctionDeclaration method = unit.declarations[0]; |
| |
| expect(method.documentationComment, isNull); |
| expect(method.externalKeyword, isNull); |
| expect(method.propertyKeyword, isNull); |
| expect(method.returnType, isNotNull); |
| expect(method.name.name, 'late'); |
| expect(method.functionExpression, isNotNull); |
| |
| BlockFunctionBody body = method.functionExpression.body; |
| ExpressionStatement statement = body.block.statements[0]; |
| MethodInvocation invocation = statement.expression; |
| expect(invocation.operator, isNull); |
| expect(invocation.toSource(), 'late()'); |
| } |
| |
| 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.fromEnableFlags2( |
| sdkLanguageVersion: Version.parse('2.3.0'), |
| flags: [], |
| ), |
| ); |
| } |
| |
| 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)); |
| } |
| |
| void test_void_type() { |
| var unit = parseCompilationUnit('extension E on void { }'); |
| 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, 'void'); |
| expect(extension.members, hasLength(0)); |
| } |
| } |
| |
| /// Implementation of [AbstractParserTestCase] specialized for testing the |
| /// Fasta parser. |
| class FastaParserTestCase |
| with ParserTestHelpers |
| implements AbstractParserTestCase { |
| static final List<ErrorCode> NO_ERROR_COMPARISON = <ErrorCode>[]; |
| |
| 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; |
| |
| @override |
| set enableOptionalNewAndConst(bool enable) { |
| // ignored |
| } |
| |
| @override |
| set enableUriInPartOf(bool value) { |
| if (value == false) { |
| throw 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<ErrorCode> codes, List<ExpectedError> 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<ErrorCode> 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 = ParserProxy(_fastaTokens, featureSet, |
| allowNativeClause: allowNativeClause, |
| expectedEndOffset: expectedEndOffset); |
| } |
| |
| @override |
| ExpectedError expectedError(ErrorCode code, int offset, int length) => |
| 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; |
| } |
| |
| @override |
| 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<CommentReference> references = comment.references; |
| if (references.isEmpty) { |
| return null; |
| } else { |
| expect(references, hasLength(1)); |
| return references[0]; |
| } |
| } |
| |
| @override |
| CompilationUnit parseCompilationUnit(String content, |
| {List<ErrorCode> codes, |
| List<ExpectedError> errors, |
| FeatureSet featureSet}) { |
| GatheringErrorListener listener = 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, |
| {LanguageVersionToken languageVersion, FeatureSet featureSet}) { |
| featureSet ??= FeatureSet.forTesting(); |
| var source = 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 = ErrorReporter( |
| listener, |
| source, |
| isNonNullableByDefault: false, |
| ); |
| fasta.Parser parser = fasta.Parser(null); |
| AstBuilder astBuilder = |
| AstBuilder(errorReporter, source.uri, true, featureSet); |
| parser.listener = astBuilder; |
| astBuilder.parser = parser; |
| astBuilder.allowNativeClause = allowNativeClause; |
| parser.parseUnit(_fastaTokens); |
| CompilationUnitImpl unit = astBuilder.pop(); |
| |
| 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<ErrorCode> errorCodes = const <ErrorCode>[]]) { |
| 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<ErrorCode> codes, |
| List<ExpectedError> 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<Expression> parseExpressionList(String code) { |
| return (_parseExpression('[$code]') as ListLiteral) |
| .elements |
| .toList() |
| .cast<Expression>(); |
| } |
| |
| @override |
| Expression parseExpressionWithoutCascade(String code) { |
| return _parseExpression(code); |
| } |
| |
| @override |
| FormalParameter parseFormalParameter(String code, ParameterKind kind, |
| {List<ErrorCode> errorCodes = const <ErrorCode>[]}) { |
| 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<ErrorCode> errorCodes = const <ErrorCode>[], |
| List<ExpectedError> 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<ErrorCode> errorCodes = const <ErrorCode>[]}) { |
| 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<ExpectedError> 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<ErrorCode> _toFastaGeneratedAnalyzerErrorCodes( |
| List<ErrorCode> 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<ExpectedError> 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_fieldFormalParameter_function_nullable() { |
| var parameter = |
| parseNNBDFormalParameter('void this.a()?', ParameterKind.REQUIRED); |
| expect(parameter, isNotNull); |
| assertNoErrors(); |
| expect(parameter, isFieldFormalParameter); |
| FieldFormalParameter functionParameter = parameter; |
| expect(functionParameter.type, isNotNull); |
| expect(functionParameter.identifier, isNotNull); |
| expect(functionParameter.typeParameters, isNull); |
| expect(functionParameter.parameters, isNotNull); |
| expect(functionParameter.question, isNotNull); |
| expect(functionParameter.endToken, functionParameter.question); |
| } |
| |
| void test_functionTyped_named_nullable() { |
| ParameterKind kind = ParameterKind.NAMED; |
| var defaultParameter = |
| parseNNBDFormalParameter('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_functionTyped_named_nullable_disabled() { |
| ParameterKind kind = ParameterKind.NAMED; |
| var defaultParameter = parseFormalParameter('a()? : null', kind, |
| errorCodes: [ParserErrorCode.EXPERIMENT_NOT_ENABLED]) |
| as DefaultFormalParameter; |
| var functionParameter = |
| defaultParameter.parameter as FunctionTypedFormalParameter; |
| 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_functionTyped_positional_nullable_disabled() { |
| ParameterKind kind = ParameterKind.POSITIONAL; |
| var defaultParameter = parseFormalParameter('a()? = null', kind, |
| errorCodes: [ParserErrorCode.EXPERIMENT_NOT_ENABLED]) |
| as DefaultFormalParameter; |
| var functionParameter = |
| defaultParameter.parameter as FunctionTypedFormalParameter; |
| expect(functionParameter.returnType, isNull); |
| expect(functionParameter.identifier, isNotNull); |
| expect(functionParameter.typeParameters, isNull); |
| expect(functionParameter.parameters, isNotNull); |
| expect(functionParameter.isOptionalPositional, isTrue); |
| expect(functionParameter.question, isNotNull); |
| expect(defaultParameter.separator, isNotNull); |
| expect(defaultParameter.defaultValue, isNotNull); |
| expect(defaultParameter.isOptionalPositional, isTrue); |
| } |
| |
| void test_functionTyped_required_nullable_disabled() { |
| ParameterKind kind = ParameterKind.REQUIRED; |
| var functionParameter = parseFormalParameter('a()?', kind, |
| errorCodes: [ParserErrorCode.EXPERIMENT_NOT_ENABLED]) |
| as FunctionTypedFormalParameter; |
| expect(functionParameter.returnType, isNull); |
| expect(functionParameter.identifier, isNotNull); |
| expect(functionParameter.typeParameters, isNull); |
| expect(functionParameter.parameters, isNotNull); |
| expect(functionParameter.isRequiredPositional, isTrue); |
| expect(functionParameter.question, isNotNull); |
| } |
| |
| 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_external() { |
| parseNNBDFormalParameter('external int i', ParameterKind.REQUIRED, errors: [ |
| expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 1, 8), |
| ]); |
| } |
| |
| 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_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); |
| expect(functionParameter.endToken, functionParameter.question); |
| } |
| } |
| |
| /// Tests of the fasta parser based on [ComplexParserTestMixin]. |
| @reflectiveTest |
| class NNBDParserTest_Fasta extends FastaParserTestCase { |
| @override |
| CompilationUnit parseCompilationUnit(String content, |
| {List<ErrorCode> codes, |
| List<ExpectedError> 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_complex2() { |
| parseCompilationUnit(r''' |
| main() { |
| A? a; |
| String? s = ''; |
| a?..foo().length..x27 = s!..toString().length; |
| } |
| '''); |
| } |
| |
| void test_assignment_simple() { |
| parseCompilationUnit('D? foo(X? x) { X? x1; X? x2 = x; }'); |
| } |
| |
| void test_bangBeforeFuctionCall1() { |
| // https://github.com/dart-lang/sdk/issues/39776 |
| var unit = parseCompilationUnit('f() { Function? f1; f1!(42); }'); |
| var funct = unit.declarations[0] as FunctionDeclaration; |
| var body = funct.functionExpression.body as BlockFunctionBody; |
| var statement1 = body.block.statements[0] as VariableDeclarationStatement; |
| expect(statement1.toSource(), "Function? f1;"); |
| var statement2 = body.block.statements[1] as ExpressionStatement; |
| |
| // expression is "f1!(42)" |
| var expression = statement2.expression as FunctionExpressionInvocation; |
| expect(expression.toSource(), "f1!(42)"); |
| |
| var functionExpression = expression.function as PostfixExpression; |
| SimpleIdentifier identifier = functionExpression.operand; |
| expect(identifier.name, 'f1'); |
| expect(functionExpression.operator.lexeme, '!'); |
| |
| expect(expression.typeArguments, null); |
| |
| expect(expression.argumentList.arguments.length, 1); |
| IntegerLiteral argument = expression.argumentList.arguments.single; |
| expect(argument.value, 42); |
| } |
| |
| void test_bangBeforeFuctionCall2() { |
| // https://github.com/dart-lang/sdk/issues/39776 |
| var unit = parseCompilationUnit('f() { Function f2; f2!<int>(42); }'); |
| var funct = unit.declarations[0] as FunctionDeclaration; |
| var body = funct.functionExpression.body as BlockFunctionBody; |
| var statement1 = body.block.statements[0] as VariableDeclarationStatement; |
| expect(statement1.toSource(), "Function f2;"); |
| var statement2 = body.block.statements[1] as ExpressionStatement; |
| |
| // expression is "f2!<int>(42)" |
| var expression = statement2.expression as FunctionExpressionInvocation; |
| expect(expression.toSource(), "f2!<int>(42)"); |
| |
| var functionExpression = expression.function as PostfixExpression; |
| SimpleIdentifier identifier = functionExpression.operand; |
| expect(identifier.name, 'f2'); |
| expect(functionExpression.operator.lexeme, '!'); |
| |
| expect(expression.typeArguments.arguments.length, 1); |
| TypeName typeArgument = expression.typeArguments.arguments.single; |
| expect(typeArgument.name.name, "int"); |
| |
| expect(expression.argumentList.arguments.length, 1); |
| IntegerLiteral argument = expression.argumentList.arguments.single; |
| expect(argument.value, 42); |
| } |
| |
| void test_bangQuestionIndex() { |
| // http://dartbug.com/41177 |
| CompilationUnit unit = parseCompilationUnit('f(dynamic a) { a!?[0]; }'); |
| FunctionDeclaration funct = unit.declarations[0]; |
| BlockFunctionBody body = funct.functionExpression.body; |
| |
| ExpressionStatement statement = body.block.statements[0]; |
| IndexExpression expression = statement.expression; |
| |
| IntegerLiteral index = expression.index; |
| expect(index.value, 0); |
| |
| Token question = expression.question; |
| expect(question, isNotNull); |
| expect(question.lexeme, "?"); |
| |
| PostfixExpression target = expression.target; |
| SimpleIdentifier identifier = target.operand; |
| expect(identifier.name, 'a'); |
| expect(target.operator.lexeme, '!'); |
| } |
| |
| 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_cascade_withNullCheck_indexExpression() { |
| var unit = parseCompilationUnit('main() { a?..[27]; }'); |
| FunctionDeclaration funct = unit.declarations[0]; |
| BlockFunctionBody body = funct.functionExpression.body; |
| ExpressionStatement statement = body.block.statements[0]; |
| CascadeExpression cascade = statement.expression; |
| IndexExpression indexExpression = cascade.cascadeSections[0]; |
| expect(indexExpression.period.lexeme, '?..'); |
| expect(indexExpression.toSource(), '?..[27]'); |
| } |
| |
| void test_cascade_withNullCheck_invalid() { |
| parseCompilationUnit('main() { a..[27]?..x; }', errors: [ |
| expectedError(ParserErrorCode.NULL_AWARE_CASCADE_OUT_OF_ORDER, 16, 3), |
| ]); |
| } |
| |
| void test_cascade_withNullCheck_methodInvocation() { |
| var unit = parseCompilationUnit('main() { a?..foo(); }'); |
| FunctionDeclaration funct = unit.declarations[0]; |
| BlockFunctionBody body = funct.functionExpression.body; |
| ExpressionStatement statement = body.block.statements[0]; |
| CascadeExpression cascade = statement.expression; |
| MethodInvocation invocation = cascade.cascadeSections[0]; |
| expect(invocation.operator.lexeme, '?..'); |
| expect(invocation.toSource(), '?..foo()'); |
| } |
| |
| void test_cascade_withNullCheck_propertyAccess() { |
| var unit = parseCompilationUnit('main() { a?..x27; }'); |
| FunctionDeclaration funct = unit.declarations[0]; |
| BlockFunctionBody body = funct.functionExpression.body; |
| ExpressionStatement statement = body.block.statements[0]; |
| CascadeExpression cascade = statement.expression; |
| PropertyAccess propertyAccess = cascade.cascadeSections[0]; |
| expect(propertyAccess.operator.lexeme, '?..'); |
| expect(propertyAccess.toSource(), '?..x27'); |
| } |
| |
| 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_functionTypedFormalParameter_nullable_disabled() { |
| parseCompilationUnit('void f(void p()?) {}', |
| errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 15, 1)], |
| featureSet: preNonNullable); |
| } |
| |
| test_fuzz_38113() async { |
| // https://github.com/dart-lang/sdk/issues/38113 |
| await parseCompilationUnit(r'+t{{r?this}}', errors: [ |
| expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 0, 1), |
| expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 1, 1), |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 4), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 1), |
| ]); |
| } |
| |
| 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.question, isNotNull); |
| 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.EXPERIMENT_NOT_ENABLED, 25, 1)]); |
| FunctionDeclaration method = unit.declarations[0]; |
| BlockFunctionBody body = method.functionExpression.body; |
| ExpressionStatement statement = body.block.statements[0]; |
| IndexExpressionImpl expression = statement.expression; |
| expect(expression.target.toSource(), 'a'); |
| expect(expression.question, isNotNull); |
| expect(expression.leftBracket.lexeme, '['); |
| expect(expression.rightBracket.lexeme, ']'); |
| expect(expression.leftBracket.endGroup, expression.rightBracket); |
| } |
| |
| void test_indexExpression_nullable_disabled() { |
| parseCompilationUnit('main(a) { a?[0]; }', |
| errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 11, 1)], |
| featureSet: preNonNullable); |
| } |
| |
| 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_nullableTypeInInitializerList_01() { |
| // http://dartbug.com/40834 |
| var unit = parseCompilationUnit(r''' |
| class Foo { |
| String? x; |
| int y; |
| |
| Foo(Object? o) : x = o as String?, y = 0; |
| } |
| '''); |
| ClassDeclaration classDeclaration = unit.declarations.first; |
| ConstructorDeclaration constructor = classDeclaration.getConstructor(null); |
| |
| // Object? o |
| SimpleFormalParameter parameter = constructor.parameters.parameters.single; |
| expect(parameter.identifier.name, 'o'); |
| TypeName type = parameter.type; |
| expect(type.question.lexeme, '?'); |
| expect(type.name.name, 'Object'); |
| |
| expect(constructor.initializers.length, 2); |
| |
| // o as String? |
| { |
| ConstructorFieldInitializer initializer = constructor.initializers[0]; |
| expect(initializer.fieldName.name, 'x'); |
| AsExpression expression = initializer.expression; |
| SimpleIdentifier identifier = expression.expression; |
| expect(identifier.name, 'o'); |
| TypeName expressionType = expression.type; |
| expect(expressionType.question.lexeme, '?'); |
| expect(expressionType.name.name, 'String'); |
| } |
| |
| // y = 0 |
| { |
| ConstructorFieldInitializer initializer = constructor.initializers[1]; |
| expect(initializer.fieldName.name, 'y'); |
| IntegerLiteral expression = initializer.expression; |
| expect(expression.value, 0); |
| } |
| } |
| |
| void test_nullableTypeInInitializerList_02() { |
| var unit = parseCompilationUnit(r''' |
| class Foo { |
| String? x; |
| int y; |
| |
| Foo(Object? o) : y = o is String? ? o.length : null, x = null; |
| } |
| '''); |
| ClassDeclaration classDeclaration = unit.declarations.first; |
| ConstructorDeclaration constructor = classDeclaration.getConstructor(null); |
| |
| // Object? o |
| SimpleFormalParameter parameter = constructor.parameters.parameters.single; |
| expect(parameter.identifier.name, 'o'); |
| TypeName type = parameter.type; |
| expect(type.question.lexeme, '?'); |
| expect(type.name.name, 'Object'); |
| |
| expect(constructor.initializers.length, 2); |
| |
| // y = o is String? ? o.length : null |
| { |
| ConstructorFieldInitializer initializer = constructor.initializers[0]; |
| expect(initializer.fieldName.name, 'y'); |
| ConditionalExpression expression = initializer.expression; |
| IsExpression condition = expression.condition; |
| SimpleIdentifier identifier = condition.expression; |
| expect(identifier.name, 'o'); |
| TypeName expressionType = condition.type; |
| expect(expressionType.question.lexeme, '?'); |
| expect(expressionType.name.name, 'String'); |
| PrefixedIdentifier thenExpression = expression.thenExpression; |
| expect(thenExpression.identifier.name, 'length'); |
| expect(thenExpression.prefix.name, 'o'); |
| NullLiteral elseExpression = expression.elseExpression; |
| expect(elseExpression, isNotNull); |
| } |
| |
| // x = null |
| { |
| ConstructorFieldInitializer initializer = constructor.initializers[1]; |
| expect(initializer.fieldName.name, 'x'); |
| NullLiteral expression = initializer.expression; |
| expect(expression, isNotNull); |
| } |
| } |
| |
| void test_nullableTypeInInitializerList_03() { |
| // As test_nullableTypeInInitializerList_02 but without ? on String in is. |
| var unit = parseCompilationUnit(r''' |
| class Foo { |
| String? x; |
| int y; |
| |
| Foo(Object? o) : y = o is String ? o.length : null, x = null; |
| } |
| '''); |
| ClassDeclaration classDeclaration = unit.declarations.first; |
| ConstructorDeclaration constructor = classDeclaration.getConstructor(null); |
| |
| // Object? o |
| SimpleFormalParameter parameter = constructor.parameters.parameters.single; |
| expect(parameter.identifier.name, 'o'); |
| TypeName type = parameter.type; |
| expect(type.question.lexeme, '?'); |
| expect(type.name.name, 'Object'); |
| |
| expect(constructor.initializers.length, 2); |
| |
| // y = o is String ? o.length : null |
| { |
| ConstructorFieldInitializer initializer = constructor.initializers[0]; |
| expect(initializer.fieldName.name, 'y'); |
| ConditionalExpression expression = initializer.expression; |
| IsExpression condition = expression.condition; |
| SimpleIdentifier identifier = condition.expression; |
| expect(identifier.name, 'o'); |
| TypeName expressionType = condition.type; |
| expect(expressionType.question, isNull); |
| expect(expressionType.name.name, 'String'); |
| PrefixedIdentifier thenExpression = expression.thenExpression; |
| expect(thenExpression.identifier.name, 'length'); |
| expect(thenExpression.prefix.name, 'o'); |
| NullLiteral elseExpression = expression.elseExpression; |
| expect(elseExpression, isNotNull); |
| } |
| |
| // x = null |
| { |
| ConstructorFieldInitializer initializer = constructor.initializers[1]; |
| expect(initializer.fieldName.name, 'x'); |
| NullLiteral expression = initializer.expression; |
| expect(expression, isNotNull); |
| } |
| } |
| |
| 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_nullCheckBeforeIndex() { |
| // https://github.com/dart-lang/sdk/issues/37708 |
| var unit = parseCompilationUnit('f() { foo.bar!.baz[arg]; }'); |
| var funct = unit.declarations[0] as FunctionDeclaration; |
| var body = funct.functionExpression.body as BlockFunctionBody; |
| var statement = body.block.statements[0] as ExpressionStatement; |
| var expression = statement.expression as IndexExpression; |
| expect(expression.index.toSource(), 'arg'); |
| var propertyAccess = expression.target as PropertyAccess; |
| expect(propertyAccess.propertyName.toSource(), 'baz'); |
| var target = propertyAccess.target as PostfixExpression; |
| expect(target.operand.toSource(), 'foo.bar'); |
| expect(target.operator.lexeme, '!'); |
| } |
| |
| 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_nullCheckOnIndex() { |
| // https://github.com/dart-lang/sdk/issues/37708 |
| var unit = parseCompilationUnit('f() { obj![arg]; }'); |
| var funct = unit.declarations[0] as FunctionDeclaration; |
| var body = funct.functionExpression.body as BlockFunctionBody; |
| var statement = body.block.statements[0] as ExpressionStatement; |
| var expression = statement.expression as IndexExpression; |
| var target = expression.target as PostfixExpression; |
| expect(target.operand.toSource(), 'obj'); |
| expect(target.operator.lexeme, '!'); |
| } |
| |
| void test_nullCheckOnIndex2() { |
| // https://github.com/dart-lang/sdk/issues/37708 |
| var unit = parseCompilationUnit('f() { obj![arg]![arg2]; }'); |
| var funct = unit.declarations[0] as FunctionDeclaration; |
| var body = funct.functionExpression.body as BlockFunctionBody; |
| var statement = body.block.statements[0] as ExpressionStatement; |
| var expression = statement.expression as IndexExpression; |
| expect(expression.index.toSource(), 'arg2'); |
| var target = expression.target as PostfixExpression; |
| expect(target.operator.lexeme, '!'); |
| expression = target.operand as IndexExpression; |
| expect(expression.index.toSource(), 'arg'); |
| target = expression.target as PostfixExpression; |
| expect(target.operator.lexeme, '!'); |
| expect(target.operand.toSource(), 'obj'); |
| } |
| |
| void test_nullCheckOnIndex3() { |
| // https://github.com/dart-lang/sdk/issues/37708 |
| var unit = parseCompilationUnit('f() { foo.bar![arg]; }'); |
| var funct = unit.declarations[0] as FunctionDeclaration; |
| var body = funct.functionExpression.body as BlockFunctionBody; |
| var statement = body.block.statements[0] as ExpressionStatement; |
| var expression = statement.expression as IndexExpression; |
| expect(expression.index.toSource(), 'arg'); |
| var target = expression.target as PostfixExpression; |
| expect(target.operand.toSource(), 'foo.bar'); |
| expect(target.operator.lexeme, '!'); |
| } |
| |
| void test_nullCheckOnIndex4() { |
| // https://github.com/dart-lang/sdk/issues/37708 |
| var unit = parseCompilationUnit('f() { foo!.bar![arg]; }'); |
| var funct = unit.declarations[0] as FunctionDeclaration; |
| var body = funct.functionExpression.body as BlockFunctionBody; |
| var statement = body.block.statements[0] as ExpressionStatement; |
| var expression = statement.expression as IndexExpression; |
| var fooBarTarget = expression.target as PostfixExpression; |
| expect(fooBarTarget.toSource(), "foo!.bar!"); |
| var propertyAccess = fooBarTarget.operand as PropertyAccess; |
| var targetFoo = propertyAccess.target as PostfixExpression; |
| expect(targetFoo.operand.toSource(), "foo"); |
| expect(targetFoo.operator.lexeme, "!"); |
| expect(propertyAccess.propertyName.toSource(), "bar"); |
| expect(fooBarTarget.operator.lexeme, '!'); |
| expect(expression.index.toSource(), 'arg'); |
| } |
| |
| void test_nullCheckOnIndex5() { |
| // https://github.com/dart-lang/sdk/issues/37708 |
| var unit = parseCompilationUnit('f() { foo.bar![arg]![arg2]; }'); |
| var funct = unit.declarations[0] as FunctionDeclaration; |
| var body = funct.functionExpression.body as BlockFunctionBody; |
| var statement = body.block.statements[0] as ExpressionStatement; |
| var expression = statement.expression as IndexExpression; |
| expect(expression.index.toSource(), 'arg2'); |
| var target = expression.target as PostfixExpression; |
| expect(target.operator.lexeme, '!'); |
| expression = target.operand as IndexExpression; |
| expect(expression.index.toSource(), 'arg'); |
| target = expression.target as PostfixExpression; |
| expect(target.operator.lexeme, '!'); |
| expect(target.operand.toSource(), 'foo.bar'); |
| } |
| |
| void test_nullCheckOnIndex6() { |
| // https://github.com/dart-lang/sdk/issues/37708 |
| var unit = parseCompilationUnit('f() { foo!.bar![arg]![arg2]; }'); |
| var funct = unit.declarations[0] as FunctionDeclaration; |
| var body = funct.functionExpression.body as BlockFunctionBody; |
| var statement = body.block.statements[0] as ExpressionStatement; |
| |
| // expression is "foo!.bar![arg]![arg2]" |
| var expression = statement.expression as IndexExpression; |
| expect(expression.index.toSource(), 'arg2'); |
| |
| // target is "foo!.bar![arg]!" |
| var target = expression.target as PostfixExpression; |
| expect(target.operator.lexeme, '!'); |
| |
| // expression is "foo!.bar![arg]" |
| expression = target.operand as IndexExpression; |
| expect(expression.index.toSource(), 'arg'); |
| |
| // target is "foo!.bar!" |
| target = expression.target as PostfixExpression; |
| expect(target.operator.lexeme, '!'); |
| |
| // propertyAccess is "foo!.bar" |
| PropertyAccess propertyAccess = target.operand as PropertyAccess; |
| expect(propertyAccess.propertyName.toSource(), "bar"); |
| |
| // target is "foo!" |
| target = propertyAccess.target as PostfixExpression; |
| expect(target.operator.lexeme, '!'); |
| |
| expect(target.operand.toSource(), "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_nullCheckOnSend() { |
| // https://github.com/dart-lang/sdk/issues/37708 |
| var unit = parseCompilationUnit('f() { obj!(arg); }'); |
| var funct = unit.declarations[0] as FunctionDeclaration; |
| var body = funct.functionExpression.body as BlockFunctionBody; |
| var statement = body.block.statements[0] as ExpressionStatement; |
| var expression = statement.expression as FunctionExpressionInvocation; |
| var target = expression.function as PostfixExpression; |
| expect(target.operand.toSource(), 'obj'); |
| expect(target.operator.lexeme, '!'); |
| } |
| |
| void test_nullCheckOnSend2() { |
| // https://github.com/dart-lang/sdk/issues/37708 |
| var unit = parseCompilationUnit('f() { obj!(arg)!(arg2); }'); |
| var funct = unit.declarations[0] as FunctionDeclaration; |
| var body = funct.functionExpression.body as BlockFunctionBody; |
| var statement = body.block.statements[0] as ExpressionStatement; |
| var expression = statement.expression as FunctionExpressionInvocation; |
| expect(expression.argumentList.toSource(), '(arg2)'); |
| var target = expression.function as PostfixExpression; |
| expect(target.operator.lexeme, '!'); |
| expression = target.operand as FunctionExpressionInvocation; |
| expect(expression.argumentList.toSource(), '(arg)'); |
| target = expression.function as PostfixExpression; |
| expect(target.operator.lexeme, '!'); |
| expect(target.operand.toSource(), 'obj'); |
| } |
| |
| 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); |
| } |
| |
| void test_typeName_nullable_disabled() { |
| parseCompilationUnit('int? x;', |
| errors: [expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 3, 1)], |
| featureSet: preNonNullable); |
| } |
| } |
| |
| /// 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 = TestSource(); |
| var errorListener = GatheringErrorListener(checkRanges: true); |
| var errorReporter = ErrorReporter( |
| errorListener, |
| source, |
| isNonNullableByDefault: false, |
| ); |
| return 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, featureSet, |
| allowNativeClause: allowNativeClause) { |
| _eventListener = ForwardingTestListener(astBuilder); |
| fastaParser.listener = _eventListener; |
| } |
| |
| @override |
| 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)); |
| } |
| |
| @override |
| List<Combinator> parseCombinators() { |
| return _run('Import', () => super.parseCombinators()); |
| } |
| |
| @override |
| List<CommentReference> parseCommentReferences( |
| List<DocumentationCommentToken> 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<CommentReference> 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, Function() 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<X super Y> {}', errors: [ |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 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 { |
| void test_method_name_notNull_37733() { |
| // https://github.com/dart-lang/sdk/issues/37733 |
| var unit = parseCompilationUnit(r'class C { f(<T>()); }', errors: [ |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 12, 1), |
| ]); |
| var classDeclaration = unit.declarations[0] as ClassDeclaration; |
| var method = classDeclaration.members[0] as MethodDeclaration; |
| expect(method.parameters.parameters, hasLength(1)); |
| var parameter = |
| method.parameters.parameters[0] as FunctionTypedFormalParameter; |
| expect(parameter.identifier, isNotNull); |
| } |
| |
| test_parseArgument() { |
| Expression result = parseArgument('3'); |
| expect(result, const TypeMatcher<IntegerLiteral>()); |
| IntegerLiteral literal = result; |
| expect(literal.value, 3); |
| } |
| |
| test_parseArgument_named() { |
| Expression result = parseArgument('foo: "a"'); |
| expect(result, const TypeMatcher<NamedExpression>()); |
| 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)); |
| } |
| |
| void test_parseVariableDeclaration_late_var() { |
| var statement = parseStatement('late var a;', featureSet: nonNullable) |
| as VariableDeclarationStatement; |
| var declarationList = statement.variables; |
| assertNoErrors(); |
| expect(declarationList.lateKeyword, isNotNull); |
| expect(declarationList.keyword?.lexeme, 'var'); |
| expect(declarationList.type, isNull); |
| expect(declarationList.variables, hasLength(1)); |
| } |
| |
| void test_typeAlias_37733() { |
| // https://github.com/dart-lang/sdk/issues/37733 |
| var unit = parseCompilationUnit(r'typedef K=Function(<>($', errors: [ |
| expectedError(CompileTimeErrorCode.INVALID_INLINE_FUNCTION_TYPE, 19, 1), |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 19, 1), |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 20, 1), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 22, 1), |
| expectedError(ScannerErrorCode.EXPECTED_TOKEN, 23, 1), |
| expectedError(ScannerErrorCode.EXPECTED_TOKEN, 23, 1), |
| ]); |
| var typeAlias = unit.declarations[0] as GenericTypeAlias; |
| expect(typeAlias.name.toSource(), 'K'); |
| var functionType = typeAlias.functionType; |
| expect(functionType.parameters.parameters, hasLength(1)); |
| var parameter = functionType.parameters.parameters[0]; |
| expect(parameter.identifier, isNotNull); |
| } |
| |
| void test_typeAlias_parameter_missingIdentifier_37733() { |
| // https://github.com/dart-lang/sdk/issues/37733 |
| var unit = parseCompilationUnit(r'typedef T=Function(<S>());', errors: [ |
| expectedError(CompileTimeErrorCode.INVALID_INLINE_FUNCTION_TYPE, 19, 1), |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 19, 1), |
| ]); |
| var typeAlias = unit.declarations[0] as GenericTypeAlias; |
| expect(typeAlias.name.toSource(), 'T'); |
| var functionType = typeAlias.functionType; |
| expect(functionType.parameters.parameters, hasLength(1)); |
| var parameter = functionType.parameters.parameters[0]; |
| expect(parameter.identifier, isNotNull); |
| } |
| } |
| |
| /// Tests of the fasta parser based on [StatementParserTestMixin]. |
| @reflectiveTest |
| class StatementParserTest_Fasta extends FastaParserTestCase |
| with StatementParserTestMixin { |
| void test_35177() { |
| ExpressionStatement statement = parseStatement('(f)()<int>();'); |
| |
| FunctionExpressionInvocation funct1 = statement.expression; |
| NodeList<TypeAnnotation> 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<List<int>> 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>(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_parseLocalVariable_external() { |
| parseStatement('external int i;', featureSet: nonNullable); |
| assertErrors(errors: [ |
| expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 0, 8), |
| ]); |
| } |
| |
| void test_partial_typeArg1_34850() { |
| var unit = parseCompilationUnit('<bar<', errors: [ |
| expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 0, 1), |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 5, 0), |
| expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 1, 3), |
| expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 5, 0), |
| ]); |
| // 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_partial_typeArg2_34850() { |
| var unit = parseCompilationUnit('foo <bar<', errors: [ |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 3), |
| expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 0, 3), |
| expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 9, 0), |
| ]); |
| // 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; |
| } |
| } |
| } |
| |
| /// Tests of the fasta parser based on [TopLevelParserTestMixin]. |
| @reflectiveTest |
| class TopLevelParserTest_Fasta extends FastaParserTestCase |
| with TopLevelParserTestMixin { |
| void test_parseClassDeclaration_native_allowed() { |
| allowNativeClause = true; |
| test_parseClassDeclaration_native(); |
| } |
| |
| void test_parseClassDeclaration_native_allowedWithFields() { |
| allowNativeClause = true; |
| createParser(r''' |
| class A native 'something' { |
| final int x; |
| A() {} |
| } |
| '''); |
| CompilationUnitMember member = parseFullCompilationUnitMember(); |
| expect(member, isNotNull); |
| assertNoErrors(); |
| } |
| |
| void test_parseClassDeclaration_native_missing_literal() { |
| createParser('class A native {}'); |
| CompilationUnitMember member = parseFullCompilationUnitMember(); |
| expect(member, isNotNull); |
| if (allowNativeClause) { |
| assertNoErrors(); |
| } else { |
| assertErrorsWithCodes([ |
| ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION, |
| ]); |
| } |
| expect(member, TypeMatcher<ClassDeclaration>()); |
| 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<TypeName> 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<T>, 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<TypeName> 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<Annotation> 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<TypeName> 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<T> {}'); |
| MixinDeclaration declaration = parseFullCompilationUnitMember(); |
| expect(declaration, isNotNull); |
| assertNoErrors(); |
| expect(declaration.metadata, isEmpty); |
| expect(declaration.documentationComment, isNull); |
| OnClause onClause = declaration.onClause; |
| expect(onClause.onKeyword, isNotNull); |
| NodeList<TypeName> 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<TypeName> 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<TypeName> 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_external() { |
| var unit = parseCompilationUnit('external int i;', featureSet: nonNullable); |
| var declaration = unit.declarations[0] as TopLevelVariableDeclaration; |
| expect(declaration.externalKeyword, isNotNull); |
| } |
| |
| void test_parseTopLevelVariable_external_late() { |
| var unit = parseCompilationUnit('external late int? i;', |
| featureSet: nonNullable, |
| errors: [ |
| expectedError(ParserErrorCode.EXTERNAL_LATE_FIELD, 0, 8), |
| ]); |
| var declaration = unit.declarations[0] as TopLevelVariableDeclaration; |
| expect(declaration.externalKeyword, isNotNull); |
| } |
| |
| void test_parseTopLevelVariable_external_late_final() { |
| var unit = parseCompilationUnit('external late final int? i;', |
| featureSet: nonNullable, |
| errors: [ |
| expectedError(ParserErrorCode.EXTERNAL_LATE_FIELD, 0, 8), |
| ]); |
| var declaration = unit.declarations[0] as TopLevelVariableDeclaration; |
| expect(declaration.externalKeyword, isNotNull); |
| } |
| |
| 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, |
| errors: [ |
| expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 5, 1) |
| ]); |
| 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, |
| errors: [ |
| expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 5, 1) |
| ]); |
| 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)); |
| } |
| |
| void test_parseTopLevelVariable_non_external() { |
| var unit = parseCompilationUnit('int i;', featureSet: nonNullable); |
| var declaration = unit.declarations[0] as TopLevelVariableDeclaration; |
| expect(declaration.externalKeyword, isNull); |
| } |
| } |
| |
| @reflectiveTest |
| class VarianceParserTest_Fasta extends FastaParserTestCase { |
| @override |
| CompilationUnit parseCompilationUnit(String content, |
| {List<ErrorCode> codes, |
| List<ExpectedError> errors, |
| FeatureSet featureSet}) { |
| return super.parseCompilationUnit(content, |
| codes: codes, |
| errors: errors, |
| featureSet: featureSet ?? |
| FeatureSet.forTesting( |
| sdkVersion: '2.5.0', |
| additionalFeatures: [Feature.variance], |
| )); |
| } |
| |
| void test_class_disabled_multiple() { |
| parseCompilationUnit('class A<in T, inout U, out V> { }', |
| errors: [ |
| expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 8, 2), |
| expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 14, 5), |
| expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 23, 3) |
| ], |
| featureSet: FeatureSet.forTesting(sdkVersion: '2.5.0')); |
| } |
| |
| void test_class_disabled_single() { |
| parseCompilationUnit('class A<out T> { }', |
| errors: [ |
| expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 8, 3), |
| ], |
| featureSet: FeatureSet.forTesting(sdkVersion: '2.5.0')); |
| } |
| |
| void test_class_enabled_multiple() { |
| var unit = parseCompilationUnit('class A<in T, inout U, out V, W> { }'); |
| expect(unit.declarations, hasLength(1)); |
| var classDecl = unit.declarations[0] as ClassDeclaration; |
| expect(classDecl.name.name, 'A'); |
| |
| expect(classDecl.typeParameters.typeParameters, hasLength(4)); |
| expect(classDecl.typeParameters.typeParameters[0].name.name, 'T'); |
| expect(classDecl.typeParameters.typeParameters[1].name.name, 'U'); |
| expect(classDecl.typeParameters.typeParameters[2].name.name, 'V'); |
| expect(classDecl.typeParameters.typeParameters[3].name.name, 'W'); |
| |
| var typeParameterImplList = classDecl.typeParameters.typeParameters; |
| expect((typeParameterImplList[0] as TypeParameterImpl).varianceKeyword, |
| isNotNull); |
| expect( |
| (typeParameterImplList[0] as TypeParameterImpl).varianceKeyword.lexeme, |
| "in"); |
| expect((typeParameterImplList[1] as TypeParameterImpl).varianceKeyword, |
| isNotNull); |
| expect( |
| (typeParameterImplList[1] as TypeParameterImpl).varianceKeyword.lexeme, |
| "inout"); |
| expect((typeParameterImplList[2] as TypeParameterImpl).varianceKeyword, |
| isNotNull); |
| expect( |
| (typeParameterImplList[2] as TypeParameterImpl).varianceKeyword.lexeme, |
| "out"); |
| expect((typeParameterImplList[3] as TypeParameterImpl).varianceKeyword, |
| isNull); |
| } |
| |
| void test_class_enabled_multipleVariances() { |
| var unit = parseCompilationUnit('class A<in out inout T> { }', errors: [ |
| expectedError(ParserErrorCode.MULTIPLE_VARIANCE_MODIFIERS, 11, 3), |
| expectedError(ParserErrorCode.MULTIPLE_VARIANCE_MODIFIERS, 15, 5) |
| ]); |
| expect(unit.declarations, hasLength(1)); |
| var classDecl = unit.declarations[0] as ClassDeclaration; |
| expect(classDecl.name.name, 'A'); |
| expect(classDecl.typeParameters.typeParameters, hasLength(1)); |
| expect(classDecl.typeParameters.typeParameters[0].name.name, 'T'); |
| } |
| |
| void test_class_enabled_single() { |
| var unit = parseCompilationUnit('class A<in T> { }'); |
| expect(unit.declarations, hasLength(1)); |
| var classDecl = unit.declarations[0] as ClassDeclaration; |
| expect(classDecl.name.name, 'A'); |
| expect(classDecl.typeParameters.typeParameters, hasLength(1)); |
| expect(classDecl.typeParameters.typeParameters[0].name.name, 'T'); |
| |
| var typeParameterImpl = |
| classDecl.typeParameters.typeParameters[0] as TypeParameterImpl; |
| expect(typeParameterImpl.varianceKeyword, isNotNull); |
| expect(typeParameterImpl.varianceKeyword.lexeme, "in"); |
| } |
| |
| void test_function_disabled() { |
| parseCompilationUnit('void A(in int value) {}', |
| errors: [ |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 7, 2), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 3), |
| ], |
| featureSet: FeatureSet.forTesting(sdkVersion: '2.5.0')); |
| } |
| |
| void test_function_enabled() { |
| parseCompilationUnit('void A(in int value) {}', errors: [ |
| expectedError(ParserErrorCode.MISSING_IDENTIFIER, 7, 2), |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 3), |
| ]); |
| } |
| |
| void test_list_disabled() { |
| parseCompilationUnit('List<out String> stringList = [];', |
| errors: [ |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 6), |
| ], |
| featureSet: FeatureSet.forTesting(sdkVersion: '2.5.0')); |
| } |
| |
| void test_list_enabled() { |
| parseCompilationUnit('List<out String> stringList = [];', errors: [ |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 6), |
| ]); |
| } |
| |
| void test_mixin_disabled_multiple() { |
| parseCompilationUnit('mixin A<inout T, out U> { }', |
| errors: [ |
| expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 8, 5), |
| expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 17, 3), |
| ], |
| featureSet: FeatureSet.forTesting(sdkVersion: '2.5.0')); |
| } |
| |
| void test_mixin_disabled_single() { |
| parseCompilationUnit('mixin A<inout T> { }', |
| errors: [ |
| expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 8, 5), |
| ], |
| featureSet: FeatureSet.forTesting(sdkVersion: '2.5.0')); |
| } |
| |
| void test_mixin_enabled_single() { |
| var unit = parseCompilationUnit('mixin A<inout T> { }'); |
| expect(unit.declarations, hasLength(1)); |
| var mixinDecl = unit.declarations[0] as MixinDeclaration; |
| expect(mixinDecl.name.name, 'A'); |
| expect(mixinDecl.typeParameters.typeParameters, hasLength(1)); |
| expect(mixinDecl.typeParameters.typeParameters[0].name.name, 'T'); |
| } |
| |
| void test_typedef_disabled() { |
| parseCompilationUnit('typedef A<inout X> = X Function(X);', |
| errors: [ |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 16, 1), |
| ], |
| featureSet: FeatureSet.forTesting(sdkVersion: '2.5.0')); |
| } |
| |
| void test_typedef_enabled() { |
| parseCompilationUnit('typedef A<inout X> = X Function(X);', errors: [ |
| expectedError(ParserErrorCode.EXPECTED_TOKEN, 16, 1), |
| ]); |
| } |
| } |