From 5d89ae97164406abd89c117682b028ad0f6f6d0e Mon Sep 17 00:00:00 2001 From: Goddchen Date: Sat, 6 Mar 2021 16:24:15 +0100 Subject: [PATCH 01/18] WIP: [pigeon] migrate to null-safety [pigeon] upgrade version Fix 2 tests Properly generate null-safe Dart code Fix now unused code JavaOptions.className is mandatory generate null-safe code during mock_handler_tester no need to run tests without sound null safety Fix analyzer issues in generated Dart code Fix more analyzer issues Try to fix format of generated Dart code Try to fix more format issues Adjust test to new generated code format Fix formatting Create null-safe pigeons during local tests Create null-safe pigeons during local tests Use ! instead of ?? Make PigeonOptions.input required --- packages/pigeon/lib/ast.dart | 32 +++- packages/pigeon/lib/dart_generator.dart | 46 ++++-- packages/pigeon/lib/generator_tools.dart | 21 +-- packages/pigeon/lib/java_generator.dart | 11 +- packages/pigeon/lib/objc_generator.dart | 19 ++- packages/pigeon/lib/pigeon_lib.dart | 147 ++++++++++-------- .../pigeon/mock_handler_tester/pubspec.yaml | 4 +- .../mock_handler_tester/test/message.dart | 111 ++++++------- .../pigeon/mock_handler_tester/test/test.dart | 30 ++-- .../mock_handler_tester/test/widget_test.dart | 31 ++-- packages/pigeon/pigeons/all_datatypes.dart | 13 ++ packages/pigeon/pigeons/async_handlers.dart | 2 + packages/pigeon/pigeons/host2flutter.dart | 8 +- packages/pigeon/pigeons/list.dart | 2 + packages/pigeon/pigeons/message.dart | 21 ++- packages/pigeon/pigeons/void_arg_flutter.dart | 2 + packages/pigeon/pigeons/void_arg_host.dart | 2 + packages/pigeon/pigeons/voidflutter.dart | 2 + packages/pigeon/pigeons/voidhost.dart | 2 + packages/pigeon/pubspec.yaml | 8 +- packages/pigeon/run_tests.sh | 5 +- packages/pigeon/test/dart_generator_test.dart | 48 +++--- packages/pigeon/test/java_generator_test.dart | 129 ++++++++------- packages/pigeon/test/pigeon_lib_test.dart | 30 ++-- packages/pigeon/test/version_test.dart | 4 +- 25 files changed, 426 insertions(+), 304 deletions(-) diff --git a/packages/pigeon/lib/ast.dart b/packages/pigeon/lib/ast.dart index 747a7ed56d48..95fb026a9c9b 100644 --- a/packages/pigeon/lib/ast.dart +++ b/packages/pigeon/lib/ast.dart @@ -17,8 +17,12 @@ class Node {} /// Represents a method on an [Api]. class Method extends Node { /// Parametric constructor for [Method]. - Method( - {this.name, this.returnType, this.argType, this.isAsynchronous = false}); + Method({ + required this.name, + required this.returnType, + required this.argType, + this.isAsynchronous = false, + }); /// The name of the method. String name; @@ -36,7 +40,12 @@ class Method extends Node { /// Represents a collection of [Method]s that are hosted on a given [location]. class Api extends Node { /// Parametric constructor for [Api]. - Api({this.name, this.location, this.methods, this.dartHostTestHandler}); + Api({ + required this.name, + required this.location, + required this.methods, + this.dartHostTestHandler, + }); /// The name of the API. String name; @@ -48,13 +57,16 @@ class Api extends Node { List methods; /// The name of the Dart test interface to generate to help with testing. - String dartHostTestHandler; + String? dartHostTestHandler; } /// Represents a field on a [Class]. class Field extends Node { /// Parametric constructor for [Field]. - Field({this.name, this.dataType}); + Field({ + required this.name, + required this.dataType, + }); /// The name of the field. String name; @@ -71,7 +83,10 @@ class Field extends Node { /// Represents a class with [Field]s. class Class extends Node { /// Parametric constructor for [Class]. - Class({this.name, this.fields}); + Class({ + required this.name, + required this.fields, + }); /// The name of the class. String name; @@ -88,7 +103,10 @@ class Class extends Node { /// Top-level node for the AST. class Root extends Node { /// Parametric constructor for [Root]. - Root({this.classes, this.apis}); + Root({ + required this.classes, + required this.apis, + }); /// All the classes contained in the AST. List classes; diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index 168ac86f42a1..1b4584223bcf 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -33,7 +33,7 @@ void _writeHostApi(DartOptions opt, Indent indent, Api api) { } String argSignature = ''; String sendArgument = 'null'; - String encodedDeclaration; + String? encodedDeclaration; if (func.argType != 'void') { argSignature = '${func.argType} arg'; sendArgument = 'encoded'; @@ -47,17 +47,18 @@ void _writeHostApi(DartOptions opt, Indent indent, Api api) { indent.writeln(encodedDeclaration); } final String channelName = makeChannelName(api, func); - indent.writeln('const BasicMessageChannel channel ='); + indent.writeln( + 'const BasicMessageChannel channel = BasicMessageChannel('); indent.nest(2, () { indent.writeln( - 'BasicMessageChannel(\'$channelName\', StandardMessageCodec());', + '\'$channelName\', StandardMessageCodec());', ); }); final String returnStatement = func.returnType == 'void' ? '// noop' : 'return ${func.returnType}.decode(replyMap[\'${Keys.result}\']$unwrapOperator);'; indent.format(''' -final Map$nullTag replyMap = await channel.send($sendArgument) as Map$nullTag; +final Map$nullTag replyMap =\n\t\tawait channel.send($sendArgument) as Map$nullTag; if (replyMap == null) { \tthrow PlatformException( \t\tcode: 'channel-error', @@ -83,12 +84,11 @@ void _writeFlutterApi( DartOptions opt, Indent indent, Api api, { - String Function(Method) channelNameFunc, + String Function(Method)? channelNameFunc, bool isMockHandler = false, }) { assert(api.location == ApiLocation.flutter); final String nullTag = opt.isNullSafe ? '?' : ''; - final String unwrapOperator = opt.isNullSafe ? '!' : ''; indent.write('abstract class ${api.name} '); indent.scoped('{', '}', () { for (final Method func in api.methods) { @@ -105,14 +105,14 @@ void _writeFlutterApi( indent.write(''); indent.scoped('{', '}', () { indent.writeln( - 'const BasicMessageChannel channel =', + 'const BasicMessageChannel channel = BasicMessageChannel(', ); final String channelName = channelNameFunc == null ? makeChannelName(api, func) : channelNameFunc(func); indent.nest(2, () { indent.writeln( - 'BasicMessageChannel(\'$channelName\', StandardMessageCodec());', + '\'$channelName\', StandardMessageCodec());', ); }); final String messageHandlerSetter = @@ -140,11 +140,13 @@ void _writeFlutterApi( indent.writeln('// ignore message'); call = 'api.${func.name}()'; } else { + if (!opt.isNullSafe) { + indent.writeln( + 'assert(message != null, \'Argument for $channelName was null. Expected $argType.\');', + ); + } indent.writeln( - 'assert(message != null, \'Argument for $channelName was null. Expected $argType.\');', - ); - indent.writeln( - 'final $argType input = $argType.decode(message$unwrapOperator);', + 'final $argType input = $argType.decode(message);', ); call = 'api.${func.name}(input)'; } @@ -236,9 +238,13 @@ void generateDart(DartOptions opt, Root root, StringSink sink) { }); indent.writeln(''); indent.write( - 'static ${klass.name} decode(Object message) ', + 'static ${klass.name} decode(Object$nullTag message) ', ); indent.scoped('{', '}', () { + indent.write('if (message == null) '); + indent.scoped('{', '}', () { + indent.writeln('return ${klass.name}();'); + }); indent.writeln( 'final Map pigeonMap = message as Map;', ); @@ -248,15 +254,20 @@ void generateDart(DartOptions opt, Root root, StringSink sink) { final Field field = klass.fields[index]; indent.write('..${field.name} = '); if (customClassNames.contains(field.dataType)) { - indent.add( - 'pigeonMap[\'${field.name}\'] != null ? ${field.dataType}.decode(pigeonMap[\'${field.name}\']$unwrapOperator) : null', - ); + indent.addln('pigeonMap[\'${field.name}\'] != null'); + indent.inc(2); + indent.writeln( + '? ${field.dataType}.decode(pigeonMap[\'${field.name}\']$unwrapOperator)'); + indent.write(': null'); } else { indent.add( 'pigeonMap[\'${field.name}\'] as ${_addGenericTypes(field.dataType, nullTag)}', ); } indent.addln(index == klass.fields.length - 1 ? ';' : ''); + if (customClassNames.contains(field.dataType)) { + indent.dec(2); + } } }); }); @@ -300,9 +311,10 @@ void generateTestDart( for (final Api api in root.apis) { if (api.location == ApiLocation.host && api.dartHostTestHandler != null) { final Api mockApi = Api( - name: api.dartHostTestHandler, + name: api.dartHostTestHandler!, methods: api.methods, location: ApiLocation.flutter, + dartHostTestHandler: api.dartHostTestHandler, ); indent.writeln(''); _writeFlutterApi( diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index 895c58e97bf3..21090509fa1a 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 = '0.1.24'; +const String pigeonVersion = '0.2.0-nullsafety.0'; /// Read all the content from [stdin] to a String. String readStdin() { @@ -64,8 +64,8 @@ class Indent { /// Scoped increase of the ident level. For the execution of [func] the /// indentation will be incremented. void scoped( - String begin, - String end, + String? begin, + String? end, Function func, { bool addTrailingNewline = true, }) { @@ -83,12 +83,12 @@ class Indent { /// Like `scoped` but writes the current indentation level. void writeScoped( - String begin, + String? begin, String end, Function func, { bool addTrailingNewline = true, }) { - scoped(str() + begin ?? '', end, func, + scoped(str() + (begin ?? ''), end, func, addTrailingNewline: addTrailingNewline); } @@ -133,7 +133,10 @@ String makeChannelName(Api api, Method func) { /// Represents the mapping of a Dart datatype to a Host datatype. class HostDatatype { /// Parametric constructor for HostDatatype. - HostDatatype({this.datatype, this.isBuiltin}); + HostDatatype({ + required this.datatype, + required this.isBuiltin, + }); /// The [String] that can be printed into host code to represent the type. final String datatype; @@ -147,9 +150,9 @@ class HostDatatype { /// `builtinResolver` will return the host datatype for the Dart datatype for /// builtin types. `customResolver` can modify the datatype of custom types. HostDatatype getHostDatatype( - Field field, List classes, String Function(String) builtinResolver, - {String Function(String) customResolver}) { - final String datatype = builtinResolver(field.dataType); + Field field, List classes, String? Function(String) builtinResolver, + {String Function(String)? customResolver}) { + final String? datatype = builtinResolver(field.dataType); if (datatype == null) { if (classes.map((Class x) => x.name).contains(field.dataType)) { final String customName = customResolver != null diff --git a/packages/pigeon/lib/java_generator.dart b/packages/pigeon/lib/java_generator.dart index 2c119e8ed58a..f61f44e95523 100644 --- a/packages/pigeon/lib/java_generator.dart +++ b/packages/pigeon/lib/java_generator.dart @@ -20,11 +20,17 @@ const Map _javaTypeForDartTypeMap = { /// Options that control how Java code will be generated. class JavaOptions { + /// Creates a [JavaOptions] object + JavaOptions({ + required this.className, + this.package, + }); + /// The name of the class that will house all the generated classes. String className; /// The package where the generated class will live. - String package; + String? package; } void _writeHostApi(Indent indent, Api api) { @@ -198,7 +204,7 @@ String _makeSetter(Field field) { return 'set$uppercased'; } -String _javaTypeForDartType(String datatype) { +String? _javaTypeForDartType(String datatype) { return _javaTypeForDartTypeMap[datatype]; } @@ -236,7 +242,6 @@ void generateJava(JavaOptions options, Root root, StringSink sink) { indent.writeln('import java.util.HashMap;'); indent.addln(''); - assert(options.className != null); indent.writeln('/** Generated class from Pigeon. */'); indent.writeln( '@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"})'); diff --git a/packages/pigeon/lib/objc_generator.dart b/packages/pigeon/lib/objc_generator.dart index 30a4b59a8690..54665b825a35 100644 --- a/packages/pigeon/lib/objc_generator.dart +++ b/packages/pigeon/lib/objc_generator.dart @@ -8,17 +8,20 @@ import 'generator_tools.dart'; /// Options that control how Objective-C code will be generated. class ObjcOptions { /// Parametric constructor for ObjcOptions. - ObjcOptions({this.header, this.prefix}); + ObjcOptions({ + this.header, + this.prefix, + }); /// The path to the header that will get placed in the source filed (example: /// "foo.h"). - String header; + String? header; /// Prefix that will be appended before all generated classes and protocols. - String prefix; + String? prefix; } -String _className(String prefix, String className) { +String _className(String? prefix, String className) { if (prefix != null) { return '$prefix$className'; } else { @@ -58,12 +61,12 @@ const Map _propertyTypeForDartTypeMap = { 'Map': 'strong', }; -String _objcTypeForDartType(String type) { +String? _objcTypeForDartType(String type) { return _objcTypeForDartTypeMap[type]; } String _propertyTypeForDartType(String type) { - final String result = _propertyTypeForDartTypeMap[type]; + final String? result = _propertyTypeForDartTypeMap[type]; if (result == null) { return 'assign'; } else { @@ -72,7 +75,7 @@ String _propertyTypeForDartType(String type) { } void _writeClassDeclarations( - Indent indent, List classes, String prefix) { + Indent indent, List classes, String? prefix) { for (final Class klass in classes) { indent.writeln('@interface ${_className(prefix, klass.name)} : NSObject'); for (final Field field in klass.fields) { @@ -191,7 +194,7 @@ void generateObjcHeader(ObjcOptions options, Root root, StringSink sink) { } String _dictGetter( - List classnames, String dict, Field field, String prefix) { + List classnames, String dict, Field field, String? prefix) { if (classnames.contains(field.dataType)) { String className = field.dataType; if (prefix != null) { diff --git a/packages/pigeon/lib/pigeon_lib.dart b/packages/pigeon/lib/pigeon_lib.dart index 4072779440e1..a579ffbfb5aa 100644 --- a/packages/pigeon/lib/pigeon_lib.dart +++ b/packages/pigeon/lib/pigeon_lib.dart @@ -58,7 +58,7 @@ class HostApi { /// testing. /// /// Defaults to `null` in which case no handler will be generated. - final String dartHostTestHandler; + final String? dartHostTestHandler; } /// Metadata to annotate a Pigeon API implemented by Flutter. @@ -75,16 +75,20 @@ class FlutterApi { /// Represents an error as a result of parsing and generating code. class Error { /// Parametric constructor for Error. - Error({this.message, this.filename, this.lineNumber}); + Error({ + required this.message, + this.filename, + this.lineNumber, + }); /// A description of the error. String message; /// What file caused the [Error]. - String filename; + String? filename; /// What line the error happened on. - int lineNumber; + int? lineNumber; @override String toString() { @@ -97,7 +101,7 @@ bool _isApi(ClassMirror classMirror) { (_getHostApi(classMirror) != null || _isFlutterApi(classMirror)); } -HostApi _getHostApi(ClassMirror apiMirror) { +HostApi? _getHostApi(ClassMirror apiMirror) { for (final InstanceMirror instance in apiMirror.metadata) { if (instance.reflectee is HostApi) { return instance.reflectee; @@ -117,38 +121,44 @@ bool _isFlutterApi(ClassMirror apiMirror) { /// Options used when running the code generator. class PigeonOptions { + /// Creates a instance of PigeonOptions + PigeonOptions({required this.input}); + /// Path to the file which will be processed. String input; /// Path to the dart file that will be generated. - String dartOut; + String? dartOut; /// Path to the dart file that will be generated for test support classes. - String dartTestOut; + String? dartTestOut; /// Path to the ".h" Objective-C file will be generated. - String objcHeaderOut; + String? objcHeaderOut; /// Path to the ".m" Objective-C file will be generated. - String objcSourceOut; + String? objcSourceOut; /// Options that control how Objective-C will be generated. - ObjcOptions objcOptions = ObjcOptions(); + ObjcOptions? objcOptions; /// Path to the java file that will be generated. - String javaOut; + String? javaOut; /// Options that control how Java will be generated. - JavaOptions javaOptions = JavaOptions(); + JavaOptions? javaOptions; /// Options that control how Dart will be generated. - DartOptions dartOptions = DartOptions(); + DartOptions? dartOptions = DartOptions(); } /// A collection of an AST represented as a [Root] and [Error]'s. class ParseResults { /// Parametric constructor for [ParseResults]. - ParseResults({this.root, this.errors}); + ParseResults({ + required this.root, + required this.errors, + }); /// The resulting AST. final Root root; @@ -169,14 +179,18 @@ class Pigeon { for (final DeclarationMirror declaration in klassMirror.declarations.values) { if (declaration is VariableMirror) { - fields.add(Field() - ..name = MirrorSystem.getName(declaration.simpleName) - ..dataType = MirrorSystem.getName(declaration.type.simpleName)); + fields.add(Field( + name: MirrorSystem.getName(declaration.simpleName), + dataType: MirrorSystem.getName( + declaration.type.simpleName, + ), + )); } } - final Class klass = Class() - ..name = MirrorSystem.getName(klassMirror.simpleName) - ..fields = fields; + final Class klass = Class( + name: MirrorSystem.getName(klassMirror.simpleName), + fields: fields, + ); return klass; } @@ -208,7 +222,6 @@ class Pigeon { /// Use reflection to parse the [types] provided. ParseResults parse(List types) { - final Root root = Root(); final Set classes = {}; final List apis = []; @@ -226,19 +239,19 @@ class Pigeon { in apiMirror.declarations.values) { if (declaration is MethodMirror && !declaration.isConstructor) { if (!isVoid(declaration.returnType)) { - classes.add(declaration.returnType); + classes.add(declaration.returnType as ClassMirror); } if (declaration.parameters.isNotEmpty) { - classes.add(declaration.parameters[0].type); + classes.add(declaration.parameters[0].type as ClassMirror); } } } } - - root.classes = - _unique(_parseClassMirrors(classes), (Class x) => x.name).toList(); - - root.apis = []; + final Root root = Root( + classes: + _unique(_parseClassMirrors(classes), (Class x) => x.name).toList(), + apis: [], + ); for (final ClassMirror apiMirror in apis) { final List functions = []; for (final DeclarationMirror declaration @@ -249,23 +262,24 @@ class Pigeon { return MirrorSystem.getName(it.type.simpleName) == '${async.runtimeType}'; }); - functions.add(Method() - ..name = MirrorSystem.getName(declaration.simpleName) - ..argType = declaration.parameters.isEmpty + functions.add(Method( + name: MirrorSystem.getName(declaration.simpleName), + argType: declaration.parameters.isEmpty ? 'void' : MirrorSystem.getName( - declaration.parameters[0].type.simpleName) - ..returnType = - MirrorSystem.getName(declaration.returnType.simpleName) - ..isAsynchronous = isAsynchronous); + declaration.parameters[0].type.simpleName), + returnType: MirrorSystem.getName(declaration.returnType.simpleName), + isAsynchronous: isAsynchronous, + )); } } - final HostApi hostApi = _getHostApi(apiMirror); + final HostApi? hostApi = _getHostApi(apiMirror); root.apis.add(Api( - name: MirrorSystem.getName(apiMirror.simpleName), - location: hostApi != null ? ApiLocation.host : ApiLocation.flutter, - methods: functions, - dartHostTestHandler: hostApi?.dartHostTestHandler)); + name: MirrorSystem.getName(apiMirror.simpleName), + location: hostApi != null ? ApiLocation.host : ApiLocation.flutter, + methods: functions, + dartHostTestHandler: hostApi?.dartHostTestHandler, + )); } final List validateErrors = _validateAst(root); @@ -309,16 +323,20 @@ options: static PigeonOptions parseArgs(List args) { final ArgResults results = _argParser.parse(args); - final PigeonOptions opts = PigeonOptions(); - opts.input = results['input']; + final PigeonOptions opts = PigeonOptions(input: results['input']); opts.dartOut = results['dart_out']; opts.dartTestOut = results['dart_test_out']; opts.objcHeaderOut = results['objc_header_out']; opts.objcSourceOut = results['objc_source_out']; - opts.objcOptions.prefix = results['objc_prefix']; + opts.objcOptions = ObjcOptions( + prefix: results['objc_prefix'], + ); opts.javaOut = results['java_out']; - opts.javaOptions.package = results['java_package']; - opts.dartOptions.isNullSafe = results['dart_null_safety']; + opts.javaOptions = JavaOptions( + className: 'Pigeon', + package: results['java_package'], + ); + opts.dartOptions = DartOptions()..isNullSafe = results['dart_null_safety']; return opts; } @@ -408,10 +426,7 @@ options: final List errors = []; final List apis = []; if (options.objcHeaderOut != null) { - options.objcOptions.header = basename(options.objcHeaderOut); - } - if (options.javaOut != null) { - options.javaOptions.className = basenameWithoutExtension(options.javaOut); + options.objcOptions?.header = basename(options.objcHeaderOut!); } for (final LibraryMirror library @@ -430,19 +445,19 @@ options: } if (options.dartOut != null) { await _runGenerator( - options.dartOut, - (StringSink sink) => - generateDart(options.dartOptions, parseResults.root, sink)); + options.dartOut!, + (StringSink sink) => generateDart( + options.dartOptions ?? DartOptions(), parseResults.root, sink)); } - if (options.dartTestOut != null) { + if (options.dartTestOut != null && options.dartOut != null) { final String mainPath = context.relative( - _posixify(options.dartOut), - from: _posixify(path.dirname(options.dartTestOut)), + _posixify(options.dartOut!), + from: _posixify(path.dirname(options.dartTestOut!)), ); await _runGenerator( - options.dartTestOut, + options.dartTestOut!, (StringSink sink) => generateTestDart( - options.dartOptions, + options.dartOptions ?? DartOptions(), parseResults.root, sink, mainPath, @@ -451,21 +466,25 @@ options: } if (options.objcHeaderOut != null) { await _runGenerator( - options.objcHeaderOut, + options.objcHeaderOut!, (StringSink sink) => generateObjcHeader( - options.objcOptions, parseResults.root, sink)); + options.objcOptions ?? ObjcOptions(), parseResults.root, sink)); } if (options.objcSourceOut != null) { await _runGenerator( - options.objcSourceOut, + options.objcSourceOut!, (StringSink sink) => generateObjcSource( - options.objcOptions, parseResults.root, sink)); + options.objcOptions ?? ObjcOptions(), parseResults.root, sink)); } if (options.javaOut != null) { await _runGenerator( - options.javaOut, - (StringSink sink) => - generateJava(options.javaOptions, parseResults.root, sink)); + options.javaOut!, + (StringSink sink) => generateJava( + JavaOptions( + className: path.basenameWithoutExtension(options.javaOut!), + package: options.javaOptions?.package), + parseResults.root, + sink)); } } else { errors.add(Error(message: 'No pigeon classes found, nothing generated.')); diff --git a/packages/pigeon/mock_handler_tester/pubspec.yaml b/packages/pigeon/mock_handler_tester/pubspec.yaml index eeabf8d49fd0..1826c25edda6 100644 --- a/packages/pigeon/mock_handler_tester/pubspec.yaml +++ b/packages/pigeon/mock_handler_tester/pubspec.yaml @@ -4,10 +4,10 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: - cupertino_icons: ^0.1.3 + cupertino_icons: ^1.0.2 flutter: sdk: flutter diff --git a/packages/pigeon/mock_handler_tester/test/message.dart b/packages/pigeon/mock_handler_tester/test/message.dart index 30ccafa5a4ac..0445fe058888 100644 --- a/packages/pigeon/mock_handler_tester/test/message.dart +++ b/packages/pigeon/mock_handler_tester/test/message.dart @@ -1,83 +1,90 @@ -// Autogenerated from Pigeon (v0.1.19), do not edit directly. +// Autogenerated from Pigeon (v0.2.0-nullsafety.0), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import -// @dart = 2.8 +// @dart = 2.12 import 'dart:async'; import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; import 'package:flutter/services.dart'; class SearchReply { - String result; - String error; + String? result; + String? error; Object encode() { - final Map pigeonMap = {}; + final Map pigeonMap = {}; pigeonMap['result'] = result; pigeonMap['error'] = error; return pigeonMap; } - static SearchReply decode(Object message) { - final Map pigeonMap = message as Map; + static SearchReply decode(Object? message) { + if (message == null) { + return SearchReply(); + } + final Map pigeonMap = message as Map; return SearchReply() - ..result = pigeonMap['result'] as String - ..error = pigeonMap['error'] as String; + ..result = pigeonMap['result'] as String? + ..error = pigeonMap['error'] as String?; } } class SearchRequest { - String query; - int anInt; - bool aBool; + String? query; + int? anInt; + bool? aBool; Object encode() { - final Map pigeonMap = {}; + final Map pigeonMap = {}; pigeonMap['query'] = query; pigeonMap['anInt'] = anInt; pigeonMap['aBool'] = aBool; return pigeonMap; } - static SearchRequest decode(Object message) { - final Map pigeonMap = message as Map; + static SearchRequest decode(Object? message) { + if (message == null) { + return SearchRequest(); + } + final Map pigeonMap = message as Map; return SearchRequest() - ..query = pigeonMap['query'] as String - ..anInt = pigeonMap['anInt'] as int - ..aBool = pigeonMap['aBool'] as bool; + ..query = pigeonMap['query'] as String? + ..anInt = pigeonMap['anInt'] as int? + ..aBool = pigeonMap['aBool'] as bool?; } } class Nested { - SearchRequest request; + SearchRequest? request; Object encode() { - final Map pigeonMap = {}; - pigeonMap['request'] = request?.encode(); + final Map pigeonMap = {}; + pigeonMap['request'] = request == null ? null : request!.encode(); return pigeonMap; } - static Nested decode(Object message) { - final Map pigeonMap = message as Map; + static Nested decode(Object? message) { + if (message == null) { + return Nested(); + } + final Map pigeonMap = message as Map; return Nested() ..request = pigeonMap['request'] != null - ? SearchRequest.decode(pigeonMap['request']) + ? SearchRequest.decode(pigeonMap['request']!) : null; } } abstract class FlutterSearchApi { SearchReply search(SearchRequest arg); - static void setup(FlutterSearchApi api) { + static void setup(FlutterSearchApi? api) { { - const BasicMessageChannel channel = BasicMessageChannel( + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.FlutterSearchApi.search', StandardMessageCodec()); if (api == null) { channel.setMessageHandler(null); } else { - channel.setMessageHandler((Object message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.FlutterSearchApi.search was null. Expected SearchRequest.'); + channel.setMessageHandler((Object? message) async { final SearchRequest input = SearchRequest.decode(message); final SearchReply output = api.search(input); return output.encode(); @@ -90,10 +97,10 @@ abstract class FlutterSearchApi { class NestedApi { Future search(Nested arg) async { final Object encoded = arg.encode(); - const BasicMessageChannel channel = BasicMessageChannel( + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.NestedApi.search', StandardMessageCodec()); - final Map replyMap = - await channel.send(encoded) as Map; + final Map? replyMap = + await channel.send(encoded) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -101,25 +108,25 @@ class NestedApi { details: null, ); } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; + final Map error = + replyMap['error']! as Map; throw PlatformException( - code: error['code'] as String, - message: error['message'] as String, + code: error['code'] as String? ?? 'unknown', + message: error['message'] as String?, details: error['details'], ); } else { - return SearchReply.decode(replyMap['result']); + return SearchReply.decode(replyMap['result']!); } } } class Api { Future initialize() async { - const BasicMessageChannel channel = BasicMessageChannel( + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.Api.initialize', StandardMessageCodec()); - final Map replyMap = - await channel.send(null) as Map; + final Map? replyMap = + await channel.send(null) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -127,11 +134,11 @@ class Api { details: null, ); } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; + final Map error = + replyMap['error']! as Map; throw PlatformException( - code: error['code'] as String, - message: error['message'] as String, + code: error['code'] as String? ?? 'unknown', + message: error['message'] as String?, details: error['details'], ); } else { @@ -141,10 +148,10 @@ class Api { Future search(SearchRequest arg) async { final Object encoded = arg.encode(); - const BasicMessageChannel channel = BasicMessageChannel( + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.Api.search', StandardMessageCodec()); - final Map replyMap = - await channel.send(encoded) as Map; + final Map? replyMap = + await channel.send(encoded) as Map?; if (replyMap == null) { throw PlatformException( code: 'channel-error', @@ -152,15 +159,15 @@ class Api { details: null, ); } else if (replyMap['error'] != null) { - final Map error = - replyMap['error'] as Map; + final Map error = + replyMap['error']! as Map; throw PlatformException( - code: error['code'] as String, - message: error['message'] as String, + code: error['code'] as String? ?? 'unknown', + message: error['message'] as String?, details: error['details'], ); } else { - return SearchReply.decode(replyMap['result']); + return SearchReply.decode(replyMap['result']!); } } } diff --git a/packages/pigeon/mock_handler_tester/test/test.dart b/packages/pigeon/mock_handler_tester/test/test.dart index 7c6ccf03de37..565922a9bd8f 100644 --- a/packages/pigeon/mock_handler_tester/test/test.dart +++ b/packages/pigeon/mock_handler_tester/test/test.dart @@ -1,7 +1,7 @@ -// Autogenerated from Pigeon (v0.1.19), do not edit directly. +// Autogenerated from Pigeon (v0.2.0-nullsafety.0), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import -// @dart = 2.8 +// @dart = 2.12 import 'dart:async'; import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; import 'package:flutter/services.dart'; @@ -11,19 +11,17 @@ import 'message.dart'; abstract class TestNestedApi { SearchReply search(Nested arg); - static void setup(TestNestedApi api) { + static void setup(TestNestedApi? api) { { - const BasicMessageChannel channel = BasicMessageChannel( + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.NestedApi.search', StandardMessageCodec()); if (api == null) { channel.setMockMessageHandler(null); } else { - channel.setMockMessageHandler((Object message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.NestedApi.search was null. Expected Nested.'); + channel.setMockMessageHandler((Object? message) async { final Nested input = Nested.decode(message); final SearchReply output = api.search(input); - return {'result': output.encode()}; + return {'result': output.encode()}; }); } } @@ -33,32 +31,30 @@ abstract class TestNestedApi { abstract class TestHostApi { void initialize(); SearchReply search(SearchRequest arg); - static void setup(TestHostApi api) { + static void setup(TestHostApi? api) { { - const BasicMessageChannel channel = BasicMessageChannel( + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.Api.initialize', StandardMessageCodec()); if (api == null) { channel.setMockMessageHandler(null); } else { - channel.setMockMessageHandler((Object message) async { + channel.setMockMessageHandler((Object? message) async { // ignore message api.initialize(); - return {}; + return {}; }); } } { - const BasicMessageChannel channel = BasicMessageChannel( + const BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.Api.search', StandardMessageCodec()); if (api == null) { channel.setMockMessageHandler(null); } else { - channel.setMockMessageHandler((Object message) async { - assert(message != null, - 'Argument for dev.flutter.pigeon.Api.search was null. Expected SearchRequest.'); + channel.setMockMessageHandler((Object? message) async { final SearchRequest input = SearchRequest.decode(message); final SearchReply output = api.search(input); - return {'result': output.encode()}; + return {'result': output.encode()}; }); } } diff --git a/packages/pigeon/mock_handler_tester/test/widget_test.dart b/packages/pigeon/mock_handler_tester/test/widget_test.dart index 4f6497c45b15..53623ba2cfe9 100644 --- a/packages/pigeon/mock_handler_tester/test/widget_test.dart +++ b/packages/pigeon/mock_handler_tester/test/widget_test.dart @@ -33,7 +33,7 @@ class MockNested implements TestNestedApi { if (arg.request == null) { return SearchReply(); } else { - return SearchReply()..result = arg.request.query; + return SearchReply()..result = arg.request?.query; } } } @@ -73,28 +73,23 @@ void main() { final Mock mock = Mock(); TestHostApi.setup(mock); expect( - await const BasicMessageChannel( + await const BasicMessageChannel( 'dev.flutter.pigeon.Api.initialize', StandardMessageCodec(), ).send(null), isEmpty, ); - try { - await const BasicMessageChannel( - 'dev.flutter.pigeon.Api.search', - StandardMessageCodec(), - ).send(null) as Map; - expect(true, isFalse); // should not reach here - } catch (error) { - expect(error, isAssertionError); - expect( - error.toString(), - contains( - 'Argument for dev.flutter.pigeon.Api.search was null. Expected SearchRequest.', - ), - ); - } - expect(mock.log, ['initialize']); + final Object? result = await const BasicMessageChannel( + 'dev.flutter.pigeon.Api.search', + StandardMessageCodec(), + ).send(null); + expect(result, isA>()); + final Map? resultMap = result as Map?; + expect( + (resultMap?['result'] as Map?)?['result'], isNull); + expect( + (resultMap?['result'] as Map?)?['error'], isNull); + expect(mock.log, ['initialize', 'search']); }, // TODO(ianh): skip can be removed after first stable release in 2021 skip: Platform.environment['CHANNEL'] == 'stable', diff --git a/packages/pigeon/pigeons/all_datatypes.dart b/packages/pigeon/pigeons/all_datatypes.dart index 981f87cc10be..5fb3fb4895b3 100644 --- a/packages/pigeon/pigeons/all_datatypes.dart +++ b/packages/pigeon/pigeons/all_datatypes.dart @@ -5,6 +5,19 @@ import 'package:pigeon/pigeon.dart'; class Everything { + Everything({ + required this.aBool, + required this.anInt, + required this.aDouble, + required this.aString, + required this.aByteArray, + required this.a4ByteArray, + required this.a8ByteArray, + required this.aFloatArray, + required this.aList, + required this.aMap, + }); + bool aBool; int anInt; double aDouble; diff --git a/packages/pigeon/pigeons/async_handlers.dart b/packages/pigeon/pigeons/async_handlers.dart index 8e86671ba4f4..44e840b2c3b6 100644 --- a/packages/pigeon/pigeons/async_handlers.dart +++ b/packages/pigeon/pigeons/async_handlers.dart @@ -5,6 +5,8 @@ import 'package:pigeon/pigeon.dart'; class Value { + Value({required this.number}); + int number; } diff --git a/packages/pigeon/pigeons/host2flutter.dart b/packages/pigeon/pigeons/host2flutter.dart index 673ff56334f9..f53b04e7fe42 100644 --- a/packages/pigeon/pigeons/host2flutter.dart +++ b/packages/pigeon/pigeons/host2flutter.dart @@ -2,13 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:pigeon/objc_generator.dart'; import 'package:pigeon/pigeon.dart'; class SearchRequest { + SearchRequest({required this.query}); + String query; } class SearchReply { + SearchReply({required this.result}); + String result; } @@ -18,5 +23,6 @@ abstract class Api { } void configurePigeon(PigeonOptions options) { - options.objcOptions.prefix = 'AC'; + options.objcOptions ??= ObjcOptions(); + options.objcOptions?.prefix = 'AC'; } diff --git a/packages/pigeon/pigeons/list.dart b/packages/pigeon/pigeons/list.dart index bed4a79227b9..34a7eb39936c 100644 --- a/packages/pigeon/pigeons/list.dart +++ b/packages/pigeon/pigeons/list.dart @@ -5,6 +5,8 @@ import 'package:pigeon/pigeon.dart'; class TestMessage { + TestMessage({required this.testList}); + // ignore: always_specify_types List testList; } diff --git a/packages/pigeon/pigeons/message.dart b/packages/pigeon/pigeons/message.dart index 02b95840f638..08640018ce5c 100644 --- a/packages/pigeon/pigeons/message.dart +++ b/packages/pigeon/pigeons/message.dart @@ -5,15 +5,28 @@ // This file is an example pigeon file that is used in compilation, unit, mock // handler, and e2e tests. +import 'package:pigeon/java_generator.dart'; +import 'package:pigeon/objc_generator.dart'; import 'package:pigeon/pigeon.dart'; class SearchRequest { + SearchRequest({ + required this.query, + required this.anInt, + required this.aBool, + }); + String query; int anInt; bool aBool; } class SearchReply { + SearchReply({ + required this.result, + required this.error, + }); + String result; String error; } @@ -25,6 +38,8 @@ abstract class Api { } class Nested { + Nested({required this.request}); + SearchRequest request; } @@ -34,8 +49,10 @@ abstract class NestedApi { } void configurePigeon(PigeonOptions options) { - options.objcOptions.prefix = 'AC'; - options.javaOptions.package = 'dev.flutter.aaclarke.pigeon'; + options.objcOptions ??= ObjcOptions(); + options.objcOptions?.prefix = 'AC'; + options.javaOptions ??= JavaOptions(className: 'Pigeon'); + options.javaOptions?.package = 'dev.flutter.aaclarke.pigeon'; } @FlutterApi() diff --git a/packages/pigeon/pigeons/void_arg_flutter.dart b/packages/pigeon/pigeons/void_arg_flutter.dart index 9886e0e10c0b..10f23cfbf625 100644 --- a/packages/pigeon/pigeons/void_arg_flutter.dart +++ b/packages/pigeon/pigeons/void_arg_flutter.dart @@ -5,6 +5,8 @@ import 'package:pigeon/pigeon.dart'; class Result { + Result({required this.code}); + int code; } diff --git a/packages/pigeon/pigeons/void_arg_host.dart b/packages/pigeon/pigeons/void_arg_host.dart index 38229a08fa70..f28f6b9b9d13 100644 --- a/packages/pigeon/pigeons/void_arg_host.dart +++ b/packages/pigeon/pigeons/void_arg_host.dart @@ -5,6 +5,8 @@ import 'package:pigeon/pigeon.dart'; class Result { + Result({required this.code}); + int code; } diff --git a/packages/pigeon/pigeons/voidflutter.dart b/packages/pigeon/pigeons/voidflutter.dart index 9606c210e8af..289ec882d9d8 100644 --- a/packages/pigeon/pigeons/voidflutter.dart +++ b/packages/pigeon/pigeons/voidflutter.dart @@ -5,6 +5,8 @@ import 'package:pigeon/pigeon.dart'; class SetRequest { + SetRequest({required this.value}); + int value; } diff --git a/packages/pigeon/pigeons/voidhost.dart b/packages/pigeon/pigeons/voidhost.dart index ffd7f01c4db0..0f65d272960b 100644 --- a/packages/pigeon/pigeons/voidhost.dart +++ b/packages/pigeon/pigeons/voidhost.dart @@ -5,6 +5,8 @@ import 'package:pigeon/pigeon.dart'; class SetRequest { + SetRequest({required this.value}); + int value; } diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index 13a236945805..18a4978e8d44 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -1,11 +1,11 @@ name: pigeon -version: 0.1.24 # This must match the version in lib/generator_tools.dart +version: 0.2.0-nullsafety.0 # This must match the version in lib/generator_tools.dart description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. homepage: https://github.com/flutter/packages/tree/master/packages/pigeon dependencies: - args: ^1.5.2 - path: ^1.6.4 + args: ^2.0.0 + path: ^1.8.0 dev_dependencies: test: ^1.11.1 environment: - sdk: '>=2.2.0 <3.0.0' + sdk: '>=2.12.0 <3.0.0' diff --git a/packages/pigeon/run_tests.sh b/packages/pigeon/run_tests.sh index f370651fe812..ab4610e38d10 100755 --- a/packages/pigeon/run_tests.sh +++ b/packages/pigeon/run_tests.sh @@ -80,6 +80,7 @@ test_pigeon_android() { pub run pigeon \ --input $1 \ + --dart_null_safety \ --dart_out $temp_dir/pigeon.dart \ --java_out $temp_dir/Pigeon.java \ --java_package foo @@ -151,7 +152,7 @@ fi pub get dart analyze bin dart analyze lib -dart --no-sound-null-safety test +dart test ############################################################################### # Execute without arguments test @@ -177,6 +178,7 @@ popd pushd $PWD pub run pigeon \ --input pigeons/message.dart \ + --dart_null_safety \ --dart_out mock_handler_tester/test/message.dart \ --dart_test_out mock_handler_tester/test/test.dart dartfmt -w mock_handler_tester/test/message.dart @@ -253,6 +255,7 @@ DARTLE_DART="e2e_tests/test_objc/lib/dartle.dart" PIGEON_JAVA="e2e_tests/test_objc/android/app/src/main/java/io/flutter/plugins/Pigeon.java" pub run pigeon \ --input pigeons/message.dart \ + --dart_null_safety \ --dart_out $DARTLE_DART \ --objc_header_out $DARTLE_H \ --objc_source_out $DARTLE_M \ diff --git a/packages/pigeon/test/dart_generator_test.dart b/packages/pigeon/test/dart_generator_test.dart index 4f6fde4b71d0..6ef917238c9b 100644 --- a/packages/pigeon/test/dart_generator_test.dart +++ b/packages/pigeon/test/dart_generator_test.dart @@ -9,16 +9,19 @@ import 'package:test/test.dart'; void main() { test('gen one class', () { - final Class klass = Class() - ..name = 'Foobar' - ..fields = [ - Field() - ..name = 'field1' - ..dataType = 'dataType1' - ]; - final Root root = Root() - ..apis = [] - ..classes = [klass]; + final Class klass = Class( + name: 'Foobar', + fields: [ + Field( + name: 'field1', + dataType: 'dataType1', + ), + ], + ); + final Root root = Root( + apis: [], + classes: [klass], + ); final StringBuffer sink = StringBuffer(); generateDart(DartOptions(), root, sink); final String code = sink.toString(); @@ -72,7 +75,7 @@ void main() { ), ); expect( - code, + code.replaceAll('\n', ' ').replaceAll(' ', ''), contains( '..nested = pigeonMap[\'nested\'] != null ? Input.decode(pigeonMap[\'nested\']) : null;', ), @@ -244,16 +247,19 @@ void main() { }); test('opt out of nndb', () { - final Class klass = Class() - ..name = 'Foobar' - ..fields = [ - Field() - ..name = 'field1' - ..dataType = 'dataType1' - ]; - final Root root = Root() - ..apis = [] - ..classes = [klass]; + final Class klass = Class( + name: 'Foobar', + fields: [ + Field( + name: 'field1', + dataType: 'dataType1', + ), + ], + ); + final Root root = Root( + apis: [], + classes: [klass], + ); final StringBuffer sink = StringBuffer(); generateDart(DartOptions(), root, sink); final String code = sink.toString(); diff --git a/packages/pigeon/test/java_generator_test.dart b/packages/pigeon/test/java_generator_test.dart index 398ca69ce05a..053049b3636a 100644 --- a/packages/pigeon/test/java_generator_test.dart +++ b/packages/pigeon/test/java_generator_test.dart @@ -8,19 +8,21 @@ import 'package:test/test.dart'; void main() { test('gen one class', () { - final Class klass = Class() - ..name = 'Foobar' - ..fields = [ - Field() - ..name = 'field1' - ..dataType = 'int' - ]; - final Root root = Root() - ..apis = [] - ..classes = [klass]; + final Class klass = Class( + name: 'Foobar', + fields: [ + Field( + name: 'field1', + dataType: 'int', + ), + ], + ); + final Root root = Root( + apis: [], + classes: [klass], + ); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public class Messages')); @@ -29,20 +31,22 @@ void main() { }); test('package', () { - final Class klass = Class() - ..name = 'Foobar' - ..fields = [ - Field() - ..name = 'field1' - ..dataType = 'int' - ]; - final Root root = Root() - ..apis = [] - ..classes = [klass]; + final Class klass = Class( + name: 'Foobar', + fields: [ + Field( + name: 'field1', + dataType: 'int', + ) + ], + ); + final Root root = Root( + apis: [], + classes: [klass], + ); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; - javaOptions.package = 'com.google.foobar'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages') + ..package = 'com.google.foobar'; generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('package com.google.foobar;')); @@ -68,8 +72,7 @@ void main() { fields: [Field(name: 'output', dataType: 'String')]) ]); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public interface Api')); @@ -92,8 +95,7 @@ void main() { ]); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('private Boolean aBool;')); @@ -125,8 +127,7 @@ void main() { fields: [Field(name: 'output', dataType: 'String')]) ]); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public static class Api')); @@ -149,8 +150,7 @@ void main() { fields: [Field(name: 'input', dataType: 'String')]), ]); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, isNot(matches('=.*doSomething'))); @@ -173,8 +173,7 @@ void main() { fields: [Field(name: 'input', dataType: 'String')]), ]); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('Reply')); @@ -198,8 +197,7 @@ void main() { fields: [Field(name: 'output', dataType: 'String')]), ]); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('Output doSomething()')); @@ -222,8 +220,7 @@ void main() { fields: [Field(name: 'output', dataType: 'String')]), ]); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('doSomething(Reply')); @@ -237,8 +234,7 @@ void main() { fields: [Field(name: 'field1', dataType: 'List')]), ]); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public static class Foobar')); @@ -252,8 +248,7 @@ void main() { fields: [Field(name: 'field1', dataType: 'Map')]), ]); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public static class Foobar')); @@ -261,26 +256,30 @@ void main() { }); test('gen nested', () { - final Class klass = Class() - ..name = 'Outer' - ..fields = [ - Field() - ..name = 'nested' - ..dataType = 'Nested' - ]; - final Class nestedClass = Class() - ..name = 'Nested' - ..fields = [ - Field() - ..name = 'data' - ..dataType = 'int' - ]; - final Root root = Root() - ..apis = [] - ..classes = [klass, nestedClass]; + final Class klass = Class( + name: 'Outer', + fields: [ + Field( + name: 'nested', + dataType: 'Nested', + ) + ], + ); + final Class nestedClass = Class( + name: 'Nested', + fields: [ + Field( + name: 'data', + dataType: 'int', + ) + ], + ); + final Root root = Root( + apis: [], + classes: [klass, nestedClass], + ); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public class Messages')); @@ -310,8 +309,7 @@ void main() { fields: [Field(name: 'output', dataType: 'String')]) ]); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public interface Api')); @@ -344,8 +342,7 @@ void main() { fields: [Field(name: 'output', dataType: 'String')]) ]); final StringBuffer sink = StringBuffer(); - final JavaOptions javaOptions = JavaOptions(); - javaOptions.className = 'Messages'; + final JavaOptions javaOptions = JavaOptions(className: 'Messages'); generateJava(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public static class Api')); diff --git a/packages/pigeon/test/pigeon_lib_test.dart b/packages/pigeon/test/pigeon_lib_test.dart index 1ae31471614f..6b3615fc3705 100644 --- a/packages/pigeon/test/pigeon_lib_test.dart +++ b/packages/pigeon/test/pigeon_lib_test.dart @@ -7,10 +7,14 @@ import 'package:pigeon/pigeon_lib.dart'; import 'package:pigeon/ast.dart'; class Input1 { + Input1({required this.input}); + String input; } class Output1 { + Output1({required this.output}); + String output; } @@ -30,6 +34,8 @@ abstract class ApiTwoMethods { } class Nested { + Nested({required this.input}); + Input1 input; } @@ -54,10 +60,14 @@ abstract class ApiWithMockDartClass { } class OnlyVisibleFromNesting { + OnlyVisibleFromNesting({required this.foo}); + String foo; } class Nestor { + Nestor({required this.nested}); + OnlyVisibleFromNesting nested; } @@ -92,7 +102,7 @@ void main() { test('parse args - java_package', () { final PigeonOptions opts = Pigeon.parseArgs(['--java_package', 'com.google.foo']); - expect(opts.javaOptions.package, equals('com.google.foo')); + expect(opts.javaOptions?.package, equals('com.google.foo')); }); test('parse args - input', () { @@ -126,8 +136,8 @@ void main() { expect(root.apis[0].methods[0].argType, equals('Input1')); expect(root.apis[0].methods[0].returnType, equals('Output1')); - Class input; - Class output; + Class? input; + Class? output; for (final Class klass in root.classes) { if (klass.name == 'Input1') { input = klass; @@ -138,13 +148,13 @@ void main() { expect(input, isNotNull); expect(output, isNotNull); - expect(input.fields.length, equals(1)); - expect(input.fields[0].name, equals('input')); - expect(input.fields[0].dataType, equals('String')); + expect(input?.fields.length, equals(1)); + expect(input?.fields[0].name, equals('input')); + expect(input?.fields[0].dataType, equals('String')); - expect(output.fields.length, equals(1)); - expect(output.fields[0].name, equals('output')); - expect(output.fields[0].dataType, equals('String')); + expect(output?.fields.length, equals(1)); + expect(output?.fields[0].name, equals('output')); + expect(output?.fields[0].dataType, equals('String')); }); test('invalid datatype', () { @@ -241,6 +251,6 @@ void main() { test('null safety flag', () { final PigeonOptions results = Pigeon.parseArgs(['--dart_null_safety']); - expect(results.dartOptions.isNullSafe, true); + expect(results.dartOptions?.isNullSafe, isTrue); }); } diff --git a/packages/pigeon/test/version_test.dart b/packages/pigeon/test/version_test.dart index a586856406af..1487b90b4e79 100644 --- a/packages/pigeon/test/version_test.dart +++ b/packages/pigeon/test/version_test.dart @@ -12,8 +12,8 @@ void main() { final String pubspecPath = '${Directory.current.path}/pubspec.yaml'; final String pubspec = File(pubspecPath).readAsStringSync(); final RegExp regex = RegExp(r'version:\s*(.*?) #'); - final RegExpMatch match = regex.firstMatch(pubspec); + final RegExpMatch? match = regex.firstMatch(pubspec); expect(match, isNotNull); - expect(pigeonVersion, match.group(1).trim()); + expect(pigeonVersion, match?.group(1)?.trim()); }); } From fb33ad7277c04f12f89169a961d5fe251a8a3251 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 10:53:48 -0700 Subject: [PATCH 02/18] reverted nonnull input argument --- packages/pigeon/lib/pigeon_lib.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/pigeon/lib/pigeon_lib.dart b/packages/pigeon/lib/pigeon_lib.dart index a579ffbfb5aa..657a1457194e 100644 --- a/packages/pigeon/lib/pigeon_lib.dart +++ b/packages/pigeon/lib/pigeon_lib.dart @@ -122,10 +122,10 @@ bool _isFlutterApi(ClassMirror apiMirror) { /// Options used when running the code generator. class PigeonOptions { /// Creates a instance of PigeonOptions - PigeonOptions({required this.input}); + PigeonOptions(); /// Path to the file which will be processed. - String input; + String? input; /// Path to the dart file that will be generated. String? dartOut; @@ -323,7 +323,8 @@ options: static PigeonOptions parseArgs(List args) { final ArgResults results = _argParser.parse(args); - final PigeonOptions opts = PigeonOptions(input: results['input']); + final PigeonOptions opts = PigeonOptions(); + opts.input = results['input']; opts.dartOut = results['dart_out']; opts.dartTestOut = results['dart_test_out']; opts.objcHeaderOut = results['objc_header_out']; From b59d0af20e9ab130204e90efda58f1d4eda2c28a Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 11:22:23 -0700 Subject: [PATCH 03/18] fixed linter problems with pigeon_cl --- packages/pigeon/lib/pigeon_cl.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/pigeon/lib/pigeon_cl.dart b/packages/pigeon/lib/pigeon_cl.dart index b605d9d55fe3..9880f4f1eb5b 100644 --- a/packages/pigeon/lib/pigeon_cl.dart +++ b/packages/pigeon/lib/pigeon_cl.dart @@ -11,7 +11,7 @@ import 'package:pigeon/pigeon_lib.dart'; /// This creates a relative path from `from` to `input`, the output being a /// posix path on all platforms. -String _posixRelative(String input, {String from}) { +String _posixRelative(String input, {required String from}) { final path.Context context = path.Context(style: path.Style.posix); final String rawInputPath = input; final String absInputPath = File(rawInputPath).absolute.path; @@ -27,7 +27,7 @@ String _posixRelative(String input, {String from}) { /// This is the main entrypoint for the command-line tool. [args] are the /// commmand line arguments and there is an optional [packageConfig] to /// accomodate users that want to integrate pigeon with other build systems. -Future runCommandLine(List args, {Uri packageConfig}) async { +Future runCommandLine(List args, {Uri? packageConfig}) async { final PigeonOptions opts = Pigeon.parseArgs(args); final Directory tempDir = Directory.systemTemp.createTempSync( 'flutter_pigeon.', @@ -35,7 +35,7 @@ Future runCommandLine(List args, {Uri packageConfig}) async { String importLine = ''; if (opts.input != null) { - final String relInputPath = _posixRelative(opts.input, from: tempDir.path); + final String relInputPath = _posixRelative(opts.input!, from: tempDir.path); importLine = 'import \'$relInputPath\';\n'; } final String code = """ From ba78048b37451ad9642cd62ae6209bc3c59b408a Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 11:43:06 -0700 Subject: [PATCH 04/18] Made the fields in pigeon files have to be nullable. --- packages/pigeon/pigeons/all_datatypes.dart | 33 ++++++------------- packages/pigeon/pigeons/async_handlers.dart | 4 +-- packages/pigeon/pigeons/host2flutter.dart | 8 ++--- packages/pigeon/pigeons/list.dart | 4 +-- packages/pigeon/pigeons/message.dart | 21 +++--------- packages/pigeon/pigeons/void_arg_flutter.dart | 4 +-- packages/pigeon/pigeons/void_arg_host.dart | 4 +-- packages/pigeon/pigeons/voidflutter.dart | 4 +-- packages/pigeon/pigeons/voidhost.dart | 4 +-- 9 files changed, 23 insertions(+), 63 deletions(-) diff --git a/packages/pigeon/pigeons/all_datatypes.dart b/packages/pigeon/pigeons/all_datatypes.dart index 5fb3fb4895b3..95a28863bc02 100644 --- a/packages/pigeon/pigeons/all_datatypes.dart +++ b/packages/pigeon/pigeons/all_datatypes.dart @@ -5,31 +5,18 @@ import 'package:pigeon/pigeon.dart'; class Everything { - Everything({ - required this.aBool, - required this.anInt, - required this.aDouble, - required this.aString, - required this.aByteArray, - required this.a4ByteArray, - required this.a8ByteArray, - required this.aFloatArray, - required this.aList, - required this.aMap, - }); - - bool aBool; - int anInt; - double aDouble; - String aString; - Uint8List aByteArray; - Int32List a4ByteArray; - Int64List a8ByteArray; - Float64List aFloatArray; + bool? aBool; + int? anInt; + double? aDouble; + String? aString; + Uint8List? aByteArray; + Int32List? a4ByteArray; + Int64List? a8ByteArray; + Float64List? aFloatArray; // ignore: always_specify_types - List aList; + List? aList; // ignore: always_specify_types - Map aMap; + Map? aMap; } @HostApi() diff --git a/packages/pigeon/pigeons/async_handlers.dart b/packages/pigeon/pigeons/async_handlers.dart index 44e840b2c3b6..67c439e7ae3a 100644 --- a/packages/pigeon/pigeons/async_handlers.dart +++ b/packages/pigeon/pigeons/async_handlers.dart @@ -5,9 +5,7 @@ import 'package:pigeon/pigeon.dart'; class Value { - Value({required this.number}); - - int number; + int? number; } @HostApi() diff --git a/packages/pigeon/pigeons/host2flutter.dart b/packages/pigeon/pigeons/host2flutter.dart index f53b04e7fe42..5a45975778b6 100644 --- a/packages/pigeon/pigeons/host2flutter.dart +++ b/packages/pigeon/pigeons/host2flutter.dart @@ -6,15 +6,11 @@ import 'package:pigeon/objc_generator.dart'; import 'package:pigeon/pigeon.dart'; class SearchRequest { - SearchRequest({required this.query}); - - String query; + String? query; } class SearchReply { - SearchReply({required this.result}); - - String result; + String? result; } @FlutterApi() diff --git a/packages/pigeon/pigeons/list.dart b/packages/pigeon/pigeons/list.dart index 34a7eb39936c..e370ae80120c 100644 --- a/packages/pigeon/pigeons/list.dart +++ b/packages/pigeon/pigeons/list.dart @@ -5,10 +5,8 @@ import 'package:pigeon/pigeon.dart'; class TestMessage { - TestMessage({required this.testList}); - // ignore: always_specify_types - List testList; + List? testList; } @HostApi() diff --git a/packages/pigeon/pigeons/message.dart b/packages/pigeon/pigeons/message.dart index 08640018ce5c..751c8f92d63b 100644 --- a/packages/pigeon/pigeons/message.dart +++ b/packages/pigeon/pigeons/message.dart @@ -10,25 +10,14 @@ import 'package:pigeon/objc_generator.dart'; import 'package:pigeon/pigeon.dart'; class SearchRequest { - SearchRequest({ - required this.query, - required this.anInt, - required this.aBool, - }); - - String query; - int anInt; - bool aBool; + String? query; + int? anInt; + bool? aBool; } class SearchReply { - SearchReply({ - required this.result, - required this.error, - }); - - String result; - String error; + String? result; + String? error; } @HostApi(dartHostTestHandler: 'TestHostApi') diff --git a/packages/pigeon/pigeons/void_arg_flutter.dart b/packages/pigeon/pigeons/void_arg_flutter.dart index 10f23cfbf625..d6fbd5490865 100644 --- a/packages/pigeon/pigeons/void_arg_flutter.dart +++ b/packages/pigeon/pigeons/void_arg_flutter.dart @@ -5,9 +5,7 @@ import 'package:pigeon/pigeon.dart'; class Result { - Result({required this.code}); - - int code; + int? code; } @FlutterApi() diff --git a/packages/pigeon/pigeons/void_arg_host.dart b/packages/pigeon/pigeons/void_arg_host.dart index f28f6b9b9d13..fec04ab930ea 100644 --- a/packages/pigeon/pigeons/void_arg_host.dart +++ b/packages/pigeon/pigeons/void_arg_host.dart @@ -5,9 +5,7 @@ import 'package:pigeon/pigeon.dart'; class Result { - Result({required this.code}); - - int code; + int? code; } @HostApi() diff --git a/packages/pigeon/pigeons/voidflutter.dart b/packages/pigeon/pigeons/voidflutter.dart index 289ec882d9d8..eb2faa946654 100644 --- a/packages/pigeon/pigeons/voidflutter.dart +++ b/packages/pigeon/pigeons/voidflutter.dart @@ -5,9 +5,7 @@ import 'package:pigeon/pigeon.dart'; class SetRequest { - SetRequest({required this.value}); - - int value; + int? value; } @FlutterApi() diff --git a/packages/pigeon/pigeons/voidhost.dart b/packages/pigeon/pigeons/voidhost.dart index 0f65d272960b..cdbbebda8d38 100644 --- a/packages/pigeon/pigeons/voidhost.dart +++ b/packages/pigeon/pigeons/voidhost.dart @@ -5,9 +5,7 @@ import 'package:pigeon/pigeon.dart'; class SetRequest { - SetRequest({required this.value}); - - int value; + int? value; } @HostApi() From c671cefab9b5bd11e49745265a73598e1bc925ad Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 11:47:12 -0700 Subject: [PATCH 05/18] oops missed one nullable type in the examples --- packages/pigeon/pigeons/message.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/pigeon/pigeons/message.dart b/packages/pigeon/pigeons/message.dart index 751c8f92d63b..449debff2fee 100644 --- a/packages/pigeon/pigeons/message.dart +++ b/packages/pigeon/pigeons/message.dart @@ -27,9 +27,7 @@ abstract class Api { } class Nested { - Nested({required this.request}); - - SearchRequest request; + SearchRequest? request; } @HostApi(dartHostTestHandler: 'TestNestedApi') From 9d618df6997e343e4bb806c60ee635038d5f5cec Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 12:12:12 -0700 Subject: [PATCH 06/18] Switched back to nullable className for java, sorry I couldn't find a good way to make it non-null the way things are setup. --- packages/pigeon/lib/java_generator.dart | 6 +++--- packages/pigeon/lib/pigeon_cl.dart | 2 +- packages/pigeon/lib/pigeon_lib.dart | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/pigeon/lib/java_generator.dart b/packages/pigeon/lib/java_generator.dart index f61f44e95523..9f1d307c3784 100644 --- a/packages/pigeon/lib/java_generator.dart +++ b/packages/pigeon/lib/java_generator.dart @@ -22,12 +22,12 @@ const Map _javaTypeForDartTypeMap = { class JavaOptions { /// Creates a [JavaOptions] object JavaOptions({ - required this.className, + this.className, this.package, }); /// The name of the class that will house all the generated classes. - String className; + String? className; /// The package where the generated class will live. String? package; @@ -245,7 +245,7 @@ void generateJava(JavaOptions options, Root root, StringSink sink) { indent.writeln('/** Generated class from Pigeon. */'); indent.writeln( '@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"})'); - indent.write('public class ${options.className} '); + indent.write('public class ${options.className!} '); indent.scoped('{', '}', () { for (final Class klass in root.classes) { indent.addln(''); diff --git a/packages/pigeon/lib/pigeon_cl.dart b/packages/pigeon/lib/pigeon_cl.dart index 9880f4f1eb5b..de70005bfc5c 100644 --- a/packages/pigeon/lib/pigeon_cl.dart +++ b/packages/pigeon/lib/pigeon_cl.dart @@ -39,7 +39,7 @@ Future runCommandLine(List args, {Uri? packageConfig}) async { importLine = 'import \'$relInputPath\';\n'; } final String code = """ -// @dart = 2.2 +// @dart = 2.12 $importLine import 'dart:io'; import 'dart:isolate'; diff --git a/packages/pigeon/lib/pigeon_lib.dart b/packages/pigeon/lib/pigeon_lib.dart index 657a1457194e..de4250ec68bb 100644 --- a/packages/pigeon/lib/pigeon_lib.dart +++ b/packages/pigeon/lib/pigeon_lib.dart @@ -334,7 +334,7 @@ options: ); opts.javaOut = results['java_out']; opts.javaOptions = JavaOptions( - className: 'Pigeon', + className: (opts.javaOut == null) ? null : path.basenameWithoutExtension(opts.javaOut!), package: results['java_package'], ); opts.dartOptions = DartOptions()..isNullSafe = results['dart_null_safety']; @@ -481,9 +481,7 @@ options: await _runGenerator( options.javaOut!, (StringSink sink) => generateJava( - JavaOptions( - className: path.basenameWithoutExtension(options.javaOut!), - package: options.javaOptions?.package), + options.javaOptions ?? JavaOptions(), parseResults.root, sink)); } From 092621146d813c818f526ebd059fac1c268f9b11 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 13:10:44 -0700 Subject: [PATCH 07/18] fixed formatting --- packages/pigeon/lib/pigeon_lib.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/pigeon/lib/pigeon_lib.dart b/packages/pigeon/lib/pigeon_lib.dart index de4250ec68bb..9d3bc2ba35fe 100644 --- a/packages/pigeon/lib/pigeon_lib.dart +++ b/packages/pigeon/lib/pigeon_lib.dart @@ -334,7 +334,9 @@ options: ); opts.javaOut = results['java_out']; opts.javaOptions = JavaOptions( - className: (opts.javaOut == null) ? null : path.basenameWithoutExtension(opts.javaOut!), + className: (opts.javaOut == null) + ? null + : path.basenameWithoutExtension(opts.javaOut!), package: results['java_package'], ); opts.dartOptions = DartOptions()..isNullSafe = results['dart_null_safety']; @@ -481,9 +483,7 @@ options: await _runGenerator( options.javaOut!, (StringSink sink) => generateJava( - options.javaOptions ?? JavaOptions(), - parseResults.root, - sink)); + options.javaOptions ?? JavaOptions(), parseResults.root, sink)); } } else { errors.add(Error(message: 'No pigeon classes found, nothing generated.')); From 9c6905c7f4719ec880682f4c4000f135b738dfcf Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 13:50:34 -0700 Subject: [PATCH 08/18] replaced inc dec calls with format --- packages/pigeon/lib/dart_generator.dart | 12 ++++-------- packages/pigeon/lib/generator_tools.dart | 14 +++++++++++--- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index 1b4584223bcf..fea616984c13 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -254,20 +254,16 @@ void generateDart(DartOptions opt, Root root, StringSink sink) { final Field field = klass.fields[index]; indent.write('..${field.name} = '); if (customClassNames.contains(field.dataType)) { - indent.addln('pigeonMap[\'${field.name}\'] != null'); - indent.inc(2); - indent.writeln( - '? ${field.dataType}.decode(pigeonMap[\'${field.name}\']$unwrapOperator)'); - indent.write(': null'); + indent.format(''' +pigeonMap['${field.name}'] != null +\t\t? ${field.dataType}.decode(pigeonMap['${field.name}']$unwrapOperator) +\t\t: null''', leadingSpace: false, trailingNewline: false); } else { indent.add( 'pigeonMap[\'${field.name}\'] as ${_addGenericTypes(field.dataType, nullTag)}', ); } indent.addln(index == klass.fields.length - 1 ? ';' : ''); - if (customClassNames.contains(field.dataType)) { - indent.dec(2); - } } }); }); diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index 21090509fa1a..2965cca5884b 100644 --- a/packages/pigeon/lib/generator_tools.dart +++ b/packages/pigeon/lib/generator_tools.dart @@ -55,9 +55,17 @@ class Indent { } /// Replaces the newlines and tabs of input and adds it to the stream. - void format(String input) { - for (final String line in input.split('\n')) { - writeln(line.replaceAll('\t', tab)); + void format(String input, {bool leadingSpace = true, bool trailingNewline = true}) { + final List lines = input.split('\n'); + for (int i = 0; i < lines.length; ++i) { + final String line = lines[i]; + if (i == 0 && !leadingSpace) { + addln(line.replaceAll('\t', tab)); + } else if (i == lines.length - 1 && !trailingNewline) { + write(line.replaceAll('\t', tab)); + } else { + writeln(line.replaceAll('\t', tab)); + } } } From a13c99500ace2a165296f6b8a0727ce9aab3f771 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 14:16:39 -0700 Subject: [PATCH 09/18] made decode take a nonnull Object again --- packages/pigeon/lib/dart_generator.dart | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index fea616984c13..295fc174bc18 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -89,6 +89,7 @@ void _writeFlutterApi( }) { assert(api.location == ApiLocation.flutter); final String nullTag = opt.isNullSafe ? '?' : ''; + final String unwrapOperator = opt.isNullSafe ? '!' : ''; indent.write('abstract class ${api.name} '); indent.scoped('{', '}', () { for (final Method func in api.methods) { @@ -140,13 +141,11 @@ void _writeFlutterApi( indent.writeln('// ignore message'); call = 'api.${func.name}()'; } else { - if (!opt.isNullSafe) { - indent.writeln( - 'assert(message != null, \'Argument for $channelName was null. Expected $argType.\');', - ); - } indent.writeln( - 'final $argType input = $argType.decode(message);', + 'assert(message != null, \'Argument for $channelName was null. Expected $argType.\');', + ); + indent.writeln( + 'final $argType input = $argType.decode(message$unwrapOperator);', ); call = 'api.${func.name}(input)'; } @@ -238,7 +237,7 @@ void generateDart(DartOptions opt, Root root, StringSink sink) { }); indent.writeln(''); indent.write( - 'static ${klass.name} decode(Object$nullTag message) ', + 'static ${klass.name} decode(Object message) ', ); indent.scoped('{', '}', () { indent.write('if (message == null) '); From 40e5243a6c721c1bb134d3d24e1536e7044b58db Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 14:18:48 -0700 Subject: [PATCH 10/18] forgot to commit the widget test --- .../mock_handler_tester/test/widget_test.dart | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/packages/pigeon/mock_handler_tester/test/widget_test.dart b/packages/pigeon/mock_handler_tester/test/widget_test.dart index 53623ba2cfe9..b44b35dd70bc 100644 --- a/packages/pigeon/mock_handler_tester/test/widget_test.dart +++ b/packages/pigeon/mock_handler_tester/test/widget_test.dart @@ -79,17 +79,22 @@ void main() { ).send(null), isEmpty, ); - final Object? result = await const BasicMessageChannel( - 'dev.flutter.pigeon.Api.search', - StandardMessageCodec(), - ).send(null); - expect(result, isA>()); - final Map? resultMap = result as Map?; - expect( - (resultMap?['result'] as Map?)?['result'], isNull); - expect( - (resultMap?['result'] as Map?)?['error'], isNull); - expect(mock.log, ['initialize', 'search']); + try { + await const BasicMessageChannel( + 'dev.flutter.pigeon.Api.search', + StandardMessageCodec(), + ).send(null) as Map; + expect(true, isFalse); // should not reach here + } catch (error) { + expect(error, isAssertionError); + expect( + error.toString(), + contains( + 'Argument for dev.flutter.pigeon.Api.search was null. Expected SearchRequest.', + ), + ); + } + expect(mock.log, ['initialize']); }, // TODO(ianh): skip can be removed after first stable release in 2021 skip: Platform.environment['CHANNEL'] == 'stable', From 83427418081e24c64c693103b2fc7f200f7369fc Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 14:25:11 -0700 Subject: [PATCH 11/18] fixed incorrect `as` cast --- packages/pigeon/mock_handler_tester/test/widget_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pigeon/mock_handler_tester/test/widget_test.dart b/packages/pigeon/mock_handler_tester/test/widget_test.dart index b44b35dd70bc..0334051cad4f 100644 --- a/packages/pigeon/mock_handler_tester/test/widget_test.dart +++ b/packages/pigeon/mock_handler_tester/test/widget_test.dart @@ -83,7 +83,7 @@ void main() { await const BasicMessageChannel( 'dev.flutter.pigeon.Api.search', StandardMessageCodec(), - ).send(null) as Map; + ).send(null) as Map?; expect(true, isFalse); // should not reach here } catch (error) { expect(error, isAssertionError); From ab4e72a9e190da1504cbf48d7e5914afe7fdfaee Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 14:31:42 -0700 Subject: [PATCH 12/18] removed unnecessary null check --- packages/pigeon/lib/dart_generator.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index 295fc174bc18..f36b62e79b83 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -240,10 +240,6 @@ void generateDart(DartOptions opt, Root root, StringSink sink) { 'static ${klass.name} decode(Object message) ', ); indent.scoped('{', '}', () { - indent.write('if (message == null) '); - indent.scoped('{', '}', () { - indent.writeln('return ${klass.name}();'); - }); indent.writeln( 'final Map pigeonMap = message as Map;', ); From 55332602ea33b2f656a26e185d4aa06cbdfcf156 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 14:36:41 -0700 Subject: [PATCH 13/18] formatter --- packages/pigeon/lib/generator_tools.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index 2965cca5884b..a95d758743dd 100644 --- a/packages/pigeon/lib/generator_tools.dart +++ b/packages/pigeon/lib/generator_tools.dart @@ -55,7 +55,8 @@ class Indent { } /// Replaces the newlines and tabs of input and adds it to the stream. - void format(String input, {bool leadingSpace = true, bool trailingNewline = true}) { + void format(String input, + {bool leadingSpace = true, bool trailingNewline = true}) { final List lines = input.split('\n'); for (int i = 0; i < lines.length; ++i) { final String line = lines[i]; From 72e33e3adc096546030781baa3c1446533a2fce2 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 14:38:24 -0700 Subject: [PATCH 14/18] removed constructors from pigeon declarations --- packages/pigeon/test/pigeon_lib_test.dart | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/packages/pigeon/test/pigeon_lib_test.dart b/packages/pigeon/test/pigeon_lib_test.dart index 6b3615fc3705..f92117d2eb60 100644 --- a/packages/pigeon/test/pigeon_lib_test.dart +++ b/packages/pigeon/test/pigeon_lib_test.dart @@ -7,15 +7,11 @@ import 'package:pigeon/pigeon_lib.dart'; import 'package:pigeon/ast.dart'; class Input1 { - Input1({required this.input}); - - String input; + String? input; } class Output1 { - Output1({required this.output}); - - String output; + String? output; } @HostApi() @@ -34,9 +30,7 @@ abstract class ApiTwoMethods { } class Nested { - Nested({required this.input}); - - Input1 input; + Input1? input; } @FlutterApi() @@ -60,15 +54,11 @@ abstract class ApiWithMockDartClass { } class OnlyVisibleFromNesting { - OnlyVisibleFromNesting({required this.foo}); - - String foo; + String? foo; } class Nestor { - Nestor({required this.nested}); - - OnlyVisibleFromNesting nested; + OnlyVisibleFromNesting? nested; } @HostApi() From bb3750201242c122b80bc127d6f45e3d0394e29a Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 14:40:21 -0700 Subject: [PATCH 15/18] updated example --- packages/pigeon/example/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/pigeon/example/README.md b/packages/pigeon/example/README.md index 0c8fdb8ee27e..a6d18e36a265 100644 --- a/packages/pigeon/example/README.md +++ b/packages/pigeon/example/README.md @@ -14,11 +14,11 @@ from Flutter to the host-platform. import 'package:pigeon/pigeon.dart'; class SearchRequest { - String query; + String? query; } class SearchReply { - String result; + String? result; } @HostApi() From 801417752c2677dd202ebc0e96424340a966e825 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 14:41:36 -0700 Subject: [PATCH 16/18] updated README.md --- packages/pigeon/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pigeon/README.md b/packages/pigeon/README.md index 699cffdb96e9..a4e5a0c8f95f 100644 --- a/packages/pigeon/README.md +++ b/packages/pigeon/README.md @@ -78,7 +78,7 @@ Example: ```dart class Value { - int number; + int? number; } @HostApi() From ecee68d3607946188fa757e2ce4e6c31c2312bd5 Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 14:56:25 -0700 Subject: [PATCH 17/18] checked up updated mock_handler_tester generated code, not sure why the test is failing remotely, works locally --- .../mock_handler_tester/test/message.dart | 33 ++++++++----------- .../pigeon/mock_handler_tester/test/test.dart | 8 +++-- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/packages/pigeon/mock_handler_tester/test/message.dart b/packages/pigeon/mock_handler_tester/test/message.dart index 0445fe058888..0896b04a9cd3 100644 --- a/packages/pigeon/mock_handler_tester/test/message.dart +++ b/packages/pigeon/mock_handler_tester/test/message.dart @@ -1,6 +1,6 @@ // Autogenerated from Pigeon (v0.2.0-nullsafety.0), do not edit directly. // See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types // @dart = 2.12 import 'dart:async'; import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List; @@ -18,10 +18,7 @@ class SearchReply { return pigeonMap; } - static SearchReply decode(Object? message) { - if (message == null) { - return SearchReply(); - } + static SearchReply decode(Object message) { final Map pigeonMap = message as Map; return SearchReply() ..result = pigeonMap['result'] as String? @@ -42,10 +39,7 @@ class SearchRequest { return pigeonMap; } - static SearchRequest decode(Object? message) { - if (message == null) { - return SearchRequest(); - } + static SearchRequest decode(Object message) { final Map pigeonMap = message as Map; return SearchRequest() ..query = pigeonMap['query'] as String? @@ -63,10 +57,7 @@ class Nested { return pigeonMap; } - static Nested decode(Object? message) { - if (message == null) { - return Nested(); - } + static Nested decode(Object message) { final Map pigeonMap = message as Map; return Nested() ..request = pigeonMap['request'] != null @@ -85,7 +76,9 @@ abstract class FlutterSearchApi { channel.setMessageHandler(null); } else { channel.setMessageHandler((Object? message) async { - final SearchRequest input = SearchRequest.decode(message); + assert(message != null, + 'Argument for dev.flutter.pigeon.FlutterSearchApi.search was null. Expected SearchRequest.'); + final SearchRequest input = SearchRequest.decode(message!); final SearchReply output = api.search(input); return output.encode(); }); @@ -109,9 +102,9 @@ class NestedApi { ); } else if (replyMap['error'] != null) { final Map error = - replyMap['error']! as Map; + (replyMap['error'] as Map?)!; throw PlatformException( - code: error['code'] as String? ?? 'unknown', + code: (error['code'] as String?)!, message: error['message'] as String?, details: error['details'], ); @@ -135,9 +128,9 @@ class Api { ); } else if (replyMap['error'] != null) { final Map error = - replyMap['error']! as Map; + (replyMap['error'] as Map?)!; throw PlatformException( - code: error['code'] as String? ?? 'unknown', + code: (error['code'] as String?)!, message: error['message'] as String?, details: error['details'], ); @@ -160,9 +153,9 @@ class Api { ); } else if (replyMap['error'] != null) { final Map error = - replyMap['error']! as Map; + (replyMap['error'] as Map?)!; throw PlatformException( - code: error['code'] as String? ?? 'unknown', + code: (error['code'] as String?)!, message: error['message'] as String?, details: error['details'], ); diff --git a/packages/pigeon/mock_handler_tester/test/test.dart b/packages/pigeon/mock_handler_tester/test/test.dart index 565922a9bd8f..0d8e4c3ad52c 100644 --- a/packages/pigeon/mock_handler_tester/test/test.dart +++ b/packages/pigeon/mock_handler_tester/test/test.dart @@ -19,7 +19,9 @@ abstract class TestNestedApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - final Nested input = Nested.decode(message); + assert(message != null, + 'Argument for dev.flutter.pigeon.NestedApi.search was null. Expected Nested.'); + final Nested input = Nested.decode(message!); final SearchReply output = api.search(input); return {'result': output.encode()}; }); @@ -52,7 +54,9 @@ abstract class TestHostApi { channel.setMockMessageHandler(null); } else { channel.setMockMessageHandler((Object? message) async { - final SearchRequest input = SearchRequest.decode(message); + assert(message != null, + 'Argument for dev.flutter.pigeon.Api.search was null. Expected SearchRequest.'); + final SearchRequest input = SearchRequest.decode(message!); final SearchReply output = api.search(input); return {'result': output.encode()}; }); From eb5eaf7a4719522d191968ce33cae5f4e9a8e4bf Mon Sep 17 00:00:00 2001 From: Aaron Clarke Date: Fri, 19 Mar 2021 15:03:47 -0700 Subject: [PATCH 18/18] Switched the version to 0.2.0. I don't think we have to put nullsafety in the name now that it is on stable. --- packages/pigeon/lib/generator_tools.dart | 2 +- packages/pigeon/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index a95d758743dd..c1cf021ee9c0 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 = '0.2.0-nullsafety.0'; +const String pigeonVersion = '0.2.0'; /// Read all the content from [stdin] to a String. String readStdin() { diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index 18a4978e8d44..8d041a398865 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -1,5 +1,5 @@ name: pigeon -version: 0.2.0-nullsafety.0 # This must match the version in lib/generator_tools.dart +version: 0.2.0 # This must match the version in lib/generator_tools.dart description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. homepage: https://github.com/flutter/packages/tree/master/packages/pigeon dependencies: