Skip to content

Commit

Permalink
Support NNBD (Null safety) for generated code of mobx_codegen (new) (#…
Browse files Browse the repository at this point in the history
…634)

* Update pubspec.yaml

* try to let generated code support null safety

* support null safety code generation for Computed

* upgrade dependencies

* support "required" keyword in Action methods

* upgrade mobx version for codegen

* change outputs of tests to be consistent with null safety

* add tests about null safety and pass them

* change @required to required
  • Loading branch information
fzyzcjy authored Mar 8, 2021
1 parent 79d5597 commit d0afa2b
Show file tree
Hide file tree
Showing 14 changed files with 649 additions and 58 deletions.
2 changes: 1 addition & 1 deletion mobx_codegen/lib/src/template/computed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class ComputedTemplate {
@override
// ignore: prefer_single_quotes
String toString() => """
Computed<$type> $computedName;
Computed<$type>? $computedName;
@override
$type get $name => ($computedName ??= Computed<$type>(() => super.$name, name: '${storeTemplate.parentTypeName}.$name')).value;""";
Expand Down
2 changes: 1 addition & 1 deletion mobx_codegen/lib/src/template/method_override.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class MethodOverrideTemplate {
..name = element.name
..type = typeNameFinder.findParameterTypeName(element)
..defaultValue = element.defaultValueCode
..hasRequiredAnnotation = element.hasRequired;
..hasRequiredKeyword = element.isRequiredNamed;

final positionalParams = method.parameters
.where((param) => param.isPositional && !param.isOptionalPositional)
Expand Down
8 changes: 3 additions & 5 deletions mobx_codegen/lib/src/template/params.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@ class ParamTemplate {
String name;
String type;
String defaultValue;
bool hasRequiredAnnotation = false;
bool hasRequiredKeyword = false;

String get asArgument => name;

NamedArgTemplate get asNamedArgument => NamedArgTemplate()..name = name;

String get metadata => hasRequiredAnnotation ? '@required ' : '';
String get metadata => hasRequiredKeyword ? 'required ' : '';

@override
String toString() => defaultValue == null
? '$metadata$type $name'
: '$type $name = $defaultValue';
String toString() => defaultValue == null ? '$metadata$type $name' : '$type $name = $defaultValue';
}

class TypeParamTemplate {
Expand Down
11 changes: 7 additions & 4 deletions mobx_codegen/lib/src/type_names.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:mobx_codegen/src/template/comma_list.dart';

Expand Down Expand Up @@ -92,8 +93,7 @@ class LibraryScopedNameFinder {
typeElement == null ||
// This is a bare type param, like "T"
type is TypeParameterType) {
// TODO(pavanpodila): Once we migrate to NNBD, change the flag to `true`
return type.getDisplayString(withNullability: false);
return type.getDisplayString(withNullability: true);
}

return _getNamedElementTypeName(typeElement, type);
Expand Down Expand Up @@ -129,9 +129,12 @@ class LibraryScopedNameFinder {
if (type is ParameterizedType && type.typeArguments.isNotEmpty) {
final typeArgNames = SurroundedCommaList(
'<', '>', type.typeArguments.map(_getDartTypeName).toList());
return '${namesByElement[typeElement]}$typeArgNames';
return '${namesByElement[typeElement]}$typeArgNames${_nullabilitySuffixToString(type.nullabilitySuffix)}';
}

return namesByElement[typeElement];
return namesByElement[typeElement] + _nullabilitySuffixToString(type.nullabilitySuffix);
}

String _nullabilitySuffixToString(NullabilitySuffix nullabilitySuffix) =>
nullabilitySuffix == NullabilitySuffix.question ? '?' : '';
}
10 changes: 8 additions & 2 deletions mobx_codegen/test/data/valid_generic_store_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@ class Item<A extends num> = _Item<A> with _$Item<A>;
@StoreConfig(hasToString: false)
abstract class _Item<T extends num> with Store {
@observable
T value;
T value1;

@observable
List<T> values;
T? value2;

@observable
List<T> values1;

@observable
List<T> values2;
}
58 changes: 44 additions & 14 deletions mobx_codegen/test/data/valid_generic_store_output.dart
Original file line number Diff line number Diff line change
@@ -1,31 +1,61 @@
mixin _$Item<T extends num> on _Item<T>, Store {
final _$valueAtom = Atom(name: '_Item.value');
final _$value1Atom = Atom(name: '_Item.value1');

@override
T get value {
_$valueAtom.reportRead();
return super.value;
T get value1 {
_$value1Atom.reportRead();
return super.value1;
}

@override
set value(T value) {
_$valueAtom.reportWrite(value, super.value, () {
super.value = value;
set value1(T value) {
_$value1Atom.reportWrite(value, super.value1, () {
super.value1 = value;
});
}

final _$valuesAtom = Atom(name: '_Item.values');
final _$value2Atom = Atom(name: '_Item.value2');

@override
List<T> get values {
_$valuesAtom.reportRead();
return super.values;
T? get value2 {
_$value2Atom.reportRead();
return super.value2;
}

@override
set values(List<T> value) {
_$valuesAtom.reportWrite(value, super.values, () {
super.values = value;
set value2(T? value) {
_$value2Atom.reportWrite(value, super.value2, () {
super.value2 = value;
});
}

final _$values1Atom = Atom(name: '_Item.values1');

@override
List<T> get values1 {
_$values1Atom.reportRead();
return super.values1;
}

@override
set values1(List<T> value) {
_$values1Atom.reportWrite(value, super.values1, () {
super.values1 = value;
});
}

final _$values2Atom = Atom(name: '_Item.values2');

@override
List<T> get values2 {
_$values2Atom.reportRead();
return super.values2;
}

@override
set values2(List<T> value) {
_$values2Atom.reportWrite(value, super.values2, () {
super.values2 = value;
});
}
}
41 changes: 41 additions & 0 deletions mobx_codegen/test/data/valid_import_prefixed_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,47 +19,88 @@ abstract class UserBase<T extends io.Process> with Store {
@observable
List<io.File> files;

@observable
List<io.File?> filesNullable;

@observable
List<T> processes;

@observable
io.File biography;

@observable
io.File? biographyNullable;

// This should output the type's constraint, prefixed
@observable
User friendWithImplicitTypeArgument;

@observable
User? friendWithImplicitTypeArgumentNullable;

@observable
User<T> friendWithExplicitTypeArgument;

@observable
User<T>? friendWithExplicitTypeArgumentNullable;

@observable
void Function(io.File, {T another}) callback;

@observable
void Function(io.File?, {T? another}) callbackNullable;

@observable
io.File Function(String, [int, io.File]) callback2;

@observable
io.File? Function(String?, [int?, io.File?]) callback2Nullable;

@observable
ValueCallback<io.Process> localTypedefCallback;

@observable
ValueCallback<io.Process?> localTypedefCallbackNullable;

@observable
io.BadCertificateCallback prefixedTypedefCallback;

@observable
io.BadCertificateCallback? prefixedTypedefCallbackNullable;

@computed
io.File get biographyNotes => io.File('${biography.path}.notes');

@computed
io.File? get biographyNotesNullable => io.File('${biography.path}.notes');

@action
void updateBiography(io.File newBiography) {
biography = newBiography;
}

@action
void updateBiographyNullable(io.File? newBiographyNullable) {
biographyNullable = newBiographyNullable;
}

@observable
Future<io.File> futureBiography() async => biography;

@observable
Future<io.File?> futureBiographyNullable() async => biographyNullable;

@observable
Stream<T> loadDirectory<T extends io.Directory>(String arg1,
{T directory}) async* {
yield directory;
}

@observable
Stream<T?> loadDirectoryNullable<T extends io.Directory>(String? arg1,
{T? directory}) async* {
yield directory;
}
}

typedef ValueCallback<T> = void Function(T);
Loading

0 comments on commit d0afa2b

Please sign in to comment.