From c3d75745eea02f64a1e43900d35c94285fdf4e17 Mon Sep 17 00:00:00 2001 From: Tarrin Neal Date: Fri, 7 Oct 2022 15:50:05 -0700 Subject: [PATCH] [pigeon] removes generated codecs if there are no custom datatypes (#2645) --- packages/pigeon/CHANGELOG.md | 4 + packages/pigeon/lib/cpp_generator.dart | 136 ++++++------- packages/pigeon/lib/dart_generator.dart | 79 ++++---- packages/pigeon/lib/generator_tools.dart | 2 +- packages/pigeon/lib/java_generator.dart | 110 ++++++----- packages/pigeon/lib/kotlin_generator.dart | 105 +++++----- packages/pigeon/lib/objc_generator.dart | 117 ++++++----- packages/pigeon/lib/swift_generator.dart | 31 ++- .../ios/RunnerTests/MultipleArityTests.swift | 5 +- .../RunnerTests/NullableReturnsTests.swift | 6 +- .../ios/RunnerTests/PrimitiveTests.swift | 26 +-- .../ios/RunnerTests/NullableReturnsTest.m | 2 +- packages/pigeon/pubspec.yaml | 2 +- packages/pigeon/test/cpp_generator_test.dart | 74 +++++++ packages/pigeon/test/dart_generator_test.dart | 75 ++++++++ packages/pigeon/test/java_generator_test.dart | 77 ++++++++ .../pigeon/test/kotlin_generator_test.dart | 181 +++++++++++++----- packages/pigeon/test/objc_generator_test.dart | 74 +++++++ .../pigeon/test/swift_generator_test.dart | 76 ++++++++ 19 files changed, 857 insertions(+), 325 deletions(-) diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index 5e32c04435..1ae940856f 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.2.2 + +* Removes unneeded custom codecs for all languages. + ## 4.2.1 * Adds documentation comment support for Kotlin. diff --git a/packages/pigeon/lib/cpp_generator.dart b/packages/pigeon/lib/cpp_generator.dart index ec1b227ff4..9c369a5125 100644 --- a/packages/pigeon/lib/cpp_generator.dart +++ b/packages/pigeon/lib/cpp_generator.dart @@ -14,6 +14,9 @@ const String _commentPrefix = '//'; const DocumentCommentSpecification _docCommentSpec = DocumentCommentSpecification(_commentPrefix); +/// The default serializer for Flutter. +const String _defaultCodecSerializer = 'flutter::StandardCodecSerializer'; + /// Options that control how C++ code will be generated. class CppOptions { /// Creates a [CppOptions] object @@ -61,83 +64,80 @@ class CppOptions { } } -String _getCodecName(Api api) => '${api.name}CodecSerializer'; +String _getCodecSerializerName(Api api) => '${api.name}CodecSerializer'; const String _pointerPrefix = 'pointer'; const String _encodablePrefix = 'encodable'; void _writeCodecHeader(Indent indent, Api api, Root root) { - final String codecName = _getCodecName(api); - indent.write('class $codecName : public flutter::StandardCodecSerializer '); + assert(getCodecClasses(api, root).isNotEmpty); + final String codeSerializerName = _getCodecSerializerName(api); + indent.write('class $codeSerializerName : public $_defaultCodecSerializer '); indent.scoped('{', '};', () { indent.scoped(' public:', '', () { indent.writeln(''); indent.format(''' -inline static $codecName& GetInstance() { -\tstatic $codecName sInstance; +inline static $codeSerializerName& GetInstance() { +\tstatic $codeSerializerName sInstance; \treturn sInstance; } '''); - indent.writeln('$codecName();'); + indent.writeln('$codeSerializerName();'); + }); + indent.writeScoped(' public:', '', () { + indent.writeln( + 'void WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const override;'); + }); + indent.writeScoped(' protected:', '', () { + indent.writeln( + 'flutter::EncodableValue ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const override;'); }); - if (getCodecClasses(api, root).isNotEmpty) { - indent.writeScoped(' public:', '', () { - indent.writeln( - 'void WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const override;'); - }); - indent.writeScoped(' protected:', '', () { - indent.writeln( - 'flutter::EncodableValue ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const override;'); - }); - } }, nestCount: 0); } void _writeCodecSource(Indent indent, Api api, Root root) { - final String codecName = _getCodecName(api); - indent.writeln('$codecName::$codecName() {}'); - if (getCodecClasses(api, root).isNotEmpty) { - indent.write( - 'flutter::EncodableValue $codecName::ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const '); + assert(getCodecClasses(api, root).isNotEmpty); + final String codeSerializerName = _getCodecSerializerName(api); + indent.writeln('$codeSerializerName::$codeSerializerName() {}'); + indent.write( + 'flutter::EncodableValue $codeSerializerName::ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const '); + indent.scoped('{', '}', () { + indent.write('switch (type) '); indent.scoped('{', '}', () { - indent.write('switch (type) '); - indent.scoped('{', '}', () { - for (final EnumeratedClass customClass in getCodecClasses(api, root)) { - indent.write('case ${customClass.enumeration}:'); - indent.writeScoped('', '', () { - indent.writeln( - 'return flutter::CustomEncodableValue(${customClass.name}(std::get(ReadValue(stream))));'); - }); - } - indent.write('default:'); + for (final EnumeratedClass customClass in getCodecClasses(api, root)) { + indent.write('case ${customClass.enumeration}:'); indent.writeScoped('', '', () { indent.writeln( - 'return flutter::StandardCodecSerializer::ReadValueOfType(type, stream);'); - }, addTrailingNewline: false); - }); + 'return flutter::CustomEncodableValue(${customClass.name}(std::get(ReadValue(stream))));'); + }); + } + indent.write('default:'); + indent.writeScoped('', '', () { + indent.writeln( + 'return $_defaultCodecSerializer::ReadValueOfType(type, stream);'); + }, addTrailingNewline: false); }); - indent.writeln(''); + }); + indent.writeln(''); + indent.write( + 'void $codeSerializerName::WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const '); + indent.writeScoped('{', '}', () { indent.write( - 'void $codecName::WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const '); - indent.writeScoped('{', '}', () { - indent.write( - 'if (const flutter::CustomEncodableValue* custom_value = std::get_if(&value)) '); - indent.scoped('{', '}', () { - for (final EnumeratedClass customClass in getCodecClasses(api, root)) { - indent.write( - 'if (custom_value->type() == typeid(${customClass.name})) '); - indent.scoped('{', '}', () { - indent.writeln('stream->WriteByte(${customClass.enumeration});'); - indent.writeln( - 'WriteValue(std::any_cast<${customClass.name}>(*custom_value).ToEncodableMap(), stream);'); - indent.writeln('return;'); - }); - } - }); - indent.writeln( - 'flutter::StandardCodecSerializer::WriteValue(value, stream);'); + 'if (const flutter::CustomEncodableValue* custom_value = std::get_if(&value)) '); + indent.scoped('{', '}', () { + for (final EnumeratedClass customClass in getCodecClasses(api, root)) { + indent + .write('if (custom_value->type() == typeid(${customClass.name})) '); + indent.scoped('{', '}', () { + indent.writeln('stream->WriteByte(${customClass.enumeration});'); + indent.writeln( + 'WriteValue(std::any_cast<${customClass.name}>(*custom_value).ToEncodableMap(), stream);'); + indent.writeln('return;'); + }); + } }); - } + indent.writeln('$_defaultCodecSerializer::WriteValue(value, stream);'); + }); } void _writeErrorOr(Indent indent, @@ -245,7 +245,7 @@ void _writeDataClassDeclaration(Indent indent, Class klass, Root root, // TODO(gaaclarke): Find a way to be more precise with our // friendships. indent.writeln('friend class ${api.name};'); - indent.writeln('friend class ${_getCodecName(api)};'); + indent.writeln('friend class ${_getCodecSerializerName(api)};'); } if (testFriend != null) { indent.writeln('friend class $testFriend;'); @@ -484,11 +484,13 @@ void _writeHostApiHeader(Indent indent, Api api, Root root) { void _writeHostApiSource(Indent indent, Api api, Root root) { assert(api.location == ApiLocation.host); - final String codecName = _getCodecName(api); + final String codeSerializerName = getCodecClasses(api, root).isNotEmpty + ? _getCodecSerializerName(api) + : _defaultCodecSerializer; indent.format(''' /// The codec used by ${api.name}. const flutter::StandardMessageCodec& ${api.name}::GetCodec() { -\treturn flutter::StandardMessageCodec::GetInstance(&$codecName::GetInstance()); +\treturn flutter::StandardMessageCodec::GetInstance(&$codeSerializerName::GetInstance()); } '''); indent.writeln( @@ -740,7 +742,7 @@ void _writeFlutterApiHeader(Indent indent, Api api) { }, nestCount: 0); } -void _writeFlutterApiSource(Indent indent, Api api) { +void _writeFlutterApiSource(Indent indent, Api api, Root root) { assert(api.location == ApiLocation.flutter); indent.writeln( '$_commentPrefix Generated class from Pigeon that represents Flutter messages that can be called from C++.'); @@ -750,10 +752,12 @@ void _writeFlutterApiSource(Indent indent, Api api) { indent.writeln('this->binary_messenger_ = binary_messenger;'); }); indent.writeln(''); - final String codecName = _getCodecName(api); + final String codeSerializerName = getCodecClasses(api, root).isNotEmpty + ? _getCodecSerializerName(api) + : _defaultCodecSerializer; indent.format(''' const flutter::StandardMessageCodec& ${api.name}::GetCodec() { -\treturn flutter::StandardMessageCodec::GetInstance(&$codecName::GetInstance()); +\treturn flutter::StandardMessageCodec::GetInstance(&$codeSerializerName::GetInstance()); } '''); for (final Method func in api.methods) { @@ -1081,7 +1085,9 @@ void generateCppHeader( } for (final Api api in root.apis) { - _writeCodecHeader(indent, api, root); + if (getCodecClasses(api, root).isNotEmpty) { + _writeCodecHeader(indent, api, root); + } indent.addln(''); if (api.location == ApiLocation.host) { _writeHostApiHeader(indent, api, root); @@ -1135,8 +1141,10 @@ void generateCppSource(CppOptions options, Root root, StringSink sink) { } for (final Api api in root.apis) { - _writeCodecSource(indent, api, root); - indent.addln(''); + if (getCodecClasses(api, root).isNotEmpty) { + _writeCodecSource(indent, api, root); + indent.addln(''); + } if (api.location == ApiLocation.host) { _writeHostApiSource(indent, api, root); @@ -1158,7 +1166,7 @@ flutter::EncodableMap ${api.name}::WrapError(const FlutterError& error) { }'''); indent.addln(''); } else if (api.location == ApiLocation.flutter) { - _writeFlutterApiSource(indent, api); + _writeFlutterApiSource(indent, api, root); } } diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index 4b2ff9dbe2..70da7caed1 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -18,6 +18,9 @@ const String _docCommentPrefix = '///'; const DocumentCommentSpecification _docCommentSpec = DocumentCommentSpecification(_docCommentPrefix); +/// The standard codec for Flutter, used for any non custom codecs and extended for custom codecs. +const String _standardMessageCodec = 'StandardMessageCodec'; + /// Options that control how Dart code will be generated. class DartOptions { /// Constructor for DartOptions. @@ -67,44 +70,43 @@ String _getCodecName(Api api) => '_${api.name}Codec'; /// /// class FooCodec extends StandardMessageCodec {...} void _writeCodec(Indent indent, String codecName, Api api, Root root) { - indent.write('class $codecName extends StandardMessageCodec '); + assert(getCodecClasses(api, root).isNotEmpty); + final Iterable codecClasses = getCodecClasses(api, root); + indent.write('class $codecName extends $_standardMessageCodec'); indent.scoped('{', '}', () { indent.writeln('const $codecName();'); - if (getCodecClasses(api, root).isNotEmpty) { - indent.writeln('@override'); - indent.write('void writeValue(WriteBuffer buffer, Object? value) '); + indent.writeln('@override'); + indent.write('void writeValue(WriteBuffer buffer, Object? value) '); + indent.scoped('{', '}', () { + for (final EnumeratedClass customClass in codecClasses) { + indent.write('if (value is ${customClass.name}) '); + indent.scoped('{', '} else ', () { + indent.writeln('buffer.putUint8(${customClass.enumeration});'); + indent.writeln('writeValue(buffer, value.encode());'); + }); + } indent.scoped('{', '}', () { - for (final EnumeratedClass customClass in getCodecClasses(api, root)) { - indent.write('if (value is ${customClass.name}) '); - indent.scoped('{', '} else ', () { - indent.writeln('buffer.putUint8(${customClass.enumeration});'); - indent.writeln('writeValue(buffer, value.encode());'); + indent.writeln('super.writeValue(buffer, value);'); + }); + }); + indent.writeln('@override'); + indent.write('Object? readValueOfType(int type, ReadBuffer buffer) '); + indent.scoped('{', '}', () { + indent.write('switch (type) '); + indent.scoped('{', '}', () { + for (final EnumeratedClass customClass in codecClasses) { + indent.write('case ${customClass.enumeration}: '); + indent.writeScoped('', '', () { + indent.writeln( + 'return ${customClass.name}.decode(readValue(buffer)!);'); }); } - indent.scoped('{', '}', () { - indent.writeln('super.writeValue(buffer, value);'); + indent.write('default:'); + indent.writeScoped('', '', () { + indent.writeln('return super.readValueOfType(type, buffer);'); }); }); - indent.writeln('@override'); - indent.write('Object? readValueOfType(int type, ReadBuffer buffer) '); - indent.scoped('{', '}', () { - indent.write('switch (type) '); - indent.scoped('{', '}', () { - for (final EnumeratedClass customClass - in getCodecClasses(api, root)) { - indent.write('case ${customClass.enumeration}: '); - indent.writeScoped('', '', () { - indent.writeln( - 'return ${customClass.name}.decode(readValue(buffer)!);'); - }); - } - indent.write('default:'); - indent.writeScoped('', '', () { - indent.writeln('return super.readValueOfType(type, buffer);'); - }); - }); - }); - } + }); }); } @@ -157,8 +159,11 @@ String _getMethodArgumentsSignature( /// } void _writeHostApi(DartOptions opt, Indent indent, Api api, Root root) { assert(api.location == ApiLocation.host); - final String codecName = _getCodecName(api); - _writeCodec(indent, codecName, api, root); + String codecName = _standardMessageCodec; + if (getCodecClasses(api, root).isNotEmpty) { + codecName = _getCodecName(api); + _writeCodec(indent, codecName, api, root); + } indent.addln(''); bool first = true; addDocumentationComments(indent, api.documentationComments, _docCommentSpec); @@ -169,7 +174,6 @@ void _writeHostApi(DartOptions opt, Indent indent, Api api, Root root) { /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. ${api.name}({BinaryMessenger? binaryMessenger}) : _binaryMessenger = binaryMessenger; - final BinaryMessenger? _binaryMessenger; '''); @@ -272,8 +276,11 @@ void _writeFlutterApi( bool isMockHandler = false, }) { assert(api.location == ApiLocation.flutter); - final String codecName = _getCodecName(api); - _writeCodec(indent, codecName, api, root); + String codecName = _standardMessageCodec; + if (getCodecClasses(api, root).isNotEmpty) { + codecName = _getCodecName(api); + _writeCodec(indent, codecName, api, root); + } addDocumentationComments(indent, api.documentationComments, _docCommentSpec); indent.write('abstract class ${api.name} '); diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index 2d8afea827..e23dc626e8 100644 --- a/packages/pigeon/lib/generator_tools.dart +++ b/packages/pigeon/lib/generator_tools.dart @@ -9,7 +9,7 @@ import 'dart:mirrors'; import 'ast.dart'; /// The current version of pigeon. This must match the version in pubspec.yaml. -const String pigeonVersion = '4.2.1'; +const String pigeonVersion = '4.2.2'; /// Read all the content from [stdin] to a String. String readStdin() { diff --git a/packages/pigeon/lib/java_generator.dart b/packages/pigeon/lib/java_generator.dart index d0f65bd087..0734569c07 100644 --- a/packages/pigeon/lib/java_generator.dart +++ b/packages/pigeon/lib/java_generator.dart @@ -24,6 +24,9 @@ const DocumentCommentSpecification _docCommentSpec = blockContinuationToken: _docCommentContinuation, ); +/// The standard codec for Flutter, used for any non custom codecs and extended for custom codecs. +const String _standardMessageCodec = 'StandardMessageCodec'; + /// Options that control how Java code will be generated. class JavaOptions { /// Creates a [JavaOptions] object @@ -93,50 +96,50 @@ String _intToEnum(String expression, String enumName) => /// Example: /// private static class FooCodec extends StandardMessageCodec {...} void _writeCodec(Indent indent, Api api, Root root) { + assert(getCodecClasses(api, root).isNotEmpty); + final Iterable codecClasses = getCodecClasses(api, root); final String codecName = _getCodecName(api); - indent.write('private static class $codecName extends StandardMessageCodec '); + indent + .write('private static class $codecName extends $_standardMessageCodec '); indent.scoped('{', '}', () { indent .writeln('public static final $codecName INSTANCE = new $codecName();'); indent.writeln('private $codecName() {}'); - if (getCodecClasses(api, root).isNotEmpty) { - indent.writeln('@Override'); - indent.write( - 'protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) '); + indent.writeln('@Override'); + indent.write( + 'protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) '); + indent.scoped('{', '}', () { + indent.write('switch (type) '); indent.scoped('{', '}', () { - indent.write('switch (type) '); - indent.scoped('{', '}', () { - for (final EnumeratedClass customClass - in getCodecClasses(api, root)) { - indent.write('case (byte)${customClass.enumeration}: '); - indent.writeScoped('', '', () { - indent.writeln( - 'return ${customClass.name}.fromMap((Map) readValue(buffer));'); - }); - } - indent.write('default:'); + for (final EnumeratedClass customClass in codecClasses) { + indent.write('case (byte)${customClass.enumeration}: '); indent.writeScoped('', '', () { - indent.writeln('return super.readValueOfType(type, buffer);'); - }); - }); - }); - indent.writeln('@Override'); - indent.write( - 'protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) '); - indent.writeScoped('{', '}', () { - for (final EnumeratedClass customClass in getCodecClasses(api, root)) { - indent.write('if (value instanceof ${customClass.name}) '); - indent.scoped('{', '} else ', () { - indent.writeln('stream.write(${customClass.enumeration});'); indent.writeln( - 'writeValue(stream, ((${customClass.name}) value).toMap());'); + 'return ${customClass.name}.fromMap((Map) readValue(buffer));'); }); } - indent.scoped('{', '}', () { - indent.writeln('super.writeValue(stream, value);'); + indent.write('default:'); + indent.writeScoped('', '', () { + indent.writeln('return super.readValueOfType(type, buffer);'); }); }); - } + }); + indent.writeln('@Override'); + indent.write( + 'protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) '); + indent.writeScoped('{', '}', () { + for (final EnumeratedClass customClass in codecClasses) { + indent.write('if (value instanceof ${customClass.name}) '); + indent.scoped('{', '} else ', () { + indent.writeln('stream.write(${customClass.enumeration});'); + indent.writeln( + 'writeValue(stream, ((${customClass.name}) value).toMap());'); + }); + } + indent.scoped('{', '}', () { + indent.writeln('super.writeValue(stream, value);'); + }); + }); }); } @@ -309,12 +312,17 @@ Result<$returnType> $resultName = new Result<$returnType>() { api.methods.forEach(writeInterfaceMethod); indent.addln(''); final String codecName = _getCodecName(api); - indent.format(''' -/** The codec used by ${api.name}. */ -static MessageCodec getCodec() { -\treturn $codecName.INSTANCE; -} -'''); + indent.writeln('/** The codec used by ${api.name}. */'); + indent.write('static MessageCodec getCodec() '); + indent.scoped('{', '}', () { + indent.write('return '); + if (getCodecClasses(api, root).isNotEmpty) { + indent.write('$codecName.INSTANCE;'); + } else { + indent.write('new $_standardMessageCodec();'); + } + }); + indent.writeln( '${_docCommentPrefix}Sets up an instance of `${api.name}` to handle messages through the `binaryMessenger`.$_docCommentSuffix'); indent.write( @@ -341,7 +349,7 @@ String _getSafeArgumentName(int count, NamedType argument) => /// } /// public int add(int x, int y, Reply callback) {...} /// } -void _writeFlutterApi(Indent indent, Api api) { +void _writeFlutterApi(Indent indent, Api api, Root root) { assert(api.location == ApiLocation.flutter); const List generatedMessages = [ ' Generated class from Pigeon that represents Flutter messages that can be called from Java.' @@ -361,11 +369,17 @@ void _writeFlutterApi(Indent indent, Api api) { indent.writeln('void reply(T reply);'); }); final String codecName = _getCodecName(api); - indent.format(''' -static MessageCodec getCodec() { -\treturn $codecName.INSTANCE; -} -'''); + indent.writeln('/** The codec used by ${api.name}. */'); + indent.write('static MessageCodec getCodec() '); + indent.scoped('{', '}', () { + indent.write('return '); + if (getCodecClasses(api, root).isNotEmpty) { + indent.writeln('$codecName.INSTANCE;'); + } else { + indent.writeln('new $_standardMessageCodec();'); + } + }); + for (final Method func in api.methods) { final String channelName = makeChannelName(api, func); final String returnType = func.returnType.isVoid @@ -715,7 +729,7 @@ void generateJava(JavaOptions options, Root root, StringSink sink) { if (api.location == ApiLocation.host) { _writeHostApi(indent, api, root); } else if (api.location == ApiLocation.flutter) { - _writeFlutterApi(indent, api); + _writeFlutterApi(indent, api, root); } } @@ -765,8 +779,10 @@ void generateJava(JavaOptions options, Root root, StringSink sink) { } for (final Api api in root.apis) { - _writeCodec(indent, api, root); - indent.addln(''); + if (getCodecClasses(api, root).isNotEmpty) { + _writeCodec(indent, api, root); + indent.addln(''); + } writeApi(api); } diff --git a/packages/pigeon/lib/kotlin_generator.dart b/packages/pigeon/lib/kotlin_generator.dart index a940d4011a..d049f860b4 100644 --- a/packages/pigeon/lib/kotlin_generator.dart +++ b/packages/pigeon/lib/kotlin_generator.dart @@ -71,48 +71,46 @@ String _getCodecName(Api api) => '${api.name}Codec'; /// Example: /// private static class FooCodec extends StandardMessageCodec {...} void _writeCodec(Indent indent, Api api, Root root) { + assert(getCodecClasses(api, root).isNotEmpty); + final Iterable codecClasses = getCodecClasses(api, root); final String codecName = _getCodecName(api); indent.writeln('@Suppress("UNCHECKED_CAST")'); indent.write('private object $codecName : StandardMessageCodec() '); indent.scoped('{', '}', () { - if (getCodecClasses(api, root).isNotEmpty) { - indent.write( - 'override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? '); + indent.write( + 'override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? '); + indent.scoped('{', '}', () { + indent.write('return when (type) '); indent.scoped('{', '}', () { - indent.write('return when (type) '); - indent.scoped('{', '}', () { - for (final EnumeratedClass customClass - in getCodecClasses(api, root)) { - indent.write('${customClass.enumeration}.toByte() -> '); + for (final EnumeratedClass customClass in codecClasses) { + indent.write('${customClass.enumeration}.toByte() -> '); + indent.scoped('{', '}', () { + indent.write( + 'return (readValue(buffer) as? Map)?.let '); indent.scoped('{', '}', () { - indent.write( - 'return (readValue(buffer) as? Map)?.let '); - indent.scoped('{', '}', () { - indent.writeln('${customClass.name}.fromMap(it)'); - }); + indent.writeln('${customClass.name}.fromMap(it)'); }); - } - indent.writeln('else -> super.readValueOfType(type, buffer)'); - }); + }); + } + indent.writeln('else -> super.readValueOfType(type, buffer)'); }); + }); - indent.write( - 'override fun writeValue(stream: ByteArrayOutputStream, value: Any?) '); - indent.writeScoped('{', '}', () { - indent.write('when (value) '); - indent.scoped('{', '}', () { - for (final EnumeratedClass customClass - in getCodecClasses(api, root)) { - indent.write('is ${customClass.name} -> '); - indent.scoped('{', '}', () { - indent.writeln('stream.write(${customClass.enumeration})'); - indent.writeln('writeValue(stream, value.toMap())'); - }); - } - indent.writeln('else -> super.writeValue(stream, value)'); - }); + indent.write( + 'override fun writeValue(stream: ByteArrayOutputStream, value: Any?) '); + indent.writeScoped('{', '}', () { + indent.write('when (value) '); + indent.scoped('{', '}', () { + for (final EnumeratedClass customClass in codecClasses) { + indent.write('is ${customClass.name} -> '); + indent.scoped('{', '}', () { + indent.writeln('stream.write(${customClass.enumeration})'); + indent.writeln('writeValue(stream, value.toMap())'); + }); + } + indent.writeln('else -> super.writeValue(stream, value)'); }); - } + }); }); } @@ -129,6 +127,8 @@ void _writeHostApi(Indent indent, Api api, Root root) { final String apiName = api.name; + final bool isCustomCodec = getCodecClasses(api, root).isNotEmpty; + const List generatedMessages = [ ' Generated interface from Pigeon that represents a handler of messages from Flutter.' ]; @@ -172,8 +172,13 @@ void _writeHostApi(Indent indent, Api api, Root root) { indent.write('companion object '); indent.scoped('{', '}', () { indent.writeln('/** The codec used by $apiName. */'); - indent.scoped('val codec: MessageCodec by lazy {', '}', () { - indent.writeln(_getCodecName(api)); + indent.write('val codec: MessageCodec by lazy '); + indent.scoped('{', '}', () { + if (isCustomCodec) { + indent.writeln(_getCodecName(api)); + } else { + indent.writeln('StandardMessageCodec()'); + } }); indent.writeln( '/** Sets up an instance of `$apiName` to handle messages through the `binaryMessenger`. */'); @@ -182,8 +187,8 @@ void _writeHostApi(Indent indent, Api api, Root root) { 'fun setUp(binaryMessenger: BinaryMessenger, api: $apiName?) '); indent.scoped('{', '}', () { for (final Method method in api.methods) { - indent.write(''); - indent.scoped('run {', '}', () { + indent.write('run '); + indent.scoped('{', '}', () { String? taskQueue; if (method.taskQueueType != TaskQueueType.serial) { taskQueue = 'taskQueue'; @@ -245,7 +250,7 @@ void _writeHostApi(Indent indent, Api api, Root root) { } }, addTrailingNewline: false); indent.add(' catch (exception: Error) '); - indent.scoped('{', '}', () { + indent.scoped('{', '', () { indent.writeln( 'wrapped["${Keys.error}"] = wrapError(exception)'); if (method.isAsynchronous) { @@ -257,7 +262,7 @@ void _writeHostApi(Indent indent, Api api, Root root) { } }); }, addTrailingNewline: false); - indent.scoped(' else {', '}', () { + indent.scoped('} else {', '}', () { indent.writeln('channel.setMessageHandler(null)'); }); }); @@ -279,8 +284,10 @@ String _getSafeArgumentName(int count, NamedType argument) => /// class Foo(private val binaryMessenger: BinaryMessenger) { /// fun add(x: Int, y: Int, callback: (Int?) -> Unit) {...} /// } -void _writeFlutterApi(Indent indent, Api api) { +void _writeFlutterApi(Indent indent, Api api, Root root) { assert(api.location == ApiLocation.flutter); + final bool isCustomCodec = getCodecClasses(api, root).isNotEmpty; + const List generatedMessages = [ ' Generated class from Pigeon that represents Flutter messages that can be called from Kotlin.' ]; @@ -296,7 +303,11 @@ void _writeFlutterApi(Indent indent, Api api) { indent.writeln('/** The codec used by $apiName. */'); indent.write('val codec: MessageCodec by lazy '); indent.scoped('{', '}', () { - indent.writeln(_getCodecName(api)); + if (isCustomCodec) { + indent.writeln(_getCodecName(api)); + } else { + indent.writeln('StandardMessageCodec()'); + } }); }); @@ -610,12 +621,14 @@ void generateKotlin(KotlinOptions options, Root root, StringSink sink) { indent, klass.documentationComments, _docCommentSpec, generatorComments: generatedMessages); - indent.write('data class ${klass.name}('); - indent.scoped('', '', () { + indent.write('data class ${klass.name} '); + indent.scoped('(', '', () { for (final NamedType element in klass.fields) { writeField(element); if (klass.fields.last != element) { indent.addln(','); + } else { + indent.addln(''); } } }); @@ -630,7 +643,7 @@ void generateKotlin(KotlinOptions options, Root root, StringSink sink) { if (api.location == ApiLocation.host) { _writeHostApi(indent, api, root); } else if (api.location == ApiLocation.flutter) { - _writeFlutterApi(indent, api); + _writeFlutterApi(indent, api, root); } } @@ -685,8 +698,10 @@ void generateKotlin(KotlinOptions options, Root root, StringSink sink) { } for (final Api api in root.apis) { - _writeCodec(indent, api, root); - indent.addln(''); + if (getCodecClasses(api, root).isNotEmpty) { + _writeCodec(indent, api, root); + indent.addln(''); + } writeApi(api); } diff --git a/packages/pigeon/lib/objc_generator.dart b/packages/pigeon/lib/objc_generator.dart index af8edd4c53..bc6077add9 100644 --- a/packages/pigeon/lib/objc_generator.dart +++ b/packages/pigeon/lib/objc_generator.dart @@ -265,52 +265,50 @@ String _getCodecGetterName(String? prefix, String className) => /// NSObject *FooHostApiCodecGetCodec() {...} void _writeCodec( Indent indent, String name, ObjcOptions options, Api api, Root root) { + assert(getCodecClasses(api, root).isNotEmpty); + final Iterable codecClasses = getCodecClasses(api, root); final String readerWriterName = '${name}ReaderWriter'; final String readerName = '${name}Reader'; final String writerName = '${name}Writer'; indent.writeln('@interface $readerName : FlutterStandardReader'); indent.writeln('@end'); indent.writeln('@implementation $readerName'); - if (getCodecClasses(api, root).isNotEmpty) { - indent.writeln('- (nullable id)readValueOfType:(UInt8)type '); + indent.writeln('- (nullable id)readValueOfType:(UInt8)type '); + indent.scoped('{', '}', () { + indent.write('switch (type) '); indent.scoped('{', '}', () { - indent.write('switch (type) '); - indent.scoped('{', '}', () { - for (final EnumeratedClass customClass in getCodecClasses(api, root)) { - indent.write('case ${customClass.enumeration}: '); - indent.writeScoped('', '', () { - indent.writeln( - 'return [${_className(options.prefix, customClass.name)} fromMap:[self readValue]];'); - }); - } - indent.write('default:'); + for (final EnumeratedClass customClass in codecClasses) { + indent.write('case ${customClass.enumeration}: '); indent.writeScoped('', '', () { - indent.writeln('return [super readValueOfType:type];'); + indent.writeln( + 'return [${_className(options.prefix, customClass.name)} fromMap:[self readValue]];'); }); + } + indent.write('default:'); + indent.writeScoped('', '', () { + indent.writeln('return [super readValueOfType:type];'); }); }); - } + }); indent.writeln('@end'); indent.addln(''); indent.writeln('@interface $writerName : FlutterStandardWriter'); indent.writeln('@end'); indent.writeln('@implementation $writerName'); - if (getCodecClasses(api, root).isNotEmpty) { - indent.writeln('- (void)writeValue:(id)value '); - indent.scoped('{', '}', () { - for (final EnumeratedClass customClass in getCodecClasses(api, root)) { - indent.write( - 'if ([value isKindOfClass:[${_className(options.prefix, customClass.name)} class]]) '); - indent.scoped('{', '} else ', () { - indent.writeln('[self writeByte:${customClass.enumeration}];'); - indent.writeln('[self writeValue:[value toMap]];'); - }); - } - indent.scoped('{', '}', () { - indent.writeln('[super writeValue:value];'); + indent.writeln('- (void)writeValue:(id)value '); + indent.scoped('{', '}', () { + for (final EnumeratedClass customClass in codecClasses) { + indent.write( + 'if ([value isKindOfClass:[${_className(options.prefix, customClass.name)} class]]) '); + indent.scoped('{', '} else ', () { + indent.writeln('[self writeByte:${customClass.enumeration}];'); + indent.writeln('[self writeValue:[value toMap]];'); }); + } + indent.scoped('{', '}', () { + indent.writeln('[super writeValue:value];'); }); - } + }); indent.writeln('@end'); indent.addln(''); indent.format(''' @@ -324,19 +322,35 @@ void _writeCodec( \treturn [[$readerName alloc] initWithData:data]; } @end - -NSObject *${_getCodecGetterName(options.prefix, api.name)}() { -\tstatic dispatch_once_t sPred = 0; -\tstatic FlutterStandardMessageCodec *sSharedObject = nil; -\tdispatch_once(&sPred, ^{ -\t\t$readerWriterName *readerWriter = [[$readerWriterName alloc] init]; -\t\tsSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; -\t}); -\treturn sSharedObject; -} '''); } +void _writeCodecGetter( + Indent indent, String name, ObjcOptions options, Api api, Root root) { + final String readerWriterName = '${name}ReaderWriter'; + + indent.write( + 'NSObject *${_getCodecGetterName(options.prefix, api.name)}() '); + indent.scoped('{', '}', () { + indent.writeln('static FlutterStandardMessageCodec *sSharedObject = nil;'); + if (getCodecClasses(api, root).isNotEmpty) { + indent.writeln('static dispatch_once_t sPred = 0;'); + indent.write('dispatch_once(&sPred, ^'); + indent.scoped('{', '});', () { + indent.writeln( + '$readerWriterName *readerWriter = [[$readerWriterName alloc] init];'); + indent.writeln( + 'sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter];'); + }); + } else { + indent.writeln( + 'sSharedObject = [FlutterStandardMessageCodec sharedInstance];'); + } + + indent.writeln('return sSharedObject;'); + }); +} + String _capitalize(String str) => (str.isEmpty) ? '' : str[0].toUpperCase() + str.substring(1); @@ -454,14 +468,15 @@ void _writeHostApiDeclaration( lastArgType = 'FlutterError *_Nullable *_Nonnull'; lastArgName = 'error'; } + final List generatorComments = []; if (!func.returnType.isNullable && !func.returnType.isVoid && !func.isAsynchronous) { - indent.writeln( - '$_docCommentPrefix @return `nil` only when `error != nil`.'); + generatorComments.add(' @return `nil` only when `error != nil`.'); } addDocumentationComments( - indent, func.documentationComments, _docCommentSpec); + indent, func.documentationComments, _docCommentSpec, + generatorComments: generatorComments); final String signature = _makeObjcSignature( func: func, @@ -579,7 +594,7 @@ void generateObjcHeader(ObjcOptions options, Root root, StringSink sink) { for (final Api api in root.apis) { indent.writeln( - '${_docCommentPrefix}The codec used by ${_className(options.prefix, api.name)}.'); + '$_docCommentPrefix The codec used by ${_className(options.prefix, api.name)}.'); indent.writeln( 'NSObject *${_getCodecGetterName(options.prefix, api.name)}(void);'); indent.addln(''); @@ -638,12 +653,14 @@ void _writeHostApiSource( indent.inc(); indent.writeln('initWithName:@"${makeChannelName(api, func)}"'); indent.writeln('binaryMessenger:binaryMessenger'); - indent.write('codec:${_getCodecGetterName(options.prefix, api.name)}()'); + indent.write('codec:'); + indent.add('${_getCodecGetterName(options.prefix, api.name)}()'); + if (taskQueue != null) { indent.addln(''); - indent.writeln('taskQueue:$taskQueue];'); + indent.addln('taskQueue:$taskQueue];'); } else { - indent.writeln('];'); + indent.addln('];'); } indent.dec(); indent.dec(); @@ -831,8 +848,8 @@ void _writeFlutterApiSource( indent.inc(); indent.writeln('messageChannelWithName:@"${makeChannelName(api, func)}"'); indent.writeln('binaryMessenger:self.binaryMessenger'); - indent.writeln( - 'codec:${_getCodecGetterName(options.prefix, api.name)}()];'); + indent.write('codec:${_getCodecGetterName(options.prefix, api.name)}()'); + indent.write('];'); indent.dec(); indent.dec(); indent.write('[channel sendMessage:$sendArgument reply:^(id reply) '); @@ -982,7 +999,11 @@ static id GetNullableObjectAtIndex(NSArray* array, NSInteger key) { void writeApi(Api api) { final String codecName = _getCodecName(options.prefix, api.name); - _writeCodec(indent, codecName, options, api, root); + if (getCodecClasses(api, root).isNotEmpty) { + _writeCodec(indent, codecName, options, api, root); + indent.addln(''); + } + _writeCodecGetter(indent, codecName, options, api, root); indent.addln(''); if (api.location == ApiLocation.host) { _writeHostApiSource(indent, options, api, root); diff --git a/packages/pigeon/lib/swift_generator.dart b/packages/pigeon/lib/swift_generator.dart index 7719b055d6..758199d77b 100644 --- a/packages/pigeon/lib/swift_generator.dart +++ b/packages/pigeon/lib/swift_generator.dart @@ -56,6 +56,7 @@ String _getCodecName(Api api) => '${api.name}Codec'; /// private class FooHostApiCodecWriter: FlutterStandardWriter {...} /// private class FooHostApiCodecReaderWriter: FlutterStandardReaderWriter {...} void _writeCodec(Indent indent, Api api, Root root) { + assert(getCodecClasses(api, root).isNotEmpty); final String codecName = _getCodecName(api); final String readerWriterName = '${codecName}ReaderWriter'; final String readerName = '${codecName}Reader'; @@ -189,8 +190,12 @@ void _writeHostApi(Indent indent, Api api, Root root) { indent.scoped('{', '}', () { final String codecName = _getCodecName(api); indent.writeln('$_docCommentPrefix The codec used by $apiName.'); - indent.writeln( - 'static var codec: FlutterStandardMessageCodec { $codecName.shared }'); + String codecArgumentString = ''; + if (getCodecClasses(api, root).isNotEmpty) { + codecArgumentString = ', codec: codec'; + indent.writeln( + 'static var codec: FlutterStandardMessageCodec { $codecName.shared }'); + } indent.writeln( '$_docCommentPrefix Sets up an instance of `$apiName` to handle messages through the `binaryMessenger`.'); indent.write( @@ -203,7 +208,7 @@ void _writeHostApi(Indent indent, Api api, Root root) { indent, method.documentationComments, _docCommentSpec); indent.writeln( - 'let $varChannelName = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger, codec: codec)'); + 'let $varChannelName = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger$codecArgumentString)'); indent.write('if let api = api '); indent.scoped('{', '}', () { indent.write('$varChannelName.setMessageHandler '); @@ -290,10 +295,14 @@ void _writeFlutterApi(Indent indent, Api api, Root root) { indent.writeln('self.binaryMessenger = binaryMessenger'); }); final String codecName = _getCodecName(api); - indent.write('var codec: FlutterStandardMessageCodec '); - indent.scoped('{', '}', () { - indent.writeln('return $codecName.shared'); - }); + String codecArgumentString = ''; + if (getCodecClasses(api, root).isNotEmpty) { + codecArgumentString = ', codec: codec'; + indent.write('var codec: FlutterStandardMessageCodec '); + indent.scoped('{', '}', () { + indent.writeln('return $codecName.shared'); + }); + } for (final Method func in api.methods) { final String channelName = makeChannelName(api, func); final String returnType = func.returnType.isVoid @@ -332,7 +341,7 @@ void _writeFlutterApi(Indent indent, Api api, Root root) { indent.scoped('{', '}', () { const String channel = 'channel'; indent.writeln( - 'let $channel = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger, codec: codec)'); + 'let $channel = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger$codecArgumentString)'); indent.write('$channel.sendMessage($sendArgument) '); if (func.returnType.isVoid) { indent.scoped('{ _ in', '}', () { @@ -641,8 +650,10 @@ import FlutterMacOS } for (final Api api in root.apis) { - _writeCodec(indent, api, root); - indent.addln(''); + if (getCodecClasses(api, root).isNotEmpty) { + _writeCodec(indent, api, root); + indent.addln(''); + } writeApi(api, root); } diff --git a/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/MultipleArityTests.swift b/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/MultipleArityTests.swift index f70f0e9913..23f3e34cc5 100644 --- a/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/MultipleArityTests.swift +++ b/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/MultipleArityTests.swift @@ -1,7 +1,6 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - import XCTest @testable import Runner @@ -12,7 +11,7 @@ class MockMultipleArityHostApi: MultipleArityHostApi { } class MultipleArityTests: XCTestCase { - + var codec = FlutterStandardMessageCodec.sharedInstance() func testSimpleHost() throws { let binaryMessenger = MockBinaryMessenger(codec: EnumApi2HostCodec.shared) MultipleArityHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockMultipleArityHostApi()) @@ -37,7 +36,7 @@ class MultipleArityTests: XCTestCase { } func testSimpleFlutter() throws { - let binaryMessenger = HandlerBinaryMessenger(codec: MultipleArityHostApiCodec.shared) { args in + let binaryMessenger = HandlerBinaryMessenger(codec: codec) { args in return (args[0] as! Int) - (args[1] as! Int) } let api = MultipleArityFlutterApi(binaryMessenger: binaryMessenger) diff --git a/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/NullableReturnsTests.swift b/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/NullableReturnsTests.swift index 7d8acf5eb9..b80c891254 100644 --- a/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/NullableReturnsTests.swift +++ b/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/NullableReturnsTests.swift @@ -1,7 +1,6 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - import XCTest @testable import Runner @@ -17,8 +16,9 @@ class MockNullableArgHostApi: NullableArgHostApi { } class NullableReturnsTests: XCTestCase { + var codec = FlutterStandardMessageCodec.sharedInstance() func testNullableParameterWithFlutterApi() { - let binaryMessenger = EchoBinaryMessenger(codec: NullableArgFlutterApiCodec.shared) + let binaryMessenger = EchoBinaryMessenger(codec: codec) binaryMessenger.defaultReturn = 99 let api = NullableArgFlutterApi(binaryMessenger: binaryMessenger) @@ -32,7 +32,7 @@ class NullableReturnsTests: XCTestCase { func testNullableParameterWithHostApi() { let api = MockNullableArgHostApi() - let binaryMessenger = MockBinaryMessenger(codec: NullableArgHostApiCodec.shared) + let binaryMessenger = MockBinaryMessenger(codec: codec) let channel = "dev.flutter.pigeon.NullableArgHostApi.doit" NullableArgHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: api) diff --git a/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/PrimitiveTests.swift b/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/PrimitiveTests.swift index f9c6b5f1a4..d825b0052e 100644 --- a/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/PrimitiveTests.swift +++ b/packages/pigeon/platform_tests/ios_swift_unit_tests/ios/RunnerTests/PrimitiveTests.swift @@ -1,7 +1,6 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - import XCTest @testable import Runner @@ -18,9 +17,10 @@ class MockPrimitiveHostApi: PrimitiveHostApi { } class PrimitiveTests: XCTestCase { + var codec = FlutterStandardMessageCodec.sharedInstance() func testIntPrimitiveHost() throws { - let binaryMessenger = MockBinaryMessenger(codec: PrimitiveHostApiCodec.shared) + let binaryMessenger = MockBinaryMessenger(codec: codec) PrimitiveHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockPrimitiveHostApi()) let channelName = "dev.flutter.pigeon.PrimitiveHostApi.anInt" XCTAssertNotNil(binaryMessenger.handlers[channelName]) @@ -42,7 +42,7 @@ class PrimitiveTests: XCTestCase { } func testIntPrimitiveFlutter() throws { - let binaryMessenger = EchoBinaryMessenger(codec: PrimitiveHostApiCodec.shared) + let binaryMessenger = EchoBinaryMessenger(codec: codec) let api = PrimitiveFlutterApi(binaryMessenger: binaryMessenger) let expectation = XCTestExpectation(description: "callback") @@ -54,7 +54,7 @@ class PrimitiveTests: XCTestCase { } func testBoolPrimitiveHost() throws { - let binaryMessenger = MockBinaryMessenger(codec: PrimitiveHostApiCodec.shared) + let binaryMessenger = MockBinaryMessenger(codec: codec) PrimitiveHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockPrimitiveHostApi()) let channelName = "dev.flutter.pigeon.PrimitiveHostApi.aBool" XCTAssertNotNil(binaryMessenger.handlers[channelName]) @@ -76,7 +76,7 @@ class PrimitiveTests: XCTestCase { } func testBoolPrimitiveFlutter() throws { - let binaryMessenger = EchoBinaryMessenger(codec: PrimitiveHostApiCodec.shared) + let binaryMessenger = EchoBinaryMessenger(codec: codec) let api = PrimitiveFlutterApi(binaryMessenger: binaryMessenger) let expectation = XCTestExpectation(description: "callback") @@ -88,7 +88,7 @@ class PrimitiveTests: XCTestCase { } func testDoublePrimitiveHost() throws { - let binaryMessenger = MockBinaryMessenger(codec: PrimitiveHostApiCodec.shared) + let binaryMessenger = MockBinaryMessenger(codec: codec) PrimitiveHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockPrimitiveHostApi()) let channelName = "dev.flutter.pigeon.PrimitiveHostApi.aDouble" XCTAssertNotNil(binaryMessenger.handlers[channelName]) @@ -110,7 +110,7 @@ class PrimitiveTests: XCTestCase { } func testDoublePrimitiveFlutter() throws { - let binaryMessenger = EchoBinaryMessenger(codec: PrimitiveHostApiCodec.shared) + let binaryMessenger = EchoBinaryMessenger(codec: codec) let api = PrimitiveFlutterApi(binaryMessenger: binaryMessenger) let expectation = XCTestExpectation(description: "callback") @@ -123,7 +123,7 @@ class PrimitiveTests: XCTestCase { } func testStringPrimitiveHost() throws { - let binaryMessenger = MockBinaryMessenger(codec: PrimitiveHostApiCodec.shared) + let binaryMessenger = MockBinaryMessenger(codec: codec) PrimitiveHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockPrimitiveHostApi()) let channelName = "dev.flutter.pigeon.PrimitiveHostApi.aString" XCTAssertNotNil(binaryMessenger.handlers[channelName]) @@ -145,7 +145,7 @@ class PrimitiveTests: XCTestCase { } func testStringPrimitiveFlutter() throws { - let binaryMessenger = EchoBinaryMessenger(codec: PrimitiveHostApiCodec.shared) + let binaryMessenger = EchoBinaryMessenger(codec: codec) let api = PrimitiveFlutterApi(binaryMessenger: binaryMessenger) let expectation = XCTestExpectation(description: "callback") @@ -158,7 +158,7 @@ class PrimitiveTests: XCTestCase { } func testListPrimitiveHost() throws { - let binaryMessenger = MockBinaryMessenger<[Int]>(codec: PrimitiveHostApiCodec.shared) + let binaryMessenger = MockBinaryMessenger<[Int]>(codec: codec) PrimitiveHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockPrimitiveHostApi()) let channelName = "dev.flutter.pigeon.PrimitiveHostApi.aList" XCTAssertNotNil(binaryMessenger.handlers[channelName]) @@ -180,7 +180,7 @@ class PrimitiveTests: XCTestCase { } func testListPrimitiveFlutter() throws { - let binaryMessenger = EchoBinaryMessenger(codec: PrimitiveHostApiCodec.shared) + let binaryMessenger = EchoBinaryMessenger(codec: codec) let api = PrimitiveFlutterApi(binaryMessenger: binaryMessenger) let expectation = XCTestExpectation(description: "callback") @@ -193,7 +193,7 @@ class PrimitiveTests: XCTestCase { } func testMapPrimitiveHost() throws { - let binaryMessenger = MockBinaryMessenger<[String: Int]>(codec: PrimitiveHostApiCodec.shared) + let binaryMessenger = MockBinaryMessenger<[String: Int]>(codec: codec) PrimitiveHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: MockPrimitiveHostApi()) let channelName = "dev.flutter.pigeon.PrimitiveHostApi.aMap" XCTAssertNotNil(binaryMessenger.handlers[channelName]) @@ -215,7 +215,7 @@ class PrimitiveTests: XCTestCase { } func testMapPrimitiveFlutter() throws { - let binaryMessenger = EchoBinaryMessenger(codec: PrimitiveHostApiCodec.shared) + let binaryMessenger = EchoBinaryMessenger(codec: codec) let api = PrimitiveFlutterApi(binaryMessenger: binaryMessenger) let expectation = XCTestExpectation(description: "callback") diff --git a/packages/pigeon/platform_tests/ios_unit_tests/ios/RunnerTests/NullableReturnsTest.m b/packages/pigeon/platform_tests/ios_unit_tests/ios/RunnerTests/NullableReturnsTest.m index a5eef4c673..3f47f707d1 100644 --- a/packages/pigeon/platform_tests/ios_unit_tests/ios/RunnerTests/NullableReturnsTest.m +++ b/packages/pigeon/platform_tests/ios_unit_tests/ios/RunnerTests/NullableReturnsTest.m @@ -33,7 +33,7 @@ - (void)testNullableParameterWithFlutterApi { EchoBinaryMessenger *binaryMessenger = - [[EchoBinaryMessenger alloc] initWithCodec:NRNullableArgFlutterApiGetCodec()]; + [[EchoBinaryMessenger alloc] initWithCodec:NRNullableArgHostApiGetCodec()]; NRNullableArgFlutterApi *api = [[NRNullableArgFlutterApi alloc] initWithBinaryMessenger:binaryMessenger]; XCTestExpectation *expectation = [self expectationWithDescription:@"callback"]; diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index cb524d59f0..84029e29c4 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -2,7 +2,7 @@ name: pigeon description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. repository: https://github.com/flutter/packages/tree/main/packages/pigeon issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3Apigeon -version: 4.2.1 # This must match the version in lib/generator_tools.dart +version: 4.2.2 # This must match the version in lib/generator_tools.dart environment: sdk: ">=2.12.0 <3.0.0" diff --git a/packages/pigeon/test/cpp_generator_test.dart b/packages/pigeon/test/cpp_generator_test.dart index 8b36e462bd..cdf3876df7 100644 --- a/packages/pigeon/test/cpp_generator_test.dart +++ b/packages/pigeon/test/cpp_generator_test.dart @@ -1122,4 +1122,78 @@ void main() { expect(code, contains('//$comment')); } }); + + test('doesnt create codecs if no custom datatypes', () { + final Root root = Root( + apis: [ + Api( + name: 'Api', + location: ApiLocation.flutter, + methods: [ + Method( + name: 'method', + returnType: const TypeDeclaration.voidDeclaration(), + arguments: [ + NamedType( + name: 'field', + type: const TypeDeclaration( + baseName: 'int', + isNullable: true, + ), + ), + ], + ) + ], + ) + ], + classes: [], + enums: [], + ); + final StringBuffer sink = StringBuffer(); + generateCppHeader('', const CppOptions(), root, sink); + final String code = sink.toString(); + expect(code, isNot(contains(' : public flutter::StandardCodecSerializer'))); + }); + + test('creates custom codecs if custom datatypes present', () { + final Root root = Root(apis: [ + Api(name: 'Api', location: ApiLocation.flutter, methods: [ + Method( + name: 'doSomething', + arguments: [ + NamedType( + type: const TypeDeclaration( + baseName: 'Input', + isNullable: false, + ), + name: '') + ], + returnType: + const TypeDeclaration(baseName: 'Output', isNullable: false), + isAsynchronous: true, + ) + ]) + ], classes: [ + Class(name: 'Input', fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'input') + ]), + Class(name: 'Output', fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'output') + ]) + ], enums: []); + final StringBuffer sink = StringBuffer(); + generateCppHeader('', const CppOptions(), root, sink); + final String code = sink.toString(); + expect(code, contains(' : public flutter::StandardCodecSerializer')); + }); } diff --git a/packages/pigeon/test/dart_generator_test.dart b/packages/pigeon/test/dart_generator_test.dart index cf467d29c8..582b29e1f0 100644 --- a/packages/pigeon/test/dart_generator_test.dart +++ b/packages/pigeon/test/dart_generator_test.dart @@ -1234,4 +1234,79 @@ name: foobar expect(code, contains('///$comment')); } }); + + test('doesnt create codecs if no custom datatypes', () { + final Root root = Root( + apis: [ + Api( + name: 'Api', + location: ApiLocation.flutter, + methods: [ + Method( + name: 'method', + returnType: const TypeDeclaration.voidDeclaration(), + arguments: [ + NamedType( + name: 'field', + type: const TypeDeclaration( + baseName: 'int', + isNullable: true, + ), + ), + ], + ) + ], + ) + ], + classes: [], + enums: [], + ); + final StringBuffer sink = StringBuffer(); + generateDart(const DartOptions(), root, sink); + final String code = sink.toString(); + expect(code, isNot(contains('extends StandardMessageCodec'))); + expect(code, contains('StandardMessageCodec')); + }); + + test('creates custom codecs if custom datatypes present', () { + final Root root = Root(apis: [ + Api(name: 'Api', location: ApiLocation.flutter, methods: [ + Method( + name: 'doSomething', + arguments: [ + NamedType( + type: const TypeDeclaration( + baseName: 'Input', + isNullable: false, + ), + name: '') + ], + returnType: + const TypeDeclaration(baseName: 'Output', isNullable: false), + isAsynchronous: true, + ) + ]) + ], classes: [ + Class(name: 'Input', fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'input') + ]), + Class(name: 'Output', fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'output') + ]) + ], enums: []); + final StringBuffer sink = StringBuffer(); + generateDart(const DartOptions(), root, sink); + final String code = sink.toString(); + expect(code, contains('extends StandardMessageCodec')); + }); } diff --git a/packages/pigeon/test/java_generator_test.dart b/packages/pigeon/test/java_generator_test.dart index 7621eecd40..bbe6db8ab3 100644 --- a/packages/pigeon/test/java_generator_test.dart +++ b/packages/pigeon/test/java_generator_test.dart @@ -1158,4 +1158,81 @@ void main() { true); } }); + + test('doesnt create codecs if no custom datatypes', () { + final Root root = Root( + apis: [ + Api( + name: 'Api', + location: ApiLocation.flutter, + methods: [ + Method( + name: 'method', + returnType: const TypeDeclaration.voidDeclaration(), + arguments: [ + NamedType( + name: 'field', + type: const TypeDeclaration( + baseName: 'int', + isNullable: true, + ), + ), + ], + ) + ], + ) + ], + classes: [], + enums: [], + ); + final StringBuffer sink = StringBuffer(); + const JavaOptions javaOptions = JavaOptions(className: 'Messages'); + generateJava(javaOptions, root, sink); + final String code = sink.toString(); + expect(code, isNot(contains(' extends StandardMessageCodec'))); + expect(code, contains('StandardMessageCodec')); + }); + + test('creates custom codecs if custom datatypes present', () { + final Root root = Root(apis: [ + Api(name: 'Api', location: ApiLocation.flutter, methods: [ + Method( + name: 'doSomething', + arguments: [ + NamedType( + type: const TypeDeclaration( + baseName: 'Input', + isNullable: false, + ), + name: '') + ], + returnType: + const TypeDeclaration(baseName: 'Output', isNullable: false), + isAsynchronous: true, + ) + ]) + ], classes: [ + Class(name: 'Input', fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'input') + ]), + Class(name: 'Output', fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'output') + ]) + ], enums: []); + final StringBuffer sink = StringBuffer(); + const JavaOptions javaOptions = JavaOptions(className: 'Messages'); + generateJava(javaOptions, root, sink); + final String code = sink.toString(); + expect(code, contains(' extends StandardMessageCodec')); + }); } diff --git a/packages/pigeon/test/kotlin_generator_test.dart b/packages/pigeon/test/kotlin_generator_test.dart index 35cd88749c..c9c8c6fa52 100644 --- a/packages/pigeon/test/kotlin_generator_test.dart +++ b/packages/pigeon/test/kotlin_generator_test.dart @@ -29,7 +29,7 @@ void main() { const KotlinOptions kotlinOptions = KotlinOptions(); generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); - expect(code, contains('data class Foobar(')); + expect(code, contains('data class Foobar (')); expect(code, contains('val field1: Long? = null')); expect(code, contains('fun fromMap(map: Map): Foobar')); expect(code, contains('fun toMap(): Map')); @@ -194,8 +194,6 @@ void main() { const KotlinOptions kotlinOptions = KotlinOptions(); generateKotlin(kotlinOptions, root, sink); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('val aBool: Boolean? = null')); expect(code, contains('val aInt: Long? = null')); @@ -246,8 +244,8 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('class Api(private val binaryMessenger: BinaryMessenger)')); @@ -283,8 +281,8 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, isNot(matches('.*doSomething(.*) ->'))); expect(code, matches('doSomething(.*)')); @@ -319,8 +317,8 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('callback: () -> Unit')); expect(code, contains('callback()')); @@ -348,8 +346,8 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doSomething(): Output')); expect(code, contains('wrapped["result"] = api.doSomething()')); @@ -379,8 +377,8 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doSomething(callback: (Output) -> Unit)')); expect(code, contains('channel.send(null)')); @@ -399,8 +397,8 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('data class Foobar')); expect(code, contains('val field1: List? = null')); @@ -419,8 +417,8 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('data class Foobar')); expect(code, contains('val field1: Map? = null')); @@ -457,8 +455,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('data class Outer')); expect(code, contains('data class Nested')); @@ -512,8 +510,8 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('interface Api')); expect(code, contains('api.doSomething(argArg) {')); @@ -560,8 +558,8 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('class Api')); expect(code, matches('fun doSomething.*Input.*callback.*Output.*Unit')); @@ -593,8 +591,8 @@ void main() { enums: [anEnum], ); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('enum class Enum1(val raw: Int)')); expect(code, contains('ONE(0)')); @@ -608,10 +606,10 @@ void main() { test('header', () { final Root root = Root(apis: [], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - final KotlinOptions swiftOptions = KotlinOptions( + final KotlinOptions kotlinOptions = KotlinOptions( copyrightHeader: makeIterable('hello world'), ); - generateKotlin(swiftOptions, root, sink); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, startsWith('// hello world')); }); @@ -637,8 +635,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('data class Foobar')); expect(code, contains('val field1: List')); @@ -666,8 +664,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('data class Foobar')); expect(code, contains('val field1: Map')); @@ -697,8 +695,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(arg: List')); }); @@ -727,8 +725,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(argArg: List')); }); @@ -752,8 +750,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(): List')); expect(code, contains('wrapped["result"] = api.doit()')); @@ -779,8 +777,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(callback: (List) -> Unit')); expect(code, contains('val result = it as List')); @@ -807,8 +805,8 @@ void main() { ]) ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun add(x: Long, y: Long): Long')); expect(code, contains('val args = message as List')); @@ -844,8 +842,8 @@ void main() { ]) ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('val channel = BasicMessageChannel')); expect(code, contains('val result = it as Long')); @@ -872,8 +870,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(): Long?')); }); @@ -896,8 +894,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(callback: (Long?) -> Unit')); }); @@ -923,8 +921,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect( code, @@ -953,8 +951,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(fooArg: Long?, callback: () -> Unit')); }); @@ -988,8 +986,8 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - const KotlinOptions swiftOptions = KotlinOptions(); - generateKotlin(swiftOptions, root, sink); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('val input: String\n')); }); @@ -1070,4 +1068,81 @@ void main() { true); } }); + + test('doesnt create codecs if no custom datatypes', () { + final Root root = Root( + apis: [ + Api( + name: 'Api', + location: ApiLocation.flutter, + methods: [ + Method( + name: 'method', + returnType: const TypeDeclaration.voidDeclaration(), + arguments: [ + NamedType( + name: 'field', + type: const TypeDeclaration( + baseName: 'int', + isNullable: true, + ), + ), + ], + ) + ], + ) + ], + classes: [], + enums: [], + ); + final StringBuffer sink = StringBuffer(); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); + final String code = sink.toString(); + expect(code, isNot(contains(' : StandardMessageCodec() '))); + expect(code, contains('StandardMessageCodec')); + }); + + test('creates custom codecs if custom datatypes present', () { + final Root root = Root(apis: [ + Api(name: 'Api', location: ApiLocation.flutter, methods: [ + Method( + name: 'doSomething', + arguments: [ + NamedType( + type: const TypeDeclaration( + baseName: 'Input', + isNullable: false, + ), + name: '') + ], + returnType: + const TypeDeclaration(baseName: 'Output', isNullable: false), + isAsynchronous: true, + ) + ]) + ], classes: [ + Class(name: 'Input', fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'input') + ]), + Class(name: 'Output', fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'output') + ]) + ], enums: []); + final StringBuffer sink = StringBuffer(); + const KotlinOptions kotlinOptions = KotlinOptions(); + generateKotlin(kotlinOptions, root, sink); + final String code = sink.toString(); + expect(code, contains(' : StandardMessageCodec() ')); + }); } diff --git a/packages/pigeon/test/objc_generator_test.dart b/packages/pigeon/test/objc_generator_test.dart index ff698b3a1a..efd177cbd9 100644 --- a/packages/pigeon/test/objc_generator_test.dart +++ b/packages/pigeon/test/objc_generator_test.dart @@ -1812,4 +1812,78 @@ void main() { expect(code, contains('///$comment')); } }); + + test('doesnt create codecs if no custom datatypes', () { + final Root root = Root( + apis: [ + Api( + name: 'Api', + location: ApiLocation.flutter, + methods: [ + Method( + name: 'method', + returnType: const TypeDeclaration.voidDeclaration(), + arguments: [ + NamedType( + name: 'field', + type: const TypeDeclaration( + baseName: 'int', + isNullable: true, + ), + ), + ], + ) + ], + ) + ], + classes: [], + enums: [], + ); + final StringBuffer sink = StringBuffer(); + generateObjcSource(const ObjcOptions(), root, sink); + final String code = sink.toString(); + expect(code, isNot(contains(' : FlutterStandardReader'))); + }); + + test('creates custom codecs if custom datatypes present', () { + final Root root = Root(apis: [ + Api(name: 'Api', location: ApiLocation.flutter, methods: [ + Method( + name: 'doSomething', + arguments: [ + NamedType( + type: const TypeDeclaration( + baseName: 'Input', + isNullable: false, + ), + name: '') + ], + returnType: + const TypeDeclaration(baseName: 'Output', isNullable: false), + isAsynchronous: true, + ) + ]) + ], classes: [ + Class(name: 'Input', fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'input') + ]), + Class(name: 'Output', fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'output') + ]) + ], enums: []); + final StringBuffer sink = StringBuffer(); + generateObjcSource(const ObjcOptions(), root, sink); + final String code = sink.toString(); + expect(code, contains(' : FlutterStandardReader')); + }); } diff --git a/packages/pigeon/test/swift_generator_test.dart b/packages/pigeon/test/swift_generator_test.dart index c40d85aefe..ab0af5b52b 100644 --- a/packages/pigeon/test/swift_generator_test.dart +++ b/packages/pigeon/test/swift_generator_test.dart @@ -1020,4 +1020,80 @@ void main() { expect(code, contains('///$comment')); } }); + + test('doesnt create codecs if no custom datatypes', () { + final Root root = Root( + apis: [ + Api( + name: 'Api', + location: ApiLocation.flutter, + methods: [ + Method( + name: 'method', + returnType: const TypeDeclaration.voidDeclaration(), + arguments: [ + NamedType( + name: 'field', + type: const TypeDeclaration( + baseName: 'int', + isNullable: true, + ), + ), + ], + ) + ], + ) + ], + classes: [], + enums: [], + ); + final StringBuffer sink = StringBuffer(); + const SwiftOptions swiftOptions = SwiftOptions(); + generateSwift(swiftOptions, root, sink); + final String code = sink.toString(); + expect(code, isNot(contains(': FlutterStandardReader '))); + }); + + test('creates custom codecs if custom datatypes present', () { + final Root root = Root(apis: [ + Api(name: 'Api', location: ApiLocation.flutter, methods: [ + Method( + name: 'doSomething', + arguments: [ + NamedType( + type: const TypeDeclaration( + baseName: 'Input', + isNullable: false, + ), + name: '') + ], + returnType: + const TypeDeclaration(baseName: 'Output', isNullable: false), + isAsynchronous: true, + ) + ]) + ], classes: [ + Class(name: 'Input', fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'input') + ]), + Class(name: 'Output', fields: [ + NamedType( + type: const TypeDeclaration( + baseName: 'String', + isNullable: true, + ), + name: 'output') + ]) + ], enums: []); + final StringBuffer sink = StringBuffer(); + const SwiftOptions swiftOptions = SwiftOptions(); + generateSwift(swiftOptions, root, sink); + final String code = sink.toString(); + expect(code, contains(': FlutterStandardReader ')); + }); }