diff --git a/lib/generators/json_serializable_generator.dart b/lib/generators/json_serializable_generator.dart index 36f7a18c..16c7f205 100644 --- a/lib/generators/json_serializable_generator.dart +++ b/lib/generators/json_serializable_generator.dart @@ -204,7 +204,7 @@ class JsonSerializableGenerator } } - if (_implementsDartList(fieldType)) { + if (_coreListChecker.isAssignableFromType(fieldType)) { var indexVal = "i${depth}"; var substitute = '${expression}[$indexVal]'; @@ -247,7 +247,7 @@ class JsonSerializableGenerator } } - if (_isDartIterable(searchType) || _isDartList(searchType)) { + if (_coreIterableChecker.isAssignableFromType(searchType)) { var iterableGenericType = _getIterableGenericType(searchType as InterfaceType); @@ -257,7 +257,7 @@ class JsonSerializableGenerator "${_writeAccessToVar(itemVal, iterableGenericType, depth: depth+1)}" ")"; - if (_isDartList(searchType)) { + if (_coreListChecker.isAssignableFromType(searchType)) { output += "?.toList()"; } @@ -287,24 +287,24 @@ String _fieldToJsonMapKey(String fieldName, FieldElement field) { } DartType _getIterableGenericType(InterfaceType type) { - var iterableThing = _typeTest(type, _isDartIterable) as InterfaceType; + var iterableImplementation = + _getImplementationType(type, _coreIterableChecker) as InterfaceType; - return iterableThing.typeArguments.single; + return iterableImplementation.typeArguments.single; } -bool _implementsDartList(DartType type) => _typeTest(type, _isDartList) != null; - -DartType _typeTest(DartType type, bool tester(DartType type)) { - if (tester(type)) return type; +DartType _getImplementationType(DartType type, TypeChecker checker) { + if (checker.isExactlyType(type)) return type; if (type is InterfaceType) { - var tests = type.interfaces.map((type) => _typeTest(type, tester)); + var tests = + type.interfaces.map((type) => _getImplementationType(type, checker)); var match = _firstNotNull(tests); if (match != null) return match; if (type.superclass != null) { - return _typeTest(type.superclass, tester); + return _getImplementationType(type.superclass, checker); } } return null; @@ -313,8 +313,6 @@ DartType _typeTest(DartType type, bool tester(DartType type)) { T _firstNotNull(Iterable values) => values.firstWhere((value) => value != null, orElse: () => null); -bool _isDartIterable(DartType type) => - const TypeChecker.fromUrl('dart:core#Iterable').isExactlyType(type); +final _coreIterableChecker = const TypeChecker.fromUrl('dart:core#Iterable'); -bool _isDartList(DartType type) => - const TypeChecker.fromUrl('dart:core#List').isExactlyType(type); +final _coreListChecker = const TypeChecker.fromUrl('dart:core#List'); diff --git a/lib/src/json_serializable/type_helper.dart b/lib/src/json_serializable/type_helper.dart index fdcd8c22..23d7154f 100644 --- a/lib/src/json_serializable/type_helper.dart +++ b/lib/src/json_serializable/type_helper.dart @@ -4,6 +4,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; +import 'package:source_gen/src/type_checker.dart'; abstract class TypeHelper { const TypeHelper(); @@ -104,7 +105,7 @@ class DateTimeHelper extends TypeHelper { bool canDeserialize(DartType type) => _matchesType(type); bool _matchesType(DartType type) => - type.element.library?.isDartCore == true && type.name == 'DateTime'; + const TypeChecker.fromUrl('dart:core#DateTime').isExactlyType(type); @override String serialize(DartType targetType, String name) => diff --git a/lib/src/type_checker.dart b/lib/src/type_checker.dart index 794ddbde..3af42b16 100644 --- a/lib/src/type_checker.dart +++ b/lib/src/type_checker.dart @@ -46,6 +46,16 @@ abstract class TypeChecker { .map((a) => a.computeConstantValue()) .where((a) => isExactlyType(a.type)); + /// Returns `true` if representing the exact same class an or a superclass of + /// [element] + bool isAssignableFrom(Element element) => + isExactly(element) || isSuperOf(element); + + /// Returns `true` if representing the exact same type as or a supertype of + /// [staticType]. + bool isAssignableFromType(DartType staticType) => + isAssignableFrom(staticType.element); + /// Returns `true` if representing the exact same class as [element]. bool isExactly(Element element); diff --git a/test/type_checker_test.dart b/test/type_checker_test.dart index e5c95364..5988ec4d 100644 --- a/test/type_checker_test.dart +++ b/test/type_checker_test.dart @@ -52,6 +52,10 @@ void main() { test('should be a super type of dart:collection#HashMap', () { expect(checkMap().isSuperTypeOf(staticHashMap), isTrue); }); + + test('should be assignable from dart:collection#HashMap', () { + expect(checkMap().isAssignableFromType(staticHashMap), isTrue); + }); }); group('(HashMap)', () { @@ -63,6 +67,10 @@ void main() { test('should not be a super type of dart:core#Map', () { expect(checkHashMap().isSuperTypeOf(staticMap), isFalse); }); + + test('should not assignable from type dart:core#Map', () { + expect(checkHashMap().isAssignableFromType(staticMap), isFalse); + }); }); }