Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add common properties with different nullability to base mixin #740

Merged
merged 26 commits into from Nov 30, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
753c5a7
feat: add common properties with different nullability to base mixin
DevNico Aug 15, 2022
f7b3489
style: fix format
DevNico Aug 15, 2022
3de63e5
feat: common properties with different nullability are non-null in co…
DevNico Aug 16, 2022
78d8526
feat: properties with common super types have getters in base mixin
DevNico Aug 17, 2022
29012d0
feat: properties with common subtypes are available in copyWith
DevNico Aug 18, 2022
fe796dc
fix: fixed failing some failing cases
DevNico Aug 18, 2022
f4f7780
refactor: address pr comments
DevNico Aug 20, 2022
5fc858c
Remove dead code
rrousselGit Sep 27, 2022
5ea73b9
Remove more dead code
rrousselGit Sep 27, 2022
db001c0
check for correct getter types in tests
DevNico Sep 28, 2022
6d4ef80
Merge remote-tracking branch 'upstream/master'
DevNico Sep 28, 2022
98d294b
fix test for analyzer 5
DevNico Sep 28, 2022
0ea877a
small refactor
DevNico Sep 28, 2022
d52f6cb
chore: update sponsors.svg
github-actions[bot] Oct 2, 2022
230e586
Test pub downgrade via matrix (#776)
SunlightBro Oct 6, 2022
ac473e9
chore: Cache flutter sdk in the CI (#777)
SunlightBro Oct 7, 2022
94cae76
Merge remote-tracking branch 'upstream/master'
DevNico Oct 8, 2022
6f3bfe8
re-add expect_error dependency
DevNico Oct 8, 2022
400c517
Merge branch 'master' of https://github.com/rrousselGit/freezed into …
rrousselGit Nov 29, 2022
41aae94
Fix error
rrousselGit Nov 29, 2022
253ae77
Cleanup
rrousselGit Nov 29, 2022
eb731cc
Improve tests
rrousselGit Nov 29, 2022
4e798fb
Remove generated/typedef support
rrousselGit Nov 29, 2022
07e7ce2
Update tests
rrousselGit Nov 29, 2022
c578a5e
Fix tests and handle {int a}|{int? a}.copyWith({int a})
rrousselGit Nov 30, 2022
2f9c522
Remove dead code
rrousselGit Nov 30, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
127 changes: 91 additions & 36 deletions packages/freezed/lib/src/freezed_generator.dart
Expand Up @@ -128,27 +128,9 @@ class FreezedGenerator extends ParserGenerator<GlobalData, Data, Freezed> {
List<Property> _commonProperties(
List<ConstructorDetails> constructorsNeedsGeneration,
) {
final commonParameters =
_commonParametersBetweenAllConstructors(constructorsNeedsGeneration);

return [
for (final commonParameter in commonParameters)
Property(
decorators: commonParameter.decorators,
name: commonParameter.name,
isFinal: commonParameter.isFinal,
doc: commonParameter.doc,
type: commonParameter.type,
defaultValueSource: commonParameter.defaultValueSource,
isNullable: commonParameter.isNullable,
isDartList: commonParameter.isDartList,
isDartMap: commonParameter.isDartMap,
isDartSet: commonParameter.isDartSet,
isPossiblyDartCollection: commonParameter.isPossiblyDartCollection,
// TODO: support hasJsonKey
hasJsonKey: false,
),
];
return _commonPropertiesBetweenAllConstructors(constructorsNeedsGeneration)
.map(Property.fromParameter)
.toList();
}

void _assertValidClassUsage(ClassElement element) {
Expand Down Expand Up @@ -247,27 +229,89 @@ Read here: https://github.com/rrousselGit/freezed/blob/master/packages/freezed/C
return false;
}

List<Parameter> _commonParametersBetweenAllConstructors(
List<Parameter> _commonPropertiesBetweenAllConstructors(
List<ConstructorDetails> constructorsNeedsGeneration,
) {
return constructorsNeedsGeneration.first.parameters.allParameters
.map((parameter) {
var hasAnyFinalProperty = false;
for (final constructor in constructorsNeedsGeneration) {
final matchingParameter =
constructor.parameters.allParameters.firstWhereOrNull((p) {
return p.name == parameter.name && p.type == parameter.type;
});
final library = parameter.parameterElement!.library!;

String typeString(DartType type, {bool withNullability = true}) {
return resolveFullTypeStringFrom(
library,
type,
withNullability: withNullability,
);
}

var anyMatchingPropertyIsFinal = false;

var commonSupertypeDartType = parameter.parameterElement!.type;
var commonSubTypeDartType = parameter.parameterElement?.type;

String? commonSupertypeString;
String? commonSubtypeString;

for (final constructor in constructorsNeedsGeneration.skip(1)) {
final matchingParameter = constructor.parameters.allParameters
.firstWhereOrNull((p) => p.name == parameter.name);

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

if (hasAnyFinalProperty) {
return parameter.copyWith(isFinal: true);
final matchingParameterType =
matchingParameter.parameterElement!.type;
if (matchingParameter.isFinal) anyMatchingPropertyIsFinal = true;

if (commonSupertypeDartType is FunctionType ||
commonSupertypeDartType.isDynamic) {
// If the type is a typedef, by finding the upper bound we would lose
// the initial definition. Therefore FunctionTypes are currently not
// supported for finding in finding common super types.
// => Resort back to type string matching.
commonSupertypeString ??= parameter.type!;
if (commonSupertypeString.contains('dynamic')) return null;

if (!typeStringsEqualIgnoringNullability(
commonSupertypeString, matchingParameter.type!)) {
return null;
}

if (commonSupertypeDartType.isNullable !=
matchingParameterType.isNullable) {
commonSupertypeString =
typeStringWithNullability(commonSupertypeString);
commonSubtypeString =
typeStringWithoutNullability(commonSupertypeString);
DevNico marked this conversation as resolved.
Show resolved Hide resolved
}
} else {
commonSupertypeDartType = library.typeSystem.leastUpperBound(
commonSupertypeDartType,
matchingParameterType,
);

if (commonSupertypeDartType
.getDisplayString(withNullability: true)
.contains('dynamic')) return null;

if (commonSubTypeDartType != null) {
if (library.typeSystem.isSubtypeOf(
matchingParameterType, commonSubTypeDartType)) {
commonSubTypeDartType = matchingParameterType;
} else if (!library.typeSystem.isSubtypeOf(
commonSubTypeDartType, matchingParameterType)) {
commonSubTypeDartType = null;
}
}
}
}

return parameter;
return parameter.copyWith(
isFinal: parameter.isFinal || anyMatchingPropertyIsFinal,
commonSupertype:
commonSupertypeString ?? typeString(commonSupertypeDartType),
commonSubtype:
commonSubtypeString ?? commonSubTypeDartType?.let(typeString),
);
})
.whereNotNull()
.toList();
Expand Down Expand Up @@ -311,7 +355,7 @@ Read here: https://github.com/rrousselGit/freezed/blob/master/packages/freezed/C
escapedName: _escapedName(element, constructor),
impliedProperties: [
for (final parameter in constructor.parameters)
await Property.fromParameter(
await Property.fromParameterElement(
parameter,
buildStep,
addImplicitFinal: options.addImplicitFinal,
Expand Down Expand Up @@ -595,18 +639,20 @@ Read here: https://github.com/rrousselGit/freezed/blob/master/packages/freezed/C
}

final commonProperties = _commonProperties(data.constructors);
final commonCopyableProperties =
commonProperties.where((p) => p.isCopyable).toList();

final commonCopyWith = !data.generateCopyWith
? null
: CopyWith(
clonedClassName: data.name,
cloneableProperties: _commonCloneableProperties(
data.constructors,
commonProperties,
commonCopyableProperties,
).toList(),
genericsDefinition: data.genericsDefinitionTemplate,
genericsParameter: data.genericsParameterTemplate,
allProperties: commonProperties,
allProperties: commonCopyableProperties,
data: data,
);

Expand Down Expand Up @@ -829,3 +875,12 @@ String? parseLateGetterSource(String source) {
}
return null;
}

extension Let<T> on T {
@pragma('vm:prefer-inline')
R let<R>(R Function(T) f) => f(this);
}

extension on DartType {
bool get isNullable => nullabilitySuffix == NullabilitySuffix.question;
}
19 changes: 14 additions & 5 deletions packages/freezed/lib/src/templates/abstract_template.dart
Expand Up @@ -18,10 +18,19 @@ class Abstract {
@override
String toString() {
final abstractProperties = commonProperties
.expand((e) => [
e.unimplementedGetter,
if (!e.isFinal) e.unimplementedSetter,
])
.expand((e) {
return <ClassMember?>[
e.unimplementedGetter,
if (!e.isFinal &&
// Don't add a setter for a field where the setters type is not
// a subtype of the getters type.
!(e.commonSupertype != null &&
e.commonSubtype != e.commonSupertype))
e.unimplementedSetter,
];
})
.whereType<ClassMember>()
.map((e) => e.toString())
.join();

return '''
Expand All @@ -41,7 +50,7 @@ ${copyWith?.abstractCopyWithGetter ?? ''}

${copyWith?.interface ?? ''}

${copyWith?.commonContreteImpl(commonProperties) ?? ''}
${copyWith?.commonContreteImpl ?? ''}
''';
}

Expand Down
3 changes: 3 additions & 0 deletions packages/freezed/lib/src/templates/concrete_template.dart
Expand Up @@ -135,6 +135,9 @@ ${copyWith?.abstractCopyWithGetter ?? ''}
doc: '',
isPossiblyDartCollection: false,
showDefaultValue: false,
commonSupertype: null,
commonSubtype: null,
parameterElement: null,
);

parameters = ParametersTemplate(
Expand Down
28 changes: 19 additions & 9 deletions packages/freezed/lib/src/templates/copy_with.dart
Expand Up @@ -51,9 +51,7 @@ ${_abstractDeepCopyMethods().join()}
return parent != null && parent!.allProperties.isNotEmpty;
}

String commonContreteImpl(
List<Property> commonProperties,
) {
String get commonContreteImpl {
var copyWith = '';

if (allProperties.isNotEmpty) {
Expand All @@ -65,7 +63,7 @@ ${_abstractDeepCopyMethods().join()}
final body = _copyWithMethodBody(
parametersTemplate: ParametersTemplate(
const [],
namedParameters: commonProperties.map((e) {
namedParameters: allProperties.map((e) {
return Parameter(
decorators: e.decorators,
name: e.name,
Expand All @@ -77,9 +75,12 @@ ${_abstractDeepCopyMethods().join()}
showDefaultValue: false,
isRequired: false,
defaultValueSource: '',
type: e.type,
type: e.commonSupertype ?? e.type,
doc: e.doc,
isPossiblyDartCollection: e.isPossiblyDartCollection,
commonSupertype: e.commonSupertype,
commonSubtype: e.commonSubtype,
parameterElement: null,
);
}).toList(),
),
Expand Down Expand Up @@ -133,7 +134,9 @@ ${_deepCopyMethods().join()}
required List<Property> properties,
}) {
final parameters = properties.map((p) {
return '${p.decorators.join()} ${p.type} ${p.name}';
final type = p.commonSubtype ?? p.type;

return '${p.decorators.join()} covariant $type ${p.name}';
}).join(',');

return _maybeOverride('''
Expand Down Expand Up @@ -197,10 +200,17 @@ $s''';
data.makeCollectionsImmutable) {
propertyName = '_$propertyName';
}
var ternary =
'${p.name} == freezed ? $accessor.$propertyName : ${p.name} ';

var ternary = '${p.name} == freezed ? $accessor.$propertyName ';

final type = p.commonSubtype ?? p.type;
if (p.commonSubtype != null && p.type != p.commonSubtype) {
ternary += 'as $type ';
DevNico marked this conversation as resolved.
Show resolved Hide resolved
}

ternary += ': ${p.name} ';
if (p.type != 'Object?' && p.type != null) {
ternary += _ignoreLints('as ${p.type}');
ternary += _ignoreLints('as $type');
}
return '$ternary,';
}
Expand Down
32 changes: 32 additions & 0 deletions packages/freezed/lib/src/templates/parameter_template.dart
Expand Up @@ -82,6 +82,9 @@ class ParametersTemplate {
doc: await documentationOfParameter(e, buildStep),
isPossiblyDartCollection: e.type.isPossiblyDartCollection,
showDefaultValue: true,
commonSupertype: null,
commonSubtype: null,
parameterElement: e,
);

if (isAssignedToThis) return LocalParameter.fromParameter(value);
Expand Down Expand Up @@ -184,6 +187,9 @@ class Parameter {
required this.isFinal,
required this.isPossiblyDartCollection,
required this.showDefaultValue,
required this.commonSupertype,
required this.commonSubtype,
required this.parameterElement,
});

Parameter.fromParameter(Parameter p)
Expand All @@ -201,6 +207,9 @@ class Parameter {
showDefaultValue: p.showDefaultValue,
doc: p.doc,
isPossiblyDartCollection: p.isPossiblyDartCollection,
commonSubtype: p.commonSubtype,
commonSupertype: p.commonSupertype,
parameterElement: p.parameterElement,
);

final String? type;
Expand All @@ -216,6 +225,9 @@ class Parameter {
final bool isPossiblyDartCollection;
final bool isFinal;
final String doc;
final String? commonSupertype;
final String? commonSubtype;
final ParameterElement? parameterElement;

Parameter copyWith({
String? type,
Expand All @@ -232,6 +244,8 @@ class Parameter {
bool? isDartMap,
bool? isDartSet,
bool? isFinal,
String? commonSupertype,
String? commonSubtype,
}) =>
Parameter(
type: type ?? this.type,
Expand All @@ -248,6 +262,9 @@ class Parameter {
isFinal: isFinal ?? this.isFinal,
isPossiblyDartCollection:
isPossiblyDartCollection ?? this.isPossiblyDartCollection,
commonSupertype: commonSupertype ?? this.commonSupertype,
commonSubtype: commonSubtype ?? this.commonSubtype,
parameterElement: parameterElement,
);

@override
Expand Down Expand Up @@ -283,6 +300,9 @@ class LocalParameter extends Parameter {
required List<String> decorators,
required String doc,
required bool isPossiblyDartCollection,
required String? commonSupertype,
required String? commonSubtype,
required ParameterElement? parameterElement,
}) : super(
name: name,
type: type,
Expand All @@ -297,6 +317,9 @@ class LocalParameter extends Parameter {
defaultValueSource: defaultValueSource,
doc: doc,
isPossiblyDartCollection: isPossiblyDartCollection,
commonSupertype: commonSupertype,
commonSubtype: commonSubtype,
parameterElement: parameterElement,
);

LocalParameter.fromParameter(Parameter p)
Expand All @@ -313,6 +336,9 @@ class LocalParameter extends Parameter {
decorators: p.decorators,
doc: p.doc,
isPossiblyDartCollection: p.isPossiblyDartCollection,
commonSupertype: p.commonSupertype,
commonSubtype: p.commonSubtype,
parameterElement: p.parameterElement,
);

@override
Expand Down Expand Up @@ -346,6 +372,9 @@ class CallbackParameter extends Parameter {
required this.parameters,
required String doc,
required bool isPossiblyDartCollection,
required String? commonSupertype,
required String? commonSubtype,
required ParameterElement? parameterElement,
}) : super(
name: name,
type: type,
Expand All @@ -360,6 +389,9 @@ class CallbackParameter extends Parameter {
defaultValueSource: defaultValueSource,
doc: doc,
isPossiblyDartCollection: isPossiblyDartCollection,
commonSupertype: commonSupertype,
commonSubtype: commonSubtype,
parameterElement: parameterElement,
);

final ParametersTemplate parameters;
Expand Down