diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index 47dce97fc0b..8b083f76704 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,3 +1,7 @@ +## 19.0.1 + +* [dart] Updates `PigeonInstanceMangerApi` to use the shared api channel code. + ## 19.0.0 * **Breaking Change** [swift] Removes `FlutterError` in favor of `PigeonError`. diff --git a/packages/pigeon/lib/dart/templates.dart b/packages/pigeon/lib/dart/templates.dart index ce986b888db..212a06e7b4f 100644 --- a/packages/pigeon/lib/dart/templates.dart +++ b/packages/pigeon/lib/dart/templates.dart @@ -215,113 +215,6 @@ class $instanceManagerClassName { '''; } -/// Creates the `InstanceManagerApi` with the passed string values. -String instanceManagerApiTemplate({ - required String dartPackageName, - required String pigeonChannelCodecVarName, -}) { - const String apiName = '${instanceManagerClassName}Api'; - - final String removeStrongReferenceName = makeChannelNameWithStrings( - apiName: apiName, - methodName: 'removeStrongReference', - dartPackageName: dartPackageName, - ); - - final String clearName = makeChannelNameWithStrings( - apiName: apiName, - methodName: 'clear', - dartPackageName: dartPackageName, - ); - - return ''' -/// Generated API for managing the Dart and native `$instanceManagerClassName`s. -class _$apiName { - /// Constructor for [_$apiName]. - _$apiName({BinaryMessenger? binaryMessenger}) - : _binaryMessenger = binaryMessenger; - - final BinaryMessenger? _binaryMessenger; - - static const MessageCodec $pigeonChannelCodecVarName = - StandardMessageCodec(); - - static void setUpMessageHandlers({ - BinaryMessenger? binaryMessenger, - $instanceManagerClassName? instanceManager, - }) { - const String channelName = - r'$removeStrongReferenceName'; - final BasicMessageChannel channel = BasicMessageChannel( - channelName, - $pigeonChannelCodecVarName, - binaryMessenger: binaryMessenger, - ); - channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for \$channelName was null.', - ); - final int? identifier = message as int?; - assert( - identifier != null, - r'Argument for \$channelName, expected non-null int.', - ); - (instanceManager ?? $instanceManagerClassName.instance).remove(identifier!); - return; - }); - } - - Future removeStrongReference(int identifier) async { - const String channelName = - r'$removeStrongReferenceName'; - final BasicMessageChannel channel = BasicMessageChannel( - channelName, - $pigeonChannelCodecVarName, - binaryMessenger: _binaryMessenger, - ); - final List? replyList = - await channel.send(identifier) as List?; - if (replyList == null) { - throw _createConnectionError(channelName); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else { - return; - } - } - - /// Clear the native `$instanceManagerClassName`. - /// - /// This is typically called after a hot restart. - Future clear() async { - const String channelName = - r'$clearName'; - final BasicMessageChannel channel = BasicMessageChannel( - channelName, - $pigeonChannelCodecVarName, - binaryMessenger: _binaryMessenger, - ); - final List? replyList = await channel.send(null) as List?; - if (replyList == null) { - throw _createConnectionError(channelName); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else { - return; - } - } -}'''; -} - /// The base class for all ProxyApis. /// /// All Dart classes generated as a ProxyApi extends this one. diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index 0129ae4210d..5769f09bb65 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -362,6 +362,7 @@ $resultAt != null name: func.name, parameters: func.parameters, returnType: func.returnType, + addSuffixVariable: true, channelName: channelNameFunc == null ? makeChannelName(api, func, dartPackageName) : channelNameFunc(func), @@ -468,11 +469,204 @@ final BinaryMessenger? ${_varNamePrefix}binaryMessenger; Indent indent, { required String dartPackageName, }) { + const String apiName = '${instanceManagerClassName}Api'; + + final cb.Parameter binaryMessengerParameter = cb.Parameter( + (cb.ParameterBuilder builder) => builder + ..name = 'binaryMessenger' + ..type = cb.refer('BinaryMessenger?') + ..named = true, + ); + + final cb.Field binaryMessengerField = cb.Field( + (cb.FieldBuilder builder) => builder + ..name = '${varNamePrefix}binaryMessenger' + ..type = cb.refer('BinaryMessenger?') + ..modifier = cb.FieldModifier.final$, + ); + + final String removeStrongReferenceName = makeChannelNameWithStrings( + apiName: apiName, + methodName: 'removeStrongReference', + dartPackageName: dartPackageName, + ); + + final cb.Class instanceManagerApi = cb.Class( + (cb.ClassBuilder builder) => builder + ..name = '_$apiName' + ..docs.add( + '/// Generated API for managing the Dart and native `$instanceManagerClassName`s.', + ) + ..constructors.add( + cb.Constructor( + (cb.ConstructorBuilder builder) { + builder + ..docs.add('/// Constructor for [_$apiName].') + ..optionalParameters.add(binaryMessengerParameter) + ..initializers.add( + cb.Code( + '${binaryMessengerField.name} = ${binaryMessengerParameter.name}', + ), + ); + }, + ), + ) + ..fields.addAll( + [ + binaryMessengerField, + cb.Field( + (cb.FieldBuilder builder) { + builder + ..name = _pigeonChannelCodec + ..type = cb.refer('MessageCodec') + ..static = true + ..modifier = cb.FieldModifier.constant + ..assignment = const cb.Code('StandardMessageCodec()'); + }, + ) + ], + ) + ..methods.add( + cb.Method( + (cb.MethodBuilder builder) { + builder + ..name = 'setUpMessageHandlers' + ..static = true + ..returns = cb.refer('void') + ..optionalParameters.addAll([ + cb.Parameter( + (cb.ParameterBuilder builder) => builder + ..name = '${classMemberNamePrefix}clearHandlers' + ..type = cb.refer('bool') + ..named = true + ..defaultTo = const cb.Code('false'), + ), + binaryMessengerParameter, + cb.Parameter( + (cb.ParameterBuilder builder) => builder + ..name = 'instanceManager' + ..named = true + ..type = cb.refer('$instanceManagerClassName?'), + ), + ]) + ..body = cb.Block.of( + cb.Block( + (cb.BlockBuilder builder) { + final StringBuffer messageHandlerSink = StringBuffer(); + _writeFlutterMethodMessageHandler( + Indent(messageHandlerSink), + name: 'removeStrongReferenceName', + parameters: [ + Parameter( + name: 'identifier', + type: const TypeDeclaration( + baseName: 'int', + isNullable: false, + ), + ) + ], + returnType: const TypeDeclaration.voidDeclaration(), + channelName: removeStrongReferenceName, + isMockHandler: false, + isAsynchronous: false, + nullHandlerExpression: + '${classMemberNamePrefix}clearHandlers', + onCreateApiCall: ( + String methodName, + Iterable parameters, + Iterable safeArgumentNames, + ) { + return '(instanceManager ?? $instanceManagerClassName.instance).remove(${safeArgumentNames.single})'; + }, + ); + builder.statements.add( + cb.Code(messageHandlerSink.toString()), + ); + }, + ).statements, + ); + }, + ), + ) + ..methods.addAll( + [ + cb.Method( + (cb.MethodBuilder builder) { + builder + ..name = 'removeStrongReference' + ..returns = cb.refer('Future') + ..modifier = cb.MethodModifier.async + ..requiredParameters.add( + cb.Parameter( + (cb.ParameterBuilder builder) => builder + ..name = 'identifier' + ..type = cb.refer('int'), + ), + ) + ..body = cb.Block( + (cb.BlockBuilder builder) { + final StringBuffer messageCallSink = StringBuffer(); + _writeHostMethodMessageCall( + Indent(messageCallSink), + addSuffixVariable: false, + channelName: removeStrongReferenceName, + parameters: [ + Parameter( + name: 'identifier', + type: const TypeDeclaration( + baseName: 'int', + isNullable: false, + ), + ), + ], + returnType: const TypeDeclaration.voidDeclaration(), + ); + builder.statements.addAll([ + cb.Code(messageCallSink.toString()), + ]); + }, + ); + }, + ), + cb.Method( + (cb.MethodBuilder builder) { + builder + ..name = 'clear' + ..returns = cb.refer('Future') + ..modifier = cb.MethodModifier.async + ..docs.addAll([ + '/// Clear the native `$instanceManagerClassName`.', + '///', + '/// This is typically called after a hot restart.', + ]) + ..body = cb.Block( + (cb.BlockBuilder builder) { + final StringBuffer messageCallSink = StringBuffer(); + _writeHostMethodMessageCall( + Indent(messageCallSink), + addSuffixVariable: false, + channelName: makeChannelNameWithStrings( + apiName: apiName, + methodName: 'clear', + dartPackageName: dartPackageName, + ), + parameters: [], + returnType: const TypeDeclaration.voidDeclaration(), + ); + builder.statements.addAll([ + cb.Code(messageCallSink.toString()), + ]); + }, + ); + }, + ), + ], + ), + ); + + final cb.DartEmitter emitter = cb.DartEmitter(useNullSafetySyntax: true); indent.format( - instanceManagerApiTemplate( - dartPackageName: dartPackageName, - pigeonChannelCodecVarName: _pigeonChannelCodec, - ), + DartFormatter().format('${instanceManagerApi.accept(emitter)}'), ); } @@ -859,7 +1053,7 @@ if (${varNamePrefix}replyList == null) { ); indent.nest(2, () { final String channelSuffix = - addSuffixVariable ? '' : r'$messageChannelSuffix'; + addSuffixVariable ? r'$messageChannelSuffix' : ''; indent.writeln("'$channelName$channelSuffix', $_pigeonChannelCodec,"); indent.writeln( 'binaryMessenger: binaryMessenger);', @@ -1451,7 +1645,6 @@ if (${varNamePrefix}replyList == null) { _writeFlutterMethodMessageHandler( Indent(messageHandlerSink), name: methodName, - addSuffixVariable: true, parameters: [ Parameter( name: '${classMemberNamePrefix}instanceIdentifier', @@ -1507,7 +1700,6 @@ if (${varNamePrefix}replyList == null) { _writeFlutterMethodMessageHandler( Indent(messageHandlerSink), name: method.name, - addSuffixVariable: true, parameters: [ Parameter( name: '${classMemberNamePrefix}instance', diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index e11c448070f..85c2a2c75ab 100644 --- a/packages/pigeon/lib/generator_tools.dart +++ b/packages/pigeon/lib/generator_tools.dart @@ -13,7 +13,7 @@ import 'ast.dart'; /// The current version of pigeon. /// /// This must match the version in pubspec.yaml. -const String pigeonVersion = '19.0.0'; +const String pigeonVersion = '19.0.1'; /// Prefix for all local variables in methods. /// diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/proxy_api_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/proxy_api_tests.gen.dart index 762f65d5aad..3e3e4b51bc1 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/proxy_api_tests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/proxy_api_tests.gen.dart @@ -284,56 +284,67 @@ class PigeonInstanceManager { class _PigeonInstanceManagerApi { /// Constructor for [_PigeonInstanceManagerApi]. _PigeonInstanceManagerApi({BinaryMessenger? binaryMessenger}) - : _binaryMessenger = binaryMessenger; + : __pigeon_binaryMessenger = binaryMessenger; - final BinaryMessenger? _binaryMessenger; + final BinaryMessenger? __pigeon_binaryMessenger; static const MessageCodec pigeonChannelCodec = StandardMessageCodec(); static void setUpMessageHandlers({ + bool pigeon_clearHandlers = false, BinaryMessenger? binaryMessenger, PigeonInstanceManager? instanceManager, }) { - const String channelName = - r'dev.flutter.pigeon.pigeon_integration_tests.PigeonInstanceManagerApi.removeStrongReference'; - final BasicMessageChannel channel = BasicMessageChannel( - channelName, - pigeonChannelCodec, - binaryMessenger: binaryMessenger, - ); - channel.setMessageHandler((Object? message) async { - assert( - message != null, - 'Argument for $channelName was null.', - ); - final int? identifier = message as int?; - assert( - identifier != null, - r'Argument for $channelName, expected non-null int.', - ); - (instanceManager ?? PigeonInstanceManager.instance).remove(identifier!); - return; - }); + { + final BasicMessageChannel __pigeon_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.pigeon_integration_tests.PigeonInstanceManagerApi.removeStrongReference', + pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (pigeon_clearHandlers) { + __pigeon_channel.setMessageHandler(null); + } else { + __pigeon_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.pigeon_integration_tests.PigeonInstanceManagerApi.removeStrongReference was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.pigeon_integration_tests.PigeonInstanceManagerApi.removeStrongReference was null, expected non-null int.'); + try { + (instanceManager ?? PigeonInstanceManager.instance) + .remove(arg_identifier!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } } Future removeStrongReference(int identifier) async { - const String channelName = - r'dev.flutter.pigeon.pigeon_integration_tests.PigeonInstanceManagerApi.removeStrongReference'; - final BasicMessageChannel channel = BasicMessageChannel( - channelName, + const String __pigeon_channelName = + 'dev.flutter.pigeon.pigeon_integration_tests.PigeonInstanceManagerApi.removeStrongReference'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, pigeonChannelCodec, - binaryMessenger: _binaryMessenger, + binaryMessenger: __pigeon_binaryMessenger, ); - final List? replyList = - await channel.send(identifier) as List?; - if (replyList == null) { - throw _createConnectionError(channelName); - } else if (replyList.length > 1) { + final List? __pigeon_replyList = + await __pigeon_channel.send([identifier]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); } else { return; @@ -344,21 +355,23 @@ class _PigeonInstanceManagerApi { /// /// This is typically called after a hot restart. Future clear() async { - const String channelName = - r'dev.flutter.pigeon.pigeon_integration_tests.PigeonInstanceManagerApi.clear'; - final BasicMessageChannel channel = BasicMessageChannel( - channelName, + const String __pigeon_channelName = + 'dev.flutter.pigeon.pigeon_integration_tests.PigeonInstanceManagerApi.clear'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, pigeonChannelCodec, - binaryMessenger: _binaryMessenger, + binaryMessenger: __pigeon_binaryMessenger, ); - final List? replyList = await channel.send(null) as List?; - if (replyList == null) { - throw _createConnectionError(channelName); - } else if (replyList.length > 1) { + final List? __pigeon_replyList = + await __pigeon_channel.send(null) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], ); } else { return; diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index f3ceac84cba..fa7ffcc9ca9 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%3A%22p%3A+pigeon%22 -version: 19.0.0 # This must match the version in lib/generator_tools.dart +version: 19.0.1 # This must match the version in lib/generator_tools.dart environment: sdk: ^3.2.0 diff --git a/packages/pigeon/test/dart/proxy_api_test.dart b/packages/pigeon/test/dart/proxy_api_test.dart index fb24a203861..95c4f90da75 100644 --- a/packages/pigeon/test/dart/proxy_api_test.dart +++ b/packages/pigeon/test/dart/proxy_api_test.dart @@ -126,6 +126,56 @@ void main() { expect(code, contains(r'Api pigeon_copy(')); }); + test('InstanceManagerApi', () { + final Root root = Root(apis: [ + AstProxyApi( + name: 'Api', + constructors: [], + fields: [], + methods: [], + ) + ], classes: [], enums: []); + final StringBuffer sink = StringBuffer(); + const DartGenerator generator = DartGenerator(); + generator.generate( + const DartOptions(), + root, + sink, + dartPackageName: DEFAULT_PACKAGE_NAME, + ); + final String code = sink.toString(); + final String collapsedCode = _collapseNewlineAndIndentation(code); + + expect(code, contains(r'class _PigeonInstanceManagerApi')); + + expect( + code, + contains( + 'Future removeStrongReference(int identifier)', + ), + ); + expect( + code, + contains( + 'dev.flutter.pigeon.$DEFAULT_PACKAGE_NAME.PigeonInstanceManagerApi.removeStrongReference', + ), + ); + expect( + collapsedCode, + contains( + '(instanceManager ?? PigeonInstanceManager.instance) .remove(arg_identifier!);', + ), + ); + + expect(code, contains('Future clear()')); + expect( + code, + contains( + 'dev.flutter.pigeon.$DEFAULT_PACKAGE_NAME.PigeonInstanceManagerApi.clear', + ), + ); + }); + group('inheritance', () { test('extends', () { final AstProxyApi api2 = AstProxyApi(