Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions lib/generators/json_serializable_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ class JsonSerializableGenerator
}
}

if (_implementsDartList(fieldType)) {
if (_coreListChecker.isAssignableFromType(fieldType)) {
var indexVal = "i${depth}";

var substitute = '${expression}[$indexVal]';
Expand Down Expand Up @@ -247,7 +247,7 @@ class JsonSerializableGenerator
}
}

if (_isDartIterable(searchType) || _isDartList(searchType)) {
if (_coreIterableChecker.isAssignableFromType(searchType)) {
var iterableGenericType =
_getIterableGenericType(searchType as InterfaceType);

Expand All @@ -257,7 +257,7 @@ class JsonSerializableGenerator
"${_writeAccessToVar(itemVal, iterableGenericType, depth: depth+1)}"
")";

if (_isDartList(searchType)) {
if (_coreListChecker.isAssignableFromType(searchType)) {
output += "?.toList()";
}

Expand Down Expand Up @@ -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;
Expand All @@ -313,8 +313,6 @@ DartType _typeTest(DartType type, bool tester(DartType type)) {
T _firstNotNull<T>(Iterable<T> 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');
3 changes: 2 additions & 1 deletion lib/src/json_serializable/type_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@matanlurey Dude – this is soooo much better. I was looking into cleaning this up for a while. Love your solution...

const TypeChecker.fromUrl('dart:core#DateTime').isExactlyType(type);

@override
String serialize(DartType targetType, String name) =>
Expand Down
10 changes: 10 additions & 0 deletions lib/src/type_checker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
8 changes: 8 additions & 0 deletions test/type_checker_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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)', () {
Expand All @@ -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);
});
});
}

Expand Down