diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md index 2af203239b6..33c5fabb787 100644 --- a/packages/pigeon/CHANGELOG.md +++ b/packages/pigeon/CHANGELOG.md @@ -1,3 +1,19 @@ +## 5.0.4 + +* Adds writeEnum method to Generator classes. + +## 5.0.3 + +* Adds writeEnum method to Generator classes. + +## 5.0.2 + +* Adds writeImports method to Generator classes. + +## 5.0.1 + +* Adds writeHeaders method to Generator classes and updates tests to use new Generators. + ## 5.0.0 * Creates new Generator classes for each language. diff --git a/packages/pigeon/lib/cpp_generator.dart b/packages/pigeon/lib/cpp_generator.dart index cddefacfc79..4c5ca20c0c4 100644 --- a/packages/pigeon/lib/cpp_generator.dart +++ b/packages/pigeon/lib/cpp_generator.dart @@ -75,17 +75,479 @@ class CppGenerator extends Generator> { /// Instantiates a Cpp Generator. CppGenerator(); - /// Generates Cpp files with specified [OutputFileOptions] + /// Generates Cpp header files with specified [CppOptions] @override - void generate(OutputFileOptions languageOptions, Root root, + void generate(OutputFileOptions generatorOptions, Root root, StringSink sink) { - final FileType fileType = languageOptions.fileType; - assert(fileType == FileType.header || fileType == FileType.source); + final FileType fileType = generatorOptions.fileType; + assert(generatorOptions.fileType == FileType.header || + generatorOptions.fileType == FileType.source); + + final Indent indent = Indent(sink); + writeFilePrologue(generatorOptions, root, sink, indent); + writeFileImports(generatorOptions, root, sink, indent); + + for (final Enum anEnum in root.enums) { + writeEnum(generatorOptions, root, sink, indent, anEnum); + } + + indent.addln(''); + if (generatorOptions.fileType == FileType.header) { + _writeErrorOr(indent, friends: root.apis.map((Api api) => api.name)); + } + for (final Class klass in root.classes) { + writeDataClass(generatorOptions, root, sink, indent, klass); + } + if (generatorOptions.fileType == FileType.header) { + generateCppHeader(generatorOptions.languageOptions, root, sink, indent); + } else { + generateCppSource(generatorOptions.languageOptions, root, sink, indent); + } + } + + @override + void writeFilePrologue(OutputFileOptions generatorOptions, + Root root, StringSink sink, Indent indent) { + final FileType fileType = generatorOptions.fileType; + if (fileType == FileType.header) { + _writeCppHeaderPrologue(generatorOptions, root, sink, indent); + } else { + _writeCppSourcePrologue(generatorOptions, root, sink, indent); + } + } + + @override + void writeFileImports(OutputFileOptions generatorOptions, + Root root, StringSink sink, Indent indent) { + final FileType fileType = generatorOptions.fileType; if (fileType == FileType.header) { - generateCppHeader(languageOptions.languageOptions, root, sink); + _writeCppHeaderImports(generatorOptions, root, sink, indent); } else { - generateCppSource(languageOptions.languageOptions, root, sink); + _writeCppSourceImports(generatorOptions, root, sink, indent); + } + } + + @override + void writeEnum(OutputFileOptions generatorOptions, Root root, + StringSink sink, Indent indent, Enum anEnum) { + final FileType fileType = generatorOptions.fileType; + if (fileType == FileType.header) { + _writeCppHeaderEnum(generatorOptions, root, sink, indent, anEnum); + } + } + + @override + void writeDataClass(OutputFileOptions generatorOptions, Root root, + StringSink sink, Indent indent, Class klass) { + if (generatorOptions.fileType == FileType.header) { + // When generating for a Pigeon unit test, add a test fixture friend class to + // allow unit testing private methods, since testing serialization via public + // methods is essentially an end-to-end test. + String? testFixtureClass; + if (generatorOptions.languageOptions.namespace?.endsWith('_pigeontest') ?? + false) { + testFixtureClass = + '${_pascalCaseFromSnakeCase(generatorOptions.languageOptions.namespace!.replaceAll('_pigeontest', ''))}Test'; + } + _writeCppHeaderDataClass(generatorOptions, root, sink, indent, klass, + testFriend: testFixtureClass); + } else { + _writeCppSourceDataClass(generatorOptions, root, sink, indent, klass); + } + } + + @override + void writeClassEncode( + OutputFileOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + _writeCppSourceClassEncode(generatorOptions.languageOptions, root, sink, + indent, klass, customClassNames, customEnumNames); + } + + @override + void writeClassDecode( + OutputFileOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + _writeCppSourceClassDecode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); + } + + /// Writes Cpp header file header to sink. + void _writeCppHeaderPrologue(OutputFileOptions generatorOptions, + Root root, StringSink sink, Indent indent) { + if (generatorOptions.languageOptions.copyrightHeader != null) { + addLines(indent, generatorOptions.languageOptions.copyrightHeader!, + linePrefix: '// '); + } + indent.writeln('$_commentPrefix $generatedCodeWarning'); + indent.writeln('$_commentPrefix $seeAlsoWarning'); + indent.addln(''); + } + + /// Writes Cpp header file imports to sink. + void _writeCppHeaderImports(OutputFileOptions generatorOptions, + Root root, StringSink sink, Indent indent) { + final String guardName = _getGuardName( + generatorOptions.languageOptions.headerIncludePath, + generatorOptions.languageOptions.namespace); + indent.writeln('#ifndef $guardName'); + indent.writeln('#define $guardName'); + + _writeSystemHeaderIncludeBlock(indent, [ + 'flutter/basic_message_channel.h', + 'flutter/binary_messenger.h', + 'flutter/encodable_value.h', + 'flutter/standard_message_codec.h', + ]); + indent.addln(''); + _writeSystemHeaderIncludeBlock(indent, [ + 'map', + 'string', + 'optional', + ]); + indent.addln(''); + if (generatorOptions.languageOptions.namespace != null) { + indent + .writeln('namespace ${generatorOptions.languageOptions.namespace} {'); + } + indent.addln(''); + if (generatorOptions.languageOptions.namespace?.endsWith('_pigeontest') ?? + false) { + final String testFixtureClass = + '${_pascalCaseFromSnakeCase(generatorOptions.languageOptions.namespace!.replaceAll('_pigeontest', ''))}Test'; + indent.writeln('class $testFixtureClass;'); + } + indent.addln(''); + indent.writeln('$_commentPrefix Generated class from Pigeon.'); + } + + /// Writes Cpp header enum to sink. + void _writeCppHeaderEnum(OutputFileOptions options, Root root, + StringSink sink, Indent indent, Enum anEnum) { + indent.writeln(''); + addDocumentationComments( + indent, anEnum.documentationComments, _docCommentSpec); + indent.write('enum class ${anEnum.name} '); + indent.scoped('{', '};', () { + enumerate(anEnum.members, (int index, final EnumMember member) { + addDocumentationComments( + indent, member.documentationComments, _docCommentSpec); + indent.writeln( + '${member.name} = $index${index == anEnum.members.length - 1 ? '' : ','}'); + }); + }); + } + + /// Writes the declaration for the custom class [klass]. + /// + /// See [_writeCppSourceDataClass] for the corresponding declaration. + /// This is intended to be added to the header. + void _writeCppHeaderDataClass(OutputFileOptions generatorOptions, + Root root, StringSink sink, Indent indent, Class klass, + {String? testFriend}) { + indent.addln(''); + + const List generatedMessages = [ + ' Generated class from Pigeon that represents data sent in messages.' + ]; + + addDocumentationComments( + indent, klass.documentationComments, _docCommentSpec, + generatorComments: generatedMessages); + + indent.write('class ${klass.name} '); + indent.scoped('{', '};', () { + indent.scoped(' public:', '', () { + indent.writeln('${klass.name}();'); + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + addDocumentationComments( + indent, field.documentationComments, _docCommentSpec); + final HostDatatype baseDatatype = getFieldHostDatatype( + field, + root.classes, + root.enums, + (TypeDeclaration x) => _baseCppTypeForBuiltinDartType(x)); + indent.writeln( + '${_getterReturnType(baseDatatype)} ${_makeGetterName(field)}() const;'); + indent.writeln( + 'void ${_makeSetterName(field)}(${_unownedArgumentType(baseDatatype)} value_arg);'); + if (field.type.isNullable) { + // Add a second setter that takes the non-nullable version of the + // argument for convenience, since setting literal values with the + // pointer version is non-trivial. + final HostDatatype nonNullType = _nonNullableType(baseDatatype); + indent.writeln( + 'void ${_makeSetterName(field)}(${_unownedArgumentType(nonNullType)} value_arg);'); + } + indent.addln(''); + } + }); + + indent.scoped(' private:', '', () { + indent.writeln('${klass.name}(const flutter::EncodableList& list);'); + indent.writeln('flutter::EncodableList ToEncodableList() const;'); + for (final Class friend in root.classes) { + if (friend != klass && + friend.fields.any( + (NamedType element) => element.type.baseName == klass.name)) { + indent.writeln('friend class ${friend.name};'); + } + } + for (final Api api in root.apis) { + // TODO(gaaclarke): Find a way to be more precise with our + // friendships. + indent.writeln('friend class ${api.name};'); + indent.writeln('friend class ${_getCodecSerializerName(api)};'); + } + if (testFriend != null) { + indent.writeln('friend class $testFriend;'); + } + + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + final HostDatatype hostDatatype = getFieldHostDatatype( + field, + root.classes, + root.enums, + (TypeDeclaration x) => _baseCppTypeForBuiltinDartType(x)); + indent.writeln( + '${_valueType(hostDatatype)} ${_makeInstanceVariableName(field)};'); + } + }); + }, nestCount: 0); + indent.writeln(''); + } + + /// Writes Cpp source file header to sink. + void _writeCppSourcePrologue(OutputFileOptions generatorOptions, + Root root, StringSink sink, Indent indent) { + if (generatorOptions.languageOptions.copyrightHeader != null) { + addLines(indent, generatorOptions.languageOptions.copyrightHeader!, + linePrefix: '// '); } + indent.writeln('$_commentPrefix $generatedCodeWarning'); + indent.writeln('$_commentPrefix $seeAlsoWarning'); + indent.addln(''); + indent.addln('#undef _HAS_EXCEPTIONS'); + indent.addln(''); + } + + /// Writes Cpp source file imports to sink. + void _writeCppSourceImports(OutputFileOptions generatorOptions, + Root root, StringSink sink, Indent indent) { + indent.writeln( + '#include "${generatorOptions.languageOptions.headerIncludePath}"'); + indent.addln(''); + _writeSystemHeaderIncludeBlock(indent, [ + 'flutter/basic_message_channel.h', + 'flutter/binary_messenger.h', + 'flutter/encodable_value.h', + 'flutter/standard_message_codec.h', + ]); + indent.addln(''); + _writeSystemHeaderIncludeBlock(indent, [ + 'map', + 'string', + 'optional', + ]); + indent.addln(''); + + if (generatorOptions.languageOptions.namespace != null) { + indent + .writeln('namespace ${generatorOptions.languageOptions.namespace} {'); + } + } + + void _writeCppSourceClassEncode( + CppOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + indent.write( + 'flutter::EncodableList ${klass.name}::ToEncodableList() const '); + indent.scoped('{', '}', () { + indent.scoped('return flutter::EncodableList{', '};', () { + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + final HostDatatype hostDatatype = getFieldHostDatatype( + field, + root.classes, + root.enums, + (TypeDeclaration x) => _baseCppTypeForBuiltinDartType(x)); + + final String instanceVariable = _makeInstanceVariableName(field); + + String encodableValue = ''; + if (!hostDatatype.isBuiltin && + customClassNames.contains(field.type.baseName)) { + final String operator = field.type.isNullable ? '->' : '.'; + encodableValue = + 'flutter::EncodableValue($instanceVariable${operator}ToEncodableList())'; + } else if (!hostDatatype.isBuiltin && + customEnumNames.contains(field.type.baseName)) { + final String nonNullValue = field.type.isNullable + ? '(*$instanceVariable)' + : instanceVariable; + encodableValue = 'flutter::EncodableValue((int)$nonNullValue)'; + } else { + final String operator = field.type.isNullable ? '*' : ''; + encodableValue = + 'flutter::EncodableValue($operator$instanceVariable)'; + } + + if (field.type.isNullable) { + encodableValue = + '$instanceVariable ? $encodableValue : flutter::EncodableValue()'; + } + + indent.writeln('$encodableValue,'); + } + }); + }); + indent.addln(''); + } + + void _writeCppSourceClassDecode( + OutputFileOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + indent.write( + '${klass.name}::${klass.name}(const flutter::EncodableList& list) '); + indent.scoped('{', '}', () { + enumerate(getFieldsInSerializationOrder(klass), + (int index, final NamedType field) { + final String instanceVariableName = _makeInstanceVariableName(field); + final String pointerFieldName = + '${_pointerPrefix}_${_makeVariableName(field)}'; + final String encodableFieldName = + '${_encodablePrefix}_${_makeVariableName(field)}'; + indent.writeln('auto& $encodableFieldName = list[$index];'); + if (customEnumNames.contains(field.type.baseName)) { + indent.writeln( + 'if (const int32_t* $pointerFieldName = std::get_if(&$encodableFieldName))\t$instanceVariableName = (${field.type.baseName})*$pointerFieldName;'); + } else { + final HostDatatype hostDatatype = getFieldHostDatatype( + field, + root.classes, + root.enums, + (TypeDeclaration x) => _baseCppTypeForBuiltinDartType(x)); + if (field.type.baseName == 'int') { + indent.format(''' +if (const int32_t* $pointerFieldName = std::get_if(&$encodableFieldName)) +\t$instanceVariableName = *$pointerFieldName; +else if (const int64_t* ${pointerFieldName}_64 = std::get_if(&$encodableFieldName)) +\t$instanceVariableName = *${pointerFieldName}_64;'''); + } else if (!hostDatatype.isBuiltin && + root.classes + .map((Class x) => x.name) + .contains(field.type.baseName)) { + indent.write( + 'if (const flutter::EncodableList* $pointerFieldName = std::get_if(&$encodableFieldName)) '); + indent.scoped('{', '}', () { + indent.writeln( + '$instanceVariableName = ${hostDatatype.datatype}(*$pointerFieldName);'); + }); + } else { + indent.write( + 'if (const ${hostDatatype.datatype}* $pointerFieldName = std::get_if<${hostDatatype.datatype}>(&$encodableFieldName)) '); + indent.scoped('{', '}', () { + indent.writeln('$instanceVariableName = *$pointerFieldName;'); + }); + } + } + }); + }); + indent.addln(''); + } + + void _writeCppSourceClassField(OutputFileOptions generatorOptions, + Root root, StringSink sink, Indent indent, Class klass, NamedType field) { + final HostDatatype hostDatatype = getFieldHostDatatype(field, root.classes, + root.enums, (TypeDeclaration x) => _baseCppTypeForBuiltinDartType(x)); + final String instanceVariableName = _makeInstanceVariableName(field); + final String qualifiedGetterName = + '${klass.name}::${_makeGetterName(field)}'; + final String qualifiedSetterName = + '${klass.name}::${_makeSetterName(field)}'; + final String returnExpression = hostDatatype.isNullable + ? '$instanceVariableName ? &(*$instanceVariableName) : nullptr' + : instanceVariableName; + + // Generates the string for a setter treating the type as [type], to allow + // generating multiple setter variants. + String makeSetter(HostDatatype type) { + const String setterArgumentName = 'value_arg'; + final String valueExpression = type.isNullable + ? '$setterArgumentName ? ${_valueType(type)}(*$setterArgumentName) : std::nullopt' + : setterArgumentName; + return 'void $qualifiedSetterName(${_unownedArgumentType(type)} $setterArgumentName) ' + '{ $instanceVariableName = $valueExpression; }'; + } + + indent.writeln( + '${_getterReturnType(hostDatatype)} $qualifiedGetterName() const ' + '{ return $returnExpression; }'); + indent.writeln(makeSetter(hostDatatype)); + if (hostDatatype.isNullable) { + // Write the non-nullable variant; see _writeCppHeaderDataClass. + final HostDatatype nonNullType = _nonNullableType(hostDatatype); + indent.writeln(makeSetter(nonNullType)); + } + + indent.addln(''); + } + + /// Writes the implementation for the custom class [klass]. + /// + /// See [_writeCppHeaderDataClass] for the corresponding declaration. + /// This is intended to be added to the implementation file. + void _writeCppSourceDataClass(OutputFileOptions generatorOptions, + Root root, StringSink sink, Indent indent, Class klass) { + final Set customClassNames = + root.classes.map((Class x) => x.name).toSet(); + final Set customEnumNames = + root.enums.map((Enum x) => x.name).toSet(); + + indent.addln(''); + indent.writeln('$_commentPrefix ${klass.name}'); + indent.addln(''); + + // Getters and setters. + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + _writeCppSourceClassField( + generatorOptions, root, sink, indent, klass, field); + } + + // Serialization. + writeClassEncode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); + + // Default constructor. + indent.writeln('${klass.name}::${klass.name}() {}'); + indent.addln(''); + + // Deserialization. + writeClassDecode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); } } @@ -213,230 +675,6 @@ $friendLines '''); } -/// Writes the declaration for the custom class [klass]. -/// -/// See [_writeDataClassImplementation] for the corresponding declaration. -/// This is intended to be added to the header. -void _writeDataClassDeclaration(Indent indent, Class klass, Root root, - {String? testFriend}) { - indent.addln(''); - - const List generatedMessages = [ - ' Generated class from Pigeon that represents data sent in messages.' - ]; - - addDocumentationComments(indent, klass.documentationComments, _docCommentSpec, - generatorComments: generatedMessages); - - indent.write('class ${klass.name} '); - indent.scoped('{', '};', () { - indent.scoped(' public:', '', () { - indent.writeln('${klass.name}();'); - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - addDocumentationComments( - indent, field.documentationComments, _docCommentSpec); - final HostDatatype baseDatatype = getFieldHostDatatype( - field, - root.classes, - root.enums, - (TypeDeclaration x) => _baseCppTypeForBuiltinDartType(x)); - indent.writeln( - '${_getterReturnType(baseDatatype)} ${_makeGetterName(field)}() const;'); - indent.writeln( - 'void ${_makeSetterName(field)}(${_unownedArgumentType(baseDatatype)} value_arg);'); - if (field.type.isNullable) { - // Add a second setter that takes the non-nullable version of the - // argument for convenience, since setting literal values with the - // pointer version is non-trivial. - final HostDatatype nonNullType = _nonNullableType(baseDatatype); - indent.writeln( - 'void ${_makeSetterName(field)}(${_unownedArgumentType(nonNullType)} value_arg);'); - } - indent.addln(''); - } - }); - - indent.scoped(' private:', '', () { - indent.writeln('${klass.name}(const flutter::EncodableList& list);'); - indent.writeln('flutter::EncodableList ToEncodableList() const;'); - for (final Class friend in root.classes) { - if (friend != klass && - friend.fields.any( - (NamedType element) => element.type.baseName == klass.name)) { - indent.writeln('friend class ${friend.name};'); - } - } - for (final Api api in root.apis) { - // TODO(gaaclarke): Find a way to be more precise with our - // friendships. - indent.writeln('friend class ${api.name};'); - indent.writeln('friend class ${_getCodecSerializerName(api)};'); - } - if (testFriend != null) { - indent.writeln('friend class $testFriend;'); - } - - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - final HostDatatype hostDatatype = getFieldHostDatatype( - field, - root.classes, - root.enums, - (TypeDeclaration x) => _baseCppTypeForBuiltinDartType(x)); - indent.writeln( - '${_valueType(hostDatatype)} ${_makeInstanceVariableName(field)};'); - } - }); - }, nestCount: 0); - indent.writeln(''); -} - -/// Writes the implementation for the custom class [klass]. -/// -/// See [_writeDataClassDeclaration] for the corresponding declaration. -/// This is intended to be added to the implementation file. -void _writeDataClassImplementation(Indent indent, Class klass, Root root) { - final Set rootClassNameSet = - root.classes.map((Class x) => x.name).toSet(); - final Set rootEnumNameSet = - root.enums.map((Enum x) => x.name).toSet(); - - indent.addln(''); - indent.writeln('$_commentPrefix ${klass.name}'); - indent.addln(''); - - // Getters and setters. - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - final HostDatatype hostDatatype = getFieldHostDatatype(field, root.classes, - root.enums, (TypeDeclaration x) => _baseCppTypeForBuiltinDartType(x)); - final String instanceVariableName = _makeInstanceVariableName(field); - final String qualifiedGetterName = - '${klass.name}::${_makeGetterName(field)}'; - final String qualifiedSetterName = - '${klass.name}::${_makeSetterName(field)}'; - final String returnExpression = hostDatatype.isNullable - ? '$instanceVariableName ? &(*$instanceVariableName) : nullptr' - : instanceVariableName; - - // Generates the string for a setter treating the type as [type], to allow - // generating multiple setter variants. - String makeSetter(HostDatatype type) { - const String setterArgumentName = 'value_arg'; - final String valueExpression = type.isNullable - ? '$setterArgumentName ? ${_valueType(type)}(*$setterArgumentName) : std::nullopt' - : setterArgumentName; - return 'void $qualifiedSetterName(${_unownedArgumentType(type)} $setterArgumentName) ' - '{ $instanceVariableName = $valueExpression; }'; - } - - indent.writeln( - '${_getterReturnType(hostDatatype)} $qualifiedGetterName() const ' - '{ return $returnExpression; }'); - indent.writeln(makeSetter(hostDatatype)); - if (hostDatatype.isNullable) { - // Write the non-nullable variant; see _writeDataClassDeclaration. - final HostDatatype nonNullType = _nonNullableType(hostDatatype); - indent.writeln(makeSetter(nonNullType)); - } - - indent.addln(''); - } - - // Serialization. - indent - .write('flutter::EncodableList ${klass.name}::ToEncodableList() const '); - indent.scoped('{', '}', () { - indent.scoped('return flutter::EncodableList{', '};', () { - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - final HostDatatype hostDatatype = getFieldHostDatatype( - field, - root.classes, - root.enums, - (TypeDeclaration x) => _baseCppTypeForBuiltinDartType(x)); - - final String instanceVariable = _makeInstanceVariableName(field); - - String encodableValue = ''; - if (!hostDatatype.isBuiltin && - rootClassNameSet.contains(field.type.baseName)) { - final String operator = field.type.isNullable ? '->' : '.'; - encodableValue = - 'flutter::EncodableValue($instanceVariable${operator}ToEncodableList())'; - } else if (!hostDatatype.isBuiltin && - rootEnumNameSet.contains(field.type.baseName)) { - final String nonNullValue = - field.type.isNullable ? '(*$instanceVariable)' : instanceVariable; - encodableValue = 'flutter::EncodableValue((int)$nonNullValue)'; - } else { - final String operator = field.type.isNullable ? '*' : ''; - encodableValue = - 'flutter::EncodableValue($operator$instanceVariable)'; - } - - if (field.type.isNullable) { - encodableValue = - '$instanceVariable ? $encodableValue : flutter::EncodableValue()'; - } - - indent.writeln('$encodableValue,'); - } - }); - }); - indent.addln(''); - - // Default constructor. - indent.writeln('${klass.name}::${klass.name}() {}'); - indent.addln(''); - - // Deserialization. - indent.write( - '${klass.name}::${klass.name}(const flutter::EncodableList& list) '); - indent.scoped('{', '}', () { - enumerate(getFieldsInSerializationOrder(klass), - (int index, final NamedType field) { - final String instanceVariableName = _makeInstanceVariableName(field); - final String pointerFieldName = - '${_pointerPrefix}_${_makeVariableName(field)}'; - final String encodableFieldName = - '${_encodablePrefix}_${_makeVariableName(field)}'; - indent.writeln('auto& $encodableFieldName = list[$index];'); - if (rootEnumNameSet.contains(field.type.baseName)) { - indent.writeln( - 'if (const int32_t* $pointerFieldName = std::get_if(&$encodableFieldName))\t$instanceVariableName = (${field.type.baseName})*$pointerFieldName;'); - } else { - final HostDatatype hostDatatype = getFieldHostDatatype( - field, - root.classes, - root.enums, - (TypeDeclaration x) => _baseCppTypeForBuiltinDartType(x)); - if (field.type.baseName == 'int') { - indent.format(''' -if (const int32_t* $pointerFieldName = std::get_if(&$encodableFieldName)) -\t$instanceVariableName = *$pointerFieldName; -else if (const int64_t* ${pointerFieldName}_64 = std::get_if(&$encodableFieldName)) -\t$instanceVariableName = *${pointerFieldName}_64;'''); - } else if (!hostDatatype.isBuiltin && - root.classes - .map((Class x) => x.name) - .contains(field.type.baseName)) { - indent.write( - 'if (const flutter::EncodableList* $pointerFieldName = std::get_if(&$encodableFieldName)) '); - indent.scoped('{', '}', () { - indent.writeln( - '$instanceVariableName = ${hostDatatype.datatype}(*$pointerFieldName);'); - }); - } else { - indent.write( - 'if (const ${hostDatatype.datatype}* $pointerFieldName = std::get_if<${hostDatatype.datatype}>(&$encodableFieldName)) '); - indent.scoped('{', '}', () { - indent.writeln('$instanceVariableName = *$pointerFieldName;'); - }); - } - } - }); - }); - indent.addln(''); -} - void _writeHostApiHeader(Indent indent, Api api, Root root) { assert(api.location == ApiLocation.host); @@ -1051,76 +1289,8 @@ void _writeSystemHeaderIncludeBlock(Indent indent, List headers) { /// Generates the ".h" file for the AST represented by [root] to [sink] with the /// provided [options] and [headerFileName]. -void generateCppHeader(CppOptions options, Root root, StringSink sink) { - final String? headerFileName = options.headerOutPath; - final Indent indent = Indent(sink); - if (options.copyrightHeader != null) { - addLines(indent, options.copyrightHeader!, linePrefix: '// '); - } - indent.writeln('$_commentPrefix $generatedCodeWarning'); - indent.writeln('$_commentPrefix $seeAlsoWarning'); - indent.addln(''); - final String guardName = _getGuardName(headerFileName, options.namespace); - indent.writeln('#ifndef $guardName'); - indent.writeln('#define $guardName'); - - _writeSystemHeaderIncludeBlock(indent, [ - 'flutter/basic_message_channel.h', - 'flutter/binary_messenger.h', - 'flutter/encodable_value.h', - 'flutter/standard_message_codec.h', - ]); - indent.addln(''); - _writeSystemHeaderIncludeBlock(indent, [ - 'map', - 'string', - 'optional', - ]); - indent.addln(''); - - if (options.namespace != null) { - indent.writeln('namespace ${options.namespace} {'); - } - - // When generating for a Pigeon unit test, add a test fixture friend class to - // allow unit testing private methods, since testing serialization via public - // methods is essentially an end-to-end test. - String? testFixtureClass; - if (options.namespace?.endsWith('_pigeontest') ?? false) { - testFixtureClass = - '${_pascalCaseFromSnakeCase(options.namespace!.replaceAll('_pigeontest', ''))}Test'; - indent.writeln('class $testFixtureClass;'); - } - - indent.addln(''); - indent.writeln('$_commentPrefix Generated class from Pigeon.'); - - for (final Enum anEnum in root.enums) { - indent.writeln(''); - addDocumentationComments( - indent, anEnum.documentationComments, _docCommentSpec); - indent.write('enum class ${anEnum.name} '); - indent.scoped('{', '};', () { - enumerate(anEnum.members, (int index, final EnumMember member) { - addDocumentationComments( - indent, member.documentationComments, _docCommentSpec); - indent.writeln( - '${member.name} = $index${index == anEnum.members.length - 1 ? '' : ','}'); - }); - }); - } - - indent.addln(''); - - _writeErrorOr(indent, friends: root.apis.map((Api api) => api.name)); - - for (final Class klass in root.classes) { - _writeDataClassDeclaration(indent, klass, root, - // Add a hook for unit testing data classes when using the namespace - // used by pigeon tests. - testFriend: testFixtureClass); - } - +void generateCppHeader( + CppOptions options, Root root, StringSink sink, Indent indent) { for (final Api api in root.apis) { if (getCodecClasses(api, root).isNotEmpty) { _writeCodecHeader(indent, api, root); @@ -1136,47 +1306,15 @@ void generateCppHeader(CppOptions options, Root root, StringSink sink) { if (options.namespace != null) { indent.writeln('} // namespace ${options.namespace}'); } - + final String guardName = + _getGuardName(options.headerIncludePath, options.namespace); indent.writeln('#endif // $guardName'); } /// Generates the ".cpp" file for the AST represented by [root] to [sink] with the /// provided [options]. -void generateCppSource(CppOptions options, Root root, StringSink sink) { - final Indent indent = Indent(sink); - if (options.copyrightHeader != null) { - addLines(indent, options.copyrightHeader!, linePrefix: '// '); - } - indent.writeln('$_commentPrefix $generatedCodeWarning'); - indent.writeln('$_commentPrefix $seeAlsoWarning'); - indent.addln(''); - indent.addln('#undef _HAS_EXCEPTIONS'); - indent.addln(''); - - indent.writeln('#include "${options.headerIncludePath}"'); - indent.addln(''); - _writeSystemHeaderIncludeBlock(indent, [ - 'flutter/basic_message_channel.h', - 'flutter/binary_messenger.h', - 'flutter/encodable_value.h', - 'flutter/standard_message_codec.h', - ]); - indent.addln(''); - _writeSystemHeaderIncludeBlock(indent, [ - 'map', - 'string', - 'optional', - ]); - indent.addln(''); - - if (options.namespace != null) { - indent.writeln('namespace ${options.namespace} {'); - } - - for (final Class klass in root.classes) { - _writeDataClassImplementation(indent, klass, root); - } - +void generateCppSource( + CppOptions options, Root root, StringSink sink, Indent indent) { for (final Api api in root.apis) { if (getCodecClasses(api, root).isNotEmpty) { _writeCodecSource(indent, api, root); diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart index e6f685052f1..f930979cc8d 100644 --- a/packages/pigeon/lib/dart_generator.dart +++ b/packages/pigeon/lib/dart_generator.dart @@ -77,20 +77,225 @@ class DartGenerator extends Generator { /// Generates Dart files with specified [DartOptions] @override - void generate(DartOptions languageOptions, Root root, StringSink sink, - {FileType fileType = FileType.na}) { - assert(fileType == FileType.na); - generateDart(languageOptions, root, sink); + void generate(DartOptions generatorOptions, Root root, StringSink sink) { + final Indent indent = Indent(sink); + + writeFilePrologue(generatorOptions, root, sink, indent); + writeFileImports(generatorOptions, root, sink, indent); + for (final Enum anEnum in root.enums) { + writeEnum(generatorOptions, root, sink, indent, anEnum); + } + for (final Class klass in root.classes) { + indent.writeln(''); + writeDataClass(generatorOptions, root, sink, indent, klass); + } + + generateDart(generatorOptions, root, sink, indent); + } + + @override + void writeFilePrologue( + DartOptions generatorOptions, Root root, StringSink sink, Indent indent) { + if (generatorOptions.copyrightHeader != null) { + addLines(indent, generatorOptions.copyrightHeader!, linePrefix: '// '); + } + indent.writeln('// $generatedCodeWarning'); + indent.writeln('// $seeAlsoWarning'); + 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(''); + } + + @override + void writeFileImports( + DartOptions generatorOptions, Root root, StringSink sink, Indent indent) { + indent.writeln("import 'dart:async';"); + indent.writeln( + "import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;", + ); + indent.addln(''); + indent.writeln( + "import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;"); + indent.writeln("import 'package:flutter/services.dart';"); + } + + @override + void writeEnum(DartOptions generatorOptions, Root root, StringSink sink, + Indent indent, Enum anEnum) { + indent.writeln(''); + addDocumentationComments( + indent, anEnum.documentationComments, _docCommentSpec); + indent.write('enum ${anEnum.name} '); + indent.scoped('{', '}', () { + for (final EnumMember member in anEnum.members) { + addDocumentationComments( + indent, member.documentationComments, _docCommentSpec); + indent.writeln('${member.name},'); + } + }); + } + + @override + void writeDataClass(DartOptions generatorOptions, Root root, StringSink sink, + Indent indent, Class klass) { + final Set customClassNames = + root.classes.map((Class x) => x.name).toSet(); + final Set customEnumNames = + root.enums.map((Enum x) => x.name).toSet(); + void writeConstructor() { + indent.write(klass.name); + indent.scoped('({', '});', () { + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + final String required = field.type.isNullable ? '' : 'required '; + indent.writeln('${required}this.${field.name},'); + } + }); + } + + addDocumentationComments( + indent, klass.documentationComments, _docCommentSpec); + + indent.write('class ${klass.name} '); + indent.scoped('{', '}', () { + writeConstructor(); + indent.addln(''); + 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(''); + } + writeClassEncode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); + indent.writeln(''); + writeClassDecode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); + }); + } + + @override + void writeClassEncode( + DartOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + indent.write('Object encode() '); + indent.scoped('{', '}', () { + indent.write( + 'return ', + ); + indent.scoped('[', '];', () { + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + final String conditional = field.type.isNullable ? '?' : ''; + if (customClassNames.contains(field.type.baseName)) { + indent.writeln( + '${field.name}$conditional.encode(),', + ); + } else if (customEnumNames.contains(field.type.baseName)) { + indent.writeln( + '${field.name}$conditional.index,', + ); + } else { + indent.writeln('${field.name},'); + } + } + }); + }); + } + + @override + void writeClassDecode( + DartOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + void writeValueDecode(NamedType field, int index) { + final String resultAt = 'result[$index]'; + if (customClassNames.contains(field.type.baseName)) { + final String nonNullValue = + '${field.type.baseName}.decode($resultAt! as List)'; + indent.format( + field.type.isNullable + ? ''' +$resultAt != null +\t\t? $nonNullValue +\t\t: null''' + : nonNullValue, + leadingSpace: false, + trailingNewline: false); + } else if (customEnumNames.contains(field.type.baseName)) { + final String nonNullValue = + '${field.type.baseName}.values[$resultAt! as int]'; + indent.format( + field.type.isNullable + ? ''' +$resultAt != null +\t\t? $nonNullValue +\t\t: null''' + : nonNullValue, + leadingSpace: false, + trailingNewline: false); + } else if (field.type.typeArguments.isNotEmpty) { + final String genericType = _makeGenericTypeArguments(field.type); + final String castCall = _makeGenericCastCall(field.type); + final String castCallPrefix = field.type.isNullable ? '?' : '!'; + indent.add( + '($resultAt as $genericType?)$castCallPrefix$castCall', + ); + } else { + final String genericdType = _addGenericTypesNullable(field.type); + if (field.type.isNullable) { + indent.add( + '$resultAt as $genericdType', + ); + } else { + indent.add( + '$resultAt! as $genericdType', + ); + } + } + } + + indent.write( + 'static ${klass.name} decode(Object result) ', + ); + indent.scoped('{', '}', () { + indent.writeln('result as List;'); + indent.write('return ${klass.name}'); + indent.scoped('(', ');', () { + enumerate(getFieldsInSerializationOrder(klass), + (int index, final NamedType field) { + indent.write('${field.name}: '); + writeValueDecode(field, index); + indent.addln(','); + }); + }); + }); } /// Generates Dart files for testing with specified [DartOptions] - void generateTest(DartOptions languageOptions, Root root, StringSink sink) { - final String sourceOutPath = languageOptions.sourceOutPath ?? ''; - final String testOutPath = languageOptions.testOutPath ?? ''; + void generateTest(DartOptions generatorOptions, Root root, StringSink sink) { + final Indent indent = Indent(sink); + final String sourceOutPath = generatorOptions.sourceOutPath ?? ''; + final String testOutPath = generatorOptions.testOutPath ?? ''; + writeTestHeader(generatorOptions, root, sink, indent); + writeTestImports(generatorOptions, root, sink, indent); generateTestDart( - languageOptions, + generatorOptions, root, sink, + indent, sourceOutPath: sourceOutPath, testOutPath: testOutPath, ); @@ -503,173 +708,7 @@ String _addGenericTypesNullable(TypeDeclaration type) { /// Generates Dart source code for the given AST represented by [root], /// outputting the code to [sink]. -void generateDart(DartOptions opt, Root root, StringSink sink) { - final List customClassNames = - root.classes.map((Class x) => x.name).toList(); - final List customEnumNames = - root.enums.map((Enum x) => x.name).toList(); - final Indent indent = Indent(sink); - - void writeHeader() { - if (opt.copyrightHeader != null) { - addLines(indent, opt.copyrightHeader!, linePrefix: '// '); - } - indent.writeln('// $generatedCodeWarning'); - indent.writeln('// $seeAlsoWarning'); - 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', - ); - } - - void writeEnums() { - for (final Enum anEnum in root.enums) { - indent.writeln(''); - addDocumentationComments( - indent, anEnum.documentationComments, _docCommentSpec); - indent.write('enum ${anEnum.name} '); - indent.scoped('{', '}', () { - for (final EnumMember member in anEnum.members) { - addDocumentationComments( - indent, member.documentationComments, _docCommentSpec); - indent.writeln('${member.name},'); - } - }); - } - } - - void writeImports() { - indent.writeln("import 'dart:async';"); - indent.writeln( - "import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;", - ); - indent.addln(''); - indent.writeln( - "import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;"); - indent.writeln("import 'package:flutter/services.dart';"); - } - - void writeDataClass(Class klass) { - void writeConstructor() { - indent.write(klass.name); - indent.scoped('({', '});', () { - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - final String required = field.type.isNullable ? '' : 'required '; - indent.writeln('${required}this.${field.name},'); - } - }); - } - - void writeEncode() { - indent.write('Object encode() '); - indent.scoped('{', '}', () { - indent.write( - 'return ', - ); - indent.scoped('[', '];', () { - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - final String conditional = field.type.isNullable ? '?' : ''; - if (customClassNames.contains(field.type.baseName)) { - indent.writeln( - '${field.name}$conditional.encode(),', - ); - } else if (customEnumNames.contains(field.type.baseName)) { - indent.writeln( - '${field.name}$conditional.index,', - ); - } else { - indent.writeln('${field.name},'); - } - } - }); - }); - } - - void writeDecode() { - void writeValueDecode(NamedType field, int index) { - final String resultAt = 'result[$index]'; - if (customClassNames.contains(field.type.baseName)) { - final String nonNullValue = - '${field.type.baseName}.decode($resultAt! as List)'; - indent.format( - field.type.isNullable - ? ''' -$resultAt != null -\t\t? $nonNullValue -\t\t: null''' - : nonNullValue, - leadingSpace: false, - trailingNewline: false); - } else if (customEnumNames.contains(field.type.baseName)) { - final String nonNullValue = - '${field.type.baseName}.values[$resultAt! as int]'; - indent.format( - field.type.isNullable - ? ''' -$resultAt != null -\t\t? $nonNullValue -\t\t: null''' - : nonNullValue, - leadingSpace: false, - trailingNewline: false); - } else if (field.type.typeArguments.isNotEmpty) { - final String genericType = _makeGenericTypeArguments(field.type); - final String castCall = _makeGenericCastCall(field.type); - final String castCallPrefix = field.type.isNullable ? '?' : '!'; - indent.add( - '($resultAt as $genericType?)$castCallPrefix$castCall', - ); - } else { - final String genericdType = _addGenericTypesNullable(field.type); - if (field.type.isNullable) { - indent.add( - '$resultAt as $genericdType', - ); - } else { - indent.add( - '$resultAt! as $genericdType', - ); - } - } - } - - indent.write( - 'static ${klass.name} decode(Object result) ', - ); - indent.scoped('{', '}', () { - indent.writeln('result as List;'); - indent.write('return ${klass.name}'); - indent.scoped('(', ');', () { - enumerate(getFieldsInSerializationOrder(klass), - (int index, final NamedType field) { - indent.write('${field.name}: '); - writeValueDecode(field, index); - indent.addln(','); - }); - }); - }); - } - - addDocumentationComments( - indent, klass.documentationComments, _docCommentSpec); - - indent.write('class ${klass.name} '); - indent.scoped('{', '}', () { - writeConstructor(); - indent.addln(''); - 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(''); - } - writeEncode(); - indent.writeln(''); - writeDecode(); - }); - } - +void generateDart(DartOptions opt, Root root, StringSink sink, Indent indent) { void writeApi(Api api) { if (api.location == ApiLocation.host) { _writeHostApi(opt, indent, api, root); @@ -678,13 +717,6 @@ $resultAt != null } } - writeHeader(); - writeImports(); - writeEnums(); - for (final Class klass in root.classes) { - indent.writeln(''); - writeDataClass(klass); - } for (final Api api in root.apis) { indent.writeln(''); writeApi(api); @@ -740,18 +772,9 @@ String _posixify(String inputPath) { return context.fromUri(path.toUri(path.absolute(inputPath))); } -/// Generates Dart source code for test support libraries based on the given AST -/// represented by [root], outputting the code to [sink]. [sourceOutPath] is the -/// path of the generated dart code to be tested. [testOutPath] is where the -/// test code will be generated. -void generateTestDart( - DartOptions opt, - Root root, - StringSink sink, { - required String sourceOutPath, - required String testOutPath, -}) { - final Indent indent = Indent(sink); +/// Writes file header to sink. +void writeTestHeader( + DartOptions opt, Root root, StringSink sink, Indent indent) { if (opt.copyrightHeader != null) { addLines(indent, opt.copyrightHeader!, linePrefix: '// '); } @@ -761,6 +784,11 @@ void generateTestDart( '// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import', ); indent.writeln('// ignore_for_file: avoid_relative_lib_imports'); +} + +/// Writes file imports to sink. +void writeTestImports( + DartOptions opt, Root root, StringSink sink, Indent indent) { indent.writeln("import 'dart:async';"); indent.writeln( "import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List;", @@ -770,6 +798,20 @@ void generateTestDart( indent.writeln("import 'package:flutter/services.dart';"); indent.writeln("import 'package:flutter_test/flutter_test.dart';"); indent.writeln(''); +} + +/// Generates Dart source code for test support libraries based on the given AST +/// represented by [root], outputting the code to [sink]. [dartOutPath] is the +/// path of the generated dart code to be tested. [testOutPath] is where the +/// test code will be generated. +void generateTestDart( + DartOptions opt, + Root root, + StringSink sink, + Indent indent, { + required String sourceOutPath, + required String testOutPath, +}) { final String relativeDartPath = path.Context(style: path.Style.posix).relative( _posixify(sourceOutPath), diff --git a/packages/pigeon/lib/generator.dart b/packages/pigeon/lib/generator.dart index 02667e4a5c9..55356611f1b 100644 --- a/packages/pigeon/lib/generator.dart +++ b/packages/pigeon/lib/generator.dart @@ -3,11 +3,88 @@ // found in the LICENSE file. import 'ast.dart'; +import 'generator_tools.dart'; /// A superclass of generator classes. /// /// This provides the structure that is common across generators for different languages. abstract class Generator { - /// Generates files for specified language with specified [languageOptions] - void generate(T languageOptions, Root root, StringSink sink); + /// Generates files for specified language with specified [generatorOptions] + /// + /// This method, when overridden, should follow a generic structure that is currently: + /// 1. Create Indent + /// 2. Write File Headers + /// 3. Write Imports + /// 4. Write Enums + /// 5. Write Data Classes + /// 6. Write Apis + void generate( + T generatorOptions, + Root root, + StringSink sink, + ); + + /// Adds specified headers to file. + void writeFilePrologue( + T generatorOptions, + Root root, + StringSink sink, + Indent indent, + ); + + /// Adds specified imports to file. + void writeFileImports( + T generatorOptions, + Root root, + StringSink sink, + Indent indent, + ); + + /// Writes a single Enum to file. + void writeEnum( + T generatorOptions, + Root root, + StringSink sink, + Indent indent, + Enum anEnum, + ); + + /// Writes a single data class to file. + void writeDataClass( + T generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + ); + + /// Writes a single class encode method to file. + void writeClassEncode( + T generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ); + + /// Writes a single class decode method to file. + void writeClassDecode( + T generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ); + + // /// Writes a single Flutter Api to file. + // void writeFlutterApi(T generatorOptions, Root root, StringSink sink, + // Indent indent, FileType fileType, Api api,); + + // /// Writes a single Host Api to file. + // void writeHostApi(T generatorOptions, Root root, StringSink sink, + // Indent indent, FileType fileType, Api api,); } diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart index b1ee06b01e8..d6ef9703cf4 100644 --- a/packages/pigeon/lib/generator_tools.dart +++ b/packages/pigeon/lib/generator_tools.dart @@ -9,7 +9,7 @@ import 'dart:mirrors'; import 'ast.dart'; /// The current version of pigeon. This must match the version in pubspec.yaml. -const String pigeonVersion = '5.0.0'; +const String pigeonVersion = '5.0.4'; /// Read all the content from [stdin] to a String. String readStdin() { @@ -510,7 +510,7 @@ enum FileType { na, } -/// Options for [Generator]'s that have multiple output file types. +/// Options for [Generator]s that have multiple output file types. /// /// Specifies which file to write as well as wraps all language options. class OutputFileOptions { diff --git a/packages/pigeon/lib/java_generator.dart b/packages/pigeon/lib/java_generator.dart index daca63876d2..f3a4a9f1629 100644 --- a/packages/pigeon/lib/java_generator.dart +++ b/packages/pigeon/lib/java_generator.dart @@ -92,10 +92,265 @@ class JavaGenerator extends Generator { /// Generates Java files with specified [JavaOptions] @override - void generate(JavaOptions languageOptions, Root root, StringSink sink, - {FileType fileType = FileType.na}) { - assert(fileType == FileType.na); - generateJava(languageOptions, root, sink); + void generate(JavaOptions generatorOptions, Root root, StringSink sink) { + final Indent indent = Indent(sink); + + writeFilePrologue(generatorOptions, root, sink, indent); + writeFileImports(generatorOptions, root, sink, indent); + indent.writeln( + '$_docCommentPrefix Generated class from Pigeon.$_docCommentSuffix'); + indent.writeln( + '@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"})'); + if (generatorOptions.useGeneratedAnnotation ?? false) { + indent.writeln('@javax.annotation.Generated("dev.flutter.pigeon")'); + } + indent.write('public class ${generatorOptions.className!} '); + indent.scoped('{', '}', () { + for (final Enum anEnum in root.enums) { + indent.writeln(''); + writeEnum(generatorOptions, root, sink, indent, anEnum); + } + for (final Class klass in root.classes) { + indent.addln(''); + writeDataClass(generatorOptions, root, sink, indent, klass); + } + generateJava(generatorOptions, root, sink, indent); + }); + } + + @override + void writeFilePrologue( + JavaOptions generatorOptions, Root root, StringSink sink, Indent indent) { + if (generatorOptions.copyrightHeader != null) { + addLines(indent, generatorOptions.copyrightHeader!, linePrefix: '// '); + } + indent.writeln('// $generatedCodeWarning'); + indent.writeln('// $seeAlsoWarning'); + indent.addln(''); + } + + @override + void writeFileImports( + JavaOptions generatorOptions, Root root, StringSink sink, Indent indent) { + if (generatorOptions.package != null) { + indent.writeln('package ${generatorOptions.package};'); + } + indent.writeln('import android.util.Log;'); + indent.writeln('import androidx.annotation.NonNull;'); + indent.writeln('import androidx.annotation.Nullable;'); + indent.writeln('import io.flutter.plugin.common.BasicMessageChannel;'); + indent.writeln('import io.flutter.plugin.common.BinaryMessenger;'); + indent.writeln('import io.flutter.plugin.common.MessageCodec;'); + 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.Collections;'); + indent.writeln('import java.util.List;'); + indent.writeln('import java.util.Map;'); + indent.writeln('import java.util.HashMap;'); + indent.addln(''); + } + + @override + void writeEnum(JavaOptions generatorOptions, Root root, StringSink sink, + Indent indent, Enum anEnum) { + String camelToSnake(String camelCase) { + final RegExp regex = RegExp('([a-z])([A-Z]+)'); + return camelCase + .replaceAllMapped(regex, (Match m) => '${m[1]}_${m[2]}') + .toUpperCase(); + } + + addDocumentationComments( + indent, anEnum.documentationComments, _docCommentSpec); + + indent.write('public enum ${anEnum.name} '); + indent.scoped('{', '}', () { + 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.writeln('private final int index;'); + indent.write('private ${anEnum.name}(final int index) '); + indent.scoped('{', '}', () { + indent.writeln('this.index = index;'); + }); + }); + } + + @override + void writeDataClass(JavaOptions generatorOptions, Root root, StringSink sink, + Indent indent, Class klass) { + final Set customClassNames = + root.classes.map((Class x) => x.name).toSet(); + final Set customEnumNames = + root.enums.map((Enum x) => x.name).toSet(); + + const List generatedMessages = [ + ' Generated class from Pigeon that represents data sent in messages.' + ]; + addDocumentationComments( + indent, klass.documentationComments, _docCommentSpec, + generatorComments: generatedMessages); + + indent.write('public static class ${klass.name} '); + indent.scoped('{', '}', () { + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + _writeClassField(generatorOptions, root, sink, indent, field); + indent.addln(''); + } + + 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'); + indent.writeln('private ${klass.name}() {}'); + } + + _writeClassBuilder(generatorOptions, root, sink, indent, klass); + writeClassEncode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); + writeClassDecode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); + }); + } + + void _writeClassField(JavaOptions generatorOptions, Root root, + StringSink sink, Indent indent, NamedType field) { + final HostDatatype hostDatatype = getFieldHostDatatype(field, root.classes, + root.enums, (TypeDeclaration x) => _javaTypeForBuiltinDartType(x)); + final String nullability = field.type.isNullable ? '@Nullable' : '@NonNull'; + addDocumentationComments( + indent, field.documentationComments, _docCommentSpec); + + indent.writeln( + 'private $nullability ${hostDatatype.datatype} ${field.name};'); + indent.writeln( + 'public $nullability ${hostDatatype.datatype} ${_makeGetter(field)}() { return ${field.name}; }'); + indent.writeScoped( + 'public void ${_makeSetter(field)}($nullability ${hostDatatype.datatype} setterArg) {', + '}', () { + if (!field.type.isNullable) { + indent.writeScoped('if (setterArg == null) {', '}', () { + indent.writeln( + 'throw new IllegalStateException("Nonnull field \\"${field.name}\\" is null.");'); + }); + } + indent.writeln('this.${field.name} = setterArg;'); + }); + } + + void _writeClassBuilder( + JavaOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + ) { + indent.write('public static final class Builder '); + indent.scoped('{', '}', () { + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + final HostDatatype hostDatatype = getFieldHostDatatype( + field, + root.classes, + root.enums, + (TypeDeclaration x) => _javaTypeForBuiltinDartType(x)); + final String nullability = + field.type.isNullable ? '@Nullable' : '@NonNull'; + indent.writeln( + 'private @Nullable ${hostDatatype.datatype} ${field.name};'); + indent.writeScoped( + 'public @NonNull Builder ${_makeSetter(field)}($nullability ${hostDatatype.datatype} setterArg) {', + '}', () { + indent.writeln('this.${field.name} = setterArg;'); + indent.writeln('return this;'); + }); + } + indent.write('public @NonNull ${klass.name} build() '); + indent.scoped('{', '}', () { + const String returnVal = 'pigeonReturn'; + indent.writeln('${klass.name} $returnVal = new ${klass.name}();'); + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + indent.writeln('$returnVal.${_makeSetter(field)}(${field.name});'); + } + indent.writeln('return $returnVal;'); + }); + }); + } + + @override + void writeClassEncode( + JavaOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + indent.write('@NonNull ArrayList toList() '); + indent.scoped('{', '}', () { + indent.writeln( + 'ArrayList toListResult = new ArrayList(${klass.fields.length});'); + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + final HostDatatype hostDatatype = getFieldHostDatatype( + field, + root.classes, + root.enums, + (TypeDeclaration x) => _javaTypeForBuiltinDartType(x)); + String toWriteValue = ''; + final String fieldName = field.name; + if (!hostDatatype.isBuiltin && + customClassNames.contains(field.type.baseName)) { + toWriteValue = '($fieldName == null) ? null : $fieldName.toList()'; + } else if (!hostDatatype.isBuiltin && + customEnumNames.contains(field.type.baseName)) { + toWriteValue = '$fieldName == null ? null : $fieldName.index'; + } else { + toWriteValue = field.name; + } + indent.writeln('toListResult.add($toWriteValue);'); + } + indent.writeln('return toListResult;'); + }); + } + + @override + void writeClassDecode( + JavaOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + indent.write( + 'static @NonNull ${klass.name} fromList(@NonNull ArrayList list) '); + indent.scoped('{', '}', () { + const String result = 'pigeonResult'; + indent.writeln('${klass.name} $result = new ${klass.name}();'); + enumerate(getFieldsInSerializationOrder(klass), + (int index, final NamedType field) { + final String fieldVariable = field.name; + final String setter = _makeSetter(field); + indent.writeln('Object $fieldVariable = list.get($index);'); + if (customEnumNames.contains(field.type.baseName)) { + indent.writeln( + '$result.$setter(${_intToEnum(fieldVariable, field.type.baseName)});'); + } else { + indent.writeln( + '$result.$setter(${_castObject(field, root.classes, root.enums, fieldVariable)});'); + } + }); + indent.writeln('return $result;'); + }); } } @@ -538,207 +793,8 @@ String _castObject( /// Generates the ".java" file for the AST represented by [root] to [sink] with the /// provided [options]. -void generateJava(JavaOptions options, Root root, StringSink sink) { - final Set rootClassNameSet = - root.classes.map((Class x) => x.name).toSet(); - final Set rootEnumNameSet = - root.enums.map((Enum x) => x.name).toSet(); - final Indent indent = Indent(sink); - - void writeHeader() { - if (options.copyrightHeader != null) { - addLines(indent, options.copyrightHeader!, linePrefix: '// '); - } - indent.writeln('// $generatedCodeWarning'); - indent.writeln('// $seeAlsoWarning'); - } - - void writeImports() { - indent.writeln('import android.util.Log;'); - indent.writeln('import androidx.annotation.NonNull;'); - indent.writeln('import androidx.annotation.Nullable;'); - indent.writeln('import io.flutter.plugin.common.BasicMessageChannel;'); - indent.writeln('import io.flutter.plugin.common.BinaryMessenger;'); - indent.writeln('import io.flutter.plugin.common.MessageCodec;'); - 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.Collections;'); - indent.writeln('import java.util.List;'); - indent.writeln('import java.util.Map;'); - indent.writeln('import java.util.HashMap;'); - } - - String camelToSnake(String camelCase) { - final RegExp regex = RegExp('([a-z])([A-Z]+)'); - return camelCase - .replaceAllMapped(regex, (Match m) => '${m[1]}_${m[2]}') - .toUpperCase(); - } - - void writeEnum(Enum anEnum) { - addDocumentationComments( - indent, anEnum.documentationComments, _docCommentSpec); - - indent.write('public enum ${anEnum.name} '); - indent.scoped('{', '}', () { - 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.writeln('private final int index;'); - indent.write('private ${anEnum.name}(final int index) '); - indent.scoped('{', '}', () { - indent.writeln('this.index = index;'); - }); - }); - } - - void writeDataClass(Class klass) { - void writeField(NamedType field) { - final HostDatatype hostDatatype = getFieldHostDatatype( - field, - root.classes, - root.enums, - (TypeDeclaration x) => _javaTypeForBuiltinDartType(x)); - final String nullability = - field.type.isNullable ? '@Nullable' : '@NonNull'; - addDocumentationComments( - indent, field.documentationComments, _docCommentSpec); - - indent.writeln( - 'private $nullability ${hostDatatype.datatype} ${field.name};'); - indent.writeln( - 'public $nullability ${hostDatatype.datatype} ${_makeGetter(field)}() { return ${field.name}; }'); - indent.writeScoped( - 'public void ${_makeSetter(field)}($nullability ${hostDatatype.datatype} setterArg) {', - '}', () { - if (!field.type.isNullable) { - indent.writeScoped('if (setterArg == null) {', '}', () { - indent.writeln( - 'throw new IllegalStateException("Nonnull field \\"${field.name}\\" is null.");'); - }); - } - indent.writeln('this.${field.name} = setterArg;'); - }); - } - - void writeToList() { - indent.write('@NonNull ArrayList toList() '); - indent.scoped('{', '}', () { - indent.writeln( - 'ArrayList toListResult = new ArrayList(${klass.fields.length});'); - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - final HostDatatype hostDatatype = getFieldHostDatatype( - field, - root.classes, - root.enums, - (TypeDeclaration x) => _javaTypeForBuiltinDartType(x)); - String toWriteValue = ''; - final String fieldName = field.name; - if (!hostDatatype.isBuiltin && - rootClassNameSet.contains(field.type.baseName)) { - toWriteValue = '($fieldName == null) ? null : $fieldName.toList()'; - } else if (!hostDatatype.isBuiltin && - rootEnumNameSet.contains(field.type.baseName)) { - toWriteValue = '$fieldName == null ? null : $fieldName.index'; - } else { - toWriteValue = field.name; - } - indent.writeln('toListResult.add($toWriteValue);'); - } - indent.writeln('return toListResult;'); - }); - } - - void writeFromList() { - indent.write( - 'static @NonNull ${klass.name} fromList(@NonNull ArrayList list) '); - indent.scoped('{', '}', () { - const String result = 'pigeonResult'; - indent.writeln('${klass.name} $result = new ${klass.name}();'); - enumerate(getFieldsInSerializationOrder(klass), - (int index, final NamedType field) { - final String fieldVariable = field.name; - final String setter = _makeSetter(field); - indent.writeln('Object $fieldVariable = list.get($index);'); - if (rootEnumNameSet.contains(field.type.baseName)) { - indent.writeln( - '$result.$setter(${_intToEnum(fieldVariable, field.type.baseName)});'); - } else { - indent.writeln( - '$result.$setter(${_castObject(field, root.classes, root.enums, fieldVariable)});'); - } - }); - indent.writeln('return $result;'); - }); - } - - void writeBuilder() { - indent.write('public static final class Builder '); - indent.scoped('{', '}', () { - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - final HostDatatype hostDatatype = getFieldHostDatatype( - field, - root.classes, - root.enums, - (TypeDeclaration x) => _javaTypeForBuiltinDartType(x)); - final String nullability = - field.type.isNullable ? '@Nullable' : '@NonNull'; - indent.writeln( - 'private @Nullable ${hostDatatype.datatype} ${field.name};'); - indent.writeScoped( - 'public @NonNull Builder ${_makeSetter(field)}($nullability ${hostDatatype.datatype} setterArg) {', - '}', () { - indent.writeln('this.${field.name} = setterArg;'); - indent.writeln('return this;'); - }); - } - indent.write('public @NonNull ${klass.name} build() '); - indent.scoped('{', '}', () { - const String returnVal = 'pigeonReturn'; - indent.writeln('${klass.name} $returnVal = new ${klass.name}();'); - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - indent.writeln('$returnVal.${_makeSetter(field)}(${field.name});'); - } - indent.writeln('return $returnVal;'); - }); - }); - } - - const List generatedMessages = [ - ' Generated class from Pigeon that represents data sent in messages.' - ]; - addDocumentationComments( - indent, klass.documentationComments, _docCommentSpec, - generatorComments: generatedMessages); - - indent.write('public static class ${klass.name} '); - indent.scoped('{', '}', () { - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - writeField(field); - indent.addln(''); - } - - 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'); - indent.writeln('private ${klass.name}() {}'); - } - - writeBuilder(); - writeToList(); - writeFromList(); - }); - } - +void generateJava( + JavaOptions options, Root root, StringSink sink, Indent indent) { void writeResultInterface() { indent.write('public interface Result '); indent.scoped('{', '}', () { @@ -766,48 +822,20 @@ void generateJava(JavaOptions options, Root root, StringSink sink) { }'''); } - writeHeader(); - indent.addln(''); - if (options.package != null) { - indent.writeln('package ${options.package};'); - } - indent.addln(''); - writeImports(); - indent.addln(''); - indent.writeln( - '$_docCommentPrefix Generated class from Pigeon.$_docCommentSuffix'); - indent.writeln( - '@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"})'); - if (options.useGeneratedAnnotation ?? false) { - indent.writeln('@javax.annotation.Generated("dev.flutter.pigeon")'); + if (root.apis.any((Api api) => + api.location == ApiLocation.host && + api.methods.any((Method it) => it.isAsynchronous))) { + indent.addln(''); + writeResultInterface(); } - indent.write('public class ${options.className!} '); - indent.scoped('{', '}', () { - for (final Enum anEnum in root.enums) { - indent.writeln(''); - writeEnum(anEnum); - } - - for (final Class klass in root.classes) { - indent.addln(''); - writeDataClass(klass); - } - if (root.apis.any((Api api) => - api.location == ApiLocation.host && - api.methods.any((Method it) => it.isAsynchronous))) { + for (final Api api in root.apis) { + if (getCodecClasses(api, root).isNotEmpty) { + _writeCodec(indent, api, root); indent.addln(''); - writeResultInterface(); - } - - for (final Api api in root.apis) { - if (getCodecClasses(api, root).isNotEmpty) { - _writeCodec(indent, api, root); - indent.addln(''); - } - writeApi(api); } + writeApi(api); + } - writeWrapError(); - }); + writeWrapError(); } diff --git a/packages/pigeon/lib/kotlin_generator.dart b/packages/pigeon/lib/kotlin_generator.dart index 18e08c7398a..f324662a884 100644 --- a/packages/pigeon/lib/kotlin_generator.dart +++ b/packages/pigeon/lib/kotlin_generator.dart @@ -72,10 +72,239 @@ class KotlinGenerator extends Generator { /// Generates Kotlin files with specified [KotlinOptions] @override - void generate(KotlinOptions languageOptions, Root root, StringSink sink, - {FileType fileType = FileType.na}) { - assert(fileType == FileType.na); - generateKotlin(languageOptions, root, sink); + void generate(KotlinOptions generatorOptions, Root root, StringSink sink) { + final Indent indent = Indent(sink); + + writeFilePrologue(generatorOptions, root, sink, indent); + writeFileImports(generatorOptions, root, sink, indent); + indent.writeln('/** Generated class from Pigeon. */'); + for (final Enum anEnum in root.enums) { + indent.writeln(''); + writeEnum(generatorOptions, root, sink, indent, anEnum); + } + for (final Class klass in root.classes) { + indent.addln(''); + writeDataClass(generatorOptions, root, sink, indent, klass); + } + generateKotlin(generatorOptions, root, sink, indent); + } + + @override + void writeFilePrologue(KotlinOptions generatorOptions, Root root, + StringSink sink, Indent indent) { + if (generatorOptions.copyrightHeader != null) { + addLines(indent, generatorOptions.copyrightHeader!, linePrefix: '// '); + } + indent.writeln('// $generatedCodeWarning'); + indent.writeln('// $seeAlsoWarning'); + indent.addln(''); + } + + @override + void writeFileImports(KotlinOptions generatorOptions, Root root, + StringSink sink, Indent indent) { + if (generatorOptions.package != null) { + indent.writeln('package ${generatorOptions.package}'); + } + indent.addln(''); + indent.writeln('import android.util.Log'); + indent.writeln('import io.flutter.plugin.common.BasicMessageChannel'); + indent.writeln('import io.flutter.plugin.common.BinaryMessenger'); + indent.writeln('import io.flutter.plugin.common.MessageCodec'); + indent.writeln('import io.flutter.plugin.common.StandardMessageCodec'); + indent.writeln('import java.io.ByteArrayOutputStream'); + indent.writeln('import java.nio.ByteBuffer'); + indent.addln(''); + } + + @override + void writeEnum(KotlinOptions generatorOptions, Root root, StringSink sink, + Indent indent, Enum anEnum) { + addDocumentationComments( + indent, anEnum.documentationComments, _docCommentSpec); + indent.write('enum class ${anEnum.name}(val raw: Int) '); + indent.scoped('{', '}', () { + enumerate(anEnum.members, (int index, final EnumMember member) { + addDocumentationComments( + indent, member.documentationComments, _docCommentSpec); + indent.write('${member.name.toUpperCase()}($index)'); + if (index != anEnum.members.length - 1) { + indent.addln(','); + } else { + indent.addln(';'); + } + }); + + indent.writeln(''); + indent.write('companion object '); + indent.scoped('{', '}', () { + indent.write('fun ofRaw(raw: Int): ${anEnum.name}? '); + indent.scoped('{', '}', () { + indent.writeln('return values().firstOrNull { it.raw == raw }'); + }); + }); + }); + } + + @override + void writeDataClass(KotlinOptions generatorOptions, Root root, + StringSink sink, Indent indent, Class klass) { + final Set customClassNames = + root.classes.map((Class x) => x.name).toSet(); + final Set customEnumNames = + root.enums.map((Enum x) => x.name).toSet(); + + const List generatedMessages = [ + ' Generated class from Pigeon that represents data sent in messages.' + ]; + addDocumentationComments( + indent, klass.documentationComments, _docCommentSpec, + generatorComments: generatedMessages); + + indent.write('data class ${klass.name} '); + indent.scoped('(', '', () { + for (final NamedType element in getFieldsInSerializationOrder(klass)) { + _writeClassField(indent, element); + if (getFieldsInSerializationOrder(klass).last != element) { + indent.addln(','); + } else { + indent.addln(''); + } + } + }); + + indent.scoped(') {', '}', () { + writeClassDecode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); + writeClassEncode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); + }); + } + + @override + void writeClassEncode( + KotlinOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + indent.write('fun toList(): List '); + indent.scoped('{', '}', () { + indent.write('return listOf'); + indent.scoped('(', ')', () { + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + final HostDatatype hostDatatype = _getHostDatatype(root, field); + String toWriteValue = ''; + final String fieldName = field.name; + if (!hostDatatype.isBuiltin && + customClassNames.contains(field.type.baseName)) { + toWriteValue = '$fieldName?.toList()'; + } else if (!hostDatatype.isBuiltin && + customEnumNames.contains(field.type.baseName)) { + toWriteValue = '$fieldName?.raw'; + } else { + toWriteValue = fieldName; + } + indent.writeln('$toWriteValue,'); + } + }); + }); + } + + @override + void writeClassDecode( + KotlinOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + final String className = klass.name; + + indent.write('companion object '); + indent.scoped('{', '}', () { + indent.writeln('@Suppress("UNCHECKED_CAST")'); + indent.write('fun fromList(list: List): $className '); + + indent.scoped('{', '}', () { + enumerate(getFieldsInSerializationOrder(klass), + (int index, final NamedType field) { + final HostDatatype hostDatatype = _getHostDatatype(root, field); + + // The StandardMessageCodec can give us [Integer, Long] for + // a Dart 'int'. To keep things simple we just use 64bit + // longs in Pigeon with Kotlin. + final bool isInt = field.type.baseName == 'int'; + + final String listValue = 'list[$index]'; + final String fieldType = _kotlinTypeForDartType(field.type); + + if (field.type.isNullable) { + if (!hostDatatype.isBuiltin && + customClassNames.contains(field.type.baseName)) { + indent.write('val ${field.name}: $fieldType? = '); + indent.add('($listValue as? List)?.let '); + indent.scoped('{', '}', () { + 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.writeln('$fieldType.ofRaw(it)'); + }); + } else if (isInt) { + indent.write('val ${field.name} = $listValue'); + indent.addln( + '.let { if (it is Int) it.toLong() else it as? Long }'); + } else { + indent.writeln('val ${field.name} = $listValue as? $fieldType'); + } + } else { + if (!hostDatatype.isBuiltin && + customClassNames.contains(field.type.baseName)) { + indent.writeln( + 'val ${field.name} = $fieldType.fromList($listValue as List)'); + } else if (!hostDatatype.isBuiltin && + customEnumNames.contains(field.type.baseName)) { + indent.write( + 'val ${field.name} = $fieldType.ofRaw($listValue as Int)!!'); + } else { + indent.writeln('val ${field.name} = $listValue as $fieldType'); + } + } + }); + + indent.writeln(''); + indent.write('return $className('); + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + final String comma = + getFieldsInSerializationOrder(klass).last == field ? '' : ', '; + indent.add('${field.name}$comma'); + } + indent.addln(')'); + }); + }); + } + + void _writeClassField(Indent indent, NamedType field) { + addDocumentationComments( + indent, field.documentationComments, _docCommentSpec); + indent.write( + 'val ${field.name}: ${_nullsafeKotlinTypeForDartType(field.type)}'); + final String defaultNil = field.type.isNullable ? ' = null' : ''; + indent.add(defaultNil); + } + + HostDatatype _getHostDatatype(Root root, NamedType field) { + return getFieldHostDatatype(field, root.classes, root.enums, + (TypeDeclaration x) => _kotlinTypeForBuiltinDartType(x)); } } @@ -451,192 +680,8 @@ String _nullsafeKotlinTypeForDartType(TypeDeclaration type) { /// Generates the ".kotlin" file for the AST represented by [root] to [sink] with the /// provided [options]. -void generateKotlin(KotlinOptions options, Root root, StringSink sink) { - final Set rootClassNameSet = - root.classes.map((Class x) => x.name).toSet(); - final Set rootEnumNameSet = - root.enums.map((Enum x) => x.name).toSet(); - final Indent indent = Indent(sink); - - HostDatatype getHostDatatype(NamedType field) { - return getFieldHostDatatype(field, root.classes, root.enums, - (TypeDeclaration x) => _kotlinTypeForBuiltinDartType(x)); - } - - void writeHeader() { - if (options.copyrightHeader != null) { - addLines(indent, options.copyrightHeader!, linePrefix: '// '); - } - indent.writeln('// $generatedCodeWarning'); - indent.writeln('// $seeAlsoWarning'); - } - - void writeImports() { - indent.writeln('import android.util.Log'); - indent.writeln('import io.flutter.plugin.common.BasicMessageChannel'); - indent.writeln('import io.flutter.plugin.common.BinaryMessenger'); - indent.writeln('import io.flutter.plugin.common.MessageCodec'); - indent.writeln('import io.flutter.plugin.common.StandardMessageCodec'); - indent.writeln('import java.io.ByteArrayOutputStream'); - indent.writeln('import java.nio.ByteBuffer'); - } - - void writeEnum(Enum anEnum) { - addDocumentationComments( - indent, anEnum.documentationComments, _docCommentSpec); - indent.write('enum class ${anEnum.name}(val raw: Int) '); - indent.scoped('{', '}', () { - enumerate(anEnum.members, (int index, final EnumMember member) { - addDocumentationComments( - indent, member.documentationComments, _docCommentSpec); - indent.write('${member.name.toUpperCase()}($index)'); - if (index != anEnum.members.length - 1) { - indent.addln(','); - } else { - indent.addln(';'); - } - }); - - indent.writeln(''); - indent.write('companion object '); - indent.scoped('{', '}', () { - indent.write('fun ofRaw(raw: Int): ${anEnum.name}? '); - indent.scoped('{', '}', () { - indent.writeln('return values().firstOrNull { it.raw == raw }'); - }); - }); - }); - } - - void writeDataClass(Class klass) { - void writeField(NamedType field) { - addDocumentationComments( - indent, field.documentationComments, _docCommentSpec); - indent.write( - 'val ${field.name}: ${_nullsafeKotlinTypeForDartType(field.type)}'); - final String defaultNil = field.type.isNullable ? ' = null' : ''; - indent.add(defaultNil); - } - - void writeToList() { - indent.write('fun toList(): List '); - indent.scoped('{', '}', () { - indent.write('return listOf'); - indent.scoped('(', ')', () { - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - final HostDatatype hostDatatype = getHostDatatype(field); - String toWriteValue = ''; - final String fieldName = field.name; - if (!hostDatatype.isBuiltin && - rootClassNameSet.contains(field.type.baseName)) { - toWriteValue = '$fieldName?.toList()'; - } else if (!hostDatatype.isBuiltin && - rootEnumNameSet.contains(field.type.baseName)) { - toWriteValue = '$fieldName?.raw'; - } else { - toWriteValue = fieldName; - } - indent.writeln('$toWriteValue,'); - } - }); - }); - } - - void writeFromList() { - final String className = klass.name; - - indent.write('companion object '); - indent.scoped('{', '}', () { - indent.writeln('@Suppress("UNCHECKED_CAST")'); - indent.write('fun fromList(list: List): $className '); - - indent.scoped('{', '}', () { - enumerate(getFieldsInSerializationOrder(klass), - (int index, final NamedType field) { - final HostDatatype hostDatatype = getHostDatatype(field); - - // The StandardMessageCodec can give us [Integer, Long] for - // a Dart 'int'. To keep things simple we just use 64bit - // longs in Pigeon with Kotlin. - final bool isInt = field.type.baseName == 'int'; - - final String listValue = 'list[$index]'; - final String fieldType = _kotlinTypeForDartType(field.type); - - if (field.type.isNullable) { - if (!hostDatatype.isBuiltin && - rootClassNameSet.contains(field.type.baseName)) { - indent.write('val ${field.name}: $fieldType? = '); - indent.add('($listValue as? List)?.let '); - indent.scoped('{', '}', () { - indent.writeln('$fieldType.fromList(it)'); - }); - } else if (!hostDatatype.isBuiltin && - rootEnumNameSet.contains(field.type.baseName)) { - indent.write('val ${field.name}: $fieldType? = '); - indent.add('($listValue as? Int)?.let '); - indent.scoped('{', '}', () { - indent.writeln('$fieldType.ofRaw(it)'); - }); - } else if (isInt) { - indent.write('val ${field.name} = $listValue'); - indent.addln( - '.let { if (it is Int) it.toLong() else it as? Long }'); - } else { - indent.writeln('val ${field.name} = $listValue as? $fieldType'); - } - } else { - if (!hostDatatype.isBuiltin && - rootClassNameSet.contains(field.type.baseName)) { - indent.writeln( - 'val ${field.name} = $fieldType.fromList($listValue as List)'); - } else if (!hostDatatype.isBuiltin && - rootEnumNameSet.contains(field.type.baseName)) { - indent.write( - 'val ${field.name} = $fieldType.ofRaw($listValue as Int)!!'); - } else { - indent.writeln('val ${field.name} = $listValue as $fieldType'); - } - } - }); - - indent.writeln(''); - indent.write('return $className('); - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - final String comma = - getFieldsInSerializationOrder(klass).last == field ? '' : ', '; - indent.add('${field.name}$comma'); - } - indent.addln(')'); - }); - }); - } - - const List generatedMessages = [ - ' Generated class from Pigeon that represents data sent in messages.' - ]; - addDocumentationComments( - indent, klass.documentationComments, _docCommentSpec, - generatorComments: generatedMessages); - - indent.write('data class ${klass.name} '); - indent.scoped('(', '', () { - for (final NamedType element in getFieldsInSerializationOrder(klass)) { - writeField(element); - if (getFieldsInSerializationOrder(klass).last != element) { - indent.addln(','); - } else { - indent.addln(''); - } - } - }); - - indent.scoped(') {', '}', () { - writeFromList(); - writeToList(); - }); - } - +void generateKotlin( + KotlinOptions options, Root root, StringSink sink, Indent indent) { void writeApi(Api api) { if (api.location == ApiLocation.host) { _writeHostApi(indent, api, root); @@ -665,25 +710,6 @@ void generateKotlin(KotlinOptions options, Root root, StringSink sink) { }); } - writeHeader(); - indent.addln(''); - if (options.package != null) { - indent.writeln('package ${options.package}'); - } - indent.addln(''); - writeImports(); - indent.addln(''); - indent.writeln('/** Generated class from Pigeon. */'); - for (final Enum anEnum in root.enums) { - indent.writeln(''); - writeEnum(anEnum); - } - - for (final Class klass in root.classes) { - indent.addln(''); - writeDataClass(klass); - } - if (root.apis.any((Api api) => api.location == ApiLocation.host && api.methods.any((Method it) => it.isAsynchronous))) { diff --git a/packages/pigeon/lib/objc_generator.dart b/packages/pigeon/lib/objc_generator.dart index 3d7e3a64da2..766917e1b1b 100644 --- a/packages/pigeon/lib/objc_generator.dart +++ b/packages/pigeon/lib/objc_generator.dart @@ -69,18 +69,389 @@ class ObjcGenerator extends Generator> { /// Instantiates a Objc Generator. ObjcGenerator(); - /// Generates Objc files with specified [OutputFileOptions] + /// Generates Objc header files with specified [ObjcOptions] @override - void generate(OutputFileOptions languageOptions, Root root, + void generate(OutputFileOptions generatorOptions, Root root, StringSink sink) { - final FileType fileType = languageOptions.fileType; - assert(fileType == FileType.header || fileType == FileType.source); + final Indent indent = Indent(sink); - if (fileType == FileType.header) { - generateObjcHeader(languageOptions.languageOptions, root, sink); + writeFilePrologue(generatorOptions, root, sink, indent); + writeFileImports(generatorOptions, root, sink, indent); + if (generatorOptions.fileType == FileType.header) { + indent.writeln('NS_ASSUME_NONNULL_BEGIN'); + + for (final Enum anEnum in root.enums) { + indent.writeln(''); + writeEnum(generatorOptions, root, sink, indent, anEnum); + } + indent.writeln(''); + for (final Class klass in root.classes) { + indent.writeln( + '@class ${_className(generatorOptions.languageOptions.prefix, klass.name)};'); + } + indent.addln(''); + } else if (generatorOptions.fileType == FileType.source) { + _writeObjcSourceHelperFunctions(indent); + indent.addln(''); + + for (final Class klass in root.classes) { + _writeObjcSourceDataClassExtension( + generatorOptions.languageOptions, indent, klass); + } + indent.writeln(''); + } + + for (final Class klass in root.classes) { + writeDataClass(generatorOptions, root, sink, indent, klass); + } + + if (generatorOptions.fileType == FileType.header) { + generateObjcHeader(generatorOptions.languageOptions, root, sink, indent); + } else { + generateObjcSource(generatorOptions.languageOptions, root, sink, indent); + } + } + + @override + void writeFilePrologue(OutputFileOptions generatorOptions, + Root root, StringSink sink, Indent indent) { + if (generatorOptions.fileType == FileType.header) { + _writeObjcHeaderPrologue( + generatorOptions.languageOptions, root, sink, indent); + } else { + _writeObjcSourcePrologue( + generatorOptions.languageOptions, root, sink, indent); + } + } + + @override + void writeFileImports(OutputFileOptions generatorOptions, + Root root, StringSink sink, Indent indent) { + if (generatorOptions.fileType == FileType.header) { + _writeObjcHeaderImports( + generatorOptions.languageOptions, root, sink, indent); } else { - generateObjcSource(languageOptions.languageOptions, root, sink); + _writeObjcSourceImports( + generatorOptions.languageOptions, root, sink, indent); + } + } + + @override + void writeEnum(OutputFileOptions generatorOptions, Root root, + StringSink sink, Indent indent, Enum anEnum) { + if (generatorOptions.fileType == FileType.header) { + _writeObjcHeaderEnum( + generatorOptions.languageOptions, root, sink, indent, anEnum); + } + } + + @override + void writeDataClass(OutputFileOptions generatorOptions, + Root root, StringSink sink, Indent indent, Class klass) { + if (generatorOptions.fileType == FileType.header) { + _writeObjcHeaderDataClass( + generatorOptions.languageOptions, root, sink, indent, klass); + } else { + _writeObjcSourceDataClassImplementation( + generatorOptions, root, sink, indent, klass); + indent.writeln(''); + } + } + + @override + void writeClassEncode( + OutputFileOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + if (generatorOptions.fileType == FileType.source) { + final String className = + _className(generatorOptions.languageOptions.prefix, klass.name); + + _writeObjcSourceClassEncode(generatorOptions.languageOptions, root, sink, + indent, klass, customClassNames, customEnumNames, className); + } + } + + @override + void writeClassDecode( + OutputFileOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + if (generatorOptions.fileType == FileType.source) { + final String className = + _className(generatorOptions.languageOptions.prefix, klass.name); + + _writeObjcSourceClassDecode(generatorOptions.languageOptions, root, sink, + indent, klass, customClassNames, customEnumNames, className); + } + } + + // Header File Methods. + + /// Writes Objc header file header to sink. + void _writeObjcHeaderPrologue( + ObjcOptions languageOptions, Root root, StringSink sink, Indent indent) { + if (languageOptions.copyrightHeader != null) { + addLines(indent, languageOptions.copyrightHeader!, linePrefix: '// '); + } + indent.writeln('// $generatedCodeWarning'); + indent.writeln('// $seeAlsoWarning'); + indent.addln(''); + } + + /// Writes Objc header file imports to sink. + void _writeObjcHeaderImports( + ObjcOptions languageOptions, Root root, StringSink sink, Indent indent) { + indent.writeln('#import '); + indent.addln(''); + + indent.writeln('@protocol FlutterBinaryMessenger;'); + indent.writeln('@protocol FlutterMessageCodec;'); + indent.writeln('@class FlutterError;'); + indent.writeln('@class FlutterStandardTypedData;'); + indent.addln(''); + } + + /// Writes single Objc header enum. + void _writeObjcHeaderEnum(ObjcOptions languageOptions, Root root, + StringSink sink, Indent indent, Enum anEnum) { + final String enumName = _className(languageOptions.prefix, anEnum.name); + addDocumentationComments( + indent, anEnum.documentationComments, _docCommentSpec); + + indent.write('typedef NS_ENUM(NSUInteger, $enumName) '); + indent.scoped('{', '};', () { + enumerate(anEnum.members, (int index, final EnumMember member) { + addDocumentationComments( + indent, member.documentationComments, _docCommentSpec); + // Capitalized first letter to ensure Swift compatibility + indent.writeln( + '$enumName${member.name[0].toUpperCase()}${member.name.substring(1)} = $index,'); + }); + }); + } + + /// Writes the class declaration for a data class. + /// + /// Example: + /// @interface Foo : NSObject + /// @property (nonatomic, copy) NSString *bar; + /// @end + void _writeObjcHeaderDataClass(ObjcOptions generatorOptions, Root root, + StringSink sink, Indent indent, Class klass) { + final List classes = root.classes; + final List enums = root.enums; + final String? prefix = generatorOptions.prefix; + final List customEnumNames = enums.map((Enum x) => x.name).toList(); + + addDocumentationComments( + indent, klass.documentationComments, _docCommentSpec); + + indent.writeln('@interface ${_className(prefix, klass.name)} : NSObject'); + if (getFieldsInSerializationOrder(klass).isNotEmpty) { + if (getFieldsInSerializationOrder(klass) + .map((NamedType e) => !e.type.isNullable) + .any((bool e) => e)) { + indent.writeln( + '$_docCommentPrefix `init` unavailable to enforce nonnull fields, see the `make` class method.'); + indent.writeln('- (instancetype)init NS_UNAVAILABLE;'); + } + _writeObjcSourceClassInitializerDeclaration( + indent, klass, classes, enums, prefix); + indent.addln(';'); + } + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + final HostDatatype hostDatatype = getFieldHostDatatype( + field, + classes, + enums, + (TypeDeclaration x) => _objcTypePtrForPrimitiveDartType(prefix, x), + customResolver: customEnumNames.contains(field.type.baseName) + ? (String x) => _className(prefix, x) + : (String x) => '${_className(prefix, x)} *'); + late final String propertyType; + addDocumentationComments( + indent, field.documentationComments, _docCommentSpec); + if (customEnumNames.contains(field.type.baseName)) { + propertyType = 'assign'; + } else { + propertyType = _propertyTypeForDartType(field); + } + final String nullability = + _isNullable(hostDatatype, field.type) ? ', nullable' : ''; + indent.writeln( + '@property(nonatomic, $propertyType$nullability) ${hostDatatype.datatype} ${field.name};'); } + indent.writeln('@end'); + indent.writeln(''); + } + + // Source File Methods. + + /// Writes Objc Source file header to sink. + void _writeObjcSourcePrologue( + ObjcOptions languageOptions, Root root, StringSink sink, Indent indent) { + if (languageOptions.copyrightHeader != null) { + addLines(indent, languageOptions.copyrightHeader!, linePrefix: '// '); + } + indent.writeln('// $generatedCodeWarning'); + indent.writeln('// $seeAlsoWarning'); + indent.addln(''); + } + + /// Writes Objc source file imports to sink. + void _writeObjcSourceImports( + ObjcOptions languageOptions, Root root, StringSink sink, Indent indent) { + indent.writeln('#import "${languageOptions.headerIncludePath}"'); + indent.writeln('#import '); + indent.addln(''); + + indent.writeln('#if !__has_feature(objc_arc)'); + indent.writeln('#error File requires ARC to be enabled.'); + indent.writeln('#endif'); + 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 @[ result ?: [NSNull null] ]; +}'''); + indent.format(''' +static id GetNullableObject(NSDictionary* dict, id key) { +\tid result = dict[key]; +\treturn (result == [NSNull null]) ? nil : result; +} +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.writeln('@interface $className ()'); + indent.writeln('+ ($className *)fromList:(NSArray *)list;'); + indent + .writeln('+ (nullable $className *)nullableFromList:(NSArray *)list;'); + indent.writeln('- (NSArray *)toList;'); + indent.writeln('@end'); + } + + void _writeObjcSourceDataClassImplementation( + OutputFileOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass) { + final Set customClassNames = + root.classes.map((Class x) => x.name).toSet(); + final Set customEnumNames = + root.enums.map((Enum x) => x.name).toSet(); + final String className = + _className(generatorOptions.languageOptions.prefix, klass.name); + + indent.writeln('@implementation $className'); + _writeObjcSourceClassInitializer(generatorOptions.languageOptions, root, + sink, indent, klass, customClassNames, customEnumNames, className); + writeClassDecode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); + writeClassEncode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); + indent.writeln('@end'); + } + + void _writeObjcSourceClassInitializer( + ObjcOptions languageOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + String className, + ) { + _writeObjcSourceClassInitializerDeclaration( + indent, klass, root.classes, root.enums, languageOptions.prefix); + indent.writeScoped(' {', '}', () { + const String result = 'pigeonResult'; + indent.writeln('$className* $result = [[$className alloc] init];'); + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + indent.writeln('$result.${field.name} = ${field.name};'); + } + indent.writeln('return $result;'); + }); + } + + void _writeObjcSourceClassDecode( + ObjcOptions languageOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + String className, + ) { + indent.write('+ ($className *)fromList:(NSArray *)list '); + indent.scoped('{', '}', () { + const String resultName = 'pigeonResult'; + indent.writeln('$className *$resultName = [[$className alloc] init];'); + enumerate(getFieldsInSerializationOrder(klass), + (int index, final NamedType field) { + if (customEnumNames.contains(field.type.baseName)) { + indent.writeln( + '$resultName.${field.name} = [${_listGetter(customClassNames, 'list', field, index, languageOptions.prefix)} integerValue];'); + } else { + indent.writeln( + '$resultName.${field.name} = ${_listGetter(customClassNames, 'list', field, index, languageOptions.prefix)};'); + if (!field.type.isNullable) { + indent.writeln('NSAssert($resultName.${field.name} != nil, @"");'); + } + } + }); + indent.writeln('return $resultName;'); + }); + + indent.writeln( + '+ (nullable $className *)nullableFromList:(NSArray *)list { return (list) ? [$className fromList:list] : nil; }'); + } + + void _writeObjcSourceClassEncode( + ObjcOptions languageOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + String className, + ) { + indent.write('- (NSArray *)toList '); + indent.scoped('{', '}', () { + indent.write('return'); + indent.scoped(' @[', '];', () { + for (final NamedType field in klass.fields) { + indent.writeln( + '${_arrayValue(customClassNames, customEnumNames, field)},'); + } + }); + }); } } @@ -183,9 +554,9 @@ bool _isNullable(HostDatatype hostDatatype, TypeDeclaration type) => /// Writes the method declaration for the initializer. /// /// Example '+ (instancetype)makeWithFoo:(NSString *)foo' -void _writeInitializerDeclaration(Indent indent, Class klass, +void _writeObjcSourceClassInitializerDeclaration(Indent indent, Class klass, List classes, List enums, String? prefix) { - final List enumNames = enums.map((Enum x) => x.name).toList(); + final List customEnumNames = enums.map((Enum x) => x.name).toList(); indent.write('+ (instancetype)makeWith'); bool isFirst = true; indent.nest(2, () { @@ -203,7 +574,7 @@ void _writeInitializerDeclaration(Indent indent, Class klass, classes, enums, (TypeDeclaration x) => _objcTypePtrForPrimitiveDartType(prefix, x), - customResolver: enumNames.contains(field.type.baseName) + customResolver: customEnumNames.contains(field.type.baseName) ? (String x) => _className(prefix, x) : (String x) => '${_className(prefix, x)} *'); final String nullable = @@ -213,58 +584,6 @@ void _writeInitializerDeclaration(Indent indent, Class klass, }); } -/// Writes the class declaration for a data class. -/// -/// Example: -/// @interface Foo : NSObject -/// @property (nonatomic, copy) NSString *bar; -/// @end -void _writeClassDeclarations( - Indent indent, List classes, List enums, String? prefix) { - final List enumNames = enums.map((Enum x) => x.name).toList(); - for (final Class klass in classes) { - addDocumentationComments( - indent, klass.documentationComments, _docCommentSpec); - - indent.writeln('@interface ${_className(prefix, klass.name)} : NSObject'); - if (getFieldsInSerializationOrder(klass).isNotEmpty) { - if (getFieldsInSerializationOrder(klass) - .map((NamedType e) => !e.type.isNullable) - .any((bool e) => e)) { - indent.writeln( - '$_docCommentPrefix `init` unavailable to enforce nonnull fields, see the `make` class method.'); - indent.writeln('- (instancetype)init NS_UNAVAILABLE;'); - } - _writeInitializerDeclaration(indent, klass, classes, enums, prefix); - indent.addln(';'); - } - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - final HostDatatype hostDatatype = getFieldHostDatatype( - field, - classes, - enums, - (TypeDeclaration x) => _objcTypePtrForPrimitiveDartType(prefix, x), - customResolver: enumNames.contains(field.type.baseName) - ? (String x) => _className(prefix, x) - : (String x) => '${_className(prefix, x)} *'); - late final String propertyType; - addDocumentationComments( - indent, field.documentationComments, _docCommentSpec); - if (enumNames.contains(field.type.baseName)) { - propertyType = 'assign'; - } else { - propertyType = _propertyTypeForDartType(field); - } - final String nullability = - _isNullable(hostDatatype, field.type) ? ', nullable' : ''; - indent.writeln( - '@property(nonatomic, $propertyType$nullability) ${hostDatatype.datatype} ${field.name};'); - } - indent.writeln('@end'); - indent.writeln(''); - } -} - /// Generates the name of the codec that will be generated. String _getCodecName(String? prefix, String className) => '${_className(prefix, className)}Codec'; @@ -553,66 +872,10 @@ void _writeFlutterApiDeclaration( /// Generates the ".h" file for the AST represented by [root] to [sink] with the /// provided [options]. -void generateObjcHeader(ObjcOptions options, Root root, StringSink sink) { - final Indent indent = Indent(sink); - - void writeHeader() { - if (options.copyrightHeader != null) { - addLines(indent, options.copyrightHeader!, linePrefix: '// '); - } - indent.writeln('// $generatedCodeWarning'); - indent.writeln('// $seeAlsoWarning'); - } - - void writeImports() { - indent.writeln('#import '); - } - - void writeForwardDeclarations() { - indent.writeln('@protocol FlutterBinaryMessenger;'); - indent.writeln('@protocol FlutterMessageCodec;'); - indent.writeln('@class FlutterError;'); - indent.writeln('@class FlutterStandardTypedData;'); - } - - void writeEnum(Enum anEnum) { - final String enumName = _className(options.prefix, anEnum.name); - addDocumentationComments( - indent, anEnum.documentationComments, _docCommentSpec); - - indent.write('typedef NS_ENUM(NSUInteger, $enumName) '); - indent.scoped('{', '};', () { - enumerate(anEnum.members, (int index, final EnumMember member) { - addDocumentationComments( - indent, member.documentationComments, _docCommentSpec); - // Capitalized first letter to ensure Swift compatibility - indent.writeln( - '$enumName${member.name[0].toUpperCase()}${member.name.substring(1)} = $index,'); - }); - }); - } - - writeHeader(); - writeImports(); - writeForwardDeclarations(); +void generateObjcHeader( + ObjcOptions options, Root root, StringSink sink, Indent indent) { indent.writeln(''); - indent.writeln('NS_ASSUME_NONNULL_BEGIN'); - - for (final Enum anEnum in root.enums) { - indent.writeln(''); - writeEnum(anEnum); - } - indent.writeln(''); - - for (final Class klass in root.classes) { - indent.writeln('@class ${_className(options.prefix, klass.name)};'); - } - - indent.writeln(''); - - _writeClassDeclarations(indent, root.classes, root.enums, options.prefix); - for (final Api api in root.apis) { indent.writeln( '$_docCommentPrefix The codec used by ${_className(options.prefix, api.name)}.'); @@ -629,9 +892,9 @@ void generateObjcHeader(ObjcOptions options, Root root, StringSink sink) { indent.writeln('NS_ASSUME_NONNULL_END'); } -String _listGetter(List classNames, String list, NamedType field, +String _listGetter(Set customClassNames, String list, NamedType field, int index, String? prefix) { - if (classNames.contains(field.type.baseName)) { + if (customClassNames.contains(field.type.baseName)) { String className = field.type.baseName; if (prefix != null) { className = '$prefix$className'; @@ -642,11 +905,11 @@ String _listGetter(List classNames, String list, NamedType field, } } -String _arrayValue( - List classNames, List enumNames, NamedType field) { - if (classNames.contains(field.type.baseName)) { +String _arrayValue(Set customClassNames, Set customEnumNames, + NamedType field) { + if (customClassNames.contains(field.type.baseName)) { return '(self.${field.name} ? [self.${field.name} toList] : [NSNull null])'; - } else if (enumNames.contains(field.type.baseName)) { + } else if (customEnumNames.contains(field.type.baseName)) { return '@(self.${field.name})'; } else { return '(self.${field.name} ?: [NSNull null])'; @@ -896,121 +1159,8 @@ void _writeFlutterApiSource( /// Generates the ".m" file for the AST represented by [root] to [sink] with the /// provided [options]. -void generateObjcSource(ObjcOptions options, Root root, StringSink sink) { - final Indent indent = Indent(sink); - final List classNames = - root.classes.map((Class x) => x.name).toList(); - final List enumNames = root.enums.map((Enum x) => x.name).toList(); - - void writeHeader() { - if (options.copyrightHeader != null) { - addLines(indent, options.copyrightHeader!, linePrefix: '// '); - } - indent.writeln('// $generatedCodeWarning'); - indent.writeln('// $seeAlsoWarning'); - } - - void writeImports() { - indent.writeln('#import "${options.headerIncludePath}"'); - indent.writeln('#import '); - } - - void writeArcEnforcer() { - indent.writeln('#if !__has_feature(objc_arc)'); - indent.writeln('#error File requires ARC to be enabled.'); - indent.writeln('#endif'); - } - - void writeHelperFunctions() { - 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 @[ result ?: [NSNull null] ]; -}'''); - indent.format(''' -static id GetNullableObject(NSDictionary* dict, id key) { -\tid result = dict[key]; -\treturn (result == [NSNull null]) ? nil : result; -} -static id GetNullableObjectAtIndex(NSArray* array, NSInteger key) { -\tid result = array[key]; -\treturn (result == [NSNull null]) ? nil : result; -} -'''); - } - - void writeDataClassExtension(Class klass) { - final String className = _className(options.prefix, klass.name); - indent.writeln('@interface $className ()'); - indent.writeln('+ ($className *)fromList:(NSArray *)list;'); - indent - .writeln('+ (nullable $className *)nullableFromList:(NSArray *)list;'); - indent.writeln('- (NSArray *)toList;'); - indent.writeln('@end'); - } - - void writeDataClassImplementation(Class klass) { - final String className = _className(options.prefix, klass.name); - void writeInitializer() { - _writeInitializerDeclaration( - indent, klass, root.classes, root.enums, options.prefix); - indent.writeScoped(' {', '}', () { - const String result = 'pigeonResult'; - indent.writeln('$className* $result = [[$className alloc] init];'); - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - indent.writeln('$result.${field.name} = ${field.name};'); - } - indent.writeln('return $result;'); - }); - } - - void writeFromList() { - indent.write('+ ($className *)fromList:(NSArray *)list '); - indent.scoped('{', '}', () { - const String resultName = 'pigeonResult'; - indent.writeln('$className *$resultName = [[$className alloc] init];'); - enumerate(getFieldsInSerializationOrder(klass), - (int index, final NamedType field) { - if (enumNames.contains(field.type.baseName)) { - indent.writeln( - '$resultName.${field.name} = [${_listGetter(classNames, 'list', field, index, options.prefix)} integerValue];'); - } else { - indent.writeln( - '$resultName.${field.name} = ${_listGetter(classNames, 'list', field, index, options.prefix)};'); - if (!field.type.isNullable) { - indent - .writeln('NSAssert($resultName.${field.name} != nil, @"");'); - } - } - }); - indent.writeln('return $resultName;'); - }); - - indent.writeln( - '+ (nullable $className *)nullableFromList:(NSArray *)list { return (list) ? [$className fromList:list] : nil; }'); - } - - void writeToList() { - indent.write('- (NSArray *)toList '); - indent.scoped('{', '}', () { - indent.write('return'); - indent.scoped(' @[', '];', () { - for (final NamedType field in klass.fields) { - indent.writeln('${_arrayValue(classNames, enumNames, field)},'); - } - }); - }); - } - - indent.writeln('@implementation $className'); - writeInitializer(); - writeFromList(); - writeToList(); - indent.writeln('@end'); - } - +void generateObjcSource( + ObjcOptions options, Root root, StringSink sink, Indent indent) { void writeApi(Api api) { final String codecName = _getCodecName(options.prefix, api.name); if (getCodecClasses(api, root).isNotEmpty) { @@ -1026,19 +1176,6 @@ static id GetNullableObjectAtIndex(NSArray* array, NSInteger key) { } } - writeHeader(); - writeImports(); - indent.writeln(''); - writeArcEnforcer(); - indent.addln(''); - writeHelperFunctions(); - indent.addln(''); - root.classes.forEach(writeDataClassExtension); - indent.writeln(''); - for (final Class klass in root.classes) { - writeDataClassImplementation(klass); - indent.writeln(''); - } root.apis.forEach(writeApi); } diff --git a/packages/pigeon/lib/pigeon_lib.dart b/packages/pigeon/lib/pigeon_lib.dart index 5082dd19e8e..40f3fee3048 100644 --- a/packages/pigeon/lib/pigeon_lib.dart +++ b/packages/pigeon/lib/pigeon_lib.dart @@ -456,11 +456,7 @@ class DartTestGeneratorAdapter implements GeneratorAdapter { testOutPath: options.dartTestOut, ); final DartGenerator testGenerator = DartGenerator(); - testGenerator.generateTest( - dartOptionsWithHeader, - root, - sink, - ); + testGenerator.generateTest(dartOptionsWithHeader, root, sink); } @override diff --git a/packages/pigeon/lib/swift_generator.dart b/packages/pigeon/lib/swift_generator.dart index 77fff7e2fac..ed7db3685dd 100644 --- a/packages/pigeon/lib/swift_generator.dart +++ b/packages/pigeon/lib/swift_generator.dart @@ -55,10 +55,210 @@ class SwiftGenerator extends Generator { /// Generates Swift files with specified [SwiftOptions] @override - void generate(SwiftOptions languageOptions, Root root, StringSink sink, - {FileType fileType = FileType.na}) { - assert(fileType == FileType.na); - generateSwift(languageOptions, root, sink); + void generate(SwiftOptions generatorOptions, Root root, StringSink sink) { + final Indent indent = Indent(sink); + writeFilePrologue(generatorOptions, root, sink, indent); + writeFileImports(generatorOptions, root, sink, indent); + indent.writeln('$_docCommentPrefix Generated class from Pigeon.'); + for (final Enum anEnum in root.enums) { + indent.writeln(''); + writeEnum(generatorOptions, root, sink, indent, anEnum); + } + for (final Class klass in root.classes) { + indent.addln(''); + writeDataClass(generatorOptions, root, sink, indent, klass); + } + generateSwift(generatorOptions, root, sink, indent); + } + + @override + void writeFilePrologue(SwiftOptions generatorOptions, Root root, + StringSink sink, Indent indent) { + if (generatorOptions.copyrightHeader != null) { + addLines(indent, generatorOptions.copyrightHeader!, linePrefix: '// '); + } + indent.writeln('// $generatedCodeWarning'); + indent.writeln('// $seeAlsoWarning'); + indent.addln(''); + } + + @override + void writeFileImports(SwiftOptions generatorOptions, Root root, + StringSink sink, Indent indent) { + indent.writeln('import Foundation'); + indent.format(''' +#if os(iOS) +import Flutter +#elseif os(macOS) +import FlutterMacOS +#else +#error("Unsupported platform.") +#endif +'''); + indent.writeln(''); + } + + @override + void writeEnum(SwiftOptions generatorOptions, Root root, StringSink sink, + Indent indent, Enum anEnum) { + addDocumentationComments( + indent, anEnum.documentationComments, _docCommentSpec); + + indent.write('enum ${anEnum.name}: Int '); + indent.scoped('{', '}', () { + enumerate(anEnum.members, (int index, final EnumMember member) { + addDocumentationComments( + indent, member.documentationComments, _docCommentSpec); + indent.writeln('case ${_camelCase(member.name)} = $index'); + }); + }); + } + + @override + void writeDataClass(SwiftOptions generatorOptions, Root root, StringSink sink, + Indent indent, Class klass) { + final Set customClassNames = + root.classes.map((Class x) => x.name).toSet(); + final Set customEnumNames = + root.enums.map((Enum x) => x.name).toSet(); + + const List generatedComments = [ + ' Generated class from Pigeon that represents data sent in messages.' + ]; + addDocumentationComments( + indent, klass.documentationComments, _docCommentSpec, + generatorComments: generatedComments); + + indent.write('struct ${klass.name} '); + indent.scoped('{', '}', () { + getFieldsInSerializationOrder(klass).forEach((NamedType field) { + _writeClassField(indent, field); + }); + + indent.writeln(''); + writeClassDecode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); + writeClassEncode(generatorOptions, root, sink, indent, klass, + customClassNames, customEnumNames); + }); + } + + @override + void writeClassEncode( + SwiftOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + indent.write('func toList() -> [Any?] '); + indent.scoped('{', '}', () { + indent.write('return '); + indent.scoped('[', ']', () { + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + final HostDatatype hostDatatype = _getHostDatatype(root, field); + String toWriteValue = ''; + final String fieldName = field.name; + final String nullsafe = field.type.isNullable ? '?' : ''; + if (!hostDatatype.isBuiltin && + customClassNames.contains(field.type.baseName)) { + toWriteValue = '$fieldName$nullsafe.toList()'; + } else if (!hostDatatype.isBuiltin && + customEnumNames.contains(field.type.baseName)) { + toWriteValue = '$fieldName$nullsafe.rawValue'; + } else { + toWriteValue = field.name; + } + + indent.writeln('$toWriteValue,'); + } + }); + }); + } + + @override + void writeClassDecode( + SwiftOptions generatorOptions, + Root root, + StringSink sink, + Indent indent, + Class klass, + Set customClassNames, + Set customEnumNames, + ) { + final String className = klass.name; + indent.write('static func fromList(_ list: [Any?]) -> $className? '); + + indent.scoped('{', '}', () { + enumerate(getFieldsInSerializationOrder(klass), + (int index, final NamedType field) { + final HostDatatype hostDatatype = _getHostDatatype(root, field); + + final String listValue = 'list[$index]'; + final String fieldType = _swiftTypeForDartType(field.type); + + if (field.type.isNullable) { + if (!hostDatatype.isBuiltin && + 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.writeln( + '${field.name} = $fieldType.fromList(${field.name}List)'); + }); + } else if (!hostDatatype.isBuiltin && + 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.writeln( + '${field.name} = $fieldType(rawValue: ${field.name}RawValue)'); + }); + } else { + indent.writeln('let ${field.name} = $listValue as? $fieldType '); + } + } else { + if (!hostDatatype.isBuiltin && + customClassNames.contains(field.type.baseName)) { + indent.writeln( + 'let ${field.name} = $fieldType.fromList($listValue as! [Any?])!'); + } else if (!hostDatatype.isBuiltin && + customEnumNames.contains(field.type.baseName)) { + indent.writeln( + 'let ${field.name} = $fieldType(rawValue: $listValue as! Int)!'); + } else { + indent.writeln('let ${field.name} = $listValue as! $fieldType'); + } + } + }); + + indent.writeln(''); + indent.write('return '); + indent.scoped('$className(', ')', () { + for (final NamedType field in getFieldsInSerializationOrder(klass)) { + final String comma = + getFieldsInSerializationOrder(klass).last == field ? '' : ','; + indent.writeln('${field.name}: ${field.name}$comma'); + } + }); + }); + } + + void _writeClassField(Indent indent, NamedType field) { + addDocumentationComments( + indent, field.documentationComments, _docCommentSpec); + + indent.write( + 'var ${field.name}: ${_nullsafeSwiftTypeForDartType(field.type)}'); + final String defaultNil = field.type.isNullable ? ' = nil' : ''; + indent.addln(defaultNil); + } + + HostDatatype _getHostDatatype(Root root, NamedType field) { + return getFieldHostDatatype(field, root.classes, root.enums, + (TypeDeclaration x) => _swiftTypeForBuiltinDartType(x)); } } @@ -449,167 +649,8 @@ String _nullsafeSwiftTypeForDartType(TypeDeclaration type) { /// Generates the ".swift" file for the AST represented by [root] to [sink] with the /// provided [options]. -void generateSwift(SwiftOptions options, Root root, StringSink sink) { - final Set rootClassNameSet = - root.classes.map((Class x) => x.name).toSet(); - final Set rootEnumNameSet = - root.enums.map((Enum x) => x.name).toSet(); - final Indent indent = Indent(sink); - - HostDatatype getHostDatatype(NamedType field) { - return getFieldHostDatatype(field, root.classes, root.enums, - (TypeDeclaration x) => _swiftTypeForBuiltinDartType(x)); - } - - void writeHeader() { - if (options.copyrightHeader != null) { - addLines(indent, options.copyrightHeader!, linePrefix: '// '); - } - indent.writeln('// $generatedCodeWarning'); - indent.writeln('// $seeAlsoWarning'); - } - - void writeImports() { - indent.writeln('import Foundation'); - indent.format(''' -#if os(iOS) -import Flutter -#elseif os(macOS) -import FlutterMacOS -#else -#error("Unsupported platform.") -#endif -'''); - } - - void writeEnum(Enum anEnum) { - addDocumentationComments( - indent, anEnum.documentationComments, _docCommentSpec); - - indent.write('enum ${anEnum.name}: Int '); - indent.scoped('{', '}', () { - enumerate(anEnum.members, (int index, final EnumMember member) { - addDocumentationComments( - indent, member.documentationComments, _docCommentSpec); - indent.writeln('case ${_camelCase(member.name)} = $index'); - }); - }); - } - - void writeDataClass(Class klass) { - void writeField(NamedType field) { - addDocumentationComments( - indent, field.documentationComments, _docCommentSpec); - - indent.write( - 'var ${field.name}: ${_nullsafeSwiftTypeForDartType(field.type)}'); - final String defaultNil = field.type.isNullable ? ' = nil' : ''; - indent.addln(defaultNil); - } - - void writeToList() { - indent.write('func toList() -> [Any?] '); - indent.scoped('{', '}', () { - indent.write('return '); - indent.scoped('[', ']', () { - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - final HostDatatype hostDatatype = getHostDatatype(field); - String toWriteValue = ''; - final String fieldName = field.name; - final String nullsafe = field.type.isNullable ? '?' : ''; - if (!hostDatatype.isBuiltin && - rootClassNameSet.contains(field.type.baseName)) { - toWriteValue = '$fieldName$nullsafe.toList()'; - } else if (!hostDatatype.isBuiltin && - rootEnumNameSet.contains(field.type.baseName)) { - toWriteValue = '$fieldName$nullsafe.rawValue'; - } else { - toWriteValue = field.name; - } - - indent.writeln('$toWriteValue,'); - } - }); - }); - } - - void writeFromList() { - final String className = klass.name; - indent.write('static func fromList(_ list: [Any?]) -> $className? '); - - indent.scoped('{', '}', () { - enumerate(getFieldsInSerializationOrder(klass), - (int index, final NamedType field) { - final HostDatatype hostDatatype = getHostDatatype(field); - - final String listValue = 'list[$index]'; - final String fieldType = _swiftTypeForDartType(field.type); - - if (field.type.isNullable) { - if (!hostDatatype.isBuiltin && - rootClassNameSet.contains(field.type.baseName)) { - indent.writeln('var ${field.name}: $fieldType? = nil'); - indent.write('if let ${field.name}List = $listValue as? [Any?] '); - indent.scoped('{', '}', () { - indent.writeln( - '${field.name} = $fieldType.fromList(${field.name}List)'); - }); - } else if (!hostDatatype.isBuiltin && - rootEnumNameSet.contains(field.type.baseName)) { - indent.writeln('var ${field.name}: $fieldType? = nil'); - indent - .write('if let ${field.name}RawValue = $listValue as? Int '); - indent.scoped('{', '}', () { - indent.writeln( - '${field.name} = $fieldType(rawValue: ${field.name}RawValue)'); - }); - } else { - indent.writeln('let ${field.name} = $listValue as? $fieldType '); - } - } else { - if (!hostDatatype.isBuiltin && - rootClassNameSet.contains(field.type.baseName)) { - indent.writeln( - 'let ${field.name} = $fieldType.fromList($listValue as! [Any?])!'); - } else if (!hostDatatype.isBuiltin && - rootEnumNameSet.contains(field.type.baseName)) { - indent.writeln( - 'let ${field.name} = $fieldType(rawValue: $listValue as! Int)!'); - } else { - indent.writeln('let ${field.name} = $listValue as! $fieldType'); - } - } - }); - - indent.writeln(''); - indent.write('return '); - indent.scoped('$className(', ')', () { - for (final NamedType field in getFieldsInSerializationOrder(klass)) { - final String comma = - getFieldsInSerializationOrder(klass).last == field ? '' : ','; - indent.writeln('${field.name}: ${field.name}$comma'); - } - }); - }); - } - - const List generatedComments = [ - ' Generated class from Pigeon that represents data sent in messages.' - ]; - addDocumentationComments( - indent, klass.documentationComments, _docCommentSpec, - generatorComments: generatedComments); - - indent.write('struct ${klass.name} '); - indent.scoped('{', '}', () { - getFieldsInSerializationOrder(klass).forEach(writeField); - - indent.writeln(''); - writeFromList(); - writeToList(); - }); - } - +void generateSwift( + SwiftOptions options, Root root, StringSink sink, Indent indent) { void writeApi(Api api, Root root) { if (api.location == ApiLocation.host) { _writeHostApi(indent, api, root); @@ -637,21 +678,6 @@ import FlutterMacOS }); } - writeHeader(); - indent.addln(''); - writeImports(); - indent.addln(''); - indent.writeln('$_docCommentPrefix Generated class from Pigeon.'); - for (final Enum anEnum in root.enums) { - indent.writeln(''); - writeEnum(anEnum); - } - - for (final Class klass in root.classes) { - indent.addln(''); - writeDataClass(klass); - } - if (root.apis.any((Api api) => api.location == ApiLocation.host && api.methods.any((Method it) => it.isAsynchronous))) { diff --git a/packages/pigeon/mock_handler_tester/test/message.dart b/packages/pigeon/mock_handler_tester/test/message.dart index 4f6c9d14457..f621ac645da 100644 --- a/packages/pigeon/mock_handler_tester/test/message.dart +++ b/packages/pigeon/mock_handler_tester/test/message.dart @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Autogenerated from Pigeon (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), 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 + import 'dart:async'; import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; diff --git a/packages/pigeon/mock_handler_tester/test/test.dart b/packages/pigeon/mock_handler_tester/test/test.dart index 9b97826b605..f9be7a1f0c6 100644 --- a/packages/pigeon/mock_handler_tester/test/test.dart +++ b/packages/pigeon/mock_handler_tester/test/test.dart @@ -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 (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), 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 diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java index 95b0e2a9509..bb5e3ba569a 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java @@ -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 (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), do not edit directly. // See also: https://pub.dev/packages/pigeon package com.example.alternate_language_test_plugin; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h index 1def5e7af69..99a55d66a71 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h @@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Autogenerated from Pigeon (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), do not edit directly. // See also: https://pub.dev/packages/pigeon + #import + @protocol FlutterBinaryMessenger; @protocol FlutterMessageCodec; @class FlutterError; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m index 244b1e236c5..1e0bc26defd 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Autogenerated from Pigeon (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), do not edit directly. // See also: https://pub.dev/packages/pigeon + #import "CoreTests.gen.h" #import diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/core_tests.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/core_tests.gen.dart index fe0fe3335ea..fbdca3b2ed4 100644 --- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/core_tests.gen.dart +++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/core_tests.gen.dart @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Autogenerated from Pigeon (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), 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 + import 'dart:async'; import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/multiple_arity.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/multiple_arity.gen.dart index e92ab29cebd..692de832122 100644 --- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/multiple_arity.gen.dart +++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/multiple_arity.gen.dart @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Autogenerated from Pigeon (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), 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 + import 'dart:async'; import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/non_null_fields.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/non_null_fields.gen.dart index 1ff71bfa346..605a5f2c8c5 100644 --- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/non_null_fields.gen.dart +++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/non_null_fields.gen.dart @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Autogenerated from Pigeon (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), 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 + import 'dart:async'; import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_fields.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_fields.gen.dart index 88f4611e746..cd6273f8d65 100644 --- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_fields.gen.dart +++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_fields.gen.dart @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Autogenerated from Pigeon (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), 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 + import 'dart:async'; import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_safe_pigeon.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_safe_pigeon.dart index 13fe926bcf1..0999065d1ae 100644 --- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_safe_pigeon.dart +++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_safe_pigeon.dart @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Autogenerated from Pigeon (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), 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 + import 'dart:async'; import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/nullable_returns.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/nullable_returns.gen.dart index be1979c8adf..03522dd4cb7 100644 --- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/nullable_returns.gen.dart +++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/nullable_returns.gen.dart @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Autogenerated from Pigeon (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), 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 + import 'dart:async'; import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/primitive.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/primitive.dart index 36a569e4f46..78eee146e5f 100644 --- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/primitive.dart +++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/primitive.dart @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Autogenerated from Pigeon (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), 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 + import 'dart:async'; import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart index fe0fe3335ea..fbdca3b2ed4 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Autogenerated from Pigeon (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), 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 + import 'dart:async'; import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt index 61a957c8b55..258a4328e98 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt @@ -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 (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), do not edit directly. // See also: https://pub.dev/packages/pigeon package com.example.test_plugin diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift index 844e541a562..a754852b62e 100644 --- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift @@ -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 (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), do not edit directly. // See also: https://pub.dev/packages/pigeon import Foundation diff --git a/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift index 844e541a562..a754852b62e 100644 --- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift @@ -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 (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), do not edit directly. // See also: https://pub.dev/packages/pigeon import Foundation diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp index 110c75e358d..5e748c1f154 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp @@ -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 (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #undef _HAS_EXCEPTIONS diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h index 527a0ff45c8..48092005912 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // -// Autogenerated from Pigeon (v5.0.0), do not edit directly. +// Autogenerated from Pigeon (v5.0.4), do not edit directly. // See also: https://pub.dev/packages/pigeon -#ifndef PIGEON_CORE_TESTS_PIGEONTEST_H_ -#define PIGEON_CORE_TESTS_PIGEONTEST_H_ +#ifndef PIGEON_CORE_TESTS_GEN_H_CORE_TESTS_PIGEONTEST_H_ +#define PIGEON_CORE_TESTS_GEN_H_CORE_TESTS_PIGEONTEST_H_ #include #include #include @@ -17,6 +17,7 @@ #include namespace core_tests_pigeontest { + class CoreTestsTest; // Generated class from Pigeon. @@ -412,4 +413,4 @@ class HostTrivialApi { HostTrivialApi() = default; }; } // namespace core_tests_pigeontest -#endif // PIGEON_CORE_TESTS_PIGEONTEST_H_ +#endif // PIGEON_CORE_TESTS_GEN_H_CORE_TESTS_PIGEONTEST_H_ diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml index e4ada89edd1..1740c655da9 100644 --- a/packages/pigeon/pubspec.yaml +++ b/packages/pigeon/pubspec.yaml @@ -2,7 +2,7 @@ name: pigeon description: Code generator tool to make communication between Flutter and the host platform type-safe and easier. repository: https://github.com/flutter/packages/tree/main/packages/pigeon issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3Apigeon -version: 5.0.0 # This must match the version in lib/generator_tools.dart +version: 5.0.4 # This must match the version in lib/generator_tools.dart environment: sdk: ">=2.12.0 <3.0.0" diff --git a/packages/pigeon/test/cpp_generator_test.dart b/packages/pigeon/test/cpp_generator_test.dart index 172ce2ea3fe..bbed3a40c88 100644 --- a/packages/pigeon/test/cpp_generator_test.dart +++ b/packages/pigeon/test/cpp_generator_test.dart @@ -4,6 +4,7 @@ import 'package:pigeon/ast.dart'; import 'package:pigeon/cpp_generator.dart'; +import 'package:pigeon/generator_tools.dart'; import 'package:pigeon/pigeon.dart' show Error; import 'package:test/test.dart'; @@ -45,7 +46,13 @@ void main() { ], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('class Input')); expect(code, contains('class Output')); @@ -53,7 +60,13 @@ void main() { } { final StringBuffer sink = StringBuffer(); - generateCppSource(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('Input::Input()')); expect(code, contains('Output::Output')); @@ -101,7 +114,13 @@ void main() { ], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); // Method name and argument names should be adjusted. expect(code, contains(' DoSomething(const Input& some_input)')); @@ -116,7 +135,13 @@ void main() { } { final StringBuffer sink = StringBuffer(); - generateCppSource(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('pointer_input_field')); expect(code, contains('Output::output_field()')); @@ -144,7 +169,17 @@ void main() { ], classes: [], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate( + generatorOptions, + root, + sink, + ); final String code = sink.toString(); expect( @@ -184,7 +219,13 @@ void main() { ], classes: [], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( @@ -238,14 +279,26 @@ void main() { ], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, isNot(contains('){'))); expect(code, isNot(contains('const{'))); } { final StringBuffer sink = StringBuffer(); - generateCppSource(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, isNot(contains('){'))); expect(code, isNot(contains('const{'))); @@ -271,7 +324,13 @@ void main() { ], classes: [], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains(''' #include @@ -286,8 +345,13 @@ void main() { } { final StringBuffer sink = StringBuffer(); - generateCppSource( - const CppOptions(headerIncludePath: 'a_header.h'), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const CppOptions(headerIncludePath: 'a_header.h'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains(''' #include "a_header.h" @@ -323,14 +387,26 @@ void main() { ], classes: [], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(namespace: 'foo'), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(namespace: 'foo'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('namespace foo {')); expect(code, contains('} // namespace foo')); } { final StringBuffer sink = StringBuffer(); - generateCppSource(const CppOptions(namespace: 'foo'), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const CppOptions(namespace: 'foo'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('namespace foo {')); expect(code, contains('} // namespace foo')); @@ -391,7 +467,13 @@ void main() { ], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); // Getters should return const pointers. expect(code, contains('const bool* nullable_bool()')); @@ -423,7 +505,13 @@ void main() { } { final StringBuffer sink = StringBuffer(); - generateCppSource(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); // Getters extract optionals. expect(code, @@ -522,7 +610,13 @@ void main() { ], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); // POD getters should return copies references. expect(code, contains('bool non_nullable_bool()')); @@ -547,7 +641,13 @@ void main() { } { final StringBuffer sink = StringBuffer(); - generateCppSource(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); // Getters just return the value. expect(code, contains('return non_nullable_bool_;')); @@ -645,7 +745,13 @@ void main() { ], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, contains('ErrorOr> ReturnNullableBool()')); @@ -750,7 +856,13 @@ void main() { ], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('ErrorOr ReturnBool()')); expect(code, contains('ErrorOr ReturnInt()')); @@ -832,7 +944,13 @@ void main() { ], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -846,7 +964,13 @@ void main() { } { final StringBuffer sink = StringBuffer(); - generateCppSource(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); // Most types should just use get_if, since the parameter is a pointer, // and get_if will automatically handle null values (since a null @@ -963,7 +1087,13 @@ void main() { ], enums: []); { final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -977,7 +1107,13 @@ void main() { } { final StringBuffer sink = StringBuffer(); - generateCppSource(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); // Most types should extract references. Since the type is non-nullable, // there's only one possible type. @@ -1037,7 +1173,13 @@ void main() { ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - generateCppSource(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); // A bare 'auto' here would create a copy, not a reference, which is // ineffecient. @@ -1149,7 +1291,13 @@ void main() { ], ); final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(headerIncludePath: 'foo'), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(headerIncludePath: 'foo'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); for (final String comment in comments) { expect(code, contains('//$comment')); @@ -1184,7 +1332,13 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, isNot(contains(' : public flutter::StandardCodecSerializer'))); }); @@ -1226,7 +1380,13 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateCppHeader(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains(' : public flutter::StandardCodecSerializer')); }); @@ -1295,7 +1455,13 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateCppSource(const CppOptions(), root, sink); + final CppGenerator generator = CppGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const CppOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, isNot(contains('reply(wrap'))); expect(code, contains('reply(flutter::EncodableValue(')); diff --git a/packages/pigeon/test/dart_generator_test.dart b/packages/pigeon/test/dart_generator_test.dart index c77e5d89e37..15ce9e09ac4 100644 --- a/packages/pigeon/test/dart_generator_test.dart +++ b/packages/pigeon/test/dart_generator_test.dart @@ -29,7 +29,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Foobar')); expect(code, contains(' dataType1? field1;')); @@ -49,7 +50,8 @@ void main() { enums: [anEnum], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('enum Foobar')); expect(code, contains(' one,')); @@ -92,7 +94,8 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Api')); expect(code, contains('Future doSomething(Input arg_input)')); @@ -118,7 +121,8 @@ void main() { ]) ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Api')); expect(code, contains('Future add(int arg_x, int arg_y)')); @@ -145,7 +149,8 @@ void main() { ]) ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Api')); expect(code, contains('int add(int x, int y)')); @@ -182,7 +187,8 @@ void main() { ) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect( code, @@ -224,7 +230,8 @@ void main() { ) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect( code, @@ -276,7 +283,8 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('abstract class Api')); expect(code, contains('static void setup(Api')); @@ -310,7 +318,8 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future doSomething')); expect(code, contains('return;')); @@ -343,7 +352,8 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); // The next line verifies that we're not setting a variable to the value of "doSomething", but // ignores the line where we assert the value of the argument isn't null, since on that line @@ -373,7 +383,8 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, matches('output.*=.*doSomething[(][)]')); expect(code, contains('Output doSomething();')); @@ -415,7 +426,8 @@ void main() { ) ]); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('enum1?.index,')); expect(code, contains('? Enum.values[result[0]! as int]')); @@ -442,7 +454,8 @@ void main() { ]) ]); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('enum Foo {')); expect(code, contains('Future bar(Foo? arg_foo) async')); @@ -485,7 +498,8 @@ void main() { ) ]); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('enum1.index,')); expect(code, contains('enum1: Enum.values[result[0]! as int]')); @@ -512,7 +526,8 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, matches('channel.send[(]null[)]')); }); @@ -570,7 +585,8 @@ void main() { ], enums: []); final StringBuffer mainCodeSink = StringBuffer(); final StringBuffer testCodeSink = StringBuffer(); - generateDart(DartOptions(), root, mainCodeSink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, mainCodeSink); final String mainCode = mainCodeSink.toString(); expect(mainCode, isNot(contains(r"import 'fo\'o.dart';"))); expect(mainCode, contains('class Api {')); @@ -578,12 +594,15 @@ void main() { expect(mainCode, isNot(contains('.ApiMock.doSomething'))); expect(mainCode, isNot(contains("'${Keys.result}': output"))); expect(mainCode, isNot(contains('return [];'))); - generateTestDart( - DartOptions(), + + final DartGenerator testGenerator = DartGenerator(); + testGenerator.generateTest( + DartOptions( + sourceOutPath: "fo'o.dart", + testOutPath: 'test.dart', + ), root, testCodeSink, - sourceOutPath: "fo'o.dart", - testOutPath: 'test.dart', ); final String testCode = testCodeSink.toString(); expect(testCode, contains(r"import 'fo\'o.dart';")); @@ -631,7 +650,8 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('abstract class Api')); expect(code, contains('Future doSomething(Input arg0);')); @@ -675,7 +695,8 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, isNot(matches('=.s*doSomething'))); expect(code, contains('await api.doSomething(')); @@ -719,7 +740,8 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Api')); expect(code, matches('Output.*doSomething.*Input')); @@ -747,7 +769,8 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, matches('channel.send[(]null[)]')); }); @@ -759,7 +782,9 @@ void main() { test('header', () { final Root root = Root(apis: [], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - generateDart( + + final DartGenerator generator = DartGenerator(); + generator.generate( DartOptions(copyrightHeader: makeIterable('hello world')), root, sink, @@ -788,7 +813,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Foobar')); expect(code, contains(' List? field1;')); @@ -815,7 +841,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('class Foobar')); expect(code, contains(' Map? field1;')); @@ -844,7 +871,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('doit(List arg')); }); @@ -872,7 +900,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('doit(List arg')); }); @@ -896,7 +925,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future> doit(')); expect(code, @@ -931,7 +961,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('List doit(')); expect( @@ -958,7 +989,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future doit()')); expect(code, contains('return (replyList[0] as int?);')); @@ -983,7 +1015,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future?> doit()')); expect(code, @@ -1008,7 +1041,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future doit()')); expect(code, contains('return (replyList[0] as int?);')); @@ -1031,7 +1065,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('int? doit();')); expect(code, contains('final int? output = api.doit();')); @@ -1055,7 +1090,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future doit();')); expect(code, contains('final int? output = await api.doit();')); @@ -1078,7 +1114,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect( code, @@ -1107,7 +1144,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('Future doit(int? arg_foo) async {')); }); @@ -1133,7 +1171,8 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('void doit(int? foo);')); }); @@ -1150,12 +1189,14 @@ name: foobar final Root root = Root(classes: [], apis: [], enums: []); final StringBuffer sink = StringBuffer(); - generateTestDart( - DartOptions(), + final DartGenerator testGenerator = DartGenerator(); + testGenerator.generateTest( + DartOptions( + sourceOutPath: path.join(foo.path, 'bar.dart'), + testOutPath: path.join(tempDir.path, 'test', 'bar_test.dart'), + ), root, sink, - sourceOutPath: path.join(foo.path, 'bar.dart'), - testOutPath: path.join(tempDir.path, 'test', 'bar_test.dart'), ); final String code = sink.toString(); expect(code, contains("import 'package:foobar/foo/bar.dart';")); @@ -1238,7 +1279,8 @@ name: foobar ], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); for (final String comment in comments) { expect(code, contains('///$comment')); @@ -1273,7 +1315,8 @@ name: foobar enums: [], ); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, isNot(contains('extends StandardMessageCodec'))); expect(code, contains('StandardMessageCodec')); @@ -1316,7 +1359,8 @@ name: foobar ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateDart(DartOptions(), root, sink); + final DartGenerator generator = DartGenerator(); + generator.generate(DartOptions(), root, sink); final String code = sink.toString(); expect(code, contains('extends StandardMessageCodec')); }); @@ -1354,13 +1398,17 @@ name: foobar ], ); final StringBuffer sink = StringBuffer(); - generateTestDart( - DartOptions(), + + final DartGenerator testGenerator = DartGenerator(); + testGenerator.generateTest( + DartOptions( + sourceOutPath: 'code.dart', + testOutPath: 'test.dart', + ), root, sink, - sourceOutPath: 'code.dart', - testOutPath: 'test.dart', ); + final String testCode = sink.toString(); expect( testCode, diff --git a/packages/pigeon/test/java_generator_test.dart b/packages/pigeon/test/java_generator_test.dart index bfcea98cfe2..61cc14d9ed3 100644 --- a/packages/pigeon/test/java_generator_test.dart +++ b/packages/pigeon/test/java_generator_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:pigeon/ast.dart'; +import 'package:pigeon/generator_tools.dart'; import 'package:pigeon/java_generator.dart'; import 'package:pigeon/pigeon.dart'; import 'package:test/test.dart'; @@ -27,7 +28,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public class Messages')); expect(code, contains('public static class Foobar')); @@ -55,7 +57,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public enum Foobar')); expect(code, contains(' ONE(0),')); @@ -86,7 +89,8 @@ void main() { final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages', package: 'com.google.foobar'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('package com.google.foobar;')); expect(code, contains('ArrayList toList()')); @@ -129,7 +133,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public interface Api')); expect(code, matches('Output.*doSomething.*Input')); @@ -200,7 +205,8 @@ void main() { final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('private @Nullable Boolean aBool;')); expect(code, contains('private @Nullable Long aInt;')); @@ -249,7 +255,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public static class Api')); expect(code, matches('doSomething.*Input.*Output')); @@ -283,7 +290,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, isNot(matches('=.*doSomething'))); expect(code, contains('doSomething(')); @@ -317,7 +325,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('Reply')); expect(code, contains('callback.reply(null)')); @@ -345,7 +354,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('Output doSomething()')); expect(code, contains('api.doSomething()')); @@ -373,7 +383,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('doSomething(Reply')); expect(code, contains('channel.send(null')); @@ -392,7 +403,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public static class Foobar')); expect(code, contains('private @Nullable List field1;')); @@ -411,7 +423,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public static class Foobar')); expect(code, contains('private @Nullable Map field1;')); @@ -447,7 +460,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public class Messages')); expect(code, contains('public static class Outer')); @@ -498,7 +512,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public interface Api')); expect(code, contains('public interface Result {')); @@ -549,7 +564,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public static class Api')); expect(code, matches('doSomething.*Input.*Output')); @@ -582,7 +598,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public enum Enum1')); expect(code, contains(' ONE(0),')); @@ -621,7 +638,8 @@ void main() { ]); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('public enum Foo')); expect( @@ -641,7 +659,8 @@ void main() { className: 'Messages', copyrightHeader: makeIterable('hello world'), ); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, startsWith('// hello world')); }); @@ -667,7 +686,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('class Foobar')); expect(code, contains('List field1;')); @@ -695,7 +715,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('class Foobar')); expect(code, contains('Map field1;')); @@ -725,7 +746,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('doit(@NonNull List arg')); }); @@ -754,7 +776,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('doit(@NonNull List arg')); }); @@ -779,7 +802,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('List doit(')); expect(code, contains('List output =')); @@ -805,7 +829,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('doit(Reply> callback)')); expect(code, contains('List output =')); @@ -828,7 +853,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('doit(Reply callback)')); expect( @@ -858,7 +884,8 @@ void main() { ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('class Messages')); expect(code, contains('Long add(@NonNull Long x, @NonNull Long y)')); @@ -889,7 +916,8 @@ void main() { ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Api'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('Object xArg = args.get(0)')); }); @@ -915,7 +943,8 @@ void main() { ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('class Messages')); expect(code, contains('BasicMessageChannel channel')); @@ -947,7 +976,8 @@ void main() { ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect( code, @@ -973,7 +1003,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('@Nullable Long doit();')); }); @@ -997,7 +1028,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); // Java doesn't accept nullability annotations in type arguments. expect(code, contains('Result')); @@ -1025,7 +1057,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains(' void doit(@Nullable Long foo);')); }); @@ -1052,7 +1085,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1083,7 +1117,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1108,7 +1143,8 @@ void main() { final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages', useGeneratedAnnotation: true); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains('@javax.annotation.Generated("dev.flutter.pigeon")')); }); @@ -1125,7 +1161,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, isNot(contains('@javax.annotation.Generated("dev.flutter.pigeon")'))); @@ -1207,7 +1244,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); for (final String comment in comments) { // This regex finds the comment only between the open and close comment block @@ -1247,7 +1285,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, isNot(contains(' extends StandardMessageCodec'))); expect(code, contains('StandardMessageCodec')); @@ -1291,7 +1330,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const JavaOptions javaOptions = JavaOptions(className: 'Messages'); - generateJava(javaOptions, root, sink); + final JavaGenerator generator = JavaGenerator(); + generator.generate(javaOptions, root, sink); final String code = sink.toString(); expect(code, contains(' extends StandardMessageCodec')); }); diff --git a/packages/pigeon/test/kotlin_generator_test.dart b/packages/pigeon/test/kotlin_generator_test.dart index 4653410837e..2e85079e426 100644 --- a/packages/pigeon/test/kotlin_generator_test.dart +++ b/packages/pigeon/test/kotlin_generator_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:pigeon/ast.dart'; +import 'package:pigeon/generator_tools.dart'; import 'package:pigeon/kotlin_generator.dart'; import 'package:test/test.dart'; @@ -27,7 +28,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('data class Foobar (')); expect(code, contains('val field1: Long? = null')); @@ -50,7 +52,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('enum class Foobar(val raw: Int) {')); expect(code, contains('ONE(0)')); @@ -78,7 +81,8 @@ void main() { ]); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('enum class Foo(val raw: Int) {')); expect(code, contains('val fooArg = Foo.ofRaw(args[0] as Int)')); @@ -124,7 +128,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('interface Api')); expect(code, contains('fun doSomething(input: Input): Output')); @@ -213,7 +218,8 @@ void main() { final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('val aBool: Boolean? = null')); expect(code, contains('val aInt: Long? = null')); @@ -265,7 +271,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('class Api(private val binaryMessenger: BinaryMessenger)')); @@ -302,7 +309,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, isNot(matches('.*doSomething(.*) ->'))); expect(code, matches('doSomething(.*)')); @@ -338,7 +346,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('callback: () -> Unit')); expect(code, contains('callback()')); @@ -367,7 +376,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doSomething(): Output')); expect(code, contains('wrapped = listOf(api.doSomething())')); @@ -398,7 +408,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doSomething(callback: (Output) -> Unit)')); expect(code, contains('channel.send(null)')); @@ -418,7 +429,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('data class Foobar')); expect(code, contains('val field1: List? = null')); @@ -438,7 +450,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('data class Foobar')); expect(code, contains('val field1: Map? = null')); @@ -476,7 +489,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('data class Outer')); expect(code, contains('data class Nested')); @@ -529,7 +543,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('interface Api')); expect(code, contains('api.doSomething(argArg) {')); @@ -577,7 +592,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('class Api')); expect(code, matches('fun doSomething.*Input.*callback.*Output.*Unit')); @@ -610,7 +626,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('enum class Enum1(val raw: Int)')); expect(code, contains('ONE(0)')); @@ -627,7 +644,8 @@ void main() { final KotlinOptions kotlinOptions = KotlinOptions( copyrightHeader: makeIterable('hello world'), ); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, startsWith('// hello world')); }); @@ -654,7 +672,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('data class Foobar')); expect(code, contains('val field1: List')); @@ -683,7 +702,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('data class Foobar')); expect(code, contains('val field1: Map')); @@ -714,7 +734,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(arg: List')); }); @@ -744,7 +765,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(argArg: List')); }); @@ -769,7 +791,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(): List')); expect(code, contains('wrapped = listOf(api.doit())')); @@ -796,7 +819,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(callback: (List) -> Unit')); expect(code, contains('val result = it as List')); @@ -824,7 +848,8 @@ void main() { ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun add(x: Long, y: Long): Long')); expect(code, contains('val args = message as List')); @@ -861,7 +886,8 @@ void main() { ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('val channel = BasicMessageChannel')); expect(code, contains('val result = it as Long')); @@ -889,7 +915,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(): Long?')); }); @@ -913,7 +940,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(callback: (Long?) -> Unit')); }); @@ -940,7 +968,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect( code, @@ -970,7 +999,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('fun doit(fooArg: Long?, callback: () -> Unit')); }); @@ -1005,7 +1035,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains('val input: String\n')); }); @@ -1086,7 +1117,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); for (final String comment in comments) { // This regex finds the comment only between the open and close comment block @@ -1126,7 +1158,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, isNot(contains(' : StandardMessageCodec() '))); expect(code, contains('StandardMessageCodec')); @@ -1170,7 +1203,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const KotlinOptions kotlinOptions = KotlinOptions(); - generateKotlin(kotlinOptions, root, sink); + final KotlinGenerator generator = KotlinGenerator(); + generator.generate(kotlinOptions, root, sink); final String code = sink.toString(); expect(code, contains(' : StandardMessageCodec() ')); }); diff --git a/packages/pigeon/test/objc_generator_test.dart b/packages/pigeon/test/objc_generator_test.dart index aeb2db68e26..c6b45fd4d43 100644 --- a/packages/pigeon/test/objc_generator_test.dart +++ b/packages/pigeon/test/objc_generator_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:pigeon/ast.dart'; +import 'package:pigeon/generator_tools.dart'; import 'package:pigeon/objc_generator.dart'; import 'package:pigeon/pigeon_lib.dart'; import 'package:test/test.dart'; @@ -17,7 +18,13 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@interface Foobar')); expect(code, matches('@property.*NSString.*field1')); @@ -32,8 +39,13 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('#import "foo.h"')); expect(code, contains('@implementation Foobar')); @@ -50,7 +62,13 @@ void main() { ) ]); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('typedef NS_ENUM(NSUInteger, Enum1) {')); expect(code, contains(' Enum1One = 0,')); @@ -68,7 +86,13 @@ void main() { ) ]); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(prefix: 'PREFIX'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(prefix: 'PREFIX'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('typedef NS_ENUM(NSUInteger, PREFIXEnum1) {')); expect(code, contains(' PREFIXEnum1One = 0,')); @@ -104,8 +128,13 @@ void main() { ], ); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('#import "foo.h"')); expect(code, contains('@implementation Foobar')); @@ -138,13 +167,25 @@ void main() { const ObjcOptions options = ObjcOptions(headerIncludePath: 'foo.h', prefix: 'AC'); { - generateObjcHeader(options, root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: options, + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('typedef NS_ENUM(NSUInteger, ACFoo)')); expect(code, contains(':(ACFoo)foo error:')); } { - generateObjcSource(options, root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: options, + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -207,8 +248,13 @@ void main() { ], ); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@property(nonatomic, assign) Enum1 enum1')); }); @@ -240,7 +286,13 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@interface Input')); expect(code, contains('@interface Output')); @@ -279,8 +331,13 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('#import "foo.h"')); expect(code, contains('@implementation Input')); @@ -327,8 +384,13 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@interface Foobar')); expect(code, contains('@class FlutterStandardTypedData;')); @@ -356,8 +418,13 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@implementation Foobar')); expect(code, @@ -378,8 +445,13 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@property(nonatomic, strong, nullable) Input * nested;')); @@ -399,8 +471,13 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -419,7 +496,13 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(prefix: 'ABC'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@interface ABCFoobar')); }); @@ -433,7 +516,13 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource(const ObjcOptions(prefix: 'ABC'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@implementation ABCFoobar')); }); @@ -467,7 +556,13 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(prefix: 'ABC'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, matches('property.*ABCInput')); expect(code, matches('ABCNested.*doSomething.*ABCInput')); @@ -503,7 +598,13 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource(const ObjcOptions(prefix: 'ABC'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('ABCInput fromList')); expect(code, matches(r'ABCInput.*=.*args.*0.*\;')); @@ -539,8 +640,13 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@interface Api : NSObject')); expect( @@ -579,8 +685,13 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h'), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@implementation Api')); expect(code, matches('void.*doSomething.*Input.*Output.*{')); @@ -609,10 +720,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('(void)doSomething:')); }); @@ -640,10 +755,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, isNot(matches('=.*doSomething'))); expect(code, matches('[.*doSomething:.*]')); @@ -673,10 +792,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('completion:(void(^)(NSError *_Nullable))')); }); @@ -704,10 +827,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('completion:(void(^)(NSError *_Nullable))')); expect(code, contains('completion(nil)')); @@ -730,10 +857,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, matches('ABCOutput.*doSomethingWithError:[(]FlutterError')); }); @@ -755,10 +886,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, matches('output.*=.*api doSomethingWithError:&error')); }); @@ -780,10 +915,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -808,10 +947,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -829,7 +972,13 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@interface Foobar')); expect(code, matches('@property.*NSArray.*field1')); @@ -844,7 +993,13 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@interface Foobar')); expect(code, matches('@property.*NSDictionary.*field1')); @@ -865,7 +1020,13 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@interface Foobar')); expect( @@ -894,7 +1055,13 @@ void main() { ]) ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('(NSDictionary *)foo')); }); @@ -928,10 +1095,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -969,10 +1140,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -998,10 +1173,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1020,10 +1199,14 @@ void main() { ]) ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1061,10 +1244,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1101,10 +1288,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1123,10 +1314,14 @@ void main() { ]) ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1152,10 +1347,14 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1170,14 +1369,16 @@ void main() { test('source copyright', () { final Root root = Root(apis: [], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource( - ObjcOptions( + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: ObjcOptions( headerIncludePath: 'foo.h', prefix: 'ABC', copyrightHeader: makeIterable('hello world')), - root, - sink, ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, startsWith('// hello world')); }); @@ -1185,14 +1386,16 @@ void main() { test('header copyright', () { final Root root = Root(apis: [], classes: [], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - ObjcOptions( + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: ObjcOptions( headerIncludePath: 'foo.h', prefix: 'ABC', copyrightHeader: makeIterable('hello world')), - root, - sink, ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, startsWith('// hello world')); }); @@ -1217,10 +1420,14 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('NSArray * field1')); }); @@ -1249,19 +1456,27 @@ void main() { ); { final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('doitArg:(NSArray *)arg')); } { final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1294,19 +1509,27 @@ void main() { ); { final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('doitArg:(NSArray *)arg')); } { final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('doitArg:(NSArray *)arg')); } @@ -1342,10 +1565,14 @@ void main() { ); { final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('doitArg:(NSArray *> *)arg')); } @@ -1371,20 +1598,28 @@ void main() { ); { final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, contains('- (nullable NSArray *)doitWithError:')); } { final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('NSArray *output =')); } @@ -1410,20 +1645,28 @@ void main() { ); { final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, contains('doitWithCompletion:(void(^)(NSArray *')); } { final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, contains('doitWithCompletion:(void(^)(NSArray *')); @@ -1451,10 +1694,14 @@ void main() { ], classes: [], enums: []); { final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1463,10 +1710,14 @@ void main() { } { final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('NSArray *args = message;')); expect(code, @@ -1500,10 +1751,14 @@ void main() { ], classes: [], enums: []); { final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1512,10 +1767,14 @@ void main() { } { final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('NSArray *args = message;')); expect(code, @@ -1547,10 +1806,14 @@ void main() { ], classes: [], enums: []); { final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1559,10 +1822,14 @@ void main() { } { final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - root, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1605,19 +1872,27 @@ void main() { final Root divideRoot = getDivideRoot(ApiLocation.host); { final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - divideRoot, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, divideRoot, sink); final String code = sink.toString(); expect(code, matches('divideValue:.*by:.*error.*;')); } { final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - divideRoot, - sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), + ); + generator.generate(generatorOptions, divideRoot, sink); final String code = sink.toString(); expect(code, matches('divideValue:.*by:.*error.*;')); } @@ -1627,21 +1902,27 @@ void main() { final Root divideRoot = getDivideRoot(ApiLocation.flutter); { final StringBuffer sink = StringBuffer(); - generateObjcHeader( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - divideRoot, - sink, + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), ); + generator.generate(generatorOptions, divideRoot, sink); final String code = sink.toString(); expect(code, matches('divideValue:.*by:.*completion.*;')); } { final StringBuffer sink = StringBuffer(); - generateObjcSource( - const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), - divideRoot, - sink, + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: + const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), ); + generator.generate(generatorOptions, divideRoot, sink); final String code = sink.toString(); expect(code, matches('divideValue:.*by:.*completion.*{')); } @@ -1656,7 +1937,13 @@ void main() { ]), ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('@interface Foobar')); expect(code, contains('@property(nonatomic, copy) NSString * field1')); @@ -1679,7 +1966,13 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1704,7 +1997,13 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateObjcSource(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, matches(r'doitWithCompletion.*NSNumber \*_Nullable')); }); @@ -1726,7 +2025,13 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, matches(r'nullable NSNumber.*doitWithError')); }); @@ -1753,13 +2058,25 @@ void main() { ); { final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('doitFoo:(nullable NSNumber *)foo')); } { final StringBuffer sink = StringBuffer(); - generateObjcSource(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('NSNumber *arg_foo = GetNullableObjectAtIndex(args, 0);')); @@ -1788,13 +2105,25 @@ void main() { ); { final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('doitFoo:(nullable NSNumber *)foo')); } { final StringBuffer sink = StringBuffer(); - generateObjcSource(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains('- (void)doitFoo:(nullable NSNumber *)arg_foo')); } @@ -1818,7 +2147,13 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateObjcSource(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect( code, @@ -1902,7 +2237,13 @@ void main() { ], ); final StringBuffer sink = StringBuffer(); - generateObjcHeader(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.header, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); for (final String comment in comments) { expect(code, contains('///$comment')); @@ -1937,7 +2278,13 @@ void main() { enums: [], ); final StringBuffer sink = StringBuffer(); - generateObjcSource(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, isNot(contains(' : FlutterStandardReader'))); }); @@ -1979,7 +2326,13 @@ void main() { ]) ], enums: []); final StringBuffer sink = StringBuffer(); - generateObjcSource(const ObjcOptions(), root, sink); + final ObjcGenerator generator = ObjcGenerator(); + final OutputFileOptions generatorOptions = + OutputFileOptions( + fileType: FileType.source, + languageOptions: const ObjcOptions(), + ); + generator.generate(generatorOptions, root, sink); final String code = sink.toString(); expect(code, contains(' : FlutterStandardReader')); }); diff --git a/packages/pigeon/test/pigeon_lib_test.dart b/packages/pigeon/test/pigeon_lib_test.dart index 64c4af7b5ab..3d5c706bf41 100644 --- a/packages/pigeon/test/pigeon_lib_test.dart +++ b/packages/pigeon/test/pigeon_lib_test.dart @@ -938,10 +938,10 @@ abstract class Api { dartTestOut: 'stdout', dartOut: 'stdout', ); - final DartTestGeneratorAdapter dartGeneratorAdapter = + final DartTestGeneratorAdapter dartTestGeneratorAdapter = DartTestGeneratorAdapter(); final StringBuffer buffer = StringBuffer(); - dartGeneratorAdapter.generate(buffer, options, root, FileType.source); + dartTestGeneratorAdapter.generate(buffer, options, root, FileType.source); expect(buffer.toString(), startsWith('// Copyright 2013')); }); diff --git a/packages/pigeon/test/swift_generator_test.dart b/packages/pigeon/test/swift_generator_test.dart index 74c8aad15ca..68c9d91fdad 100644 --- a/packages/pigeon/test/swift_generator_test.dart +++ b/packages/pigeon/test/swift_generator_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:pigeon/ast.dart'; +import 'package:pigeon/generator_tools.dart'; import 'package:pigeon/swift_generator.dart'; import 'package:test/test.dart'; @@ -26,7 +27,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('struct Foobar')); expect(code, contains('var field1: Int32? = nil')); @@ -49,7 +51,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('enum Foobar: Int')); expect(code, contains(' case one = 0')); @@ -77,7 +80,8 @@ void main() { ]); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('enum Foo: Int')); expect(code, contains('let fooArg = Foo(rawValue: args[0] as! Int)!')); @@ -120,7 +124,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('protocol Api')); expect(code, matches('func doSomething.*Input.*Output')); @@ -183,7 +188,8 @@ void main() { final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('var aBool: Bool? = nil')); expect(code, contains('var aInt: Int32? = nil')); @@ -232,7 +238,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('class Api')); expect(code, contains('init(binaryMessenger: FlutterBinaryMessenger)')); @@ -267,7 +274,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, isNot(matches('.*doSomething(.*) ->'))); expect(code, matches('doSomething(.*)')); @@ -301,7 +309,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('completion: @escaping () -> Void')); expect(code, contains('completion()')); @@ -329,7 +338,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('func doSomething() -> Output')); expect(code, contains('let result = api.doSomething()')); @@ -358,7 +368,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('func doSomething(completion: @escaping (Output) -> Void)')); @@ -378,7 +389,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('struct Foobar')); expect(code, contains('var field1: [Any?]? = nil')); @@ -397,7 +409,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('struct Foobar')); expect(code, contains('var field1: [AnyHashable: Any?]? = nil')); @@ -433,7 +446,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('struct Outer')); expect(code, contains('struct Nested')); @@ -481,7 +495,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('protocol Api')); expect(code, contains('api.doSomething(arg: argArg) { result in')); @@ -526,7 +541,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('class Api')); expect(code, matches('func doSomething.*Input.*completion.*Output.*Void')); @@ -558,7 +574,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('enum Enum1: Int')); expect(code, contains('case one = 0')); @@ -575,7 +592,8 @@ void main() { final SwiftOptions swiftOptions = SwiftOptions( copyrightHeader: makeIterable('hello world'), ); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, startsWith('// hello world')); }); @@ -601,7 +619,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('struct Foobar')); expect(code, contains('var field1: [Int32?]')); @@ -629,7 +648,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('struct Foobar')); expect(code, contains('var field1: [String?: String?]')); @@ -659,7 +679,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('func doit(arg: [Int32?]')); }); @@ -688,7 +709,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('func doit(arg argArg: [Int32?]')); }); @@ -713,7 +735,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('func doit() -> [Int32?]')); expect(code, contains('let result = api.doit()')); @@ -740,7 +763,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect( code, contains('func doit(completion: @escaping ([Int32?]) -> Void')); @@ -769,7 +793,8 @@ void main() { ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('func add(x: Int32, y: Int32) -> Int32')); expect(code, contains('let args = message as! [Any?]')); @@ -800,7 +825,8 @@ void main() { ], classes: [], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('let channel = FlutterBasicMessageChannel')); expect(code, contains('let result = response as! Int32')); @@ -830,7 +856,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('func doit() -> Int32?')); }); @@ -854,7 +881,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('func doit(completion: @escaping (Int32?) -> Void')); }); @@ -881,7 +909,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('let fooArg = args[0] as? Int32')); }); @@ -908,7 +937,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect( code, @@ -944,7 +974,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains('var input: String\n')); }); @@ -1025,7 +1056,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); for (final String comment in comments) { expect(code, contains('///$comment')); @@ -1061,7 +1093,8 @@ void main() { ); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, isNot(contains(': FlutterStandardReader '))); }); @@ -1104,7 +1137,8 @@ void main() { ], enums: []); final StringBuffer sink = StringBuffer(); const SwiftOptions swiftOptions = SwiftOptions(); - generateSwift(swiftOptions, root, sink); + final SwiftGenerator generator = SwiftGenerator(); + generator.generate(swiftOptions, root, sink); final String code = sink.toString(); expect(code, contains(': FlutterStandardReader ')); });