blob: ef4476f19a8606641585837f2104030e3c418836 [file] [log] [blame]
// Copyright (c) 2019, 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:nnbd_migration/src/decorated_type.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'migration_visitor_test_base.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(NodeBuilderTest);
});
}
@reflectiveTest
class NodeBuilderTest extends MigrationVisitorTestBase {
/// Gets the [DecoratedType] associated with the constructor declaration whose
/// name matches [search].
DecoratedType decoratedConstructorDeclaration(String search) => variables
.decoratedElementType(findNode.constructor(search).declaredElement);
/// Gets the [DecoratedType] associated with the function declaration whose
/// name matches [search].
DecoratedType decoratedFunctionType(String search) =>
variables.decoratedElementType(
findNode.functionDeclaration(search).declaredElement);
DecoratedType decoratedTypeParameterBound(String search) => variables
.decoratedElementType(findNode.typeParameter(search).declaredElement);
test_constructor_returnType_implicit_dynamic() async {
await analyze('''
class C {
C();
}
''');
var decoratedType = decoratedConstructorDeclaration('C(').returnType;
expect(decoratedType.node, same(never));
}
test_dynamic_type() async {
await analyze('''
dynamic f() {}
''');
var decoratedType = decoratedTypeAnnotation('dynamic');
expect(decoratedFunctionType('f').returnType, same(decoratedType));
assertEdge(always, decoratedType.node, hard: false);
}
test_field_type_simple() async {
await analyze('''
class C {
int f = 0;
}
''');
var decoratedType = decoratedTypeAnnotation('int');
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
expect(
variables.decoratedElementType(
findNode.fieldDeclaration('f').fields.variables[0].declaredElement),
same(decoratedType));
}
test_genericFunctionType_namedParameterType() async {
await analyze('''
void f(void Function({int y}) x) {}
''');
var decoratedType =
decoratedGenericFunctionTypeAnnotation('void Function({int y})');
expect(decoratedFunctionType('f').positionalParameters[0],
same(decoratedType));
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
var decoratedIntType = decoratedTypeAnnotation('int');
expect(decoratedType.namedParameters['y'], same(decoratedIntType));
expect(decoratedIntType.node, isNotNull);
expect(decoratedIntType.node, isNot(never));
}
test_genericFunctionType_returnType() async {
await analyze('''
void f(int Function() x) {}
''');
var decoratedType =
decoratedGenericFunctionTypeAnnotation('int Function()');
expect(decoratedFunctionType('f').positionalParameters[0],
same(decoratedType));
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
var decoratedIntType = decoratedTypeAnnotation('int');
expect(decoratedType.returnType, same(decoratedIntType));
expect(decoratedIntType.node, isNotNull);
expect(decoratedIntType.node, isNot(never));
}
test_genericFunctionType_unnamedParameterType() async {
await analyze('''
void f(void Function(int) x) {}
''');
var decoratedType =
decoratedGenericFunctionTypeAnnotation('void Function(int)');
expect(decoratedFunctionType('f').positionalParameters[0],
same(decoratedType));
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
var decoratedIntType = decoratedTypeAnnotation('int');
expect(decoratedType.positionalParameters[0], same(decoratedIntType));
expect(decoratedIntType.node, isNotNull);
expect(decoratedIntType.node, isNot(never));
}
test_interfaceType_generic_instantiate_to_dynamic() async {
await analyze('''
void f(List x) {}
''');
var decoratedListType = decoratedTypeAnnotation('List');
expect(decoratedFunctionType('f').positionalParameters[0],
same(decoratedListType));
expect(decoratedListType.node, isNotNull);
expect(decoratedListType.node, isNot(never));
var decoratedArgType = decoratedListType.typeArguments[0];
expect(decoratedArgType.node, same(always));
}
test_interfaceType_generic_instantiate_to_generic_type() async {
await analyze('''
class C<T> {}
class D<T extends C<int>> {}
void f(D x) {}
''');
var decoratedListType = decoratedTypeAnnotation('D x');
expect(decoratedFunctionType('f').positionalParameters[0],
same(decoratedListType));
expect(decoratedListType.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedListType.typeArguments, hasLength(1));
var decoratedArgType = decoratedListType.typeArguments[0];
expect(decoratedArgType.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedArgType.typeArguments, hasLength(1));
var decoratedArgArgType = decoratedArgType.typeArguments[0];
expect(decoratedArgArgType.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedArgArgType.typeArguments, isEmpty);
}
test_interfaceType_generic_instantiate_to_generic_type_2() async {
await analyze('''
class C<T, U> {}
class D<T extends C<int, String>, U extends C<num, double>> {}
void f(D x) {}
''');
var decoratedDType = decoratedTypeAnnotation('D x');
expect(decoratedFunctionType('f').positionalParameters[0],
same(decoratedDType));
expect(decoratedDType.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedDType.typeArguments, hasLength(2));
var decoratedArg0Type = decoratedDType.typeArguments[0];
expect(decoratedArg0Type.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedArg0Type.typeArguments, hasLength(2));
var decoratedArg0Arg0Type = decoratedArg0Type.typeArguments[0];
expect(decoratedArg0Arg0Type.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedArg0Arg0Type.typeArguments, isEmpty);
var decoratedArg0Arg1Type = decoratedArg0Type.typeArguments[1];
expect(decoratedArg0Arg1Type.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedArg0Arg1Type.typeArguments, isEmpty);
var decoratedArg1Type = decoratedDType.typeArguments[1];
expect(decoratedArg1Type.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedArg1Type.typeArguments, hasLength(2));
var decoratedArg1Arg0Type = decoratedArg1Type.typeArguments[0];
expect(decoratedArg1Arg0Type.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedArg1Arg0Type.typeArguments, isEmpty);
var decoratedArg1Arg1Type = decoratedArg1Type.typeArguments[1];
expect(decoratedArg1Arg1Type.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedArg1Arg1Type.typeArguments, isEmpty);
}
test_interfaceType_generic_instantiate_to_object() async {
await analyze('''
class C<T extends Object> {}
void f(C x) {}
''');
var decoratedListType = decoratedTypeAnnotation('C x');
expect(decoratedFunctionType('f').positionalParameters[0],
same(decoratedListType));
expect(decoratedListType.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedListType.typeArguments, hasLength(1));
var decoratedArgType = decoratedListType.typeArguments[0];
expect(decoratedArgType.node, TypeMatcher<NullabilityNodeMutable>());
expect(decoratedArgType.typeArguments, isEmpty);
}
test_interfaceType_typeParameter() async {
await analyze('''
void f(List<int> x) {}
''');
var decoratedListType = decoratedTypeAnnotation('List<int>');
expect(decoratedFunctionType('f').positionalParameters[0],
same(decoratedListType));
expect(decoratedListType.node, isNotNull);
expect(decoratedListType.node, isNot(never));
var decoratedIntType = decoratedTypeAnnotation('int');
expect(decoratedListType.typeArguments[0], same(decoratedIntType));
expect(decoratedIntType.node, isNotNull);
expect(decoratedIntType.node, isNot(never));
}
test_topLevelFunction_parameterType_implicit_dynamic() async {
await analyze('''
void f(x) {}
''');
var decoratedType =
variables.decoratedElementType(findNode.simple('x').staticElement);
expect(decoratedFunctionType('f').positionalParameters[0],
same(decoratedType));
expect(decoratedType.type.isDynamic, isTrue);
assertUnion(always, decoratedType.node);
}
test_topLevelFunction_parameterType_named_no_default() async {
await analyze('''
void f({String s}) {}
''');
var decoratedType = decoratedTypeAnnotation('String');
var functionType = decoratedFunctionType('f');
expect(functionType.namedParameters['s'], same(decoratedType));
expect(decoratedType.node, isNotNull);
expect(decoratedType.node, isNot(never));
expect(decoratedType.node, isNot(always));
expect(functionType.namedParameters['s'].node.isPossiblyOptional, true);
}
test_topLevelFunction_parameterType_named_no_default_required() async {
addMetaPackage();
await analyze('''
import 'package:meta/meta.dart';
void f({@required String s}) {}
''');
var decoratedType = decoratedTypeAnnotation('String');
var functionType = decoratedFunctionType('f');
expect(functionType.namedParameters['s'], same(decoratedType));
expect(decoratedType.node, isNotNull);
expect(decoratedType.node, isNot(never));
expect(decoratedType.node, isNot(always));
expect(functionType.namedParameters['s'].node.isPossiblyOptional, false);
}
test_topLevelFunction_parameterType_named_with_default() async {
await analyze('''
void f({String s: 'x'}) {}
''');
var decoratedType = decoratedTypeAnnotation('String');
var functionType = decoratedFunctionType('f');
expect(functionType.namedParameters['s'], same(decoratedType));
expect(decoratedType.node, isNotNull);
expect(decoratedType.node, isNot(never));
expect(functionType.namedParameters['s'].node.isPossiblyOptional, false);
}
test_topLevelFunction_parameterType_positionalOptional() async {
await analyze('''
void f([int i]) {}
''');
var decoratedType = decoratedTypeAnnotation('int');
expect(decoratedFunctionType('f').positionalParameters[0],
same(decoratedType));
expect(decoratedType.node, isNotNull);
expect(decoratedType.node, isNot(never));
}
test_topLevelFunction_parameterType_simple() async {
await analyze('''
void f(int i) {}
''');
var decoratedType = decoratedTypeAnnotation('int');
expect(decoratedFunctionType('f').positionalParameters[0],
same(decoratedType));
expect(decoratedType.node, isNotNull);
expect(decoratedType.node, isNot(never));
}
test_topLevelFunction_returnType_implicit_dynamic() async {
await analyze('''
f() {}
''');
var decoratedType = decoratedFunctionType('f').returnType;
expect(decoratedType.type.isDynamic, isTrue);
assertUnion(always, decoratedType.node);
}
test_topLevelFunction_returnType_simple() async {
await analyze('''
int f() => 0;
''');
var decoratedType = decoratedTypeAnnotation('int');
expect(decoratedFunctionType('f').returnType, same(decoratedType));
expect(decoratedType.node, isNotNull);
expect(decoratedType.node, isNot(never));
}
test_type_comment_bang() async {
await analyze('''
void f(int/*!*/ i) {}
''');
assertEdge(decoratedTypeAnnotation('int').node, never, hard: true);
}
test_type_comment_question() async {
await analyze('''
void f(int/*?*/ i) {}
''');
assertEdge(always, decoratedTypeAnnotation('int').node, hard: false);
}
test_type_parameter_explicit_bound() async {
await analyze('''
class C<T extends Object> {}
''');
var bound = decoratedTypeParameterBound('T');
expect(decoratedTypeAnnotation('Object'), same(bound));
expect(bound.node, isNot(always));
expect(bound.type, typeProvider.objectType);
}
test_type_parameter_implicit_bound() async {
// The implicit bound of `T` is automatically `Object?`. TODO(paulberry):
// consider making it possible for type inference to infer an explicit bound
// of `Object`.
await analyze('''
class C<T> {}
''');
var bound = decoratedTypeParameterBound('T');
assertUnion(always, bound.node);
expect(bound.type, same(typeProvider.objectType));
}
test_variableDeclaration_type_simple() async {
await analyze('''
main() {
int i;
}
''');
var decoratedType = decoratedTypeAnnotation('int');
expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
}
test_void_type() async {
await analyze('''
void f() {}
''');
var decoratedType = decoratedTypeAnnotation('void');
expect(decoratedFunctionType('f').returnType, same(decoratedType));
assertEdge(always, decoratedType.node, hard: false);
}
}