[pigeon] Change generator formatting to closer match formatter output (#3072)

* dart and some java

* java

* objc header

* objc source

* newln

* loopable new lines

* better counting

* cpp and redo previous changes

* changelog

* nest and nits

* addScoped

* rewrite description of newln

* regex tests
This commit is contained in:
Tarrin Neal
2023-01-20 12:55:04 -08:00
committed by GitHub
parent a4bc6acb69
commit 2b7c60ad58
29 changed files with 644 additions and 571 deletions

View File

@ -1,3 +1,8 @@
## 7.0.1
* [generator_tools] adds `newln` method for adding empty lines and ending lines.
* Updates generators to more closely match Flutter formatter tool output.
## 7.0.0
* [java] **BREAKING CHANGE**: Makes data classes final.

View File

@ -104,7 +104,7 @@ class CppHeaderGenerator extends StructuredGenerator<CppOptions> {
}
indent.writeln('$_commentPrefix $generatedCodeWarning');
indent.writeln('$_commentPrefix $seeAlsoWarning');
indent.addln('');
indent.newln();
}
@override
@ -119,34 +119,34 @@ class CppHeaderGenerator extends StructuredGenerator<CppOptions> {
'flutter/encodable_value.h',
'flutter/standard_message_codec.h',
]);
indent.addln('');
indent.newln();
_writeSystemHeaderIncludeBlock(indent, <String>[
'map',
'string',
'optional',
]);
indent.addln('');
indent.newln();
if (generatorOptions.namespace != null) {
indent.writeln('namespace ${generatorOptions.namespace} {');
}
indent.addln('');
indent.newln();
if (generatorOptions.namespace?.endsWith('_pigeontest') ?? false) {
final String testFixtureClass =
'${_pascalCaseFromSnakeCase(generatorOptions.namespace!.replaceAll('_pigeontest', ''))}Test';
indent.writeln('class $testFixtureClass;');
}
indent.addln('');
indent.newln();
indent.writeln('$_commentPrefix Generated class from Pigeon.');
}
@override
void writeEnum(
CppOptions generatorOptions, Root root, Indent indent, Enum anEnum) {
indent.writeln('');
indent.newln();
addDocumentationComments(
indent, anEnum.documentationComments, _docCommentSpec);
indent.write('enum class ${anEnum.name} ');
indent.scoped('{', '};', () {
indent.addScoped('{', '};', () {
enumerate(anEnum.members, (int index, final EnumMember member) {
addDocumentationComments(
indent, member.documentationComments, _docCommentSpec);
@ -173,7 +173,7 @@ class CppHeaderGenerator extends StructuredGenerator<CppOptions> {
testFixtureClass =
'${_pascalCaseFromSnakeCase(generatorOptions.namespace!.replaceAll('_pigeontest', ''))}Test';
}
indent.addln('');
indent.newln();
const List<String> generatedMessages = <String>[
' Generated class from Pigeon that represents data sent in messages.'
@ -184,8 +184,8 @@ class CppHeaderGenerator extends StructuredGenerator<CppOptions> {
generatorComments: generatedMessages);
indent.write('class ${klass.name} ');
indent.scoped('{', '};', () {
indent.scoped(' public:', '', () {
indent.addScoped('{', '};', () {
indent.addScoped(' public:', '', () {
indent.writeln('${klass.name}();');
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
addDocumentationComments(
@ -204,11 +204,11 @@ class CppHeaderGenerator extends StructuredGenerator<CppOptions> {
indent.writeln(
'void ${_makeSetterName(field)}(${_unownedArgumentType(nonNullType)} value_arg);');
}
indent.addln('');
indent.newln();
}
});
indent.scoped(' private:', '', () {
indent.addScoped(' private:', '', () {
indent.writeln('${klass.name}(const flutter::EncodableList& list);');
indent.writeln('flutter::EncodableList ToEncodableList() const;');
for (final Class friend in root.classes) {
@ -236,7 +236,7 @@ class CppHeaderGenerator extends StructuredGenerator<CppOptions> {
}
});
}, nestCount: 0);
indent.writeln('');
indent.newln();
}
@override
@ -256,14 +256,14 @@ class CppHeaderGenerator extends StructuredGenerator<CppOptions> {
addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
generatorComments: generatedMessages);
indent.write('class ${api.name} ');
indent.scoped('{', '};', () {
indent.scoped(' private:', '', () {
indent.addScoped('{', '};', () {
indent.addScoped(' private:', '', () {
indent.writeln('flutter::BinaryMessenger* binary_messenger_;');
});
indent.scoped(' public:', '', () {
indent.addScoped(' public:', '', () {
indent
.write('${api.name}(flutter::BinaryMessenger* binary_messenger);');
indent.writeln('');
indent.newln();
indent
.writeln('static const flutter::StandardMessageCodec& GetCodec();');
for (final Method func in api.methods) {
@ -288,7 +288,7 @@ class CppHeaderGenerator extends StructuredGenerator<CppOptions> {
}
});
}, nestCount: 0);
indent.writeln('');
indent.newln();
}
@override
@ -308,8 +308,8 @@ class CppHeaderGenerator extends StructuredGenerator<CppOptions> {
addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
generatorComments: generatedMessages);
indent.write('class ${api.name} ');
indent.scoped('{', '};', () {
indent.scoped(' public:', '', () {
indent.addScoped('{', '};', () {
indent.addScoped(' public:', '', () {
indent.writeln('${api.name}(const ${api.name}&) = delete;');
indent.writeln('${api.name}& operator=(const ${api.name}&) = delete;');
indent.writeln('virtual ~${api.name}() { };');
@ -347,7 +347,7 @@ class CppHeaderGenerator extends StructuredGenerator<CppOptions> {
'virtual $returnTypeName ${_makeMethodName(method)}(${argSignature.join(', ')}) = 0;');
}
}
indent.addln('');
indent.newln();
indent.writeln('$_commentPrefix The codec used by ${api.name}.');
indent
.writeln('static const flutter::StandardMessageCodec& GetCodec();');
@ -360,7 +360,7 @@ class CppHeaderGenerator extends StructuredGenerator<CppOptions> {
indent.writeln(
'static flutter::EncodableValue WrapError(const FlutterError& error);');
});
indent.scoped(' protected:', '', () {
indent.addScoped(' protected:', '', () {
indent.writeln('${api.name}() = default;');
});
}, nestCount: 0);
@ -372,9 +372,9 @@ class CppHeaderGenerator extends StructuredGenerator<CppOptions> {
final String codeSerializerName = _getCodecSerializerName(api);
indent
.write('class $codeSerializerName : public $_defaultCodecSerializer ');
indent.scoped('{', '};', () {
indent.scoped(' public:', '', () {
indent.writeln('');
indent.addScoped('{', '};', () {
indent.addScoped(' public:', '', () {
indent.newln();
indent.format('''
inline static $codeSerializerName& GetInstance() {
\tstatic $codeSerializerName sInstance;
@ -392,7 +392,7 @@ inline static $codeSerializerName& GetInstance() {
'flutter::EncodableValue ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const override;');
});
}, nestCount: 0);
indent.addln('');
indent.newln();
}
void _writeErrorOr(Indent indent,
@ -468,28 +468,28 @@ class CppSourceGenerator extends StructuredGenerator<CppOptions> {
}
indent.writeln('$_commentPrefix $generatedCodeWarning');
indent.writeln('$_commentPrefix $seeAlsoWarning');
indent.addln('');
indent.newln();
indent.addln('#undef _HAS_EXCEPTIONS');
indent.addln('');
indent.newln();
}
@override
void writeFileImports(CppOptions generatorOptions, Root root, Indent indent) {
indent.writeln('#include "${generatorOptions.headerIncludePath}"');
indent.addln('');
indent.newln();
_writeSystemHeaderIncludeBlock(indent, <String>[
'flutter/basic_message_channel.h',
'flutter/binary_messenger.h',
'flutter/encodable_value.h',
'flutter/standard_message_codec.h',
]);
indent.addln('');
indent.newln();
_writeSystemHeaderIncludeBlock(indent, <String>[
'map',
'string',
'optional',
]);
indent.addln('');
indent.newln();
}
@override
@ -508,9 +508,9 @@ class CppSourceGenerator extends StructuredGenerator<CppOptions> {
final Set<String> customEnumNames =
root.enums.map((Enum x) => x.name).toSet();
indent.addln('');
indent.newln();
indent.writeln('$_commentPrefix ${klass.name}');
indent.addln('');
indent.newln();
// Getters and setters.
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
@ -523,7 +523,7 @@ class CppSourceGenerator extends StructuredGenerator<CppOptions> {
// Default constructor.
indent.writeln('${klass.name}::${klass.name}() {}');
indent.addln('');
indent.newln();
// Deserialization.
writeClassDecode(generatorOptions, root, indent, klass, customClassNames,
@ -541,8 +541,8 @@ class CppSourceGenerator extends StructuredGenerator<CppOptions> {
) {
indent.write(
'flutter::EncodableList ${klass.name}::ToEncodableList() const ');
indent.scoped('{', '}', () {
indent.scoped('return flutter::EncodableList{', '};', () {
indent.addScoped('{', '}', () {
indent.addScoped('return flutter::EncodableList{', '};', () {
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
final HostDatatype hostDatatype = getFieldHostDatatype(
field, root.classes, root.enums, _baseCppTypeForBuiltinDartType);
@ -552,7 +552,7 @@ class CppSourceGenerator extends StructuredGenerator<CppOptions> {
}
});
});
indent.addln('');
indent.newln();
}
@override
@ -566,7 +566,7 @@ class CppSourceGenerator extends StructuredGenerator<CppOptions> {
) {
indent.write(
'${klass.name}::${klass.name}(const flutter::EncodableList& list) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
enumerate(getFieldsInSerializationOrder(klass),
(int index, final NamedType field) {
final String instanceVariableName = _makeInstanceVariableName(field);
@ -593,21 +593,20 @@ else if (const int64_t* ${pointerFieldName}_64 = std::get_if<int64_t>(&$encodabl
.contains(field.type.baseName)) {
indent.write(
'if (const flutter::EncodableList* $pointerFieldName = std::get_if<flutter::EncodableList>(&$encodableFieldName)) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln(
'$instanceVariableName = ${hostDatatype.datatype}(*$pointerFieldName);');
});
} else {
indent.write(
'if (const ${hostDatatype.datatype}* $pointerFieldName = std::get_if<${hostDatatype.datatype}>(&$encodableFieldName)) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('$instanceVariableName = *$pointerFieldName;');
});
}
}
});
});
indent.addln('');
}
@override
@ -625,10 +624,10 @@ else if (const int64_t* ${pointerFieldName}_64 = std::get_if<int64_t>(&$encodabl
'$_commentPrefix Generated class from Pigeon that represents Flutter messages that can be called from C++.');
indent.write(
'${api.name}::${api.name}(flutter::BinaryMessenger* binary_messenger) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('this->binary_messenger_ = binary_messenger;');
});
indent.writeln('');
indent.newln();
final String codeSerializerName = getCodecClasses(api, root).isNotEmpty
? _getCodecSerializerName(api)
: _defaultCodecSerializer;
@ -657,7 +656,7 @@ const flutter::StandardMessageCodec& ${api.name}::GetCodec() {
];
indent.write(
'void ${api.name}::${_makeMethodName(func)}(${parameters.join(', ')}) ');
indent.scoped('{', '}', () {
indent.writeScoped('{', '}', () {
const String channel = 'channel';
indent.writeln(
'auto channel = std::make_unique<flutter::BasicMessageChannel<>>(binary_messenger_, '
@ -669,7 +668,7 @@ const flutter::StandardMessageCodec& ${api.name}::GetCodec() {
if (func.arguments.isEmpty) {
indent.addln('flutter::EncodableValue();');
} else {
indent.scoped(
indent.addScoped(
'flutter::EncodableValue(flutter::EncodableList{', '});', () {
for (final _HostNamedType param in hostParameters) {
final String encodedArgument = _wrappedHostApiArgumentExpression(
@ -683,7 +682,7 @@ const flutter::StandardMessageCodec& ${api.name}::GetCodec() {
// ignore: missing_whitespace_between_adjacent_strings
'[on_success = std::move(on_success), on_error = std::move(on_error)]'
'(const uint8_t* reply, size_t reply_size) ');
indent.scoped('{', '});', () {
indent.addScoped('{', '});', () {
final String successCallbackArgument;
if (func.returnType.isVoid) {
successCallbackArgument = '';
@ -725,21 +724,21 @@ const flutter::StandardMessageCodec& ${api.name}::GetCodec() {
'$_commentPrefix Sets up an instance of `${api.name}` to handle messages through the `binary_messenger`.');
indent.write(
'void ${api.name}::SetUp(flutter::BinaryMessenger* binary_messenger, ${api.name}* api) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final Method method in api.methods) {
final String channelName = makeChannelName(api, method);
indent.write('');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln(
'auto channel = std::make_unique<flutter::BasicMessageChannel<>>(binary_messenger, '
'"$channelName", &GetCodec());');
indent.write('if (api != nullptr) ');
indent.scoped('{', '} else {', () {
indent.addScoped('{', '} else {', () {
indent.write(
'channel->SetMessageHandler([api](const flutter::EncodableValue& message, const flutter::MessageReply<flutter::EncodableValue>& reply) ');
indent.scoped('{', '});', () {
indent.addScoped('{', '});', () {
indent.write('try ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
final List<String> methodArgument = <String>[];
if (method.arguments.isNotEmpty) {
indent.writeln(
@ -760,7 +759,7 @@ const flutter::StandardMessageCodec& ${api.name}::GetCodec() {
'const auto& $encodableArgName = args.at($index);');
if (!arg.type.isNullable) {
indent.write('if ($encodableArgName.IsNull()) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln(
'reply(WrapError("$argName unexpectedly null."));');
indent.writeln('return;');
@ -793,9 +792,9 @@ const flutter::StandardMessageCodec& ${api.name}::GetCodec() {
indent.writeln('$returnTypeName output = $call;');
indent.format(_wrapResponse(indent, root, method.returnType));
}
});
indent.write('catch (const std::exception& exception) ');
indent.scoped('{', '}', () {
}, addTrailingNewline: false);
indent.add(' catch (const std::exception& exception) ');
indent.addScoped('{', '}', () {
// There is a potential here for `reply` to be called twice, which
// is a violation of the API contract, because there's no way of
// knowing whether or not the plugin code called `reply` before
@ -808,14 +807,14 @@ const flutter::StandardMessageCodec& ${api.name}::GetCodec() {
});
});
});
indent.scoped(null, '}', () {
indent.addScoped(null, '}', () {
indent.writeln('channel->SetMessageHandler(nullptr);');
});
});
}
});
indent.addln('');
indent.newln();
indent.format('''
flutter::EncodableValue ${api.name}::WrapError(std::string_view error_message) {
\treturn flutter::EncodableValue(flutter::EncodableList{
@ -831,7 +830,7 @@ flutter::EncodableValue ${api.name}::WrapError(const FlutterError& error) {
\t\terror.details()
\t});
}''');
indent.addln('');
indent.newln();
}
void _writeCodec(
@ -842,12 +841,13 @@ flutter::EncodableValue ${api.name}::WrapError(const FlutterError& error) {
) {
assert(getCodecClasses(api, root).isNotEmpty);
final String codeSerializerName = _getCodecSerializerName(api);
indent.newln();
indent.writeln('$codeSerializerName::$codeSerializerName() {}');
indent.write(
'flutter::EncodableValue $codeSerializerName::ReadValueOfType(uint8_t type, flutter::ByteStreamReader* stream) const ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('switch (type) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
indent.write('case ${customClass.enumeration}:');
indent.writeScoped('', '', () {
@ -862,17 +862,17 @@ flutter::EncodableValue ${api.name}::WrapError(const FlutterError& error) {
}, addTrailingNewline: false);
});
});
indent.writeln('');
indent.newln();
indent.write(
'void $codeSerializerName::WriteValue(const flutter::EncodableValue& value, flutter::ByteStreamWriter* stream) const ');
indent.writeScoped('{', '}', () {
indent.write(
'if (const flutter::CustomEncodableValue* custom_value = std::get_if<flutter::CustomEncodableValue>(&value)) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final EnumeratedClass customClass in getCodecClasses(api, root)) {
indent.write(
'if (custom_value->type() == typeid(${customClass.name})) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('stream->WriteByte(${customClass.enumeration});');
indent.writeln(
'WriteValue(flutter::EncodableValue(std::any_cast<${customClass.name}>(*custom_value).ToEncodableList()), stream);');
@ -882,7 +882,7 @@ flutter::EncodableValue ${api.name}::WrapError(const FlutterError& error) {
});
indent.writeln('$_defaultCodecSerializer::WriteValue(value, stream);');
});
indent.writeln('');
indent.newln();
}
void _writeCppSourceClassField(CppOptions generatorOptions, Root root,
@ -919,7 +919,7 @@ flutter::EncodableValue ${api.name}::WrapError(const FlutterError& error) {
indent.writeln(makeSetter(nonNullType));
}
indent.addln('');
indent.newln();
}
String _wrapResponse(Indent indent, Root root, TypeDeclaration returnType,

View File

@ -86,7 +86,7 @@ class DartGenerator extends StructuredGenerator<DartOptions> {
indent.writeln(
'// 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, unused_shown_name, unnecessary_import',
);
indent.addln('');
indent.newln();
}
@override
@ -96,7 +96,7 @@ class DartGenerator extends StructuredGenerator<DartOptions> {
indent.writeln(
"import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;",
);
indent.addln('');
indent.newln();
indent.writeln(
"import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;");
indent.writeln("import 'package:flutter/services.dart';");
@ -105,11 +105,11 @@ class DartGenerator extends StructuredGenerator<DartOptions> {
@override
void writeEnum(
DartOptions generatorOptions, Root root, Indent indent, Enum anEnum) {
indent.writeln('');
indent.newln();
addDocumentationComments(
indent, anEnum.documentationComments, _docCommentSpec);
indent.write('enum ${anEnum.name} ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final EnumMember member in anEnum.members) {
addDocumentationComments(
indent, member.documentationComments, _docCommentSpec);
@ -126,25 +126,25 @@ class DartGenerator extends StructuredGenerator<DartOptions> {
final Set<String> customEnumNames =
root.enums.map((Enum x) => x.name).toSet();
indent.writeln('');
indent.newln();
addDocumentationComments(
indent, klass.documentationComments, _docCommentSpec);
indent.write('class ${klass.name} ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
_writeConstructor(indent, klass);
indent.addln('');
indent.newln();
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
addDocumentationComments(
indent, field.documentationComments, _docCommentSpec);
final String datatype = _addGenericTypesNullable(field.type);
indent.writeln('$datatype ${field.name};');
indent.writeln('');
indent.newln();
}
writeClassEncode(generatorOptions, root, indent, klass, customClassNames,
customEnumNames);
indent.writeln('');
indent.newln();
writeClassDecode(generatorOptions, root, indent, klass, customClassNames,
customEnumNames);
});
@ -152,7 +152,7 @@ class DartGenerator extends StructuredGenerator<DartOptions> {
void _writeConstructor(Indent indent, Class klass) {
indent.write(klass.name);
indent.scoped('({', '});', () {
indent.addScoped('({', '});', () {
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
final String required = field.type.isNullable ? '' : 'required ';
indent.writeln('${required}this.${field.name},');
@ -170,11 +170,11 @@ class DartGenerator extends StructuredGenerator<DartOptions> {
Set<String> customEnumNames,
) {
indent.write('Object encode() ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write(
'return <Object?>',
);
indent.scoped('[', '];', () {
indent.addScoped('[', '];', () {
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
final String conditional = field.type.isNullable ? '?' : '';
if (customClassNames.contains(field.type.baseName)) {
@ -207,27 +207,25 @@ class DartGenerator extends StructuredGenerator<DartOptions> {
if (customClassNames.contains(field.type.baseName)) {
final String nonNullValue =
'${field.type.baseName}.decode($resultAt! as List<Object?>)';
indent.format(
field.type.isNullable
? '''
if (field.type.isNullable) {
indent.format('''
$resultAt != null
\t\t? $nonNullValue
\t\t: null'''
: nonNullValue,
leadingSpace: false,
trailingNewline: false);
\t\t: null''', leadingSpace: false, trailingNewline: false);
} else {
indent.add(nonNullValue);
}
} else if (customEnumNames.contains(field.type.baseName)) {
final String nonNullValue =
'${field.type.baseName}.values[$resultAt! as int]';
indent.format(
field.type.isNullable
? '''
if (field.type.isNullable) {
indent.format('''
$resultAt != null
\t\t? $nonNullValue
\t\t: null'''
: nonNullValue,
leadingSpace: false,
trailingNewline: false);
\t\t: null''', leadingSpace: false, trailingNewline: false);
} else {
indent.add(nonNullValue);
}
} else if (field.type.typeArguments.isNotEmpty) {
final String genericType = _makeGenericTypeArguments(field.type);
final String castCall = _makeGenericCastCall(field.type);
@ -252,10 +250,10 @@ $resultAt != null
indent.write(
'static ${klass.name} decode(Object result) ',
);
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('result as List<Object?>;');
indent.write('return ${klass.name}');
indent.scoped('(', ');', () {
indent.addScoped('(', ');', () {
enumerate(getFieldsInSerializationOrder(klass),
(int index, final NamedType field) {
indent.write('${field.name}: ');
@ -292,15 +290,15 @@ $resultAt != null
codecName = _getCodecName(api);
_writeCodec(indent, codecName, api, root);
}
indent.addln('');
indent.newln();
addDocumentationComments(
indent, api.documentationComments, _docCommentSpec);
indent.write('abstract class ${api.name} ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent
.writeln('static const MessageCodec<Object?> codec = $codecName();');
indent.addln('');
indent.newln();
for (final Method func in api.methods) {
addDocumentationComments(
indent, func.documentationComments, _docCommentSpec);
@ -314,14 +312,14 @@ $resultAt != null
_getArgumentName,
);
indent.writeln('$returnType ${func.name}($argSignature);');
indent.writeln('');
indent.newln();
}
indent.write(
'static void setup(${api.name}? api, {BinaryMessenger? binaryMessenger}) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final Method func in api.methods) {
indent.write('');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln(
'final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(',
);
@ -337,15 +335,15 @@ $resultAt != null
final String messageHandlerSetter =
isMockHandler ? 'setMockMessageHandler' : 'setMessageHandler';
indent.write('if (api == null) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('channel.$messageHandlerSetter(null);');
}, addTrailingNewline: false);
indent.add(' else ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write(
'channel.$messageHandlerSetter((Object? message) async ',
);
indent.scoped('{', '});', () {
indent.addScoped('{', '});', () {
final String returnType =
_addGenericTypesNullable(func.returnType);
final bool isAsync = func.isAsynchronous;
@ -382,8 +380,9 @@ $resultAt != null
'$leftHandSide = ($argsArray[$count] as $genericArgType?)${castCall.isEmpty ? '' : '?$castCall'};');
}
if (!arg.type.isNullable) {
indent.writeln('assert($argName != null,');
indent.writeln(
"assert($argName != null, 'Argument for $channelName was null, expected non-null $argType.');");
" 'Argument for $channelName was null, expected non-null $argType.');");
}
});
final Iterable<String> argNames =
@ -446,12 +445,12 @@ $resultAt != null
codecName = _getCodecName(api);
_writeCodec(indent, codecName, api, root);
}
indent.addln('');
indent.newln();
bool first = true;
addDocumentationComments(
indent, api.documentationComments, _docCommentSpec);
indent.write('class ${api.name} ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.format('''
/// Constructor for [${api.name}]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
@ -463,10 +462,10 @@ final BinaryMessenger? _binaryMessenger;
indent
.writeln('static const MessageCodec<Object?> codec = $codecName();');
indent.addln('');
indent.newln();
for (final Method func in api.methods) {
if (!first) {
indent.writeln('');
indent.newln();
} else {
first = false;
}
@ -494,7 +493,7 @@ final BinaryMessenger? _binaryMessenger;
indent.write(
'Future<${_addGenericTypesNullable(func.returnType)}> ${func.name}($argSignature) async ',
);
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
final String channelName = makeChannelName(api, func);
indent.writeln(
'final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(');
@ -585,7 +584,6 @@ if (replyList == null) {
dartHostTestHandler: api.dartHostTestHandler,
documentationComments: api.documentationComments,
);
indent.writeln('');
writeFlutterApi(
generatorOptions,
root,
@ -621,7 +619,7 @@ if (replyList == null) {
"import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;");
indent.writeln("import 'package:flutter/services.dart';");
indent.writeln("import 'package:flutter_test/flutter_test.dart';");
indent.writeln('');
indent.newln();
}
}
@ -642,33 +640,34 @@ String _getCodecName(Api api) => '_${api.name}Codec';
void _writeCodec(Indent indent, String codecName, Api api, Root root) {
assert(getCodecClasses(api, root).isNotEmpty);
final Iterable<EnumeratedClass> codecClasses = getCodecClasses(api, root);
indent.newln();
indent.write('class $codecName extends $_standardMessageCodec');
indent.scoped(' {', '}', () {
indent.addScoped(' {', '}', () {
indent.writeln('const $codecName();');
indent.writeln('@override');
indent.write('void writeValue(WriteBuffer buffer, Object? value) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
enumerate(codecClasses, (int index, final EnumeratedClass customClass) {
final String ifValue = 'if (value is ${customClass.name}) ';
if (index == 0) {
indent.write('');
}
indent.add(ifValue);
indent.scoped('{', '} else ', () {
indent.addScoped('{', '} else ', () {
indent.writeln('buffer.putUint8(${customClass.enumeration});');
indent.writeln('writeValue(buffer, value.encode());');
}, addTrailingNewline: false);
});
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('super.writeValue(buffer, value);');
});
});
indent.writeln('');
indent.newln();
indent.writeln('@override');
indent.write('Object? readValueOfType(int type, ReadBuffer buffer) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('switch (type) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final EnumeratedClass customClass in codecClasses) {
indent.write('case ${customClass.enumeration}: ');
indent.writeScoped('', '', () {
@ -677,7 +676,7 @@ void _writeCodec(Indent indent, String codecName, Api api, Root root) {
});
}
indent.writeln('default:');
indent.scoped('', '', () {
indent.nest(1, () {
indent.writeln('return super.readValueOfType(type, buffer);');
});
});

View File

@ -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 = '7.0.0';
const String pigeonVersion = '7.0.1';
/// Read all the content from [stdin] to a String.
String readStdin() {
@ -83,7 +83,7 @@ class Indent {
/// Scoped increase of the ident level. For the execution of [func] the
/// indentation will be incremented.
void scoped(
void addScoped(
String? begin,
String? end,
Function func, {
@ -102,14 +102,14 @@ class Indent {
}
}
/// Like `scoped` but writes the current indentation level.
/// Like `addScoped` but writes the current indentation level.
void writeScoped(
String? begin,
String end,
Function func, {
bool addTrailingNewline = true,
}) {
scoped(str() + (begin ?? ''), end, func,
addScoped(str() + (begin ?? ''), end, func,
addTrailingNewline: addTrailingNewline);
}
@ -144,6 +144,13 @@ class Indent {
void add(String text) {
_sink.write(text);
}
/// Adds [lines] number of newlines.
void newln([int lines = 1]) {
for (; lines > 0; lines--) {
_sink.write(newline);
}
}
}
/// Create the generated channel name for a [func] on a [api].

View File

@ -98,7 +98,7 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
}
indent.writeln('// $generatedCodeWarning');
indent.writeln('// $seeAlsoWarning');
indent.addln('');
indent.newln();
}
@override
@ -106,6 +106,7 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
JavaOptions generatorOptions, Root root, Indent indent) {
if (generatorOptions.package != null) {
indent.writeln('package ${generatorOptions.package};');
indent.newln();
}
indent.writeln('import android.util.Log;');
indent.writeln('import androidx.annotation.NonNull;');
@ -116,13 +117,13 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
indent.writeln('import io.flutter.plugin.common.StandardMessageCodec;');
indent.writeln('import java.io.ByteArrayOutputStream;');
indent.writeln('import java.nio.ByteBuffer;');
indent.writeln('import java.util.Arrays;');
indent.writeln('import java.util.ArrayList;');
indent.writeln('import java.util.Arrays;');
indent.writeln('import java.util.Collections;');
indent.writeln('import java.util.HashMap;');
indent.writeln('import java.util.List;');
indent.writeln('import java.util.Map;');
indent.writeln('import java.util.HashMap;');
indent.addln('');
indent.newln();
}
@override
@ -149,22 +150,23 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
.toUpperCase();
}
indent.writeln('');
indent.newln();
addDocumentationComments(
indent, anEnum.documentationComments, _docCommentSpec);
indent.write('public enum ${anEnum.name} ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
enumerate(anEnum.members, (int index, final EnumMember member) {
addDocumentationComments(
indent, member.documentationComments, _docCommentSpec);
indent.writeln(
'${camelToSnake(member.name)}($index)${index == anEnum.members.length - 1 ? ';' : ','}');
});
indent.writeln('');
indent.newln();
indent.writeln('private final int index;');
indent.newln();
indent.write('private ${anEnum.name}(final int index) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('this.index = index;');
});
});
@ -181,24 +183,25 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
const List<String> generatedMessages = <String>[
' Generated class from Pigeon that represents data sent in messages.'
];
indent.addln('');
indent.newln();
addDocumentationComments(
indent, klass.documentationComments, _docCommentSpec,
generatorComments: generatedMessages);
indent.write('public static final class ${klass.name} ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
_writeClassField(generatorOptions, root, indent, field);
indent.addln('');
indent.newln();
}
if (getFieldsInSerializationOrder(klass)
.map((NamedType e) => !e.type.isNullable)
.any((bool e) => e)) {
indent.writeln(
'${_docCommentPrefix}Constructor is private to enforce null safety; use Builder.$_docCommentSuffix');
'$_docCommentPrefix Constructor is private to enforce null safety; use Builder.$_docCommentSuffix');
indent.writeln('private ${klass.name}() {}');
indent.newln();
}
_writeClassBuilder(generatorOptions, root, indent, klass);
@ -219,8 +222,13 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
indent.writeln(
'private $nullability ${hostDatatype.datatype} ${field.name};');
indent.writeln(
'public $nullability ${hostDatatype.datatype} ${_makeGetter(field)}() { return ${field.name}; }');
indent.newln();
indent.write(
'public $nullability ${hostDatatype.datatype} ${_makeGetter(field)}() ');
indent.addScoped('{', '}', () {
indent.writeln('return ${field.name};');
});
indent.newln();
indent.writeScoped(
'public void ${_makeSetter(field)}($nullability ${hostDatatype.datatype} setterArg) {',
'}', () {
@ -241,7 +249,7 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
Class klass,
) {
indent.write('public static final class Builder ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
final HostDatatype hostDatatype = getFieldHostDatatype(
field,
@ -250,8 +258,10 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
(TypeDeclaration x) => _javaTypeForBuiltinDartType(x));
final String nullability =
field.type.isNullable ? '@Nullable' : '@NonNull';
indent.newln();
indent.writeln(
'private @Nullable ${hostDatatype.datatype} ${field.name};');
indent.newln();
indent.writeScoped(
'public @NonNull Builder ${_makeSetter(field)}($nullability ${hostDatatype.datatype} setterArg) {',
'}', () {
@ -259,8 +269,9 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
indent.writeln('return this;');
});
}
indent.newln();
indent.write('public @NonNull ${klass.name} build() ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
const String returnVal = 'pigeonReturn';
indent.writeln('${klass.name} $returnVal = new ${klass.name}();');
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
@ -280,8 +291,10 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
Set<String> customClassNames,
Set<String> customEnumNames,
) {
indent.write('@NonNull ArrayList<Object> toList() ');
indent.scoped('{', '}', () {
indent.newln();
indent.writeln('@NonNull');
indent.write('ArrayList<Object> toList() ');
indent.addScoped('{', '}', () {
indent.writeln(
'ArrayList<Object> toListResult = new ArrayList<Object>(${klass.fields.length});');
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
@ -316,9 +329,10 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
Set<String> customClassNames,
Set<String> customEnumNames,
) {
indent.newln();
indent.write(
'static @NonNull ${klass.name} fromList(@NonNull ArrayList<Object> list) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
const String result = 'pigeonResult';
indent.writeln('${klass.name} $result = new ${klass.name}();');
enumerate(getFieldsInSerializationOrder(klass),
@ -365,26 +379,28 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
generatorComments: generatedMessages);
indent.write('public static final class ${api.name} ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('private final BinaryMessenger binaryMessenger;');
indent.write('public ${api.name}(BinaryMessenger argBinaryMessenger)');
indent.scoped('{', '}', () {
indent.newln();
indent.write('public ${api.name}(BinaryMessenger argBinaryMessenger) ');
indent.addScoped('{', '}', () {
indent.writeln('this.binaryMessenger = argBinaryMessenger;');
});
indent.newln();
indent.write('/** Public interface for sending reply. */ ');
indent.write('public interface Reply<T> ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('void reply(T reply);');
});
final String codecName = _getCodecName(api);
indent.writeln('/** The codec used by ${api.name}. */');
indent.write('static MessageCodec<Object> getCodec() ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('return ');
if (getCodecClasses(api, root).isNotEmpty) {
indent.writeln('$codecName.INSTANCE;');
indent.addln('$codecName.INSTANCE;');
} else {
indent.writeln('new $_standardMessageCodec();');
indent.addln('new $_standardMessageCodec();');
}
});
@ -418,32 +434,36 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
indent.write(
'public void ${func.name}($argsSignature, Reply<$returnType> callback) ');
}
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
const String channel = 'channel';
indent.writeln('BasicMessageChannel<Object> $channel =');
indent.inc();
indent.inc();
indent.writeln(
'new BasicMessageChannel<>(binaryMessenger, "$channelName", getCodec());');
indent.dec();
indent.dec();
indent.write('$channel.send($sendArgument, channelReply -> ');
if (func.returnType.isVoid) {
indent.addln('callback.reply(null));');
} else {
indent.scoped('{', '});', () {
const String output = 'output';
indent.writeln('@SuppressWarnings("ConstantConditions")');
if (func.returnType.baseName == 'int') {
indent.writeln(
'$returnType $output = channelReply == null ? null : ((Number)channelReply).longValue();');
} else {
indent.writeln(
'$returnType $output = ($returnType)channelReply;');
}
indent.writeln('callback.reply($output);');
indent.nest(2, () {
indent.writeln('new BasicMessageChannel<>(');
indent.nest(2, () {
indent.writeln('binaryMessenger, "$channelName", getCodec());');
});
}
});
indent.writeln('$channel.send(');
indent.nest(2, () {
indent.writeln('$sendArgument,');
indent.write('channelReply -> ');
if (func.returnType.isVoid) {
indent.addln('callback.reply(null));');
} else {
indent.addScoped('{', '});', () {
const String output = 'output';
indent.writeln('@SuppressWarnings("ConstantConditions")');
if (func.returnType.baseName == 'int') {
indent.writeln(
'$returnType $output = channelReply == null ? null : ((Number) channelReply).longValue();');
} else {
indent.writeln(
'$returnType $output = ($returnType) channelReply;');
}
indent.writeln('callback.reply($output);');
});
}
});
});
}
});
@ -454,7 +474,7 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
if (root.apis.any((Api api) =>
api.location == ApiLocation.host &&
api.methods.any((Method it) => it.isAsynchronous))) {
indent.addln('');
indent.newln();
_writeResultInterface(indent);
}
super.writeApis(generatorOptions, root, indent);
@ -480,20 +500,20 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
generatorComments: generatedMessages);
indent.write('public interface ${api.name} ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final Method method in api.methods) {
_writeInterfaceMethod(generatorOptions, root, indent, api, method);
}
indent.addln('');
indent.newln();
final String codecName = _getCodecName(api);
indent.writeln('/** The codec used by ${api.name}. */');
indent.write('static MessageCodec<Object> getCodec() ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('return ');
if (getCodecClasses(api, root).isNotEmpty) {
indent.write('$codecName.INSTANCE;');
indent.addln('$codecName.INSTANCE;');
} else {
indent.write('new $_standardMessageCodec();');
indent.addln('new $_standardMessageCodec();');
}
});
@ -501,7 +521,7 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
'${_docCommentPrefix}Sets up an instance of `${api.name}` to handle messages through the `binaryMessenger`.$_docCommentSuffix');
indent.write(
'static void setup(BinaryMessenger binaryMessenger, ${api.name} api) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final Method method in api.methods) {
_writeMethodSetup(generatorOptions, root, indent, api, method);
}
@ -514,9 +534,12 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
/// int add(int x, int y);
void _writeInterfaceMethod(JavaOptions generatorOptions, Root root,
Indent indent, Api api, final Method method) {
final String nullableType = method.isAsynchronous
? ''
: _nullabilityAnnotationFromType(method.returnType);
final String returnType = method.isAsynchronous
? 'void'
: _nullsafeJavaTypeForDartType(method.returnType);
: _javaTypeForDartType(method.returnType);
final List<String> argSignature = <String>[];
if (method.arguments.isNotEmpty) {
final Iterable<String> argTypes = method.arguments
@ -534,9 +557,15 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
: _javaTypeForDartType(method.returnType);
argSignature.add('Result<$resultType> result');
}
addDocumentationComments(
indent, method.documentationComments, _docCommentSpec);
if (method.documentationComments.isNotEmpty) {
addDocumentationComments(
indent, method.documentationComments, _docCommentSpec);
} else {
indent.newln();
}
if (nullableType != '') {
indent.writeln(nullableType);
}
indent.writeln('$returnType ${method.name}(${argSignature.join(', ')});');
}
@ -547,7 +576,7 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
Api api, final Method method) {
final String channelName = makeChannelName(api, method);
indent.write('');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
String? taskQueue;
if (method.taskQueueType != TaskQueueType.serial) {
taskQueue = 'taskQueue';
@ -555,106 +584,111 @@ class JavaGenerator extends StructuredGenerator<JavaOptions> {
'BinaryMessenger.TaskQueue taskQueue = binaryMessenger.makeBackgroundTaskQueue();');
}
indent.writeln('BasicMessageChannel<Object> channel =');
indent.inc();
indent.inc();
indent.write(
'new BasicMessageChannel<>(binaryMessenger, "$channelName", getCodec()');
if (taskQueue != null) {
indent.addln(', $taskQueue);');
} else {
indent.addln(');');
}
indent.dec();
indent.dec();
indent.write('if (api != null) ');
indent.scoped('{', '} else {', () {
indent.write('channel.setMessageHandler((message, reply) -> ');
indent.scoped('{', '});', () {
final String returnType = method.returnType.isVoid
? 'Void'
: _javaTypeForDartType(method.returnType);
indent.writeln('ArrayList wrapped = new ArrayList<>();');
indent.write('try ');
indent.scoped('{', '}', () {
final List<String> methodArgument = <String>[];
if (method.arguments.isNotEmpty) {
indent.writeln(
'ArrayList<Object> args = (ArrayList<Object>)message;');
indent.writeln('assert args != null;');
enumerate(method.arguments, (int index, NamedType arg) {
// The StandardMessageCodec can give us [Integer, Long] for
// a Dart 'int'. To keep things simple we just use 64bit
// longs in Pigeon with Java.
final bool isInt = arg.type.baseName == 'int';
final String argType =
isInt ? 'Number' : _javaTypeForDartType(arg.type);
final String argName = _getSafeArgumentName(index, arg);
final String argExpression = isInt
? '($argName == null) ? null : $argName.longValue()'
: argName;
String accessor = 'args.get($index)';
if (isEnum(root, arg.type)) {
accessor = _intToEnum(accessor, arg.type.baseName);
} else if (argType != 'Object') {
accessor = '($argType)$accessor';
}
indent.writeln('$argType $argName = $accessor;');
if (!arg.type.isNullable) {
indent.write('if ($argName == null) ');
indent.scoped('{', '}', () {
indent.writeln(
'throw new NullPointerException("$argName unexpectedly null.");');
});
}
methodArgument.add(argExpression);
});
}
if (method.isAsynchronous) {
final String resultValue =
method.returnType.isVoid ? 'null' : 'result';
const String resultName = 'resultCallback';
indent.format('''
Result<$returnType> $resultName = new Result<$returnType>() {
\tpublic void success($returnType result) {
\t\twrapped.add(0, $resultValue);
\t\treply.reply(wrapped);
\t}
\tpublic void error(Throwable error) {
\t\tArrayList<Object> wrappedError = wrapError(error);
\t\treply.reply(wrappedError);
\t}
};
''');
methodArgument.add(resultName);
}
final String call =
'api.${method.name}(${methodArgument.join(', ')})';
if (method.isAsynchronous) {
indent.writeln('$call;');
} else if (method.returnType.isVoid) {
indent.writeln('$call;');
indent.writeln('wrapped.add(0, null);');
} else {
indent.writeln('$returnType output = $call;');
indent.writeln('wrapped.add(0, output);');
}
});
indent.write('catch (Error | RuntimeException exception) ');
indent.scoped('{', '}', () {
indent.writeln(
'ArrayList<Object> wrappedError = wrapError(exception);');
if (method.isAsynchronous) {
indent.writeln('reply.reply(wrappedError);');
} else {
indent.writeln('wrapped = wrappedError;');
}
});
if (!method.isAsynchronous) {
indent.writeln('reply.reply(wrapped);');
indent.nest(2, () {
indent.writeln('new BasicMessageChannel<>(');
indent.nest(2, () {
indent.write('binaryMessenger, "$channelName", getCodec()');
if (taskQueue != null) {
indent.addln(', $taskQueue);');
} else {
indent.addln(');');
}
});
});
indent.scoped(null, '}', () {
indent.write('if (api != null) ');
indent.addScoped('{', '} else {', () {
indent.writeln('channel.setMessageHandler(');
indent.nest(2, () {
indent.write('(message, reply) -> ');
indent.addScoped('{', '});', () {
final String returnType = method.returnType.isVoid
? 'Void'
: _javaTypeForDartType(method.returnType);
indent.writeln('ArrayList wrapped = new ArrayList<>();');
indent.write('try ');
indent.addScoped('{', '}', () {
final List<String> methodArgument = <String>[];
if (method.arguments.isNotEmpty) {
indent.writeln(
'ArrayList<Object> args = (ArrayList<Object>) message;');
indent.writeln('assert args != null;');
enumerate(method.arguments, (int index, NamedType arg) {
// The StandardMessageCodec can give us [Integer, Long] for
// a Dart 'int'. To keep things simple we just use 64bit
// longs in Pigeon with Java.
final bool isInt = arg.type.baseName == 'int';
final String argType =
isInt ? 'Number' : _javaTypeForDartType(arg.type);
final String argName = _getSafeArgumentName(index, arg);
final String argExpression = isInt
? '($argName == null) ? null : $argName.longValue()'
: argName;
String accessor = 'args.get($index)';
if (isEnum(root, arg.type)) {
accessor = _intToEnum(accessor, arg.type.baseName);
} else if (argType != 'Object') {
accessor = '($argType) $accessor';
}
indent.writeln('$argType $argName = $accessor;');
if (!arg.type.isNullable) {
indent.write('if ($argName == null) ');
indent.addScoped('{', '}', () {
indent.writeln(
'throw new NullPointerException("$argName unexpectedly null.");');
});
}
methodArgument.add(argExpression);
});
}
if (method.isAsynchronous) {
final String resultValue =
method.returnType.isVoid ? 'null' : 'result';
const String resultName = 'resultCallback';
indent.format('''
Result<$returnType> $resultName =
\t\tnew Result<$returnType>() {
\t\t\tpublic void success($returnType result) {
\t\t\t\twrapped.add(0, $resultValue);
\t\t\t\treply.reply(wrapped);
\t\t\t}
\t\t\tpublic void error(Throwable error) {
\t\t\t\tArrayList<Object> wrappedError = wrapError(error);
\t\t\t\treply.reply(wrappedError);
\t\t\t}
\t\t};
''');
methodArgument.add(resultName);
}
final String call =
'api.${method.name}(${methodArgument.join(', ')})';
if (method.isAsynchronous) {
indent.writeln('$call;');
} else if (method.returnType.isVoid) {
indent.writeln('$call;');
indent.writeln('wrapped.add(0, null);');
} else {
indent.writeln('$returnType output = $call;');
indent.writeln('wrapped.add(0, output);');
}
}, addTrailingNewline: false);
indent.add(' catch (Error | RuntimeException exception) ');
indent.addScoped('{', '}', () {
indent.writeln(
'ArrayList<Object> wrappedError = wrapError(exception);');
if (method.isAsynchronous) {
indent.writeln('reply.reply(wrappedError);');
} else {
indent.writeln('wrapped = wrappedError;');
}
});
if (!method.isAsynchronous) {
indent.writeln('reply.reply(wrapped);');
}
});
});
});
indent.addScoped(null, '}', () {
indent.writeln('channel.setMessageHandler(null);');
});
});
@ -667,66 +701,78 @@ Result<$returnType> $resultName = new Result<$returnType>() {
assert(getCodecClasses(api, root).isNotEmpty);
final Iterable<EnumeratedClass> codecClasses = getCodecClasses(api, root);
final String codecName = _getCodecName(api);
indent.newln();
indent.write(
'private static class $codecName extends $_standardMessageCodec ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln(
'public static final $codecName INSTANCE = new $codecName();');
indent.newln();
indent.writeln('private $codecName() {}');
indent.newln();
indent.writeln('@Override');
indent.write(
'protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('switch (type) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final EnumeratedClass customClass in codecClasses) {
indent.write('case (byte)${customClass.enumeration}: ');
indent.write('case (byte) ${customClass.enumeration}: ');
indent.writeScoped('', '', () {
indent.writeln(
'return ${customClass.name}.fromList((ArrayList<Object>) readValue(buffer));');
});
}
indent.write('default:');
indent.writeScoped('', '', () {
indent.addScoped('', '', () {
indent.writeln('return super.readValueOfType(type, buffer);');
});
}, addTrailingNewline: false);
});
});
indent.newln();
indent.writeln('@Override');
indent.write(
'protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) ');
indent.writeScoped('{', '}', () {
indent.addScoped('{', '}', () {
bool firstClass = true;
for (final EnumeratedClass customClass in codecClasses) {
indent.write('if (value instanceof ${customClass.name}) ');
indent.scoped('{', '} else ', () {
if (firstClass) {
indent.write('');
firstClass = false;
}
indent.add('if (value instanceof ${customClass.name}) ');
indent.addScoped('{', '} else ', () {
indent.writeln('stream.write(${customClass.enumeration});');
indent.writeln(
'writeValue(stream, ((${customClass.name}) value).toList());');
});
}, addTrailingNewline: false);
}
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('super.writeValue(stream, value);');
});
});
});
indent.addln('');
indent.newln();
}
void _writeResultInterface(Indent indent) {
indent.write('public interface Result<T> ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('void success(T result);');
indent.newln();
indent.writeln('void error(Throwable error);');
});
}
void _writeWrapError(Indent indent) {
indent.format('''
@NonNull private static ArrayList<Object> wrapError(@NonNull Throwable exception) {
@NonNull
private static ArrayList<Object> wrapError(@NonNull Throwable exception) {
\tArrayList<Object> errorList = new ArrayList<>(3);
\terrorList.add(exception.toString());
\terrorList.add(exception.getClass().getSimpleName());
\terrorList.add("Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception));
\terrorList.add(
\t\t"Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception));
\treturn errorList;
}''');
}
@ -751,7 +797,7 @@ String _getCodecName(Api api) => '${api.name}Codec';
/// Converts an expression that evaluates to an nullable int to an expression
/// that evaluates to a nullable enum.
String _intToEnum(String expression, String enumName) =>
'$expression == null ? null : $enumName.values()[(int)$expression]';
'$expression == null ? null : $enumName.values()[(int) $expression]';
String _getArgumentName(int count, NamedType argument) =>
argument.name.isEmpty ? 'arg$count' : argument.name;
@ -815,9 +861,12 @@ String _javaTypeForDartType(TypeDeclaration type) {
return _javaTypeForBuiltinDartType(type) ?? type.baseName;
}
String _nullabilityAnnotationFromType(TypeDeclaration type) {
return type.isVoid ? '' : (type.isNullable ? '@Nullable ' : '@NonNull ');
}
String _nullsafeJavaTypeForDartType(TypeDeclaration type) {
final String nullSafe =
type.isVoid ? '' : (type.isNullable ? '@Nullable ' : '@NonNull ');
final String nullSafe = _nullabilityAnnotationFromType(type);
return '$nullSafe${_javaTypeForDartType(type)}';
}
@ -829,11 +878,11 @@ String _castObject(
final HostDatatype hostDatatype = getFieldHostDatatype(field, classes, enums,
(TypeDeclaration x) => _javaTypeForBuiltinDartType(x));
if (field.type.baseName == 'int') {
return '($varName == null) ? null : (($varName instanceof Integer) ? (Integer)$varName : (${hostDatatype.datatype})$varName)';
return '($varName == null) ? null : (($varName instanceof Integer) ? (Integer) $varName : (${hostDatatype.datatype}) $varName)';
} else if (!hostDatatype.isBuiltin &&
classes.map((Class x) => x.name).contains(field.type.baseName)) {
return '($varName == null) ? null : ${hostDatatype.datatype}.fromList((ArrayList<Object>)$varName)';
return '($varName == null) ? null : ${hostDatatype.datatype}.fromList((ArrayList<Object>) $varName)';
} else {
return '(${hostDatatype.datatype})$varName';
return '(${hostDatatype.datatype}) $varName';
}
}

View File

@ -83,11 +83,11 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
@override
void writeFileImports(
KotlinOptions generatorOptions, Root root, Indent indent) {
indent.addln('');
indent.newln();
if (generatorOptions.package != null) {
indent.writeln('package ${generatorOptions.package}');
}
indent.addln('');
indent.newln();
indent.writeln('import android.util.Log');
indent.writeln('import io.flutter.plugin.common.BasicMessageChannel');
indent.writeln('import io.flutter.plugin.common.BinaryMessenger');
@ -100,11 +100,11 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
@override
void writeEnum(
KotlinOptions generatorOptions, Root root, Indent indent, Enum anEnum) {
indent.writeln('');
indent.newln();
addDocumentationComments(
indent, anEnum.documentationComments, _docCommentSpec);
indent.write('enum class ${anEnum.name}(val raw: Int) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
enumerate(anEnum.members, (int index, final EnumMember member) {
addDocumentationComments(
indent, member.documentationComments, _docCommentSpec);
@ -116,11 +116,11 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
}
});
indent.writeln('');
indent.newln();
indent.write('companion object ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('fun ofRaw(raw: Int): ${anEnum.name}? ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('return values().firstOrNull { it.raw == raw }');
});
});
@ -138,24 +138,24 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
const List<String> generatedMessages = <String>[
' Generated class from Pigeon that represents data sent in messages.'
];
indent.addln('');
indent.newln();
addDocumentationComments(
indent, klass.documentationComments, _docCommentSpec,
generatorComments: generatedMessages);
indent.write('data class ${klass.name} ');
indent.scoped('(', '', () {
indent.addScoped('(', '', () {
for (final NamedType element in getFieldsInSerializationOrder(klass)) {
_writeClassField(indent, element);
if (getFieldsInSerializationOrder(klass).last != element) {
indent.addln(',');
} else {
indent.addln('');
indent.newln();
}
}
});
indent.scoped(') {', '}', () {
indent.addScoped(') {', '}', () {
writeClassDecode(generatorOptions, root, indent, klass, customClassNames,
customEnumNames);
writeClassEncode(generatorOptions, root, indent, klass, customClassNames,
@ -173,9 +173,9 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
Set<String> customEnumNames,
) {
indent.write('fun toList(): List<Any?> ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('return listOf<Any?>');
indent.scoped('(', ')', () {
indent.addScoped('(', ')', () {
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
final HostDatatype hostDatatype = _getHostDatatype(root, field);
String toWriteValue = '';
@ -207,11 +207,11 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
final String className = klass.name;
indent.write('companion object ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('@Suppress("UNCHECKED_CAST")');
indent.write('fun fromList(list: List<Any?>): $className ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
enumerate(getFieldsInSerializationOrder(klass),
(int index, final NamedType field) {
final HostDatatype hostDatatype = _getHostDatatype(root, field);
@ -229,14 +229,14 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
customClassNames.contains(field.type.baseName)) {
indent.write('val ${field.name}: $fieldType? = ');
indent.add('($listValue as? List<Any?>)?.let ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('$fieldType.fromList(it)');
});
} else if (!hostDatatype.isBuiltin &&
customEnumNames.contains(field.type.baseName)) {
indent.write('val ${field.name}: $fieldType? = ');
indent.add('($listValue as? Int)?.let ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('$fieldType.ofRaw(it)');
});
} else if (isInt) {
@ -290,7 +290,7 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
if (root.apis.any((Api api) =>
api.location == ApiLocation.host &&
api.methods.any((Method it) => it.isAsynchronous))) {
indent.addln('');
indent.newln();
}
super.writeApis(generatorOptions, root, indent);
}
@ -323,12 +323,12 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
indent.writeln('@Suppress("UNCHECKED_CAST")');
indent
.write('class $apiName(private val binaryMessenger: BinaryMessenger) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('companion object ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('/** The codec used by $apiName. */');
indent.write('val codec: MessageCodec<Any?> by lazy ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
if (isCustomCodec) {
indent.writeln(_getCodecName(api));
} else {
@ -366,18 +366,18 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
'fun ${func.name}($argsSignature, callback: ($returnType) -> Unit) ');
}
}
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
const String channel = 'channel';
indent.writeln(
'val $channel = BasicMessageChannel<Any?>(binaryMessenger, "$channelName", codec)');
indent.write('$channel.send($sendArgument) ');
if (func.returnType.isVoid) {
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('callback()');
});
} else {
final String forceUnwrap = func.returnType.isNullable ? '?' : '';
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('val result = it as$forceUnwrap $returnType');
indent.writeln('callback(result)');
});
@ -418,7 +418,7 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
generatorComments: generatedMessages);
indent.write('interface $apiName ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final Method method in api.methods) {
final List<String> argSignature = <String>[];
if (method.arguments.isNotEmpty) {
@ -450,12 +450,12 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
}
}
indent.addln('');
indent.newln();
indent.write('companion object ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('/** The codec used by $apiName. */');
indent.write('val codec: MessageCodec<Any?> by lazy ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
if (isCustomCodec) {
indent.writeln(_getCodecName(api));
} else {
@ -467,10 +467,10 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
indent.writeln('@Suppress("UNCHECKED_CAST")');
indent.write(
'fun setUp(binaryMessenger: BinaryMessenger, api: $apiName?) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final Method method in api.methods) {
indent.write('run ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
String? taskQueue;
if (method.taskQueueType != TaskQueueType.serial) {
taskQueue = 'taskQueue';
@ -490,15 +490,15 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
}
indent.write('if (api != null) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
final String messageVarName =
method.arguments.isNotEmpty ? 'message' : '_';
indent.write('channel.setMessageHandler ');
indent.scoped('{ $messageVarName, reply ->', '}', () {
indent.addScoped('{ $messageVarName, reply ->', '}', () {
indent.writeln('var wrapped = listOf<Any?>()');
indent.write('try ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
final List<String> methodArgument = <String>[];
if (method.arguments.isNotEmpty) {
indent.writeln('val args = message as List<Any?>');
@ -516,7 +516,7 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
indent.write('$call ');
final String resultValue =
method.returnType.isVoid ? 'null' : 'it';
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('reply.reply(wrapResult($resultValue))');
});
} else if (method.returnType.isVoid) {
@ -527,7 +527,7 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
}
}, addTrailingNewline: false);
indent.add(' catch (exception: Error) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('wrapped = wrapError(exception)');
if (method.isAsynchronous) {
indent.writeln('reply.reply(wrapped)');
@ -538,7 +538,7 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
}
});
}, addTrailingNewline: false);
indent.scoped(' else {', '}', () {
indent.addScoped(' else {', '}', () {
indent.writeln('channel.setMessageHandler(null)');
});
});
@ -557,17 +557,17 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
final String codecName = _getCodecName(api);
indent.writeln('@Suppress("UNCHECKED_CAST")');
indent.write('private object $codecName : StandardMessageCodec() ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write(
'override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('return when (type) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final EnumeratedClass customClass in codecClasses) {
indent.write('${customClass.enumeration}.toByte() -> ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('return (readValue(buffer) as? List<Any?>)?.let ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('${customClass.name}.fromList(it)');
});
});
@ -580,10 +580,10 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
'override fun writeValue(stream: ByteArrayOutputStream, value: Any?) ');
indent.writeScoped('{', '}', () {
indent.write('when (value) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final EnumeratedClass customClass in codecClasses) {
indent.write('is ${customClass.name} -> ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('stream.write(${customClass.enumeration})');
indent.writeln('writeValue(stream, value.toList())');
});
@ -592,23 +592,23 @@ class KotlinGenerator extends StructuredGenerator<KotlinOptions> {
});
});
});
indent.addln('');
indent.newln();
}
void _writeWrapResult(Indent indent) {
indent.addln('');
indent.newln();
indent.write('private fun wrapResult(result: Any?): List<Any?> ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('return listOf(result)');
});
}
void _writeWrapError(Indent indent) {
indent.addln('');
indent.newln();
indent.write('private fun wrapError(exception: Throwable): List<Any> ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('return ');
indent.scoped('listOf<Any>(', ')', () {
indent.addScoped('listOf<Any>(', ')', () {
indent.writeln('exception.javaClass.simpleName,');
indent.writeln('exception.toString(),');
indent.writeln(

View File

@ -96,20 +96,20 @@ class ObjcHeaderGenerator extends StructuredGenerator<ObjcOptions> {
}
indent.writeln('// $generatedCodeWarning');
indent.writeln('// $seeAlsoWarning');
indent.addln('');
indent.newln();
}
@override
void writeFileImports(
ObjcOptions generatorOptions, Root root, Indent indent) {
indent.writeln('#import <Foundation/Foundation.h>');
indent.addln('');
indent.newln();
indent.writeln('@protocol FlutterBinaryMessenger;');
indent.writeln('@protocol FlutterMessageCodec;');
indent.writeln('@class FlutterError;');
indent.writeln('@class FlutterStandardTypedData;');
indent.addln('');
indent.newln();
indent.writeln('NS_ASSUME_NONNULL_BEGIN');
}
@ -117,12 +117,12 @@ class ObjcHeaderGenerator extends StructuredGenerator<ObjcOptions> {
void writeEnum(
ObjcOptions generatorOptions, Root root, Indent indent, Enum anEnum) {
final String enumName = _className(generatorOptions.prefix, anEnum.name);
indent.writeln('');
indent.newln();
addDocumentationComments(
indent, anEnum.documentationComments, _docCommentSpec);
indent.write('typedef NS_ENUM(NSUInteger, $enumName) ');
indent.scoped('{', '};', () {
indent.addScoped('{', '};', () {
enumerate(anEnum.members, (int index, final EnumMember member) {
addDocumentationComments(
indent, member.documentationComments, _docCommentSpec);
@ -136,12 +136,12 @@ class ObjcHeaderGenerator extends StructuredGenerator<ObjcOptions> {
@override
void writeDataClasses(
ObjcOptions generatorOptions, Root root, Indent indent) {
indent.writeln('');
indent.newln();
for (final Class klass in root.classes) {
indent.writeln(
'@class ${_className(generatorOptions.prefix, klass.name)};');
}
indent.writeln('');
indent.newln();
super.writeDataClasses(generatorOptions, root, indent);
}
@ -192,7 +192,7 @@ class ObjcHeaderGenerator extends StructuredGenerator<ObjcOptions> {
'@property(nonatomic, $propertyType$nullability) ${hostDatatype.datatype} ${field.name};');
}
indent.writeln('@end');
indent.writeln('');
indent.newln();
}
@override
@ -232,7 +232,7 @@ class ObjcHeaderGenerator extends StructuredGenerator<ObjcOptions> {
'$_docCommentPrefix The codec used by ${_className(generatorOptions.prefix, api.name)}.');
indent.writeln(
'NSObject<FlutterMessageCodec> *${_getCodecGetterName(generatorOptions.prefix, api.name)}(void);');
indent.addln('');
indent.newln();
final String apiName = _className(generatorOptions.prefix, api.name);
addDocumentationComments(
indent, api.documentationComments, _docCommentSpec);
@ -257,7 +257,7 @@ class ObjcHeaderGenerator extends StructuredGenerator<ObjcOptions> {
)};');
}
indent.writeln('@end');
indent.writeln('');
indent.newln();
}
@override
@ -271,7 +271,7 @@ class ObjcHeaderGenerator extends StructuredGenerator<ObjcOptions> {
'$_docCommentPrefix The codec used by ${_className(generatorOptions.prefix, api.name)}.');
indent.writeln(
'NSObject<FlutterMessageCodec> *${_getCodecGetterName(generatorOptions.prefix, api.name)}(void);');
indent.addln('');
indent.newln();
final String apiName = _className(generatorOptions.prefix, api.name);
addDocumentationComments(
indent, api.documentationComments, _docCommentSpec);
@ -287,11 +287,11 @@ class ObjcHeaderGenerator extends StructuredGenerator<ObjcOptions> {
if (func.isAsynchronous) {
returnType = 'void';
if (func.returnType.isVoid) {
lastArgType = 'void(^)(FlutterError *_Nullable)';
lastArgType = 'void (^)(FlutterError *_Nullable)';
lastArgName = 'completion';
} else {
lastArgType =
'void(^)(${returnTypeName.ptr}_Nullable, FlutterError *_Nullable)';
'void (^)(${returnTypeName.ptr}_Nullable, FlutterError *_Nullable)';
lastArgName = 'completion';
}
} else {
@ -322,10 +322,10 @@ class ObjcHeaderGenerator extends StructuredGenerator<ObjcOptions> {
indent.writeln('$signature;');
}
indent.writeln('@end');
indent.writeln('');
indent.newln();
indent.writeln(
'extern void ${apiName}Setup(id<FlutterBinaryMessenger> binaryMessenger, NSObject<$apiName> *_Nullable api);');
indent.writeln('');
indent.newln();
}
}
@ -342,7 +342,7 @@ class ObjcSourceGenerator extends StructuredGenerator<ObjcOptions> {
}
indent.writeln('// $generatedCodeWarning');
indent.writeln('// $seeAlsoWarning');
indent.addln('');
indent.newln();
}
@override
@ -350,24 +350,23 @@ class ObjcSourceGenerator extends StructuredGenerator<ObjcOptions> {
ObjcOptions generatorOptions, Root root, Indent indent) {
indent.writeln('#import "${generatorOptions.headerIncludePath}"');
indent.writeln('#import <Flutter/Flutter.h>');
indent.addln('');
indent.newln();
indent.writeln('#if !__has_feature(objc_arc)');
indent.writeln('#error File requires ARC to be enabled.');
indent.writeln('#endif');
indent.addln('');
indent.newln();
}
@override
void writeDataClasses(
ObjcOptions generatorOptions, Root root, Indent indent) {
_writeObjcSourceHelperFunctions(indent);
indent.addln('');
for (final Class klass in root.classes) {
_writeObjcSourceDataClassExtension(generatorOptions, indent, klass);
}
indent.writeln('');
indent.newln();
super.writeDataClasses(generatorOptions, root, indent);
}
@ -388,7 +387,7 @@ class ObjcSourceGenerator extends StructuredGenerator<ObjcOptions> {
writeClassEncode(generatorOptions, root, indent, klass, customClassNames,
customEnumNames);
indent.writeln('@end');
indent.writeln('');
indent.newln();
}
@override
@ -401,9 +400,9 @@ class ObjcSourceGenerator extends StructuredGenerator<ObjcOptions> {
Set<String> customEnumNames,
) {
indent.write('- (NSArray *)toList ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('return');
indent.scoped(' @[', '];', () {
indent.addScoped(' @[', '];', () {
for (final NamedType field in klass.fields) {
indent.writeln(
'${_arrayValue(customClassNames, customEnumNames, field)},');
@ -423,7 +422,7 @@ class ObjcSourceGenerator extends StructuredGenerator<ObjcOptions> {
) {
final String className = _className(generatorOptions.prefix, klass.name);
indent.write('+ ($className *)fromList:(NSArray *)list ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
const String resultName = 'pigeonResult';
indent.writeln('$className *$resultName = [[$className alloc] init];');
enumerate(getFieldsInSerializationOrder(klass),
@ -442,8 +441,10 @@ class ObjcSourceGenerator extends StructuredGenerator<ObjcOptions> {
indent.writeln('return $resultName;');
});
indent.writeln(
'+ (nullable $className *)nullableFromList:(NSArray *)list { return (list) ? [$className fromList:list] : nil; }');
indent.write('+ (nullable $className *)nullableFromList:(NSArray *)list ');
indent.addScoped('{', '}', () {
indent.writeln('return (list) ? [$className fromList:list] : nil;');
});
}
void _writeCodecAndGetter(
@ -451,10 +452,10 @@ class ObjcSourceGenerator extends StructuredGenerator<ObjcOptions> {
final String codecName = _getCodecName(generatorOptions.prefix, api.name);
if (getCodecClasses(api, root).isNotEmpty) {
_writeCodec(indent, codecName, generatorOptions, api, root);
indent.addln('');
indent.newln();
}
_writeCodecGetter(indent, codecName, generatorOptions, api, root);
indent.addln('');
indent.newln();
}
@override
@ -470,15 +471,15 @@ class ObjcSourceGenerator extends StructuredGenerator<ObjcOptions> {
_writeCodecAndGetter(generatorOptions, root, indent, api);
_writeExtension(indent, apiName);
indent.addln('');
indent.newln();
indent.writeln('@implementation $apiName');
indent.addln('');
indent.newln();
_writeInitializer(indent);
for (final Method func in api.methods) {
_writeMethod(generatorOptions, root, indent, api, func);
}
indent.writeln('@end');
indent.writeln('');
indent.newln();
}
@override
@ -496,13 +497,12 @@ class ObjcSourceGenerator extends StructuredGenerator<ObjcOptions> {
const String channelName = 'channel';
indent.write(
'void ${apiName}Setup(id<FlutterBinaryMessenger> binaryMessenger, NSObject<$apiName> *api) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final Method func in api.methods) {
indent.write('');
addDocumentationComments(
indent, func.documentationComments, _docCommentSpec);
indent.scoped('{', '}', () {
indent.writeScoped('{', '}', () {
String? taskQueue;
if (func.taskQueueType != TaskQueueType.serial) {
taskQueue = 'taskQueue';
@ -512,12 +512,12 @@ class ObjcSourceGenerator extends StructuredGenerator<ObjcOptions> {
_writeChannelAllocation(
generatorOptions, indent, api, func, channelName, taskQueue);
indent.write('if (api) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
_writeChannelApiBinding(
generatorOptions, root, indent, apiName, func, channelName);
});
indent.write('else ');
indent.scoped('{', '}', () {
}, addTrailingNewline: false);
indent.add(' else ');
indent.addScoped('{', '}', () {
indent.writeln('[$channelName setMessageHandler:nil];');
});
});
@ -595,7 +595,7 @@ class ObjcSourceGenerator extends StructuredGenerator<ObjcOptions> {
'NSCAssert([api respondsToSelector:@selector($selector)], @"$apiName api (%@) doesn\'t respond to @selector($selector)", api);');
indent.write(
'[$channel setMessageHandler:^(id _Nullable message, FlutterReply callback) ');
indent.scoped('{', '}];', () {
indent.addScoped('{', '}];', () {
final _ObjcPtr returnType =
_objcTypeForDartType(generatorOptions.prefix, func.returnType);
final Iterable<String> selectorComponents =
@ -624,54 +624,56 @@ class ObjcSourceGenerator extends StructuredGenerator<ObjcOptions> {
void _writeChannelAllocation(ObjcOptions generatorOptions, Indent indent,
Api api, Method func, String varName, String? taskQueue) {
indent.writeln('FlutterBasicMessageChannel *$varName =');
indent.inc();
indent.writeln('[[FlutterBasicMessageChannel alloc]');
indent.inc();
indent.writeln('initWithName:@"${makeChannelName(api, func)}"');
indent.writeln('binaryMessenger:binaryMessenger');
indent.write('codec:');
indent.add('${_getCodecGetterName(generatorOptions.prefix, api.name)}()');
indent.nest(1, () {
indent.writeln('[[FlutterBasicMessageChannel alloc]');
indent.nest(1, () {
indent.writeln('initWithName:@"${makeChannelName(api, func)}"');
indent.writeln('binaryMessenger:binaryMessenger');
indent.write('codec:');
indent
.add('${_getCodecGetterName(generatorOptions.prefix, api.name)}()');
if (taskQueue != null) {
indent.addln('');
indent.addln('taskQueue:$taskQueue];');
} else {
indent.addln('];');
}
indent.dec();
indent.dec();
if (taskQueue != null) {
indent.newln();
indent.addln('taskQueue:$taskQueue];');
} else {
indent.addln('];');
}
});
});
}
void _writeObjcSourceHelperFunctions(Indent indent) {
indent.format('''
static NSArray *wrapResult(id result, FlutterError *error) {
\tif (error) {
\t\treturn @[ error.code ?: [NSNull null], error.message ?: [NSNull null], error.details ?: [NSNull null] ];
\t\treturn @[
\t\t\terror.code ?: [NSNull null], error.message ?: [NSNull null], error.details ?: [NSNull null]
\t\t];
\t}
\treturn @[ result ?: [NSNull null] ];
\treturn @[ result ?: [NSNull null] ];
}''');
indent.format('''
static id GetNullableObject(NSDictionary* dict, id key) {
static id GetNullableObject(NSDictionary *dict, id key) {
\tid result = dict[key];
\treturn (result == [NSNull null]) ? nil : result;
}
static id GetNullableObjectAtIndex(NSArray* array, NSInteger key) {
static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) {
\tid result = array[key];
\treturn (result == [NSNull null]) ? nil : result;
}
''');
}''');
}
void _writeObjcSourceDataClassExtension(
ObjcOptions languageOptions, Indent indent, Class klass) {
final String className = _className(languageOptions.prefix, klass.name);
indent.newln();
indent.writeln('@interface $className ()');
indent.writeln('+ ($className *)fromList:(NSArray *)list;');
indent
.writeln('+ (nullable $className *)nullableFromList:(NSArray *)list;');
indent.writeln('- (NSArray *)toList;');
indent.writeln('@end');
indent.writeln('');
}
void _writeObjcSourceClassInitializer(
@ -715,10 +717,10 @@ static id GetNullableObjectAtIndex(NSArray* array, NSInteger key) {
indent.writeln('@interface $readerName : FlutterStandardReader');
indent.writeln('@end');
indent.writeln('@implementation $readerName');
indent.writeln('- (nullable id)readValueOfType:(UInt8)type ');
indent.scoped('{', '}', () {
indent.write('- (nullable id)readValueOfType:(UInt8)type ');
indent.addScoped('{', '}', () {
indent.write('switch (type) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final EnumeratedClass customClass in codecClasses) {
indent.write('case ${customClass.enumeration}: ');
indent.writeScoped('', '', () {
@ -726,33 +728,38 @@ static id GetNullableObjectAtIndex(NSArray* array, NSInteger key) {
'return [${_className(options.prefix, customClass.name)} fromList:[self readValue]];');
});
}
indent.write('default:');
indent.writeScoped('', '', () {
indent.writeln('default:');
indent.nest(1, () {
indent.writeln('return [super readValueOfType:type];');
});
});
});
indent.writeln('@end');
indent.addln('');
indent.newln();
indent.writeln('@interface $writerName : FlutterStandardWriter');
indent.writeln('@end');
indent.writeln('@implementation $writerName');
indent.writeln('- (void)writeValue:(id)value ');
indent.scoped('{', '}', () {
indent.write('- (void)writeValue:(id)value ');
indent.addScoped('{', '}', () {
bool firstClass = true;
for (final EnumeratedClass customClass in codecClasses) {
indent.write(
if (firstClass) {
indent.write('');
firstClass = false;
}
indent.add(
'if ([value isKindOfClass:[${_className(options.prefix, customClass.name)} class]]) ');
indent.scoped('{', '} else ', () {
indent.addScoped('{', '} else ', () {
indent.writeln('[self writeByte:${customClass.enumeration}];');
indent.writeln('[self writeValue:[value toList]];');
});
}, addTrailingNewline: false);
}
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('[super writeValue:value];');
});
});
indent.writeln('@end');
indent.addln('');
indent.newln();
indent.format('''
@interface $readerWriterName : FlutterStandardReaderWriter
@end
@ -763,8 +770,7 @@ static id GetNullableObjectAtIndex(NSArray* array, NSInteger key) {
- (FlutterStandardReader *)readerWithData:(NSData *)data {
\treturn [[$readerName alloc] initWithData:data];
}
@end
''');
@end''');
}
void _writeCodecGetter(
@ -773,13 +779,13 @@ static id GetNullableObjectAtIndex(NSArray* array, NSInteger key) {
indent.write(
'NSObject<FlutterMessageCodec> *${_getCodecGetterName(options.prefix, api.name)}() ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
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.addScoped('{', '});', () {
indent.writeln(
'$readerWriterName *readerWriter = [[$readerWriterName alloc] init];');
indent.writeln(
@ -809,7 +815,7 @@ void _writeObjcSourceClassInitializerDeclaration(Indent indent, Class klass,
final void Function(String) printer = isFirst
? indent.add
: (String x) {
indent.addln('');
indent.newln();
indent.write(x);
};
isFirst = false;
@ -840,8 +846,8 @@ String _className(String? prefix, String className) {
/// Calculates callback block signature for for async methods.
String _callbackForType(TypeDeclaration type, _ObjcPtr objcType) {
return type.isVoid
? 'void(^)(NSError *_Nullable)'
: 'void(^)(${objcType.ptr.trim()}_Nullable, NSError *_Nullable)';
? 'void (^)(NSError *_Nullable)'
: 'void (^)(${objcType.ptr.trim()}_Nullable, NSError *_Nullable)';
}
/// Represents an ObjC pointer (ex 'id', 'NSString *').
@ -1050,17 +1056,17 @@ String _getSafeArgName(int count, NamedType arg) =>
void _writeExtension(Indent indent, String apiName) {
indent.writeln('@interface $apiName ()');
indent.writeln(
'@property (nonatomic, strong) NSObject<FlutterBinaryMessenger> *binaryMessenger;');
'@property(nonatomic, strong) NSObject<FlutterBinaryMessenger> *binaryMessenger;');
indent.writeln('@end');
}
void _writeInitializer(Indent indent) {
indent.write(
'- (instancetype)initWithBinaryMessenger:(NSObject<FlutterBinaryMessenger> *)binaryMessenger ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('self = [super init];');
indent.write('if (self) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('_binaryMessenger = binaryMessenger;');
});
indent.writeln('return self;');
@ -1091,20 +1097,21 @@ void _writeMethod(ObjcOptions languageOptions, Root root, Indent indent,
argNameFunc: argNameFunc,
isEnum: (TypeDeclaration t) => isEnum(root, t),
));
indent.scoped(' {', '}', () {
indent.addScoped(' {', '}', () {
indent.writeln('FlutterBasicMessageChannel *channel =');
indent.inc();
indent.writeln('[FlutterBasicMessageChannel');
indent.inc();
indent.writeln('messageChannelWithName:@"${makeChannelName(api, func)}"');
indent.writeln('binaryMessenger:self.binaryMessenger');
indent.write(
'codec:${_getCodecGetterName(languageOptions.prefix, api.name)}()');
indent.addln('];');
indent.dec();
indent.dec();
indent.nest(1, () {
indent.writeln('[FlutterBasicMessageChannel');
indent.nest(1, () {
indent
.writeln('messageChannelWithName:@"${makeChannelName(api, func)}"');
indent.writeln('binaryMessenger:self.binaryMessenger');
indent.write(
'codec:${_getCodecGetterName(languageOptions.prefix, api.name)}()');
indent.addln('];');
});
});
indent.write('[channel sendMessage:$sendArgument reply:^(id reply) ');
indent.scoped('{', '}];', () {
indent.addScoped('{', '}];', () {
if (func.returnType.isVoid) {
indent.writeln('completion(nil);');
} else {

View File

@ -61,7 +61,7 @@ class SwiftGenerator extends StructuredGenerator<SwiftOptions> {
}
indent.writeln('// $generatedCodeWarning');
indent.writeln('// $seeAlsoWarning');
indent.addln('');
indent.newln();
}
@override
@ -77,18 +77,18 @@ import FlutterMacOS
#error("Unsupported platform.")
#endif
''');
indent.writeln('');
indent.newln();
}
@override
void writeEnum(
SwiftOptions generatorOptions, Root root, Indent indent, Enum anEnum) {
indent.writeln('');
indent.newln();
addDocumentationComments(
indent, anEnum.documentationComments, _docCommentSpec);
indent.write('enum ${anEnum.name}: Int ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
enumerate(anEnum.members, (int index, final EnumMember member) {
addDocumentationComments(
indent, member.documentationComments, _docCommentSpec);
@ -108,18 +108,18 @@ import FlutterMacOS
const List<String> generatedComments = <String>[
' Generated class from Pigeon that represents data sent in messages.'
];
indent.addln('');
indent.newln();
addDocumentationComments(
indent, klass.documentationComments, _docCommentSpec,
generatorComments: generatedComments);
indent.write('struct ${klass.name} ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
getFieldsInSerializationOrder(klass).forEach((NamedType field) {
_writeClassField(indent, field);
});
indent.writeln('');
indent.newln();
writeClassDecode(generatorOptions, root, indent, klass, customClassNames,
customEnumNames);
writeClassEncode(generatorOptions, root, indent, klass, customClassNames,
@ -137,9 +137,9 @@ import FlutterMacOS
Set<String> customEnumNames,
) {
indent.write('func toList() -> [Any?] ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('return ');
indent.scoped('[', ']', () {
indent.addScoped('[', ']', () {
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
final HostDatatype hostDatatype = _getHostDatatype(root, field);
String toWriteValue = '';
@ -173,7 +173,7 @@ import FlutterMacOS
final String className = klass.name;
indent.write('static func fromList(_ list: [Any?]) -> $className? ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
enumerate(getFieldsInSerializationOrder(klass),
(int index, final NamedType field) {
final HostDatatype hostDatatype = _getHostDatatype(root, field);
@ -186,7 +186,7 @@ import FlutterMacOS
customClassNames.contains(field.type.baseName)) {
indent.writeln('var ${field.name}: $fieldType? = nil');
indent.write('if let ${field.name}List = $listValue as? [Any?] ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln(
'${field.name} = $fieldType.fromList(${field.name}List)');
});
@ -194,7 +194,7 @@ import FlutterMacOS
customEnumNames.contains(field.type.baseName)) {
indent.writeln('var ${field.name}: $fieldType? = nil');
indent.write('if let ${field.name}RawValue = $listValue as? Int ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln(
'${field.name} = $fieldType(rawValue: ${field.name}RawValue)');
});
@ -216,9 +216,9 @@ import FlutterMacOS
}
});
indent.writeln('');
indent.newln();
indent.write('return ');
indent.scoped('$className(', ')', () {
indent.addScoped('$className(', ')', () {
for (final NamedType field in getFieldsInSerializationOrder(klass)) {
final String comma =
getFieldsInSerializationOrder(klass).last == field ? '' : ',';
@ -247,7 +247,7 @@ import FlutterMacOS
if (root.apis.any((Api api) =>
api.location == ApiLocation.host &&
api.methods.any((Method it) => it.isAsynchronous))) {
indent.addln('');
indent.newln();
}
super.writeApis(generatorOptions, root, indent);
}
@ -278,10 +278,10 @@ import FlutterMacOS
generatorComments: generatedComments);
indent.write('class ${api.name} ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('private let binaryMessenger: FlutterBinaryMessenger');
indent.write('init(binaryMessenger: FlutterBinaryMessenger)');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('self.binaryMessenger = binaryMessenger');
});
final String codecName = _getCodecName(api);
@ -289,7 +289,7 @@ import FlutterMacOS
if (getCodecClasses(api, root).isNotEmpty) {
codecArgumentString = ', codec: codec';
indent.write('var codec: FlutterStandardMessageCodec ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('return $codecName.shared');
});
}
@ -328,17 +328,17 @@ import FlutterMacOS
'func ${func.name}($argsSignature, completion: @escaping ($returnType) -> Void) ');
}
}
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
const String channel = 'channel';
indent.writeln(
'let $channel = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger$codecArgumentString)');
indent.write('$channel.sendMessage($sendArgument) ');
if (func.returnType.isVoid) {
indent.scoped('{ _ in', '}', () {
indent.addScoped('{ _ in', '}', () {
indent.writeln('completion()');
});
} else {
indent.scoped('{ response in', '}', () {
indent.addScoped('{ response in', '}', () {
indent.writeln(
'let result = ${_castForceUnwrap("response", func.returnType, root)}');
indent.writeln('completion(result)');
@ -377,7 +377,7 @@ import FlutterMacOS
generatorComments: generatedComments);
indent.write('protocol $apiName ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final Method method in api.methods) {
final List<String> argSignature = <String>[];
if (method.arguments.isNotEmpty) {
@ -409,11 +409,11 @@ import FlutterMacOS
}
});
indent.addln('');
indent.newln();
indent.writeln(
'$_docCommentPrefix Generated setup class from Pigeon to handle messages through the `binaryMessenger`.');
indent.write('class ${apiName}Setup ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
final String codecName = _getCodecName(api);
indent.writeln('$_docCommentPrefix The codec used by $apiName.');
String codecArgumentString = '';
@ -426,7 +426,7 @@ import FlutterMacOS
'$_docCommentPrefix Sets up an instance of `$apiName` to handle messages through the `binaryMessenger`.');
indent.write(
'static func setUp(binaryMessenger: FlutterBinaryMessenger, api: $apiName?) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final Method method in api.methods) {
final String channelName = makeChannelName(api, method);
final String varChannelName = '${method.name}Channel';
@ -436,11 +436,11 @@ import FlutterMacOS
indent.writeln(
'let $varChannelName = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger$codecArgumentString)');
indent.write('if let api = api ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('$varChannelName.setMessageHandler ');
final String messageVarName =
method.arguments.isNotEmpty ? 'message' : '_';
indent.scoped('{ $messageVarName, reply in', '}', () {
indent.addScoped('{ $messageVarName, reply in', '}', () {
final List<String> methodArgument = <String>[];
if (method.arguments.isNotEmpty) {
indent.writeln('let args = message as! [Any?]');
@ -457,11 +457,11 @@ import FlutterMacOS
if (method.isAsynchronous) {
indent.write('$call ');
if (method.returnType.isVoid) {
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('reply(wrapResult(nil))');
});
} else {
indent.scoped('{ result in', '}', () {
indent.addScoped('{ result in', '}', () {
indent.writeln('reply(wrapResult(result))');
});
}
@ -476,7 +476,7 @@ import FlutterMacOS
}
});
}, addTrailingNewline: false);
indent.scoped(' else {', '}', () {
indent.addScoped(' else {', '}', () {
indent.writeln('$varChannelName.setMessageHandler(nil)');
});
}
@ -498,22 +498,22 @@ import FlutterMacOS
// Generate Reader
indent.write('private class $readerName: FlutterStandardReader ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
if (getCodecClasses(api, root).isNotEmpty) {
indent.write('override func readValue(ofType type: UInt8) -> Any? ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('switch type ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
for (final EnumeratedClass customClass
in getCodecClasses(api, root)) {
indent.write('case ${customClass.enumeration}:');
indent.scoped('', '', () {
indent.write(
indent.writeln('case ${customClass.enumeration}:');
indent.nest(1, () {
indent.writeln(
'return ${customClass.name}.fromList(self.readValue() as! [Any])');
});
}
indent.write('default:');
indent.scoped('', '', () {
indent.writeln('default:');
indent.nest(1, () {
indent.writeln('return super.readValue(ofType: type)');
});
});
@ -522,69 +522,70 @@ import FlutterMacOS
});
// Generate Writer
indent.newln();
indent.write('private class $writerName: FlutterStandardWriter ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
if (getCodecClasses(api, root).isNotEmpty) {
indent.write('override func writeValue(_ value: Any) ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('');
for (final EnumeratedClass customClass
in getCodecClasses(api, root)) {
indent.add('if let value = value as? ${customClass.name} ');
indent.scoped('{', '} else ', () {
indent.addScoped('{', '} else ', () {
indent.writeln('super.writeByte(${customClass.enumeration})');
indent.writeln('super.writeValue(value.toList())');
}, addTrailingNewline: false);
}
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('super.writeValue(value)');
});
});
}
});
indent.writeln('');
indent.newln();
// Generate ReaderWriter
indent
.write('private class $readerWriterName: FlutterStandardReaderWriter ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write(
'override func reader(with data: Data) -> FlutterStandardReader ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('return $readerName(data: data)');
});
indent.writeln('');
indent.newln();
indent.write(
'override func writer(with data: NSMutableData) -> FlutterStandardWriter ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('return $writerName(data: data)');
});
});
indent.writeln('');
indent.newln();
// Generate Codec
indent.write('class $codecName: FlutterStandardMessageCodec ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln(
'static let shared = $codecName(readerWriter: $readerWriterName())');
});
indent.addln('');
indent.newln();
}
void _writeWrapResult(Indent indent) {
indent.addln('');
indent.newln();
indent.write('private func wrapResult(_ result: Any?) -> [Any?] ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.writeln('return [result]');
});
}
void _writeWrapError(Indent indent) {
indent.addln('');
indent.newln();
indent.write('private func wrapError(_ error: FlutterError) -> [Any?] ');
indent.scoped('{', '}', () {
indent.addScoped('{', '}', () {
indent.write('return ');
indent.scoped('[', ']', () {
indent.addScoped('[', ']', () {
indent.writeln('error.code,');
indent.writeln('error.message,');
indent.writeln('error.details');

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), 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, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), 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, unnecessary_parenthesis, unnecessary_import
// ignore_for_file: avoid_relative_lib_imports

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), do not edit directly.
// See also: https://pub.dev/packages/pigeon
package com.example.alternate_language_test_plugin;
@ -196,6 +196,7 @@ public class CoreTests {
private AllTypes() {}
public static final class Builder {
private @Nullable Boolean aBool;
public @NonNull Builder setABool(@NonNull Boolean setterArg) {
@ -479,6 +480,7 @@ public class CoreTests {
}
public static final class Builder {
private @Nullable Boolean aNullableBool;
public @NonNull Builder setANullableBool(@Nullable Boolean setterArg) {
@ -675,6 +677,7 @@ public class CoreTests {
private AllNullableTypesWrapper() {}
public static final class Builder {
private @Nullable AllNullableTypes values;
public @NonNull Builder setValues(@NonNull AllNullableTypes setterArg) {
@ -2177,6 +2180,7 @@ public class CoreTests {
public FlutterIntegrationCoreApi(BinaryMessenger argBinaryMessenger) {
this.binaryMessenger = argBinaryMessenger;
}
/** Public interface for sending reply. */
public interface Reply<T> {
void reply(T reply);
@ -2459,6 +2463,7 @@ public class CoreTests {
* <p>Generated interface from Pigeon that represents a handler of messages from Flutter.
*/
public interface HostTrivialApi {
void noop();
/** The codec used by HostTrivialApi. */

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), do not edit directly.
// See also: https://pub.dev/packages/pigeon
#import <Foundation/Foundation.h>

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), do not edit directly.
// See also: https://pub.dev/packages/pigeon
#import "CoreTests.gen.h"

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), 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, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), 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, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), 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, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), 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, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), 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, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), 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, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), 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, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), 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, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), do not edit directly.
// See also: https://pub.dev/packages/pigeon
package com.example.test_plugin

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
@ -194,10 +194,10 @@ private class HostIntegrationCoreApiCodecReader: FlutterStandardReader {
return AllTypes.fromList(self.readValue() as! [Any])
default:
return super.readValue(ofType: type)
}
}
}
private class HostIntegrationCoreApiCodecWriter: FlutterStandardWriter {
override func writeValue(_ value: Any) {
if let value = value as? AllNullableTypes {
@ -776,10 +776,10 @@ private class FlutterIntegrationCoreApiCodecReader: FlutterStandardReader {
return AllTypes.fromList(self.readValue() as! [Any])
default:
return super.readValue(ofType: type)
}
}
}
private class FlutterIntegrationCoreApiCodecWriter: FlutterStandardWriter {
override func writeValue(_ value: Any) {
if let value = value as? AllNullableTypes {

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), do not edit directly.
// See also: https://pub.dev/packages/pigeon
import Foundation
@ -194,10 +194,10 @@ private class HostIntegrationCoreApiCodecReader: FlutterStandardReader {
return AllTypes.fromList(self.readValue() as! [Any])
default:
return super.readValue(ofType: type)
}
}
}
private class HostIntegrationCoreApiCodecWriter: FlutterStandardWriter {
override func writeValue(_ value: Any) {
if let value = value as? AllNullableTypes {
@ -776,10 +776,10 @@ private class FlutterIntegrationCoreApiCodecReader: FlutterStandardReader {
return AllTypes.fromList(self.readValue() as! [Any])
default:
return super.readValue(ofType: type)
}
}
}
private class FlutterIntegrationCoreApiCodecWriter: FlutterStandardWriter {
override func writeValue(_ value: Any) {
if let value = value as? AllNullableTypes {

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), do not edit directly.
// See also: https://pub.dev/packages/pigeon
#undef _HAS_EXCEPTIONS

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Autogenerated from Pigeon (v7.0.0), do not edit directly.
// Autogenerated from Pigeon (v7.0.1), do not edit directly.
// See also: https://pub.dev/packages/pigeon
#ifndef PIGEON_CORE_TESTS_GEN_H_

View File

@ -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: 7.0.0 # This must match the version in lib/generator_tools.dart
version: 7.0.1 # This must match the version in lib/generator_tools.dart
environment:
sdk: ">=2.12.0 <3.0.0"

View File

@ -36,8 +36,8 @@ void main() {
expect(code, contains('private @Nullable Long field1;'));
expect(
code,
contains(
'@NonNull private static ArrayList<Object> wrapError(@NonNull Throwable exception)'));
contains(RegExp(
r'@NonNull\s*private static ArrayList<Object> wrapError\(@NonNull Throwable exception\)')));
});
test('gen one enum', () {
@ -386,7 +386,7 @@ void main() {
generator.generate(javaOptions, root, sink);
final String code = sink.toString();
expect(code, contains('doSomething(Reply<Output>'));
expect(code, contains('channel.send(null'));
expect(code, contains(RegExp(r'channel.send\(\s*null')));
});
test('gen list', () {
@ -469,7 +469,7 @@ void main() {
expect(
code,
contains(
'(nested == null) ? null : Nested.fromList((ArrayList<Object>)nested)'));
'(nested == null) ? null : Nested.fromList((ArrayList<Object>) nested)'));
expect(code, contains('add((nested == null) ? null : nested.toList());'));
});
@ -613,7 +613,7 @@ void main() {
expect(
code,
contains(
'pigeonResult.setEnum1(enum1 == null ? null : Enum1.values()[(int)enum1])'));
'pigeonResult.setEnum1(enum1 == null ? null : Enum1.values()[(int) enum1])'));
});
test('primitive enum host', () {
@ -644,7 +644,7 @@ void main() {
expect(
code,
contains(
'Foo fooArg = args.get(0) == null ? null : Foo.values()[(int)args.get(0)];'));
'Foo fooArg = args.get(0) == null ? null : Foo.values()[(int) args.get(0)];'));
});
Iterable<String> makeIterable(String string) sync* {
@ -859,7 +859,7 @@ void main() {
expect(
code,
contains(
'Long output = channelReply == null ? null : ((Number)channelReply).longValue();'));
'Long output = channelReply == null ? null : ((Number) channelReply).longValue();'));
});
test('host multiple args', () {
@ -888,10 +888,10 @@ void main() {
final String code = sink.toString();
expect(code, contains('class Messages'));
expect(code, contains('Long add(@NonNull Long x, @NonNull Long y)'));
expect(
code, contains('ArrayList<Object> args = (ArrayList<Object>)message;'));
expect(code, contains('Number xArg = (Number)args.get(0)'));
expect(code, contains('Number yArg = (Number)args.get(1)'));
expect(code,
contains('ArrayList<Object> args = (ArrayList<Object>) message;'));
expect(code, contains('Number xArg = (Number) args.get(0)'));
expect(code, contains('Number yArg = (Number) args.get(1)'));
expect(
code,
contains(
@ -954,8 +954,8 @@ void main() {
'public void add(@NonNull Long xArg, @NonNull Long yArg, Reply<Long> callback)'));
expect(
code,
contains(
'channel.send(new ArrayList<Object>(Arrays.asList(xArg, yArg)), channelReply ->'));
contains(RegExp(
r'channel.send\(\s*new ArrayList<Object>\(Arrays.asList\(xArg, yArg\)\),\s*channelReply ->')));
});
test('flutter single args', () {
@ -980,8 +980,8 @@ void main() {
final String code = sink.toString();
expect(
code,
contains(
'channel.send(new ArrayList<Object>(Collections.singletonList(xArg)), channelReply ->'));
contains(RegExp(
r'channel.send\(\s*new ArrayList<Object>\(Collections.singletonList\(xArg\)\),\s*channelReply ->')));
});
test('return nullable host', () {
@ -1005,7 +1005,7 @@ void main() {
const JavaGenerator generator = JavaGenerator();
generator.generate(javaOptions, root, sink);
final String code = sink.toString();
expect(code, contains('@Nullable Long doit();'));
expect(code, contains(RegExp(r'@Nullable\s*Long doit\(\);')));
});
test('return nullable host async', () {
@ -1125,8 +1125,8 @@ void main() {
'BinaryMessenger.TaskQueue taskQueue = binaryMessenger.makeBackgroundTaskQueue();'));
expect(
code,
contains(
'new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.Api.doit", getCodec(), taskQueue)'));
contains(RegExp(
r'new BasicMessageChannel<>\(\s*binaryMessenger, "dev.flutter.pigeon.Api.doit", getCodec\(\), taskQueue\)')));
});
test('generated annotation', () {

View File

@ -801,7 +801,7 @@ void main() {
);
generator.generate(generatorOptions, root, sink);
final String code = sink.toString();
expect(code, contains('completion:(void(^)(NSError *_Nullable))'));
expect(code, contains('completion:(void (^)(NSError *_Nullable))'));
});
test('gen flutter void return source', () {
@ -836,7 +836,7 @@ void main() {
);
generator.generate(generatorOptions, root, sink);
final String code = sink.toString();
expect(code, contains('completion:(void(^)(NSError *_Nullable))'));
expect(code, contains('completion:(void (^)(NSError *_Nullable))'));
expect(code, contains('completion(nil)'));
});
@ -927,7 +927,7 @@ void main() {
expect(
code,
contains(
'(void)doSomethingWithCompletion:(void(^)(ABCOutput *_Nullable, NSError *_Nullable))completion'));
'(void)doSomethingWithCompletion:(void (^)(ABCOutput *_Nullable, NSError *_Nullable))completion'));
});
test('gen flutter void arg source', () {
@ -959,7 +959,7 @@ void main() {
expect(
code,
contains(
'(void)doSomethingWithCompletion:(void(^)(ABCOutput *_Nullable, NSError *_Nullable))completion'));
'(void)doSomethingWithCompletion:(void (^)(ABCOutput *_Nullable, NSError *_Nullable))completion'));
expect(code, contains('channel sendMessage:nil'));
});
@ -1066,7 +1066,7 @@ void main() {
expect(code, contains('(NSDictionary<NSString *, id> *)foo'));
});
test('async void(input) HostApi header', () {
test('async void (input) HostApi header', () {
final Root root = Root(apis: <Api>[
Api(name: 'Api', location: ApiLocation.host, methods: <Method>[
Method(
@ -1107,7 +1107,7 @@ void main() {
expect(
code,
contains(
'(void)doSomethingInput:(ABCInput *)input completion:(void(^)(FlutterError *_Nullable))completion'));
'(void)doSomethingInput:(ABCInput *)input completion:(void (^)(FlutterError *_Nullable))completion'));
});
test('async output(input) HostApi header', () {
@ -1152,7 +1152,7 @@ void main() {
expect(
code,
contains(
'(void)doSomethingInput:(ABCInput *)input completion:(void(^)(ABCOutput *_Nullable, FlutterError *_Nullable))completion'));
'(void)doSomethingInput:(ABCInput *)input completion:(void (^)(ABCOutput *_Nullable, FlutterError *_Nullable))completion'));
});
test('async output(void) HostApi header', () {
@ -1185,10 +1185,10 @@ void main() {
expect(
code,
contains(
'(void)doSomethingWithCompletion:(void(^)(ABCOutput *_Nullable, FlutterError *_Nullable))completion'));
'(void)doSomethingWithCompletion:(void (^)(ABCOutput *_Nullable, FlutterError *_Nullable))completion'));
});
test('async void(void) HostApi header', () {
test('async void (void) HostApi header', () {
final Root root = Root(apis: <Api>[
Api(name: 'Api', location: ApiLocation.host, methods: <Method>[
Method(
@ -1211,7 +1211,7 @@ void main() {
expect(
code,
contains(
'(void)doSomethingWithCompletion:(void(^)(FlutterError *_Nullable))completion'));
'(void)doSomethingWithCompletion:(void (^)(FlutterError *_Nullable))completion'));
});
test('async output(input) HostApi source', () {
@ -1259,7 +1259,7 @@ void main() {
'[api doSomething:arg0 completion:^(ABCOutput *_Nullable output, FlutterError *_Nullable error) {'));
});
test('async void(input) HostApi source', () {
test('async void (input) HostApi source', () {
final Root root = Root(apis: <Api>[
Api(name: 'Api', location: ApiLocation.host, methods: <Method>[
Method(
@ -1303,7 +1303,7 @@ void main() {
'[api doSomethingFoo:arg_foo completion:^(FlutterError *_Nullable error) {'));
});
test('async void(void) HostApi source', () {
test('async void (void) HostApi source', () {
final Root root = Root(apis: <Api>[
Api(name: 'Api', location: ApiLocation.host, methods: <Method>[
Method(
@ -1655,7 +1655,7 @@ void main() {
generator.generate(generatorOptions, root, sink);
final String code = sink.toString();
expect(
code, contains('doitWithCompletion:(void(^)(NSArray<NSNumber *> *'));
code, contains('doitWithCompletion:(void (^)(NSArray<NSNumber *> *'));
}
{
final StringBuffer sink = StringBuffer();
@ -1669,7 +1669,7 @@ void main() {
generator.generate(generatorOptions, root, sink);
final String code = sink.toString();
expect(
code, contains('doitWithCompletion:(void(^)(NSArray<NSNumber *> *'));
code, contains('doitWithCompletion:(void (^)(NSArray<NSNumber *> *'));
}
});
@ -1763,7 +1763,7 @@ void main() {
expect(
code,
contains(
'- (void)addX:(NSNumber *)x y:(NSNumber *)y completion:(void(^)(NSNumber *_Nullable, FlutterError *_Nullable))completion;'));
'- (void)addX:(NSNumber *)x y:(NSNumber *)y completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion;'));
}
{
final StringBuffer sink = StringBuffer();
@ -1818,7 +1818,7 @@ void main() {
expect(
code,
contains(
'- (void)addX:(NSNumber *)x y:(NSNumber *)y completion:(void(^)(NSNumber *_Nullable, NSError *_Nullable))completion;'));
'- (void)addX:(NSNumber *)x y:(NSNumber *)y completion:(void (^)(NSNumber *_Nullable, NSError *_Nullable))completion;'));
}
{
final StringBuffer sink = StringBuffer();
@ -1834,7 +1834,7 @@ void main() {
expect(
code,
contains(
'- (void)addX:(NSNumber *)arg_x y:(NSNumber *)arg_y completion:(void(^)(NSNumber *_Nullable, NSError *_Nullable))completion {'));
'- (void)addX:(NSNumber *)arg_x y:(NSNumber *)arg_y completion:(void (^)(NSNumber *_Nullable, NSError *_Nullable))completion {'));
expect(
code,
contains(