blob: f3fdf5e877ccd3e670a5a798805f9cb5be3ad571 [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:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:nnbd_migration/src/decorated_class_hierarchy.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(DecoratedClassHierarchyTest);
});
}
@reflectiveTest
class DecoratedClassHierarchyTest extends MigrationVisitorTestBase {
DecoratedClassHierarchy _hierarchy;
@override
Future<CompilationUnit> analyze(String code) async {
var unit = await super.analyze(code);
_hierarchy = DecoratedClassHierarchy(variables, graph);
return unit;
}
Future<void> test_asInstanceOf_complex() async {
await analyze('''
class Base<T> {}
class Derived<U> extends Base<List<U>> {}
Derived<int> x;
''');
var decoratedType = decoratedTypeAnnotation('Derived<int>');
var asInstanceOfBase =
_hierarchy.asInstanceOf(decoratedType, findElement.class_('Base'));
_assertType(asInstanceOfBase.type, 'Base<List<int>>');
expect(asInstanceOfBase.node, same(decoratedType.node));
var listOfUType = decoratedTypeAnnotation('List<U>');
expect(asInstanceOfBase.typeArguments[0].node, same(listOfUType.node));
var substitution = asInstanceOfBase.typeArguments[0].typeArguments[0].node
as NullabilityNodeForSubstitution;
expect(substitution.innerNode, same(decoratedType.typeArguments[0].node));
expect(substitution.outerNode, same(listOfUType.typeArguments[0].node));
}
Future<void> test_getDecoratedSupertype_complex() async {
await analyze('''
class Base<T> {}
class Intermediate<U> extends Base<List<U>> {}
class Derived<V> extends Intermediate<Map<int, V>> {}
''');
var decoratedSupertype = _hierarchy.getDecoratedSupertype(
findElement.class_('Derived'), findElement.class_('Base'));
var listRef = decoratedTypeAnnotation('List');
var uRef = decoratedTypeAnnotation('U>>');
var mapRef = decoratedTypeAnnotation('Map');
var intRef = decoratedTypeAnnotation('int');
var vRef = decoratedTypeAnnotation('V>>');
_assertType(decoratedSupertype.type, 'Base<List<Map<int, V>>>');
expect(decoratedSupertype.node, same(never));
var baseArgs = decoratedSupertype.typeArguments;
expect(baseArgs, hasLength(1));
_assertType(baseArgs[0].type, 'List<Map<int, V>>');
expect(baseArgs[0].node, same(listRef.node));
var listArgs = baseArgs[0].typeArguments;
expect(listArgs, hasLength(1));
_assertType(listArgs[0].type, 'Map<int, V>');
var mapNode = listArgs[0].node as NullabilityNodeForSubstitution;
expect(mapNode.innerNode, same(mapRef.node));
expect(mapNode.outerNode, same(uRef.node));
var mapArgs = listArgs[0].typeArguments;
expect(mapArgs, hasLength(2));
_assertType(mapArgs[0].type, 'int');
expect(mapArgs[0].node, same(intRef.node));
_assertType(mapArgs[1].type, 'V');
expect(mapArgs[1].node, same(vRef.node));
}
Future<void> test_getDecoratedSupertype_extends_simple() async {
await analyze('''
class Base<T, U> {}
class Derived<V, W> extends Base<V, W> {}
''');
var decoratedSupertype = _hierarchy.getDecoratedSupertype(
findElement.class_('Derived'), findElement.class_('Base'));
var vRef = decoratedTypeAnnotation('V, W> {');
var wRef = decoratedTypeAnnotation('W> {');
_assertType(decoratedSupertype.type, 'Base<V, W>');
expect(decoratedSupertype.node, same(never));
expect(decoratedSupertype.typeArguments, hasLength(2));
_assertType(decoratedSupertype.typeArguments[0].type, 'V');
expect(decoratedSupertype.typeArguments[0].node, same(vRef.node));
_assertType(decoratedSupertype.typeArguments[1].type, 'W');
expect(decoratedSupertype.typeArguments[1].node, same(wRef.node));
}
Future<void> test_getDecoratedSupertype_implements_simple() async {
await analyze('''
class Base<T, U> {}
class Derived<V, W> implements Base<V, W> {}
''');
var decoratedSupertype = _hierarchy.getDecoratedSupertype(
findElement.class_('Derived'), findElement.class_('Base'));
var vRef = decoratedTypeAnnotation('V, W> {');
var wRef = decoratedTypeAnnotation('W> {');
_assertType(decoratedSupertype.type, 'Base<V, W>');
expect(decoratedSupertype.node, same(never));
expect(decoratedSupertype.typeArguments, hasLength(2));
_assertType(decoratedSupertype.typeArguments[0].type, 'V');
expect(decoratedSupertype.typeArguments[0].node, same(vRef.node));
_assertType(decoratedSupertype.typeArguments[1].type, 'W');
expect(decoratedSupertype.typeArguments[1].node, same(wRef.node));
}
Future<void> test_getDecoratedSupertype_not_generic() async {
await analyze('''
class Base {}
class Derived<T> extends Base {}
''');
var decoratedSupertype = _hierarchy.getDecoratedSupertype(
findElement.class_('Derived'), findElement.class_('Base'));
_assertType(decoratedSupertype.type, 'Base');
expect(decoratedSupertype.node, same(never));
expect(decoratedSupertype.typeArguments, isEmpty);
}
Future<void> test_getDecoratedSupertype_on_simple() async {
await analyze('''
class Base<T, U> {}
mixin Derived<V, W> on Base<V, W> {}
''');
var decoratedSupertype = _hierarchy.getDecoratedSupertype(
findElement.mixin('Derived'), findElement.class_('Base'));
var vRef = decoratedTypeAnnotation('V, W> {');
var wRef = decoratedTypeAnnotation('W> {');
_assertType(decoratedSupertype.type, 'Base<V, W>');
expect(decoratedSupertype.node, same(never));
expect(decoratedSupertype.typeArguments, hasLength(2));
_assertType(decoratedSupertype.typeArguments[0].type, 'V');
expect(decoratedSupertype.typeArguments[0].node, same(vRef.node));
_assertType(decoratedSupertype.typeArguments[1].type, 'W');
expect(decoratedSupertype.typeArguments[1].node, same(wRef.node));
}
Future<void> test_getDecoratedSupertype_unrelated_type() async {
await analyze('''
class A<T> {}
class B<T> {}
''');
expect(
() => _hierarchy.getDecoratedSupertype(
findElement.class_('A'), findElement.class_('B')),
throwsA(TypeMatcher<StateError>()));
}
Future<void> test_getDecoratedSupertype_with_simple() async {
await analyze('''
class Base<T, U> {}
class Derived<V, W> extends Object with Base<V, W> {}
''');
var decoratedSupertype = _hierarchy.getDecoratedSupertype(
findElement.class_('Derived'), findElement.class_('Base'));
var vRef = decoratedTypeAnnotation('V, W> {');
var wRef = decoratedTypeAnnotation('W> {');
_assertType(decoratedSupertype.type, 'Base<V, W>');
expect(decoratedSupertype.node, same(never));
expect(decoratedSupertype.typeArguments, hasLength(2));
_assertType(decoratedSupertype.typeArguments[0].type, 'V');
expect(decoratedSupertype.typeArguments[0].node, same(vRef.node));
_assertType(decoratedSupertype.typeArguments[1].type, 'W');
expect(decoratedSupertype.typeArguments[1].node, same(wRef.node));
}
void _assertType(DartType type, String expected) {
var typeStr = type.getDisplayString(withNullability: false);
expect(typeStr, expected);
}
}