blob: 3af77e73854edf0a3110d823dc2b9c78061ab4de [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/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/resolver.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;
Element getBaseElement(Element e) {
if (e is Member) {
return e.baseElement;
} else {
return e;
}
}
@reflectiveTest
class FunctionTypeTest with ElementsTypesMixin {
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,
name: isNull}) {
// DartType properties
expect(f.displayName, displayName, reason: 'displayName');
expect(f.element, element, reason: 'element');
expect(f.name, name, reason: 'name');
// 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');
}
GenericTypeAliasElementImpl genericTypeAliasElement(
String name, {
List<ParameterElement> parameters: const [],
DartType returnType,
List<TypeParameterElement> typeParameters: const [],
List<TypeParameterElement> innerTypeParameters: const [],
}) {
var aliasElement = GenericTypeAliasElementImpl(name, 0);
aliasElement.typeParameters = typeParameters;
var functionElement = GenericFunctionTypeElementImpl.forOffset(0);
aliasElement.function = functionElement;
functionElement.typeParameters = innerTypeParameters;
functionElement.parameters = parameters;
functionElement.returnType = returnType;
return aliasElement;
}
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_synthetic() {
FunctionType f = new FunctionTypeImpl.synthetic(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: typeParameterType(t));
FunctionType f = new FunctionTypeImpl.synthetic(
typeParameterType(t), [t], [x],
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 = new FunctionTypeImpl.synthetic(dynamicType, [t], [],
nullabilitySuffix: NullabilitySuffix.star);
expect(() => f.instantiate([]), throwsA(new TypeMatcher<ArgumentError>()));
}
test_synthetic_instantiate_no_type_formals() {
FunctionType f = new FunctionTypeImpl.synthetic(dynamicType, [], [],
nullabilitySuffix: NullabilitySuffix.star);
expect(f.instantiate([]), same(f));
}
test_synthetic_instantiate_share_parameters() {
// T Function<T>(int x)
var t = typeParameter('T');
var x = requiredParameter(name: 'x', type: intType);
FunctionType f = new FunctionTypeImpl.synthetic(
typeParameterType(t), [t], [x],
nullabilitySuffix: NullabilitySuffix.star);
FunctionType instantiated = f.instantiate([objectType]);
basicChecks(instantiated,
element: isNull,
displayName: 'Object Function(int)',
returnType: same(objectType),
normalParameterNames: ['x'],
normalParameterTypes: [same(intType)],
parameters: same(f.parameters));
}
test_synthetic_namedParameter() {
var p = namedParameter(name: 'x', type: objectType);
FunctionType f = new FunctionTypeImpl.synthetic(dynamicType, [], [p],
nullabilitySuffix: NullabilitySuffix.star);
basicChecks(f,
element: isNull,
displayName: 'dynamic Function({x: Object})',
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 = new FunctionTypeImpl.synthetic(dynamicType, [], [p],
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 = new FunctionTypeImpl.synthetic(dynamicType, [], [p],
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 = new FunctionTypeImpl.synthetic(objectType, [], [],
nullabilitySuffix: NullabilitySuffix.star);
basicChecks(f,
element: isNull,
displayName: 'Object Function()',
returnType: same(objectType));
}
@deprecated
test_synthetic_substitute() {
// Map<T, U> Function<U extends T>(T x, U y)
var t = typeParameter('T');
var u = typeParameter('U', bound: typeParameterType(t));
var x = requiredParameter(name: 'x', type: typeParameterType(t));
var y = requiredParameter(name: 'y', type: typeParameterType(u));
FunctionType f = new FunctionTypeImpl.synthetic(
mapOf(typeParameterType(t), typeParameterType(u)), [u], [x, y],
nullabilitySuffix: NullabilitySuffix.star);
FunctionType substituted =
f.substitute2([objectType], [typeParameterType(t)]);
var uSubstituted = substituted.typeFormals[0];
basicChecks(substituted,
element: isNull,
displayName: 'Map<Object, U> Function<U extends Object>(Object, U)',
returnType: mapOf(objectType, typeParameterType(uSubstituted)),
typeFormals: [uSubstituted],
normalParameterNames: ['x', 'y'],
normalParameterTypes: [
same(objectType),
typeParameterType(uSubstituted)
],
parameters: hasLength(2));
}
@deprecated
test_synthetic_substitute_argument_length_mismatch() {
// dynamic Function()
var t = typeParameter('T');
FunctionType f = new FunctionTypeImpl.synthetic(dynamicType, [], [],
nullabilitySuffix: NullabilitySuffix.star);
expect(() => f.substitute2([], [typeParameterType(t)]),
throwsA(new TypeMatcher<ArgumentError>()));
}
@deprecated
test_synthetic_substitute_unchanged() {
// dynamic Function<U>(U x)
var t = typeParameter('T');
var u = typeParameter('U');
var x = requiredParameter(name: 'x', type: typeParameterType(u));
FunctionType f = new FunctionTypeImpl.synthetic(dynamicType, [u], [x],
nullabilitySuffix: NullabilitySuffix.star);
FunctionType substituted =
f.substitute2([objectType], [typeParameterType(t)]);
expect(substituted, same(f));
}
test_synthetic_typeFormals() {
var t = typeParameter('T');
FunctionType f = new FunctionTypeImpl.synthetic(
typeParameterType(t), [t], [],
nullabilitySuffix: NullabilitySuffix.star);
basicChecks(f,
element: isNull,
displayName: 'T Function<T>()',
returnType: typeParameterType(t),
typeFormals: [same(t)]);
}
}
class MockCompilationUnitElement implements CompilationUnitElement {
const MockCompilationUnitElement();
@override
get enclosingElement => const MockLibraryElement();
noSuchMethod(Invocation invocation) {
return super.noSuchMethod(invocation);
}
}
class MockFunctionTypedElement implements FunctionTypedElement {
@override
final List<ParameterElement> parameters;
@override
final DartType returnType;
@override
final List<TypeParameterElement> typeParameters;
@override
final Element enclosingElement;
MockFunctionTypedElement(
{this.parameters: const [],
DartType returnType,
this.typeParameters: const [],
this.enclosingElement: const MockCompilationUnitElement()})
: returnType = returnType ?? dynamicType;
MockFunctionTypedElement.withNullReturn(
{this.parameters: const [],
this.typeParameters: const [],
this.enclosingElement: const MockCompilationUnitElement()})
: returnType = null;
noSuchMethod(Invocation invocation) {
return super.noSuchMethod(invocation);
}
}
class MockLibraryElement implements LibraryElement {
const MockLibraryElement();
@override
get enclosingElement => null;
noSuchMethod(Invocation invocation) {
return super.noSuchMethod(invocation);
}
}