Skip to content

Commit

Permalink
feat: add common properties with different nullability to base mixin
Browse files Browse the repository at this point in the history
  • Loading branch information
DevNico committed Aug 15, 2022
1 parent 8e92683 commit 753c5a7
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 27 deletions.
41 changes: 34 additions & 7 deletions packages/freezed/lib/src/freezed_generator.dart
Expand Up @@ -147,6 +147,8 @@ class FreezedGenerator extends ParserGenerator<GlobalData, Data, Freezed> {
isPossiblyDartCollection: commonParameter.isPossiblyDartCollection,
// TODO: support hasJsonKey
hasJsonKey: false,
isCommonWithDifferentNullability:
commonParameter.isCommonWithDifferentNullability,
),
];
}
Expand Down Expand Up @@ -252,27 +254,50 @@ Read here: https://github.com/rrousselGit/freezed/blob/master/packages/freezed/C
) {
return constructorsNeedsGeneration.first.parameters.allParameters
.map((parameter) {
var hasAnyFinalProperty = false;
var anyMatchingPropertyIsFinal = false;
var anyMatchingPropertyIsNullable = false;

for (final constructor in constructorsNeedsGeneration) {
final matchingParameter =
constructor.parameters.allParameters.firstWhereOrNull((p) {
return p.name == parameter.name && p.type == parameter.type;
return p.name == parameter.name &&
_typeStringWithoutNullability(p.type) ==
_typeStringWithoutNullability(parameter.type);
});

if (matchingParameter == null) return null;
if (matchingParameter.isFinal) hasAnyFinalProperty = true;
if (matchingParameter.isFinal) anyMatchingPropertyIsFinal = true;
if (matchingParameter.isNullable)
anyMatchingPropertyIsNullable = true;
}

if (hasAnyFinalProperty) {
return parameter.copyWith(isFinal: true);
final isNullable =
parameter.isNullable || anyMatchingPropertyIsNullable;

if (parameter.isNullable != isNullable) {
print(parameter.name);
}

return parameter;
return parameter.copyWith(
isFinal: parameter.isFinal || anyMatchingPropertyIsFinal,
isNullable: isNullable,
type: isNullable && (parameter.type?.endsWith('?') == false)
? '${parameter.type}?'
: parameter.type,
isCommonWithDifferentNullability:
parameter.isNullable != isNullable,
);
})
.whereNotNull()
.toList();
}

String? _typeStringWithoutNullability(String? type) {
return type?.endsWith('?') == true
? type?.substring(0, type.length - 1)
: type;
}

Future<List<ConstructorDetails>> _parseConstructorsNeedsGeneration(
BuildStep buildStep,
ClassElement element,
Expand Down Expand Up @@ -606,7 +631,9 @@ Read here: https://github.com/rrousselGit/freezed/blob/master/packages/freezed/C
).toList(),
genericsDefinition: data.genericsDefinitionTemplate,
genericsParameter: data.genericsParameterTemplate,
allProperties: commonProperties,
allProperties: commonProperties
.whereNot((element) => element.isCommonWithDifferentNullability)
.toList(),
data: data,
);

Expand Down
1 change: 1 addition & 0 deletions packages/freezed/lib/src/templates/concrete_template.dart
Expand Up @@ -135,6 +135,7 @@ ${copyWith?.abstractCopyWithGetter ?? ''}
doc: '',
isPossiblyDartCollection: false,
showDefaultValue: false,
isCommonWithDifferentNullability: false,
);

parameters = ParametersTemplate(
Expand Down
40 changes: 23 additions & 17 deletions packages/freezed/lib/src/templates/copy_with.dart
@@ -1,3 +1,4 @@
import 'package:collection/collection.dart';
import 'package:freezed/src/templates/parameter_template.dart';
import 'package:freezed/src/templates/properties.dart';

Expand Down Expand Up @@ -65,23 +66,28 @@ ${_abstractDeepCopyMethods().join()}
final body = _copyWithMethodBody(
parametersTemplate: ParametersTemplate(
const [],
namedParameters: commonProperties.map((e) {
return Parameter(
decorators: e.decorators,
name: e.name,
isNullable: false,
isFinal: false,
isDartList: false,
isDartMap: false,
isDartSet: false,
showDefaultValue: false,
isRequired: false,
defaultValueSource: '',
type: e.type,
doc: e.doc,
isPossiblyDartCollection: e.isPossiblyDartCollection,
);
}).toList(),
namedParameters: commonProperties
.map((e) {
return Parameter(
decorators: e.decorators,
name: e.name,
isNullable: false,
isFinal: false,
isDartList: false,
isDartMap: false,
isDartSet: false,
showDefaultValue: false,
isRequired: false,
defaultValueSource: '',
type: e.type,
doc: e.doc,
isPossiblyDartCollection: e.isPossiblyDartCollection,
isCommonWithDifferentNullability:
e.isCommonWithDifferentNullability,
);
})
.whereNot((element) => element.isCommonWithDifferentNullability)
.toList(),
),
returnType: '_value.copyWith',
);
Expand Down
12 changes: 12 additions & 0 deletions packages/freezed/lib/src/templates/parameter_template.dart
Expand Up @@ -82,6 +82,7 @@ class ParametersTemplate {
doc: await documentationOfParameter(e, buildStep),
isPossiblyDartCollection: e.type.isPossiblyDartCollection,
showDefaultValue: true,
isCommonWithDifferentNullability: false,
);

if (isAssignedToThis) return LocalParameter.fromParameter(value);
Expand Down Expand Up @@ -184,6 +185,7 @@ class Parameter {
required this.isFinal,
required this.isPossiblyDartCollection,
required this.showDefaultValue,
required this.isCommonWithDifferentNullability,
});

Parameter.fromParameter(Parameter p)
Expand All @@ -201,6 +203,7 @@ class Parameter {
showDefaultValue: p.showDefaultValue,
doc: p.doc,
isPossiblyDartCollection: p.isPossiblyDartCollection,
isCommonWithDifferentNullability: p.isCommonWithDifferentNullability,
);

final String? type;
Expand All @@ -216,6 +219,7 @@ class Parameter {
final bool isPossiblyDartCollection;
final bool isFinal;
final String doc;
final bool isCommonWithDifferentNullability;

Parameter copyWith({
String? type,
Expand All @@ -232,6 +236,7 @@ class Parameter {
bool? isDartMap,
bool? isDartSet,
bool? isFinal,
bool? isCommonWithDifferentNullability,
}) =>
Parameter(
type: type ?? this.type,
Expand All @@ -248,6 +253,8 @@ class Parameter {
isFinal: isFinal ?? this.isFinal,
isPossiblyDartCollection:
isPossiblyDartCollection ?? this.isPossiblyDartCollection,
isCommonWithDifferentNullability: isCommonWithDifferentNullability ??
this.isCommonWithDifferentNullability,
);

@override
Expand Down Expand Up @@ -283,6 +290,7 @@ class LocalParameter extends Parameter {
required List<String> decorators,
required String doc,
required bool isPossiblyDartCollection,
required bool isCommonWithDifferentNullability,
}) : super(
name: name,
type: type,
Expand All @@ -297,6 +305,7 @@ class LocalParameter extends Parameter {
defaultValueSource: defaultValueSource,
doc: doc,
isPossiblyDartCollection: isPossiblyDartCollection,
isCommonWithDifferentNullability: isCommonWithDifferentNullability,
);

LocalParameter.fromParameter(Parameter p)
Expand All @@ -313,6 +322,7 @@ class LocalParameter extends Parameter {
decorators: p.decorators,
doc: p.doc,
isPossiblyDartCollection: p.isPossiblyDartCollection,
isCommonWithDifferentNullability: p.isCommonWithDifferentNullability,
);

@override
Expand Down Expand Up @@ -346,6 +356,7 @@ class CallbackParameter extends Parameter {
required this.parameters,
required String doc,
required bool isPossiblyDartCollection,
required bool isCommonWithDifferentNullability,
}) : super(
name: name,
type: type,
Expand All @@ -360,6 +371,7 @@ class CallbackParameter extends Parameter {
defaultValueSource: defaultValueSource,
doc: doc,
isPossiblyDartCollection: isPossiblyDartCollection,
isCommonWithDifferentNullability: isCommonWithDifferentNullability,
);

final ParametersTemplate parameters;
Expand Down
6 changes: 6 additions & 0 deletions packages/freezed/lib/src/templates/properties.dart
Expand Up @@ -31,6 +31,7 @@ class Property {
required this.isDartMap,
required this.isDartSet,
required this.isPossiblyDartCollection,
required this.isCommonWithDifferentNullability,
}) : type = type ?? 'dynamic';

static Future<Property> fromParameter(
Expand Down Expand Up @@ -60,6 +61,7 @@ class Property {
defaultValueSource: defaultValue,
hasJsonKey: element.hasJsonKey,
isPossiblyDartCollection: element.type.isPossiblyDartCollection,
isCommonWithDifferentNullability: false,
);
}

Expand All @@ -75,6 +77,7 @@ class Property {
final bool hasJsonKey;
final String doc;
final bool isPossiblyDartCollection;
final bool isCommonWithDifferentNullability;

@override
String toString() {
Expand Down Expand Up @@ -135,6 +138,7 @@ class Property {
bool? hasJsonKey,
String? doc,
bool? isPossiblyDartCollection,
bool? isCommonWithDifferentNullability,
}) {
return Property(
type: type ?? this.type,
Expand All @@ -150,6 +154,8 @@ class Property {
isDartSet: isDartSet ?? this.isDartSet,
isPossiblyDartCollection:
isPossiblyDartCollection ?? this.isPossiblyDartCollection,
isCommonWithDifferentNullability: isCommonWithDifferentNullability ??
this.isCommonWithDifferentNullability,
);
}
}
Expand Down
2 changes: 2 additions & 0 deletions packages/freezed/lib/src/templates/prototypes.dart
Expand Up @@ -127,6 +127,7 @@ String _mapPrototype(
// TODO: do we want to support freezed classes that implements MapView/ListView?
isPossiblyDartCollection: false,
showDefaultValue: false,
isCommonWithDifferentNullability: false,
),
]);
},
Expand Down Expand Up @@ -191,6 +192,7 @@ String _unionPrototype(
defaultValueSource: '',
doc: '',
isPossiblyDartCollection: false,
isCommonWithDifferentNullability: false,
);

if (constructor.isDefault) {
Expand Down
4 changes: 2 additions & 2 deletions packages/freezed/pubspec.yaml
Expand Up @@ -6,10 +6,10 @@ version: 2.1.0+1
homepage: https://github.com/rrousselGit/freezed

environment:
sdk: '>=2.17.0 <3.0.0'
sdk: ">=2.17.0 <3.0.0"

dependencies:
analyzer: ">=4.2.0 <5.0.0"
analyzer: ">=4.6.0 <5.0.0"
build: ^2.0.0
build_config: ^1.0.0
collection: ^1.15.0
Expand Down
8 changes: 8 additions & 0 deletions packages/freezed/test/integration/multiple_constructors.dart
Expand Up @@ -64,6 +64,14 @@ class SharedParam with _$SharedParam {
const factory SharedParam.named(String a, int c) = SharedParam1;
}

@freezed
class SharedParamNullable with _$SharedParamNullable {
const factory SharedParamNullable(String a, String b, int c) =
SharedParamNullable0;
const factory SharedParamNullable.named(String? a, String b, int d) =
SharedParamNullable1;
}

@freezed
class Complex with _$Complex {
@Assert("a != ''", '"Hello"')
Expand Down
42 changes: 41 additions & 1 deletion packages/freezed/test/multiple_constructors_test.dart
Expand Up @@ -504,8 +504,48 @@ void main() {
}
'''), throwsCompileError);
});
});

group('SharedParamNullable', () {
test('has the common properties available', () {
SharedParamNullable value = SharedParamNullable('a', 'b', 42);
expect(value.a, 'a');

value = SharedParamNullable.named('b', 'c', 24);
expect(value.a, 'b');
});

test(
"copy doesn't have shared params with different nullability",
() async {
await expectLater(compile(r'''
import 'multiple_constructors.dart';
void main() {
final param = SharedParamNullable('a', 'b', 42);
param.copyWith(a: '2');
}
'''), throwsCompileError);

await expectLater(compile(r'''
import 'multiple_constructors.dart';
void main() {
final param = SharedParamNullable('a', 'b', 42);
param.copyWith(b: '1');
}
'''), completes);

// TODO: shared property name but different type
await expectLater(compile(r'''
import 'multiple_constructors.dart';
void main() {
final param = SharedParamNullable('a', 'b', 42);
param.copyWith(c: 42);
}
'''), throwsCompileError);
},
);
});

test('Can have a named constructor and a property using the same name', () {
Expand Down

0 comments on commit 753c5a7

Please sign in to comment.