Skip to content
This repository has been archived by the owner on Feb 13, 2020. It is now read-only.

Commit

Permalink
Support for inheritance and getters
Browse files Browse the repository at this point in the history
  • Loading branch information
simc committed Oct 6, 2019
1 parent 104a8e2 commit 21c2234
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 34 deletions.
11 changes: 10 additions & 1 deletion lib/src/builder.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';

class AdapterField {
final int index;
final String name;
final DartType type;

AdapterField(this.index, this.name, this.type);
}

abstract class Builder {
final ClassElement cls;
final Map<int, FieldElement> fields;
final List<AdapterField> fields;

Builder(this.cls, this.fields)
: assert(cls != null),
Expand Down
29 changes: 14 additions & 15 deletions lib/src/class_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class ClassBuilder extends Builder {
var iterableChecker = const TypeChecker.fromRuntime(Iterable);
var uint8ListChecker = const TypeChecker.fromRuntime(Uint8List);

ClassBuilder(ClassElement cls, Map<int, FieldElement> fields)
ClassBuilder(ClassElement cls, List<AdapterField> fields)
: super(cls, fields);

@override
Expand All @@ -32,14 +32,15 @@ class ClassBuilder extends Builder {
);

// The remaining fields to initialize.
var remainingFields = <String, int>{
for (var entry in fields.entries) entry.value.name: entry.key,
};
var remainingFields = fields.toList();

for (var param in constructor.parameters
.where((param) => param.isInitializingFormal)) {
var index = remainingFields.remove(param.name);
if (index == null) {
var field = remainingFields.firstWhere(
(it) => it.name == param.name,
orElse: () => null,
);
if (field == null) {
// This is a parameter of the form `this.field`, but it's not present
// in the binary encoding.
continue;
Expand All @@ -48,18 +49,16 @@ class ClassBuilder extends Builder {
if (param.isNamed) {
code.write('${param.name}: ');
}
code.writeln('${_cast(param.type, 'fields[$index]')},');
code.writeln('${_cast(param.type, 'fields[${field.index}]')},');
}

code.writeln(')');

// There may still be fields to initialize that were not in the constructor
// as initializing formals. We do so using cascades.
for (var entry in remainingFields.entries) {
var field = entry.key;
var index = entry.value;
var type = fields[index].type;
code.writeln('..$field = ${_cast(type, 'fields[$index]')}');
for (var field in remainingFields) {
code.writeln(
'..${field.name} = ${_cast(field.type, 'fields[${field.index}]')}');
}

code.writeln(';');
Expand Down Expand Up @@ -121,12 +120,12 @@ class ClassBuilder extends Builder {
var code = StringBuffer();
code.writeln('writer');
code.writeln('..writeByte(${fields.length})');
fields.forEach((index, field) {
for (var field in fields) {
var value = _convertIterable(field.type, 'obj.${field.name}');
code.writeln('''
..writeByte($index)
..writeByte(${field.index})
..write($value)''');
});
}
code.writeln(';');

return code.toString();
Expand Down
15 changes: 7 additions & 8 deletions lib/src/enum_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@ import 'package:analyzer/dart/element/element.dart';
import 'package:hive_generator/src/builder.dart';

class EnumBuilder extends Builder {
EnumBuilder(ClassElement cls, Map<int, FieldElement> fields)
: super(cls, fields);
EnumBuilder(ClassElement cls, List<AdapterField> fields) : super(cls, fields);

@override
String buildRead() {
var code = StringBuffer();
code.writeln('switch(reader.readByte()) {');

fields.forEach((index, field) {
for (var field in fields) {
code.writeln('''
case $index:
case ${field.index}:
return ${cls.name}.${field.name};''');
});
}

code.writeln('''
default:
Expand All @@ -29,12 +28,12 @@ class EnumBuilder extends Builder {
var code = StringBuffer();
code.writeln('switch(obj) {');

fields.forEach((index, field) {
for (var field in fields) {
code.writeln('''
case ${cls.name}.${field.name}:
writer.writeByte($index);
writer.writeByte(${field.index});
break;''');
});
}

code.writeln('}');

Expand Down
16 changes: 16 additions & 0 deletions lib/src/helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@ import 'package:analyzer/dart/element/element.dart';
import 'package:hive/hive.dart';
import 'package:source_gen/source_gen.dart';

final _hiveTypeChecker = const TypeChecker.fromRuntime(HiveType);
final _hiveFieldChecker = const TypeChecker.fromRuntime(HiveField);

HiveType getHiveTypeAnn(Element element) {
var obj = _hiveTypeChecker.firstAnnotationOfExact(element);
if (obj == null) return null;
return HiveType(
adapterName: obj.getField('adapterName').toStringValue(),
);
}

HiveField getHiveFieldAnn(Element element) {
var obj = _hiveFieldChecker.firstAnnotationOfExact(element);
if (obj == null) return null;
Expand All @@ -12,6 +21,13 @@ HiveField getHiveFieldAnn(Element element) {
);
}

Iterable<ClassElement> getTypeAndAllSupertypes(ClassElement cls) {
var types = <ClassElement>{};
types.add(cls);
types.addAll(cls.allSupertypes.map((it) => it.element));
return types;
}

void check(bool condition, dynamic error) {
if (!condition) {
throw error;
Expand Down
53 changes: 43 additions & 10 deletions lib/src/type_adapter_generator.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';
import 'package:hive_generator/src/builder.dart';
import 'package:hive_generator/src/class_builder.dart';
import 'package:hive_generator/src/enum_builder.dart';
import 'package:hive_generator/src/helper.dart';
Expand All @@ -17,7 +18,6 @@ class TypeAdapterGenerator extends GeneratorForAnnotation<HiveType> {
cls.isEnum ? EnumBuilder(cls, fields) : ClassBuilder(cls, fields);

return '''
class $adapterName extends TypeAdapter<${cls.name}> {
@override
${cls.name} read(BinaryReader reader) {
Expand All @@ -44,20 +44,53 @@ class TypeAdapterGenerator extends GeneratorForAnnotation<HiveType> {
return cls;
}

Map<int, FieldElement> getFields(ClassElement cls) {
var typeFields = <int, FieldElement>{};
Iterable<AdapterField> getAccessors(ClassElement cls) {
var fields = <AdapterField>[];
for (var field in cls.fields) {
var fieldAnn = getHiveFieldAnn(field);
if (fieldAnn == null) continue;

var fieldNum = fieldAnn.index;
check(fieldNum >= 0 || fieldNum <= 255,
'Field numbers can only be in the range 0-255.');
check(!typeFields.containsKey(fieldNum),
'Duplicate field number: $fieldNum.');
typeFields[fieldNum] = field;
fields.add(AdapterField(fieldAnn.index, field.name, field.type));
}

for (var field in cls.accessors) {
var fieldAnn = getHiveFieldAnn(field);
if (fieldAnn == null || !field.isGetter) continue;

fields.add(AdapterField(fieldAnn.index, field.name, field.type));
}

return fields;
}

List<AdapterField> getFields(ClassElement cls) {
var types =
getTypeAndAllSupertypes(cls).where((it) => getHiveTypeAnn(it) != null);
for (var type in types) {
print('TYPE: $type');
}
var adapterFields = <AdapterField>[];
for (var type in types) {
var fields = getAccessors(type);
for (var field in fields) {
print(field.name);
check(field.index >= 0 || field.index <= 255,
'Field numbers can only be in the range 0-255.');

for (var otherField in fields) {
if (otherField == field) continue;
if (otherField.index == field.index) {
throw HiveError(
'Duplicate field number: ${field.index}. Fields "${field.name}" '
'and "${otherField.name}" have the same number.',
);
}
}

adapterFields.add(field);
}
}
return typeFields;
return adapterFields;
}

String getAdapterName(String typeName, ConstantReader annotation) {
Expand Down

0 comments on commit 21c2234

Please sign in to comment.