From 9a0a3485349f34e096bb4dc86ad1c141e90ef68e Mon Sep 17 00:00:00 2001 From: Ailton Vieira Pinto Filho Date: Sat, 12 Mar 2022 15:48:16 -0300 Subject: [PATCH 1/3] Adds non-null object fields --- packages/pigeon/lib/dart_generator.dart | 34 +++- packages/pigeon/pigeons/non_null_fields.dart | 15 +- packages/pigeon/test/dart_generator_test.dart | 167 +++++++++++++++++- 3 files changed, 203 insertions(+), 13 deletions(-) diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index 95ecbcbf531..01f859c6066 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -470,15 +470,23 @@ void generateDart(DartOptions opt, Root root, StringSink sink) { 'final Map pigeonMap = {};', ); for (final NamedType field in klass.fields) { + final String nullsafe = field.type.isNullable ? '?' : ''; indent.write('pigeonMap[\'${field.name}\'] = '); if (customClassNames.contains(field.type.baseName)) { - indent.addln( - '${field.name} == null ? null : ${field.name}$unwrapOperator.encode();', - ); + if (opt.isNullSafe) { + indent.addln('${field.name}$nullsafe.encode();'); + } else { + indent.addln( + '${field.name} == null ? null : ${field.name}.encode();'); + } } else if (customEnumNames.contains(field.type.baseName)) { - indent.addln( - '${field.name} == null ? null : ${field.name}$unwrapOperator.index;', - ); + if (opt.isNullSafe) { + indent.addln('${field.name}$nullsafe.index;'); + } else { + indent.addln( + '${field.name} == null ? null : ${field.name}$unwrapOperator.index;', + ); + } } else { indent.addln('${field.name};'); } @@ -490,15 +498,25 @@ void generateDart(DartOptions opt, Root root, StringSink sink) { void writeDecode() { void writeValueDecode(NamedType field) { if (customClassNames.contains(field.type.baseName)) { - indent.format(''' + if (field.type.isNullable) { + indent.format(''' pigeonMap['${field.name}'] != null \t\t? ${field.type.baseName}.decode(pigeonMap['${field.name}']$unwrapOperator) \t\t: null''', leadingSpace: false, trailingNewline: false); + } else { + indent.add( + '${field.type.baseName}.decode(pigeonMap[\'${field.name}\']$unwrapOperator)'); + } } else if (customEnumNames.contains(field.type.baseName)) { - indent.format(''' + if (field.type.isNullable) { + indent.format(''' pigeonMap['${field.name}'] != null \t\t? ${field.type.baseName}.values[pigeonMap['${field.name}']$unwrapOperator as int] \t\t: null''', leadingSpace: false, trailingNewline: false); + } else { + indent.add( + '${field.type.baseName}.values[pigeonMap[\'${field.name}\']$unwrapOperator as int]'); + } } else if (field.type.typeArguments.isNotEmpty) { final String genericType = _makeGenericTypeArguments(field.type, nullTag); diff --git a/packages/pigeon/pigeons/non_null_fields.dart b/packages/pigeon/pigeons/non_null_fields.dart index bbce3367b66..909c14f5f69 100644 --- a/packages/pigeon/pigeons/non_null_fields.dart +++ b/packages/pigeon/pigeons/non_null_fields.dart @@ -12,11 +12,24 @@ class SearchRequest { String query; } +enum SearchReplyType { + success, + error, +} + class SearchReply { - SearchReply(this.result, this.error, this.indices); + SearchReply( + this.result, + this.error, + this.indices, + this.request, + this.type, + ); String result; String error; List indices; + SearchRequest request; + SearchReplyType type; } @HostApi() diff --git a/packages/pigeon/test/dart_generator_test.dart b/packages/pigeon/test/dart_generator_test.dart index 00c81585471..4209cbb9c70 100644 --- a/packages/pigeon/test/dart_generator_test.dart +++ b/packages/pigeon/test/dart_generator_test.dart @@ -204,6 +204,168 @@ void main() { ); }); + test('nested null class nullsafe', () { + final Root root = Root(apis: [], classes: [ + Class( + name: 'Input', + fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'input', + offset: null) + ], + ), + Class( + name: 'Nested', + fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'Input', + isNullable: true, + ), + name: 'nested', + offset: null) + ], + ) + ], enums: []); + final StringBuffer sink = StringBuffer(); + generateDart(const DartOptions(isNullSafe: true), root, sink); + final String code = sink.toString(); + expect( + code, + contains( + 'pigeonMap[\'nested\'] = nested?.encode()', + ), + ); + expect( + code.replaceAll('\n', ' ').replaceAll(' ', ''), + contains( + 'nested: pigeonMap[\'nested\'] != null ? Input.decode(pigeonMap[\'nested\']!) : null', + ), + ); + }); + + test('nested non-null class nullsafe', () { + final Root root = Root(apis: [], classes: [ + Class( + name: 'Input', + fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'input', + offset: null) + ], + ), + Class( + name: 'Nested', + fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'Input', + isNullable: false, + ), + name: 'nested', + offset: null) + ], + ) + ], enums: []); + final StringBuffer sink = StringBuffer(); + generateDart(const DartOptions(isNullSafe: true), root, sink); + final String code = sink.toString(); + expect( + code, + contains( + 'pigeonMap[\'nested\'] = nested.encode()', + ), + ); + expect( + code.replaceAll('\n', ' ').replaceAll(' ', ''), + contains( + 'nested: Input.decode(pigeonMap[\'nested\']!)', + ), + ); + }); + + test('nested null enum nullsafe', () { + final Root root = Root(apis: [], classes: [ + Class( + name: 'Nested', + fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'Input', + isNullable: true, + ), + name: 'nested', + offset: null) + ], + ) + ], enums: [ + Enum( + name: 'Input', + members: ['A', 'B'], + ) + ]); + final StringBuffer sink = StringBuffer(); + generateDart(const DartOptions(isNullSafe: true), root, sink); + final String code = sink.toString(); + expect( + code, + contains( + 'pigeonMap[\'nested\'] = nested?.index', + ), + ); + expect( + code.replaceAll('\n', ' ').replaceAll(' ', ''), + contains( + 'nested: pigeonMap[\'nested\'] != null ? Input.values[pigeonMap[\'nested\']! as int] : null', + ), + ); + }); + + test('nested non-null enum nullsafe', () { + final Root root = Root(apis: [], classes: [ + Class( + name: 'Nested', + fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'Input', + isNullable: false, + ), + name: 'nested', + offset: null) + ], + ) + ], enums: [ + Enum( + name: 'Input', + members: ['A', 'B'], + ) + ]); + final StringBuffer sink = StringBuffer(); + generateDart(const DartOptions(isNullSafe: true), root, sink); + final String code = sink.toString(); + expect( + code, + contains( + 'pigeonMap[\'nested\'] = nested.index', + ), + ); + expect( + code.replaceAll('\n', ' ').replaceAll(' ', ''), + contains( + 'nested: Input.values[pigeonMap[\'nested\']! as int]', + ), + ); + }); + test('flutterapi', () { final Root root = Root(apis: [ Api(name: 'Api', location: ApiLocation.flutter, methods: [ @@ -443,10 +605,7 @@ void main() { final StringBuffer sink = StringBuffer(); generateDart(const DartOptions(isNullSafe: true), root, sink); final String code = sink.toString(); - expect( - code, - contains( - 'pigeonMap[\'enum1\'] = enum1 == null ? null : enum1!.index;')); + expect(code, contains('pigeonMap[\'enum1\'] = enum1?.index;')); expect(code, contains('? Enum.values[pigeonMap[\'enum1\']! as int]')); expect(code, contains('EnumClass doSomething(EnumClass arg0);')); }); From 57782e5e3d50abffed95805ac9d782659d5dd384 Mon Sep 17 00:00:00 2001 From: Ailton Vieira Pinto Filho Date: Sat, 12 Mar 2022 15:50:18 -0300 Subject: [PATCH 2/3] Bump version to 2.0.2 --- packages/pigeon/CHANGELOG.md | 4 ++++ packages/pigeon/lib/generator_tools.dart | 2 +- packages/pigeon/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index 2e8c814c6ae..5366fa656af 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.2 + +* Adds non-null object fields. + ## 2.0.1 * Adds support for TaskQueues for serial background execution. diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index 107f03541a7..15272f7f693 100644 --- a/packages/pigeon/lib/generator_tools.dart +++ b/packages/pigeon/lib/generator_tools.dart @@ -8,7 +8,7 @@ import 'dart:mirrors'; import 'ast.dart'; /// The current version of pigeon. This must match the version in pubspec.yaml. -const String pigeonVersion = '2.0.1'; +const String pigeonVersion = '2.0.2'; /// Read all the content from [stdin] to a String. String readStdin() { diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index 098cfac72b8..5efd3477f88 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -2,7 +2,7 @@ name: pigeon description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. repository: https://github.com/flutter/packages/tree/main/packages/pigeon issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3Apigeon -version: 2.0.1 # This must match the version in lib/generator_tools.dart +version: 2.0.2 # This must match the version in lib/generator_tools.dart environment: sdk: ">=2.12.0 <3.0.0" From ec74255eaa5bfb4437f92ebbdda73e01a219785b Mon Sep 17 00:00:00 2001 From: Ailton Vieira Pinto Filho Date: Tue, 15 Mar 2022 18:56:36 -0300 Subject: [PATCH 3/3] Refactor code --- packages/pigeon/lib/dart_generator.dart | 26 +++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index 01f859c6066..cb679c60de1 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -470,25 +470,27 @@ void generateDart(DartOptions opt, Root root, StringSink sink) { 'final Map pigeonMap = {};', ); for (final NamedType field in klass.fields) { - final String nullsafe = field.type.isNullable ? '?' : ''; indent.write('pigeonMap[\'${field.name}\'] = '); - if (customClassNames.contains(field.type.baseName)) { - if (opt.isNullSafe) { - indent.addln('${field.name}$nullsafe.encode();'); + if (opt.isNullSafe) { + final String nullAwareOperator = field.type.isNullable ? '?' : ''; + if (customClassNames.contains(field.type.baseName)) { + indent.addln('${field.name}$nullAwareOperator.encode();'); + } else if (customEnumNames.contains(field.type.baseName)) { + indent.addln('${field.name}$nullAwareOperator.index;'); } else { + indent.addln('${field.name};'); + } + } else { + if (customClassNames.contains(field.type.baseName)) { indent.addln( '${field.name} == null ? null : ${field.name}.encode();'); - } - } else if (customEnumNames.contains(field.type.baseName)) { - if (opt.isNullSafe) { - indent.addln('${field.name}$nullsafe.index;'); - } else { + } else if (customEnumNames.contains(field.type.baseName)) { indent.addln( - '${field.name} == null ? null : ${field.name}$unwrapOperator.index;', + '${field.name} == null ? null : ${field.name}.index;', ); + } else { + indent.addln('${field.name};'); } - } else { - indent.addln('${field.name};'); } } indent.writeln('return pigeonMap;');