blob: b34773fd4ba6d2d1978dfd1a6357d47399d4b068 [file] [log] [blame]
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../util/feature_sets.dart';
import 'parser_test_base.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(NewAsIdentifierParserTest);
});
}
/// Tests exercising the fasta parser's handling of generic instantiations.
@reflectiveTest
class NewAsIdentifierParserTest extends FastaParserTestCase {
void test_constructor_field_initializer() {
// Even though `C() : this.new();` is allowed, `C() : this.new = ...;`
// should not be.
parseCompilationUnit(
'''
class C {
C() : this.new = null;
}
''',
errors: [
expectedError(ParserErrorCode.missingAssignmentInInitializer, 18, 4),
expectedError(ParserErrorCode.missingIdentifier, 23, 3),
expectedError(ParserErrorCode.missingFunctionBody, 23, 3),
expectedError(ParserErrorCode.expectedClassMember, 23, 3),
expectedError(ParserErrorCode.missingKeywordOperator, 27, 1),
expectedError(ParserErrorCode.invalidOperator, 27, 1),
expectedError(ParserErrorCode.missingMethodParameters, 27, 1),
expectedError(ParserErrorCode.missingFunctionBody, 29, 4),
expectedError(ParserErrorCode.expectedClassMember, 29, 4),
expectedError(ParserErrorCode.expectedClassMember, 33, 1),
],
);
}
void test_constructor_invocation_const() {
var instanceCreationExpression =
parseExpression('const C.new()') as InstanceCreationExpression;
// Parsing treats `new` as an identifier, so `D.new` is classified as a
// type. Resolution will change the type to `D` and the name to `new` if
// appropriate.
var constructorName = instanceCreationExpression.constructorName;
var type = constructorName.type;
expect(type.importPrefix!.name.lexeme, 'C');
expect(type.name.lexeme, 'new');
expect(constructorName.type.typeArguments, isNull);
expect(constructorName.name, isNull);
expect(instanceCreationExpression.argumentList, isNotNull);
}
void test_constructor_invocation_const_generic() {
var instanceCreationExpression =
parseExpression('const C<int>.new()') as InstanceCreationExpression;
var constructorName = instanceCreationExpression.constructorName;
var type = constructorName.type;
expect(type.name.lexeme, 'C');
expect(constructorName.type.typeArguments!.arguments, hasLength(1));
expect(constructorName.name!.name, 'new');
expect(instanceCreationExpression.argumentList, isNotNull);
}
void test_constructor_invocation_const_prefixed() {
var instanceCreationExpression =
parseExpression('const prefix.C.new()') as InstanceCreationExpression;
var constructorName = instanceCreationExpression.constructorName;
var type = constructorName.type;
expect(type.importPrefix!.name.lexeme, 'prefix');
expect(type.name.lexeme, 'C');
expect(constructorName.type.typeArguments, isNull);
expect(constructorName.name!.name, 'new');
expect(instanceCreationExpression.argumentList, isNotNull);
}
void test_constructor_invocation_const_prefixed_generic() {
var instanceCreationExpression =
parseExpression('const prefix.C<int>.new()')
as InstanceCreationExpression;
var constructorName = instanceCreationExpression.constructorName;
var type = constructorName.type;
expect(type.importPrefix!.name.lexeme, 'prefix');
expect(type.name.lexeme, 'C');
expect(constructorName.type.typeArguments!.arguments, hasLength(1));
expect(constructorName.name!.name, 'new');
expect(instanceCreationExpression.argumentList, isNotNull);
}
void test_constructor_invocation_explicit() {
var instanceCreationExpression =
parseExpression('new C.new()') as InstanceCreationExpression;
// Parsing treats `new` as an identifier, so `D.new` is classified as a
// type. Resolution will change the type to `D` and the name to `new` if
// appropriate.
var constructorName = instanceCreationExpression.constructorName;
var type = constructorName.type;
expect(type.importPrefix!.name.lexeme, 'C');
expect(type.name.lexeme, 'new');
expect(constructorName.type.typeArguments, isNull);
expect(constructorName.name, isNull);
expect(instanceCreationExpression.argumentList, isNotNull);
}
void test_constructor_invocation_explicit_generic() {
var instanceCreationExpression =
parseExpression('new C<int>.new()') as InstanceCreationExpression;
var constructorName = instanceCreationExpression.constructorName;
var type = constructorName.type;
expect(type.name.lexeme, 'C');
expect(constructorName.type.typeArguments!.arguments, hasLength(1));
expect(constructorName.name!.name, 'new');
expect(instanceCreationExpression.argumentList, isNotNull);
}
void test_constructor_invocation_explicit_prefixed() {
var instanceCreationExpression =
parseExpression('new prefix.C.new()') as InstanceCreationExpression;
var constructorName = instanceCreationExpression.constructorName;
var type = constructorName.type;
expect(type.importPrefix!.name.lexeme, 'prefix');
expect(type.name.lexeme, 'C');
expect(constructorName.type.typeArguments, isNull);
expect(constructorName.name!.name, 'new');
expect(instanceCreationExpression.argumentList, isNotNull);
}
void test_constructor_invocation_explicit_prefixed_generic() {
var instanceCreationExpression =
parseExpression('new prefix.C<int>.new()')
as InstanceCreationExpression;
var constructorName = instanceCreationExpression.constructorName;
var type = constructorName.type;
expect(type.importPrefix!.name.lexeme, 'prefix');
expect(type.name.lexeme, 'C');
expect(constructorName.type.typeArguments!.arguments, hasLength(1));
expect(constructorName.name!.name, 'new');
expect(instanceCreationExpression.argumentList, isNotNull);
}
void test_constructor_invocation_implicit() {
var methodInvocation = parseExpression('C.new()') as MethodInvocation;
var target = methodInvocation.target as SimpleIdentifier;
expect(target.name, 'C');
expect(methodInvocation.methodName.name, 'new');
expect(methodInvocation.typeArguments, isNull);
expect(methodInvocation.argumentList, isNotNull);
}
void test_constructor_invocation_implicit_generic() {
var instanceCreationExpression =
parseExpression('C<int>.new()') as InstanceCreationExpression;
var constructorName = instanceCreationExpression.constructorName;
var type = constructorName.type;
expect(type.name.lexeme, 'C');
expect(constructorName.type.typeArguments!.arguments, hasLength(1));
expect(constructorName.name!.name, 'new');
expect(instanceCreationExpression.argumentList, isNotNull);
}
void test_constructor_invocation_implicit_prefixed() {
var methodInvocation =
parseExpression('prefix.C.new()') as MethodInvocation;
var target = methodInvocation.target as PrefixedIdentifier;
expect(target.prefix.name, 'prefix');
expect(target.identifier.name, 'C');
expect(methodInvocation.methodName.name, 'new');
expect(methodInvocation.typeArguments, isNull);
expect(methodInvocation.argumentList, isNotNull);
}
void test_constructor_invocation_implicit_prefixed_generic() {
var instanceCreationExpression =
parseExpression('prefix.C<int>.new()') as InstanceCreationExpression;
var constructorName = instanceCreationExpression.constructorName;
var type = constructorName.type;
expect(type.importPrefix!.name.lexeme, 'prefix');
expect(type.name.lexeme, 'C');
expect(constructorName.type.typeArguments!.arguments, hasLength(1));
expect(constructorName.name!.name, 'new');
expect(instanceCreationExpression.argumentList, isNotNull);
}
void test_constructor_name() {
var unit = parseCompilationUnit('''
class C {
C.new();
}
''');
var classDeclaration = unit.declarations.single as ClassDeclaration;
var constructorDeclaration =
classDeclaration.members.single as ConstructorDeclaration;
expect(constructorDeclaration.name!.lexeme, 'new');
}
void test_constructor_name_factory() {
var unit = parseCompilationUnit('''
class C {
factory C.new() => C._();
C._();
}
''');
var classDeclaration = unit.declarations.single as ClassDeclaration;
var constructorDeclaration =
classDeclaration.members[0] as ConstructorDeclaration;
expect(constructorDeclaration.name!.lexeme, 'new');
}
void test_constructor_tearoff() {
var prefixedIdentifier = parseExpression('C.new') as PrefixedIdentifier;
expect(prefixedIdentifier.prefix.name, 'C');
expect(prefixedIdentifier.identifier.name, 'new');
}
void test_constructor_tearoff_generic() {
var propertyAccess = parseExpression('C<int>.new') as PropertyAccess;
var target = propertyAccess.target as FunctionReference;
var className = target.function as SimpleIdentifier;
expect(className.name, 'C');
expect(target.typeArguments, isNotNull);
expect(propertyAccess.propertyName.name, 'new');
}
void test_constructor_tearoff_generic_method_invocation() {
var methodInvocation =
parseExpression('C<int>.new.toString()') as MethodInvocation;
var target = methodInvocation.target as PropertyAccess;
var functionReference = target.target as FunctionReference;
var className = functionReference.function as SimpleIdentifier;
expect(className.name, 'C');
expect(functionReference.typeArguments, isNotNull);
expect(target.propertyName.name, 'new');
expect(methodInvocation.methodName.name, 'toString');
expect(methodInvocation.typeArguments, isNull);
expect(methodInvocation.argumentList, isNotNull);
}
void test_constructor_tearoff_in_comment_reference() {
createParser('');
var commentReference = parseCommentReference('C.new', 5)!;
var identifier = commentReference.expression as PrefixedIdentifier;
expect(identifier.prefix.name, 'C');
expect(identifier.identifier.name, 'new');
}
void test_constructor_tearoff_method_invocation() {
var methodInvocation =
parseExpression('C.new.toString()') as MethodInvocation;
var target = methodInvocation.target as PrefixedIdentifier;
expect(target.prefix.name, 'C');
expect(target.identifier.name, 'new');
expect(methodInvocation.methodName.name, 'toString');
expect(methodInvocation.typeArguments, isNull);
expect(methodInvocation.argumentList, isNotNull);
}
void test_constructor_tearoff_prefixed() {
var propertyAccess = parseExpression('prefix.C.new') as PropertyAccess;
var target = propertyAccess.target as PrefixedIdentifier;
expect(target.prefix.name, 'prefix');
expect(target.identifier.name, 'C');
expect(propertyAccess.propertyName.name, 'new');
}
void test_constructor_tearoff_prefixed_generic() {
var propertyAccess = parseExpression('prefix.C<int>.new') as PropertyAccess;
var target = propertyAccess.target as FunctionReference;
var className = target.function as PrefixedIdentifier;
expect(className.prefix.name, 'prefix');
expect(className.identifier.name, 'C');
expect(target.typeArguments, isNotNull);
expect(propertyAccess.propertyName.name, 'new');
}
void test_constructor_tearoff_prefixed_generic_method_invocation() {
var methodInvocation =
parseExpression('prefix.C<int>.new.toString()') as MethodInvocation;
var target = methodInvocation.target as PropertyAccess;
var functionReference = target.target as FunctionReference;
var className = functionReference.function as PrefixedIdentifier;
expect(className.prefix.name, 'prefix');
expect(className.identifier.name, 'C');
expect(functionReference.typeArguments, isNotNull);
expect(target.propertyName.name, 'new');
expect(methodInvocation.methodName.name, 'toString');
expect(methodInvocation.typeArguments, isNull);
expect(methodInvocation.argumentList, isNotNull);
}
void test_constructor_tearoff_prefixed_method_invocation() {
var methodInvocation =
parseExpression('prefix.C.new.toString()') as MethodInvocation;
var target = methodInvocation.target as PropertyAccess;
var prefixedIdentifier = target.target as PrefixedIdentifier;
expect(prefixedIdentifier.prefix.name, 'prefix');
expect(prefixedIdentifier.identifier.name, 'C');
expect(target.propertyName.name, 'new');
expect(methodInvocation.methodName.name, 'toString');
expect(methodInvocation.typeArguments, isNull);
expect(methodInvocation.argumentList, isNotNull);
}
void test_disabled() {
var unit = parseCompilationUnit(
'''
class C {
C.new();
}
''',
featureSet: FeatureSets.language_2_13,
errors: [expectedError(ParserErrorCode.experimentNotEnabled, 14, 3)],
);
var classDeclaration = unit.declarations.single as ClassDeclaration;
var constructorDeclaration =
classDeclaration.members.single as ConstructorDeclaration;
expect(constructorDeclaration.name!.lexeme, 'new');
}
void test_factory_redirection() {
var unit = parseCompilationUnit('''
class C {
factory C() = D.new;
}
''');
var classDeclaration = unit.declarations.single as ClassDeclaration;
var constructorDeclaration =
classDeclaration.members.single as ConstructorDeclaration;
expect(constructorDeclaration.initializers, isEmpty);
// Parsing treats `new` as an identifier, so `D.new` is classified as a
// type. Resolution will change the type to `D` and the name to `new` if
// appropriate.
var redirectedConstructor = constructorDeclaration.redirectedConstructor!;
var type = redirectedConstructor.type;
expect(type.importPrefix!.name.lexeme, 'D');
expect(type.name.lexeme, 'new');
expect(redirectedConstructor.type.typeArguments, isNull);
expect(redirectedConstructor.name, isNull);
}
void test_factory_redirection_generic() {
var unit = parseCompilationUnit('''
class C {
factory C() = D<int>.new;
}
''');
var classDeclaration = unit.declarations.single as ClassDeclaration;
var constructorDeclaration =
classDeclaration.members.single as ConstructorDeclaration;
expect(constructorDeclaration.initializers, isEmpty);
var redirectedConstructor = constructorDeclaration.redirectedConstructor!;
var type = redirectedConstructor.type;
expect(type.name.lexeme, 'D');
expect(redirectedConstructor.type.typeArguments!.arguments, hasLength(1));
expect(redirectedConstructor.name!.name, 'new');
}
void test_factory_redirection_prefixed() {
var unit = parseCompilationUnit('''
class C {
factory C() = prefix.D.new;
}
''');
var classDeclaration = unit.declarations.single as ClassDeclaration;
var constructorDeclaration =
classDeclaration.members.single as ConstructorDeclaration;
expect(constructorDeclaration.initializers, isEmpty);
var redirectedConstructor = constructorDeclaration.redirectedConstructor!;
var type = redirectedConstructor.type;
expect(type.importPrefix!.name.lexeme, 'prefix');
expect(type.name.lexeme, 'D');
expect(redirectedConstructor.type.typeArguments, isNull);
expect(redirectedConstructor.name!.name, 'new');
}
void test_factory_redirection_prefixed_generic() {
var unit = parseCompilationUnit('''
class C {
factory C() = prefix.D<int>.new;
}
''');
var classDeclaration = unit.declarations.single as ClassDeclaration;
var constructorDeclaration =
classDeclaration.members.single as ConstructorDeclaration;
expect(constructorDeclaration.initializers, isEmpty);
var redirectedConstructor = constructorDeclaration.redirectedConstructor!;
var type = redirectedConstructor.type;
expect(type.importPrefix!.name.lexeme, 'prefix');
expect(type.name.lexeme, 'D');
expect(redirectedConstructor.type.typeArguments!.arguments, hasLength(1));
expect(redirectedConstructor.name!.name, 'new');
}
void test_super_invocation() {
var unit = parseCompilationUnit('''
class C extends B {
C() : super.new();
}
''');
var classDeclaration = unit.declarations.single as ClassDeclaration;
var constructorDeclaration =
classDeclaration.members.single as ConstructorDeclaration;
expect(constructorDeclaration.redirectedConstructor, isNull);
var superConstructorInvocation =
constructorDeclaration.initializers.single
as SuperConstructorInvocation;
expect(superConstructorInvocation.constructorName!.name, 'new');
}
void test_this_redirection() {
var unit = parseCompilationUnit('''
class C {
C.named() : this.new();
C();
}
''');
var classDeclaration = unit.declarations.single as ClassDeclaration;
var constructorDeclaration =
classDeclaration.members[0] as ConstructorDeclaration;
expect(constructorDeclaration.redirectedConstructor, isNull);
var redirectingConstructorInvocation =
constructorDeclaration.initializers.single
as RedirectingConstructorInvocation;
expect(redirectingConstructorInvocation.constructorName!.name, 'new');
}
}