blob: 7fffdbff7419531c58b125fa466b2e9521d8204f [file] [log] [blame]
// Copyright (c) 2018, 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/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/testing/test_type_provider.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../../generated/elements_types_mixin.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(FunctionTypeTest);
});
}
DynamicTypeImpl get dynamicType => DynamicTypeImpl.instance;
VoidTypeImpl get voidType => VoidTypeImpl.instance;
@reflectiveTest
class FunctionTypeTest with ElementsTypesMixin {
@override
final TypeProvider typeProvider = TestTypeProvider();
InterfaceType get intType => typeProvider.intType;
ClassElement get listElement => typeProvider.listElement;
ClassElement get mapElement => typeProvider.mapElement;
InterfaceType get objectType => typeProvider.objectType;
void basicChecks(FunctionType f,
{element,
displayName = 'dynamic Function()',
returnType,
namedParameterTypes = isEmpty,
normalParameterNames = isEmpty,
normalParameterTypes = isEmpty,
optionalParameterNames = isEmpty,
optionalParameterTypes = isEmpty,
parameters = isEmpty,
typeFormals = isEmpty,
typeArguments = isEmpty,
typeParameters = isEmpty}) {
// DartType properties
expect(
f.getDisplayString(withNullability: false),
displayName,
reason: 'displayName',
);
expect(f.element, element, reason: 'element');
// ParameterizedType properties
expect(f.typeArguments, typeArguments, reason: 'typeArguments');
// FunctionType properties
expect(f.namedParameterTypes, namedParameterTypes,
reason: 'namedParameterTypes');
expect(f.normalParameterNames, normalParameterNames,
reason: 'normalParameterNames');
expect(f.normalParameterTypes, normalParameterTypes,
reason: 'normalParameterTypes');
expect(f.optionalParameterNames, optionalParameterNames,
reason: 'optionalParameterNames');
expect(f.optionalParameterTypes, optionalParameterTypes,
reason: 'optionalParameterTypes');
expect(f.parameters, parameters, reason: 'parameters');
expect(f.returnType, returnType ?? same(dynamicType), reason: 'returnType');
expect(f.typeFormals, typeFormals, reason: 'typeFormals');
}
DartType listOf(DartType elementType) => listElement.instantiate(
typeArguments: [elementType],
nullabilitySuffix: NullabilitySuffix.star,
);
DartType mapOf(DartType keyType, DartType valueType) =>
mapElement.instantiate(
typeArguments: [keyType, valueType],
nullabilitySuffix: NullabilitySuffix.star,
);
test_equality_leftRequired_rightPositional() {
var f1 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
requiredParameter(name: 'a', type: typeProvider.intType),
],
);
var f2 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
positionalParameter(name: 'a', type: typeProvider.intType),
],
);
expect(f1, isNot(equals(f2)));
}
test_equality_namedParameters_differentName() {
var f1 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedParameter(name: 'a', type: typeProvider.intType),
],
);
var f2 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedParameter(name: 'b', type: typeProvider.intType),
],
);
expect(f1, isNot(equals(f2)));
}
test_equality_namedParameters_differentType() {
var f1 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedParameter(name: 'a', type: typeProvider.intType),
],
);
var f2 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedParameter(name: 'a', type: typeProvider.doubleType),
],
);
expect(f1, isNot(equals(f2)));
}
test_equality_namedParameters_equal() {
var f1 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedParameter(name: 'a', type: typeProvider.intType),
namedParameter(name: 'b', type: typeProvider.doubleType),
],
);
var f2 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedParameter(name: 'a', type: typeProvider.intType),
namedParameter(name: 'b', type: typeProvider.doubleType),
],
);
expect(f1, f2);
}
test_equality_namedParameters_extraLeft() {
var f1 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedParameter(name: 'a', type: typeProvider.intType),
namedParameter(name: 'b', type: typeProvider.doubleType),
],
);
var f2 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedParameter(name: 'a', type: typeProvider.intType),
],
);
expect(f1, isNot(equals(f2)));
}
test_equality_namedParameters_extraRight() {
var f1 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedParameter(name: 'a', type: typeProvider.intType),
],
);
var f2 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedParameter(name: 'a', type: typeProvider.intType),
namedParameter(name: 'b', type: typeProvider.doubleType),
],
);
expect(f1, isNot(equals(f2)));
}
test_equality_namedParameters_required_left() {
var f1 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedRequiredParameter(name: 'a', type: typeProvider.intType),
],
);
var f2 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedParameter(name: 'a', type: typeProvider.intType),
],
);
expect(f1, isNot(equals(f2)));
}
test_equality_namedParameters_required_right() {
var f1 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedParameter(name: 'a', type: typeProvider.intType),
],
);
var f2 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
namedRequiredParameter(name: 'a', type: typeProvider.intType),
],
);
expect(f1, isNot(equals(f2)));
}
test_equality_requiredParameters_extraLeft() {
var f1 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
requiredParameter(name: 'a', type: typeProvider.intType),
requiredParameter(name: 'b', type: typeProvider.doubleType),
],
);
var f2 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
requiredParameter(name: 'a', type: typeProvider.intType),
],
);
expect(f1, isNot(equals(f2)));
}
test_equality_requiredParameters_extraRight() {
var f1 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
requiredParameter(name: 'a', type: typeProvider.intType),
],
);
var f2 = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
requiredParameter(name: 'a', type: typeProvider.intType),
requiredParameter(name: 'b', type: typeProvider.doubleType),
],
);
expect(f1, isNot(equals(f2)));
}
test_new_sortsNamedParameters() {
var f = functionTypeNone(
returnType: typeProvider.voidType,
parameters: [
requiredParameter(name: 'a', type: typeProvider.intType),
namedParameter(name: 'c', type: typeProvider.intType),
namedParameter(name: 'b', type: typeProvider.intType),
],
);
var parameters = f.parameters;
expect(parameters, hasLength(3));
expect(parameters[0].name, 'a');
expect(parameters[1].name, 'b');
expect(parameters[2].name, 'c');
}
test_synthetic() {
FunctionType f = FunctionTypeImpl(
typeFormals: const [],
parameters: const [],
returnType: dynamicType,
nullabilitySuffix: NullabilitySuffix.star,
);
basicChecks(f, element: isNull);
}
test_synthetic_instantiate() {
// T Function<T>(T x)
var t = typeParameter('T');
var x = requiredParameter(name: 'x', type: typeParameterTypeNone(t));
FunctionType f = FunctionTypeImpl(
typeFormals: [t],
parameters: [x],
returnType: typeParameterTypeNone(t),
nullabilitySuffix: NullabilitySuffix.star,
);
FunctionType instantiated = f.instantiate([objectType]);
basicChecks(instantiated,
element: isNull,
displayName: 'Object Function(Object)',
returnType: same(objectType),
normalParameterNames: ['x'],
normalParameterTypes: [same(objectType)],
parameters: hasLength(1));
}
test_synthetic_instantiate_argument_length_mismatch() {
// dynamic Function<T>()
var t = typeParameter('T');
FunctionType f = FunctionTypeImpl(
typeFormals: [t],
parameters: const [],
returnType: dynamicType,
nullabilitySuffix: NullabilitySuffix.star,
);
expect(() => f.instantiate([]), throwsA(TypeMatcher<ArgumentError>()));
}
test_synthetic_instantiate_no_type_formals() {
FunctionType f = FunctionTypeImpl(
typeFormals: const [],
parameters: const [],
returnType: dynamicType,
nullabilitySuffix: NullabilitySuffix.star,
);
expect(f.instantiate([]), same(f));
}
test_synthetic_namedParameter() {
var p = namedParameter(name: 'x', type: objectType);
FunctionType f = FunctionTypeImpl(
typeFormals: const [],
parameters: [p],
returnType: dynamicType,
nullabilitySuffix: NullabilitySuffix.star,
);
basicChecks(f,
element: isNull,
displayName: 'dynamic Function({Object x})',
namedParameterTypes: {'x': same(objectType)},
parameters: hasLength(1));
expect(f.parameters[0].isNamed, isTrue);
expect(f.parameters[0].name, 'x');
expect(f.parameters[0].type, same(objectType));
}
test_synthetic_normalParameter() {
var p = requiredParameter(name: 'x', type: objectType);
FunctionType f = FunctionTypeImpl(
typeFormals: const [],
parameters: [p],
returnType: dynamicType,
nullabilitySuffix: NullabilitySuffix.star,
);
basicChecks(f,
element: isNull,
displayName: 'dynamic Function(Object)',
normalParameterNames: ['x'],
normalParameterTypes: [same(objectType)],
parameters: hasLength(1));
expect(f.parameters[0].isRequiredPositional, isTrue);
expect(f.parameters[0].name, 'x');
expect(f.parameters[0].type, same(objectType));
}
test_synthetic_optionalParameter() {
var p = positionalParameter(name: 'x', type: objectType);
FunctionType f = FunctionTypeImpl(
typeFormals: const [],
parameters: [p],
returnType: dynamicType,
nullabilitySuffix: NullabilitySuffix.star,
);
basicChecks(f,
element: isNull,
displayName: 'dynamic Function([Object])',
optionalParameterNames: ['x'],
optionalParameterTypes: [same(objectType)],
parameters: hasLength(1));
expect(f.parameters[0].isOptionalPositional, isTrue);
expect(f.parameters[0].name, 'x');
expect(f.parameters[0].type, same(objectType));
}
test_synthetic_returnType() {
FunctionType f = FunctionTypeImpl(
typeFormals: const [],
parameters: const [],
returnType: objectType,
nullabilitySuffix: NullabilitySuffix.star,
);
basicChecks(f,
element: isNull,
displayName: 'Object Function()',
returnType: same(objectType));
}
test_synthetic_typeFormals() {
var t = typeParameter('T');
FunctionType f = FunctionTypeImpl(
typeFormals: [t],
parameters: const [],
returnType: typeParameterTypeStar(t),
nullabilitySuffix: NullabilitySuffix.star,
);
basicChecks(f,
element: isNull,
displayName: 'T Function<T>()',
returnType: typeParameterTypeStar(t),
typeFormals: [same(t)]);
}
}
class MockCompilationUnitElement implements CompilationUnitElement {
const MockCompilationUnitElement();
@override
get enclosingElement => const MockLibraryElement();
@override
noSuchMethod(Invocation invocation) {
return super.noSuchMethod(invocation);
}
}
class MockLibraryElement implements LibraryElement {
const MockLibraryElement();
@override
get enclosingElement => null;
@override
noSuchMethod(Invocation invocation) {
return super.noSuchMethod(invocation);
}
}