From 6236d01a12061b895babd98e66225c9c8c6e016b Mon Sep 17 00:00:00 2001 From: David Morgan Date: Mon, 26 Aug 2019 13:56:54 +0200 Subject: [PATCH] Fix custom builders with import prefixes. --- .../lib/src/value_source_class.dart | 2 +- .../lib/src/value_source_field.dart | 33 +- .../lib/src/value_source_field.g.dart | 5 + end_to_end_test/lib/imported_values.dart | 51 +++ end_to_end_test/lib/imported_values.g.dart | 362 ++++++++++++++++++ end_to_end_test/lib/serializers.dart | 2 + end_to_end_test/lib/serializers.g.dart | 8 + .../test/imported_values_serializer_test.dart | 56 +++ .../test/imported_values_test.dart | 18 + 9 files changed, 534 insertions(+), 3 deletions(-) diff --git a/built_value_generator/lib/src/value_source_class.dart b/built_value_generator/lib/src/value_source_class.dart index c822a1d7..7fcb1ab2 100644 --- a/built_value_generator/lib/src/value_source_class.dart +++ b/built_value_generator/lib/src/value_source_class.dart @@ -707,7 +707,7 @@ abstract class ValueSourceClass if (hasBuilder) { for (var field in fields) { final type = field.typeInCompilationUnit(compilationUnit); - final typeInBuilder = field.typeInBuilder(compilationUnit); + final typeInBuilder = field.builderElementTypeWithPrefix; final name = field.name; if (field.isNestedBuilder) { diff --git a/built_value_generator/lib/src/value_source_field.dart b/built_value_generator/lib/src/value_source_field.dart index 8730adc3..e254fd6e 100644 --- a/built_value_generator/lib/src/value_source_field.dart +++ b/built_value_generator/lib/src/value_source_field.dart @@ -124,8 +124,9 @@ abstract class ValueSourceField // Try to get a resolved type first, it's faster. var result = builderElement.getter?.returnType?.displayName; if (result != null && result != 'dynamic') return result; - // Go via AST to allow use of unresolvable types not yet generated. - return parsedLibrary + // Go via AST to allow use of unresolvable types not yet generated; + // this includes generated Builder types. + result = parsedLibrary .getElementDeclaration(builderElement) ?.node ?.parent @@ -133,6 +134,34 @@ abstract class ValueSourceField ?.first .toString() ?? 'dynamic'; + // If we went via the AST there may be an import prefix, but we don't + // want one here. Strip it off. + if (result.contains('.')) { + result = result.substring(result.indexOf('.') + 1); + } + return result; + } + + /// The [builderElementType] plus any import prefix. + @memoized + String get builderElementTypeWithPrefix { + // If it's a real field, it's a [VariableDeclaration] which is guaranteed + // to have parent node [VariableDeclarationList] giving the type. + var fieldDeclaration = parsedLibrary.getElementDeclaration(builderElement); + if (fieldDeclaration != null) { + return (((fieldDeclaration.node as VariableDeclaration).parent) + as VariableDeclarationList) + ?.type + ?.toSource() ?? + 'dynamic'; + } else { + // Otherwise it's an explicit getter/setter pair; get the type from the getter. + return (parsedLibrary.getElementDeclaration(builderElement.getter).node + as MethodDeclaration) + ?.returnType + ?.toSource() ?? + 'dynamic'; + } } /// Gets the type name for the builder. Specify the compilation unit to diff --git a/built_value_generator/lib/src/value_source_field.g.dart b/built_value_generator/lib/src/value_source_field.g.dart index 2ebf6b5d..573dd6a9 100644 --- a/built_value_generator/lib/src/value_source_field.g.dart +++ b/built_value_generator/lib/src/value_source_field.g.dart @@ -26,6 +26,7 @@ class _$ValueSourceField extends ValueSourceField { bool __builderFieldIsNormalField; bool __builderFieldIsGetterSetterPair; String __buildElementType; + String __builderElementTypeWithPrefix; bool __isNestedBuilder; factory _$ValueSourceField( @@ -83,6 +84,10 @@ class _$ValueSourceField extends ValueSourceField { @override String get buildElementType => __buildElementType ??= super.buildElementType; + @override + String get builderElementTypeWithPrefix => + __builderElementTypeWithPrefix ??= super.builderElementTypeWithPrefix; + @override bool get isNestedBuilder => __isNestedBuilder ??= super.isNestedBuilder; diff --git a/end_to_end_test/lib/imported_values.dart b/end_to_end_test/lib/imported_values.dart index 44a53ad1..99515851 100644 --- a/end_to_end_test/lib/imported_values.dart +++ b/end_to_end_test/lib/imported_values.dart @@ -22,3 +22,54 @@ abstract class ImportedValue _$ImportedValue; ImportedValue._(); } + +// With a custom builder. +abstract class ImportedCustomValue + implements Built { + static Serializer get serializer => + _$importedCustomValueSerializer; + + prefix.SimpleValue get simpleValue; + BuiltList get simpleValues; + + factory ImportedCustomValue( + [void Function(ImportedCustomValueBuilder) updates]) = + _$ImportedCustomValue; + ImportedCustomValue._(); +} + +abstract class ImportedCustomValueBuilder + implements Builder { + prefix.SimpleValue simpleValue; + BuiltList simpleValues; + + ImportedCustomValueBuilder._(); + factory ImportedCustomValueBuilder() = _$ImportedCustomValueBuilder; +} + +// With a custom builder using nested buliders. +abstract class ImportedCustomNestedValue + implements + Built { + static Serializer get serializer => + _$importedCustomNestedValueSerializer; + + prefix.SimpleValue get simpleValue; + BuiltList get simpleValues; + + factory ImportedCustomNestedValue( + [void Function(ImportedCustomNestedValueBuilder) updates]) = + _$ImportedCustomNestedValue; + ImportedCustomNestedValue._(); +} + +abstract class ImportedCustomNestedValueBuilder + implements + Builder { + prefix.SimpleValueBuilder simpleValue; + ListBuilder simpleValues; + + ImportedCustomNestedValueBuilder._(); + factory ImportedCustomNestedValueBuilder() = + _$ImportedCustomNestedValueBuilder; +} diff --git a/end_to_end_test/lib/imported_values.g.dart b/end_to_end_test/lib/imported_values.g.dart index d05d4b43..c50ad3e1 100644 --- a/end_to_end_test/lib/imported_values.g.dart +++ b/end_to_end_test/lib/imported_values.g.dart @@ -8,6 +8,10 @@ part of imported_values; Serializer _$importedValueSerializer = new _$ImportedValueSerializer(); +Serializer _$importedCustomValueSerializer = + new _$ImportedCustomValueSerializer(); +Serializer _$importedCustomNestedValueSerializer = + new _$ImportedCustomNestedValueSerializer(); class _$ImportedValueSerializer implements StructuredSerializer { @override @@ -61,6 +65,120 @@ class _$ImportedValueSerializer implements StructuredSerializer { } } +class _$ImportedCustomValueSerializer + implements StructuredSerializer { + @override + final Iterable types = const [ + ImportedCustomValue, + _$ImportedCustomValue + ]; + @override + final String wireName = 'ImportedCustomValue'; + + @override + Iterable serialize( + Serializers serializers, ImportedCustomValue object, + {FullType specifiedType = FullType.unspecified}) { + final result = [ + 'simpleValue', + serializers.serialize(object.simpleValue, + specifiedType: const FullType(prefix.SimpleValue)), + 'simpleValues', + serializers.serialize(object.simpleValues, + specifiedType: const FullType( + BuiltList, const [const FullType(prefix.SimpleValue)])), + ]; + + return result; + } + + @override + ImportedCustomValue deserialize( + Serializers serializers, Iterable serialized, + {FullType specifiedType = FullType.unspecified}) { + final result = new ImportedCustomValueBuilder(); + + final iterator = serialized.iterator; + while (iterator.moveNext()) { + final key = iterator.current as String; + iterator.moveNext(); + final dynamic value = iterator.current; + switch (key) { + case 'simpleValue': + result.simpleValue = serializers.deserialize(value, + specifiedType: const FullType(prefix.SimpleValue)) + as prefix.SimpleValue; + break; + case 'simpleValues': + result.simpleValues = serializers.deserialize(value, + specifiedType: const FullType( + BuiltList, const [const FullType(prefix.SimpleValue)])) + as BuiltList; + break; + } + } + + return result.build(); + } +} + +class _$ImportedCustomNestedValueSerializer + implements StructuredSerializer { + @override + final Iterable types = const [ + ImportedCustomNestedValue, + _$ImportedCustomNestedValue + ]; + @override + final String wireName = 'ImportedCustomNestedValue'; + + @override + Iterable serialize( + Serializers serializers, ImportedCustomNestedValue object, + {FullType specifiedType = FullType.unspecified}) { + final result = [ + 'simpleValue', + serializers.serialize(object.simpleValue, + specifiedType: const FullType(prefix.SimpleValue)), + 'simpleValues', + serializers.serialize(object.simpleValues, + specifiedType: const FullType( + BuiltList, const [const FullType(prefix.SimpleValue)])), + ]; + + return result; + } + + @override + ImportedCustomNestedValue deserialize( + Serializers serializers, Iterable serialized, + {FullType specifiedType = FullType.unspecified}) { + final result = new ImportedCustomNestedValueBuilder(); + + final iterator = serialized.iterator; + while (iterator.moveNext()) { + final key = iterator.current as String; + iterator.moveNext(); + final dynamic value = iterator.current; + switch (key) { + case 'simpleValue': + result.simpleValue.replace(serializers.deserialize(value, + specifiedType: const FullType(prefix.SimpleValue)) + as prefix.SimpleValue); + break; + case 'simpleValues': + result.simpleValues.replace(serializers.deserialize(value, + specifiedType: const FullType( + BuiltList, const [const FullType(prefix.SimpleValue)])) + as BuiltList); + break; + } + } + + return result.build(); + } +} + class _$ImportedValue extends ImportedValue { @override final prefix.SimpleValue simpleValue; @@ -174,4 +292,248 @@ class ImportedValueBuilder } } +class _$ImportedCustomValue extends ImportedCustomValue { + @override + final prefix.SimpleValue simpleValue; + @override + final BuiltList simpleValues; + + factory _$ImportedCustomValue( + [void Function(ImportedCustomValueBuilder) updates]) => + (new ImportedCustomValueBuilder()..update(updates)).build() + as _$ImportedCustomValue; + + _$ImportedCustomValue._({this.simpleValue, this.simpleValues}) : super._() { + if (simpleValue == null) { + throw new BuiltValueNullFieldError('ImportedCustomValue', 'simpleValue'); + } + if (simpleValues == null) { + throw new BuiltValueNullFieldError('ImportedCustomValue', 'simpleValues'); + } + } + + @override + ImportedCustomValue rebuild( + void Function(ImportedCustomValueBuilder) updates) => + (toBuilder()..update(updates)).build(); + + @override + _$ImportedCustomValueBuilder toBuilder() => + new _$ImportedCustomValueBuilder()..replace(this); + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is ImportedCustomValue && + simpleValue == other.simpleValue && + simpleValues == other.simpleValues; + } + + @override + int get hashCode { + return $jf($jc($jc(0, simpleValue.hashCode), simpleValues.hashCode)); + } + + @override + String toString() { + return (newBuiltValueToStringHelper('ImportedCustomValue') + ..add('simpleValue', simpleValue) + ..add('simpleValues', simpleValues)) + .toString(); + } +} + +class _$ImportedCustomValueBuilder extends ImportedCustomValueBuilder { + _$ImportedCustomValue _$v; + + @override + prefix.SimpleValue get simpleValue { + _$this; + return super.simpleValue; + } + + @override + set simpleValue(prefix.SimpleValue simpleValue) { + _$this; + super.simpleValue = simpleValue; + } + + @override + BuiltList get simpleValues { + _$this; + return super.simpleValues; + } + + @override + set simpleValues(BuiltList simpleValues) { + _$this; + super.simpleValues = simpleValues; + } + + _$ImportedCustomValueBuilder() : super._(); + + ImportedCustomValueBuilder get _$this { + if (_$v != null) { + super.simpleValue = _$v.simpleValue; + super.simpleValues = _$v.simpleValues; + _$v = null; + } + return this; + } + + @override + void replace(ImportedCustomValue other) { + if (other == null) { + throw new ArgumentError.notNull('other'); + } + _$v = other as _$ImportedCustomValue; + } + + @override + void update(void Function(ImportedCustomValueBuilder) updates) { + if (updates != null) updates(this); + } + + @override + _$ImportedCustomValue build() { + final _$result = _$v ?? + new _$ImportedCustomValue._( + simpleValue: simpleValue, simpleValues: simpleValues); + replace(_$result); + return _$result; + } +} + +class _$ImportedCustomNestedValue extends ImportedCustomNestedValue { + @override + final prefix.SimpleValue simpleValue; + @override + final BuiltList simpleValues; + + factory _$ImportedCustomNestedValue( + [void Function(ImportedCustomNestedValueBuilder) updates]) => + (new ImportedCustomNestedValueBuilder()..update(updates)).build() + as _$ImportedCustomNestedValue; + + _$ImportedCustomNestedValue._({this.simpleValue, this.simpleValues}) + : super._() { + if (simpleValue == null) { + throw new BuiltValueNullFieldError( + 'ImportedCustomNestedValue', 'simpleValue'); + } + if (simpleValues == null) { + throw new BuiltValueNullFieldError( + 'ImportedCustomNestedValue', 'simpleValues'); + } + } + + @override + ImportedCustomNestedValue rebuild( + void Function(ImportedCustomNestedValueBuilder) updates) => + (toBuilder()..update(updates)).build(); + + @override + _$ImportedCustomNestedValueBuilder toBuilder() => + new _$ImportedCustomNestedValueBuilder()..replace(this); + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is ImportedCustomNestedValue && + simpleValue == other.simpleValue && + simpleValues == other.simpleValues; + } + + @override + int get hashCode { + return $jf($jc($jc(0, simpleValue.hashCode), simpleValues.hashCode)); + } + + @override + String toString() { + return (newBuiltValueToStringHelper('ImportedCustomNestedValue') + ..add('simpleValue', simpleValue) + ..add('simpleValues', simpleValues)) + .toString(); + } +} + +class _$ImportedCustomNestedValueBuilder + extends ImportedCustomNestedValueBuilder { + _$ImportedCustomNestedValue _$v; + + @override + prefix.SimpleValueBuilder get simpleValue { + _$this; + return super.simpleValue ??= new prefix.SimpleValueBuilder(); + } + + @override + set simpleValue(prefix.SimpleValueBuilder simpleValue) { + _$this; + super.simpleValue = simpleValue; + } + + @override + ListBuilder get simpleValues { + _$this; + return super.simpleValues ??= new ListBuilder(); + } + + @override + set simpleValues(ListBuilder simpleValues) { + _$this; + super.simpleValues = simpleValues; + } + + _$ImportedCustomNestedValueBuilder() : super._(); + + ImportedCustomNestedValueBuilder get _$this { + if (_$v != null) { + super.simpleValue = _$v.simpleValue?.toBuilder(); + super.simpleValues = _$v.simpleValues?.toBuilder(); + _$v = null; + } + return this; + } + + @override + void replace(ImportedCustomNestedValue other) { + if (other == null) { + throw new ArgumentError.notNull('other'); + } + _$v = other as _$ImportedCustomNestedValue; + } + + @override + void update(void Function(ImportedCustomNestedValueBuilder) updates) { + if (updates != null) updates(this); + } + + @override + _$ImportedCustomNestedValue build() { + _$ImportedCustomNestedValue _$result; + try { + _$result = _$v ?? + new _$ImportedCustomNestedValue._( + simpleValue: simpleValue.build(), + simpleValues: simpleValues.build()); + } catch (_) { + String _$failedField; + try { + _$failedField = 'simpleValue'; + simpleValue.build(); + _$failedField = 'simpleValues'; + simpleValues.build(); + } catch (e) { + throw new BuiltValueNestedFieldError( + 'ImportedCustomNestedValue', _$failedField, e.toString()); + } + rethrow; + } + replace(_$result); + return _$result; + } +} + // ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new diff --git a/end_to_end_test/lib/serializers.dart b/end_to_end_test/lib/serializers.dart index 7e473af2..603823ec 100644 --- a/end_to_end_test/lib/serializers.dart +++ b/end_to_end_test/lib/serializers.dart @@ -38,6 +38,8 @@ part 'serializers.g.dart'; HasDouble, HasString, ImportedValue, + ImportedCustomValue, + ImportedCustomNestedValue, NamedFactoryValue, NestedGenericContainer, NonBuiltGeneric, diff --git a/end_to_end_test/lib/serializers.g.dart b/end_to_end_test/lib/serializers.g.dart index df37e293..013415c4 100644 --- a/end_to_end_test/lib/serializers.g.dart +++ b/end_to_end_test/lib/serializers.g.dart @@ -26,6 +26,8 @@ Serializers _$serializers = (new Serializers().toBuilder() ..add(GenericValue.serializer) ..add(HasDouble.serializer) ..add(HasString.serializer) + ..add(ImportedCustomNestedValue.serializer) + ..add(ImportedCustomValue.serializer) ..add(ImportedValue.serializer) ..add(NamedFactoryValue.serializer) ..add(NestedGenericContainer.serializer) @@ -56,6 +58,12 @@ Serializers _$serializers = (new Serializers().toBuilder() ..addBuilderFactory( const FullType(BuiltList, const [const FullType(SimpleValue)]), () => new ListBuilder()) + ..addBuilderFactory( + const FullType(BuiltList, const [const FullType(SimpleValue)]), + () => new ListBuilder()) + ..addBuilderFactory( + const FullType(BuiltList, const [const FullType(SimpleValue)]), + () => new ListBuilder()) ..addBuilderFactory( const FullType( BuiltList, const [const FullType(ThirdDiscoverableValue)]), diff --git a/end_to_end_test/test/imported_values_serializer_test.dart b/end_to_end_test/test/imported_values_serializer_test.dart index 3c29fbd5..ad2a79b5 100644 --- a/end_to_end_test/test/imported_values_serializer_test.dart +++ b/end_to_end_test/test/imported_values_serializer_test.dart @@ -2,8 +2,10 @@ // 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:built_collection/built_collection.dart'; import 'package:end_to_end_test/imported_values.dart'; import 'package:end_to_end_test/serializers.dart'; +import 'package:end_to_end_test/values.dart'; import 'package:test/test.dart'; void main() { @@ -32,4 +34,58 @@ void main() { expect(serializers.deserialize(serialized), data); }); }); + + group('ImportedCustomValue', () { + var data = ImportedCustomValue((b) => b + ..simpleValue = SimpleValue((b) => b + ..anInt = 1 + ..aString = 'two') + ..simpleValues = BuiltList.of([])); + var serialized = [ + 'ImportedCustomValue', + 'simpleValue', + [ + 'anInt', + 1, + 'aString', + 'two', + ], + 'simpleValues', + [], + ]; + + test('can be serialized', () { + expect(serializers.serialize(data), serialized); + }); + + test('can be deserialized', () { + expect(serializers.deserialize(serialized), data); + }); + }); + + group('ImportedCustomNestedValue', () { + var data = ImportedCustomNestedValue((b) => b.simpleValue + ..anInt = 1 + ..aString = 'two'); + var serialized = [ + 'ImportedCustomNestedValue', + 'simpleValue', + [ + 'anInt', + 1, + 'aString', + 'two', + ], + 'simpleValues', + [], + ]; + + test('can be serialized', () { + expect(serializers.serialize(data), serialized); + }); + + test('can be deserialized', () { + expect(serializers.deserialize(serialized), data); + }); + }); } diff --git a/end_to_end_test/test/imported_values_test.dart b/end_to_end_test/test/imported_values_test.dart index 1c5ba909..2c731765 100644 --- a/end_to_end_test/test/imported_values_test.dart +++ b/end_to_end_test/test/imported_values_test.dart @@ -2,7 +2,9 @@ // 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:built_collection/built_collection.dart'; import 'package:end_to_end_test/imported_values.dart'; +import 'package:end_to_end_test/values.dart'; import 'package:test/test.dart'; void main() { @@ -11,4 +13,20 @@ void main() { ImportedValue((b) => b..simpleValue.anInt = 3); }); }); + + group('ImportedCustomValue', () { + test('can be instantiated', () { + ImportedCustomValue((b) => b + ..simpleValue = SimpleValue((b) => b..anInt = 3) + ..simpleValues = BuiltList.of([])); + }); + }); + + group('ImportedCustomNestedValue', () { + test('can be instantiated', () { + ImportedCustomNestedValue((b) => b + ..simpleValue.anInt = 3 + ..simpleValues.add(SimpleValue((b) => b..anInt = 4))); + }); + }); }