| // Copyright (c) 2020, 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/nullability_suffix.dart'; |
| import 'package:analyzer/dart/element/type.dart'; |
| import 'package:analyzer/src/dart/element/type_visitor.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import 'element_test.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(RecursiveTypeVisitorTest); |
| }); |
| } |
| |
| @reflectiveTest |
| class RecursiveTypeVisitorTest extends AbstractTypeTest { |
| late final _MockRecursiveVisitor visitor; |
| |
| @override |
| void setUp() { |
| super.setUp(); |
| visitor = _MockRecursiveVisitor(); |
| } |
| |
| void test_callsDefaultBehavior() { |
| expect(intNone.accept(visitor), true); |
| visitor.assertVisitedType(intNone); |
| } |
| |
| void test_functionType_complex() { |
| final T = typeParameter('T', bound: intNone); |
| final K = typeParameter('K', bound: stringNone); |
| final a = positionalParameter(type: numNone); |
| final b = positionalParameter(type: doubleNone); |
| final c = namedParameter(name: 'c', type: voidNone); |
| final d = namedParameter(name: 'd', type: objectNone); |
| final type = functionType( |
| returnType: dynamicType, |
| typeFormals: [T, K], |
| parameters: [a, b, c, d], |
| nullabilitySuffix: NullabilitySuffix.none); |
| expect(type.accept(visitor), true); |
| visitor.assertVisitedTypes([ |
| dynamicType, |
| intNone, |
| stringNone, |
| numNone, |
| doubleNone, |
| voidNone, |
| objectNone |
| ]); |
| } |
| |
| void test_functionType_positionalParameter() { |
| final a = positionalParameter(type: intNone); |
| final type = functionType( |
| returnType: dynamicType, |
| typeFormals: [], |
| parameters: [a], |
| nullabilitySuffix: NullabilitySuffix.none); |
| expect(type.accept(visitor), true); |
| visitor.assertVisitedType(intNone); |
| } |
| |
| void test_functionType_returnType() { |
| final type = functionType( |
| returnType: intNone, |
| typeFormals: [], |
| parameters: [], |
| nullabilitySuffix: NullabilitySuffix.none); |
| expect(type.accept(visitor), true); |
| visitor.assertVisitedType(intNone); |
| } |
| |
| void test_functionType_typeFormal_bound() { |
| final T = typeParameter('T', bound: intNone); |
| final type = functionType( |
| returnType: dynamicType, |
| typeFormals: [T], |
| parameters: [], |
| nullabilitySuffix: NullabilitySuffix.none); |
| expect(type.accept(visitor), true); |
| visitor.assertVisitedTypes([dynamicType, intNone]); |
| } |
| |
| void test_functionType_typeFormal_noBound() { |
| final T = typeParameter('T'); |
| final type = functionType( |
| returnType: dynamicType, |
| typeFormals: [T], |
| parameters: [], |
| nullabilitySuffix: NullabilitySuffix.none); |
| expect(type.accept(visitor), true); |
| visitor.assertVisitedType(dynamicType); |
| } |
| |
| void test_interfaceType_typeParameter() { |
| final type = typeProvider.listType(intNone); |
| expect(type.accept(visitor), true); |
| visitor.assertVisitedType(intNone); |
| } |
| |
| void test_interfaceType_typeParameters() { |
| final type = typeProvider.mapType(intNone, stringNone); |
| expect(type.accept(visitor), true); |
| visitor.assertVisitedTypes([intNone, stringNone]); |
| } |
| |
| void test_interfaceType_typeParameters_nested() { |
| final innerList = typeProvider.listType(intNone); |
| final outerList = typeProvider.listType(innerList); |
| expect(outerList.accept(visitor), true); |
| visitor.assertVisitedType(intNone); |
| } |
| |
| void test_stopVisiting_first() { |
| final T = typeParameter('T', bound: intNone); |
| final K = typeParameter('K', bound: stringNone); |
| final a = positionalParameter(type: numNone); |
| final b = positionalParameter(type: doubleNone); |
| final c = namedParameter(name: 'c', type: voidNone); |
| final d = namedParameter(name: 'd', type: objectNone); |
| final type = functionType( |
| returnType: dynamicType, |
| typeFormals: [T, K], |
| parameters: [a, b, c, d], |
| nullabilitySuffix: NullabilitySuffix.none); |
| visitor.stopOnType = dynamicType; |
| expect(type.accept(visitor), false); |
| visitor.assertNotVisitedTypes( |
| [intNone, stringNone, numNone, doubleNone, voidNone, objectNone]); |
| } |
| |
| void test_stopVisiting_halfway() { |
| final T = typeParameter('T', bound: intNone); |
| final K = typeParameter('K', bound: stringNone); |
| final a = positionalParameter(type: numNone); |
| final b = positionalParameter(type: doubleNone); |
| final c = namedParameter(name: 'c', type: voidNone); |
| final d = namedParameter(name: 'd', type: objectNone); |
| final type = functionType( |
| returnType: dynamicType, |
| typeFormals: [T, K], |
| parameters: [a, b, c, d], |
| nullabilitySuffix: NullabilitySuffix.none); |
| visitor.stopOnType = intNone; |
| expect(type.accept(visitor), false); |
| visitor.assertNotVisitedTypes([stringNone, voidNone, objectNone]); |
| } |
| |
| void test_stopVisiting_nested() { |
| final innerType = typeProvider.mapType(intNone, stringNone); |
| final outerList = typeProvider.listType(innerType); |
| visitor.stopOnType = intNone; |
| expect(outerList.accept(visitor), false); |
| visitor.assertNotVisitedType(stringNone); |
| } |
| |
| void test_stopVisiting_nested_parent() { |
| final innerTypeStop = typeProvider.listType(intNone); |
| final innerTypeSkipped = typeProvider.listType(stringNone); |
| final outerType = typeProvider.mapType(innerTypeStop, innerTypeSkipped); |
| visitor.stopOnType = intNone; |
| expect(outerType.accept(visitor), false); |
| visitor.assertNotVisitedType(stringNone); |
| } |
| |
| void test_stopVisiting_typeParameters() { |
| final type = typeProvider.mapType(intNone, stringNone); |
| visitor.stopOnType = intNone; |
| expect(type.accept(visitor), false); |
| visitor.assertVisitedType(intNone); |
| visitor.assertNotVisitedType(stringNone); |
| } |
| } |
| |
| class _MockRecursiveVisitor extends RecursiveTypeVisitor { |
| final Set<DartType> visitedTypes = {}; |
| DartType? stopOnType; |
| |
| void assertNotVisitedType(DartType type) { |
| expect(visitedTypes, isNot(contains(type))); |
| } |
| |
| void assertNotVisitedTypes(Iterable<DartType> types) => |
| types.forEach(assertNotVisitedType); |
| |
| void assertVisitedType(DartType type) { |
| expect(visitedTypes, contains(type)); |
| } |
| |
| void assertVisitedTypes(Iterable<DartType> types) => |
| types.forEach(assertVisitedType); |
| |
| @override |
| bool visitDartType(DartType type) { |
| expect(type, isNotNull); |
| visitedTypes.add(type); |
| return type != stopOnType; |
| } |
| |
| @override |
| bool visitInterfaceType(InterfaceType type) { |
| visitedTypes.add(type); |
| if (type == stopOnType) { |
| return false; |
| } |
| return super.visitInterfaceType(type); |
| } |
| } |