[pigeon] Documentation comments (#2578)
diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md
index 71f7162..6f7531c 100644
--- a/packages/pigeon/CHANGELOG.md
+++ b/packages/pigeon/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 4.1.0
+
+* Adds documentation comment support for all currently supported languages.
+
## 4.0.3
* [swift] Makes swift output work on macOS.
diff --git a/packages/pigeon/lib/ast.dart b/packages/pigeon/lib/ast.dart
index ade2287..6db4a5e 100644
--- a/packages/pigeon/lib/ast.dart
+++ b/packages/pigeon/lib/ast.dart
@@ -33,6 +33,7 @@
this.offset,
this.objcSelector = '',
this.taskQueueType = TaskQueueType.serial,
+ this.documentationComments = const <String>[],
});
/// The name of the method.
@@ -56,11 +57,18 @@
/// Specifies how handlers are dispatched with respect to threading.
TaskQueueType taskQueueType;
+ /// List of documentation comments, seperated by line.
+ ///
+ /// Lines should not include the comment marker itself, but should include any
+ /// leading whitespace, so that any indentation in the original comment is preserved.
+ /// For example: [" List of documentation comments, separated by line.", ...]
+ List<String> documentationComments;
+
@override
String toString() {
final String objcSelectorStr =
objcSelector.isEmpty ? '' : ' objcSelector:$objcSelector';
- return '(Method name:$name returnType:$returnType arguments:$arguments isAsynchronous:$isAsynchronous$objcSelectorStr)';
+ return '(Method name:$name returnType:$returnType arguments:$arguments isAsynchronous:$isAsynchronous$objcSelectorStr documentationComments:$documentationComments)';
}
}
@@ -72,6 +80,7 @@
required this.location,
required this.methods,
this.dartHostTestHandler,
+ this.documentationComments = const <String>[],
});
/// The name of the API.
@@ -86,9 +95,16 @@
/// The name of the Dart test interface to generate to help with testing.
String? dartHostTestHandler;
+ /// List of documentation comments, seperated by line.
+ ///
+ /// Lines should not include the comment marker itself, but should include any
+ /// leading whitespace, so that any indentation in the original comment is preserved.
+ /// For example: [" List of documentation comments, separated by line.", ...]
+ List<String> documentationComments;
+
@override
String toString() {
- return '(Api name:$name location:$location methods:$methods)';
+ return '(Api name:$name location:$location methods:$methods documentationComments:$documentationComments)';
}
}
@@ -156,7 +172,12 @@
/// Represents a named entity that has a type.
class NamedType extends Node {
/// Parametric constructor for [NamedType].
- NamedType({required this.name, required this.type, this.offset});
+ NamedType({
+ required this.name,
+ required this.type,
+ this.offset,
+ this.documentationComments = const <String>[],
+ });
/// The name of the entity.
String name;
@@ -167,9 +188,16 @@
/// The offset in the source file where the [NamedType] appears.
int? offset;
+ /// List of documentation comments, seperated by line.
+ ///
+ /// Lines should not include the comment marker itself, but should include any
+ /// leading whitespace, so that any indentation in the original comment is preserved.
+ /// For example: [" List of documentation comments, separated by line.", ...]
+ List<String> documentationComments;
+
@override
String toString() {
- return '(NamedType name:$name type:$type)';
+ return '(NamedType name:$name type:$type documentationComments:$documentationComments)';
}
}
@@ -179,6 +207,7 @@
Class({
required this.name,
required this.fields,
+ this.documentationComments = const <String>[],
});
/// The name of the class.
@@ -187,9 +216,16 @@
/// All the fields contained in the class.
List<NamedType> fields;
+ /// List of documentation comments, seperated by line.
+ ///
+ /// Lines should not include the comment marker itself, but should include any
+ /// leading whitespace, so that any indentation in the original comment is preserved.
+ /// For example: [" List of documentation comments, separated by line.", ...]
+ List<String> documentationComments;
+
@override
String toString() {
- return '(Class name:$name fields:$fields)';
+ return '(Class name:$name fields:$fields documentationComments:$documentationComments)';
}
}
@@ -199,6 +235,7 @@
Enum({
required this.name,
required this.members,
+ this.documentationComments = const <String>[],
});
/// The name of the enum.
@@ -207,9 +244,16 @@
/// All of the members of the enum.
List<String> members;
+ /// List of documentation comments, seperated by line.
+ ///
+ /// Lines should not include the comment marker itself, but should include any
+ /// leading whitespace, so that any indentation in the original comment is preserved.
+ /// For example: [" List of documentation comments, separated by line.", ...]
+ List<String> documentationComments;
+
@override
String toString() {
- return '(Enum name:$name members:$members)';
+ return '(Enum name:$name members:$members documentationComments:$documentationComments)';
}
}
diff --git a/packages/pigeon/lib/cpp_generator.dart b/packages/pigeon/lib/cpp_generator.dart
index ca2c964..ec1b227 100644
--- a/packages/pigeon/lib/cpp_generator.dart
+++ b/packages/pigeon/lib/cpp_generator.dart
@@ -7,6 +7,13 @@
import 'generator_tools.dart';
import 'pigeon_lib.dart' show Error;
+/// General comment opening token.
+const String _commentPrefix = '//';
+
+/// Documentation comment spec.
+const DocumentCommentSpecification _docCommentSpec =
+ DocumentCommentSpecification(_commentPrefix);
+
/// Options that control how C++ code will be generated.
class CppOptions {
/// Creates a [CppOptions] object
@@ -188,13 +195,21 @@
void _writeDataClassDeclaration(Indent indent, Class klass, Root root,
{String? testFriend}) {
indent.addln('');
- indent.writeln(
- '/* Generated class from Pigeon that represents data sent in messages. */');
+
+ const List<String> generatedMessages = <String>[
+ ' 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 klass.fields) {
+ addDocumentationComments(
+ indent, field.documentationComments, _docCommentSpec);
final HostDatatype baseDatatype = getFieldHostDatatype(
field,
root.classes,
@@ -261,7 +276,7 @@
root.enums.map((Enum x) => x.name).toSet();
indent.addln('');
- indent.writeln('/* ${klass.name} */');
+ indent.writeln('$_commentPrefix ${klass.name}');
indent.addln('');
// Getters and setters.
@@ -398,8 +413,11 @@
void _writeHostApiHeader(Indent indent, Api api, Root root) {
assert(api.location == ApiLocation.host);
- indent.writeln(
- '/* Generated class from Pigeon that represents a handler of messages from Flutter. */');
+ const List<String> generatedMessages = <String>[
+ ' Generated interface from Pigeon that represents a handler of messages from Flutter.'
+ ];
+ addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
+ generatorComments: generatedMessages);
indent.write('class ${api.name} ');
indent.scoped('{', '};', () {
indent.scoped(' public:', '', () {
@@ -432,6 +450,10 @@
return '$argType $argName';
}));
}
+
+ addDocumentationComments(
+ indent, method.documentationComments, _docCommentSpec);
+
if (method.isAsynchronous) {
argSignature.add('std::function<void($returnTypeName reply)> result');
indent.writeln(
@@ -442,10 +464,10 @@
}
}
indent.addln('');
- indent.writeln('/** The codec used by ${api.name}. */');
+ indent.writeln('$_commentPrefix The codec used by ${api.name}.');
indent.writeln('static const flutter::StandardMessageCodec& GetCodec();');
indent.writeln(
- '/** Sets up an instance of `${api.name}` to handle messages through the `binary_messenger`. */');
+ '$_commentPrefix Sets up an instance of `${api.name}` to handle messages through the `binary_messenger`.');
indent.writeln(
'static void SetUp(flutter::BinaryMessenger* binary_messenger, ${api.name}* api);');
indent.writeln(
@@ -464,13 +486,13 @@
final String codecName = _getCodecName(api);
indent.format('''
-/** The codec used by ${api.name}. */
+/// The codec used by ${api.name}.
const flutter::StandardMessageCodec& ${api.name}::GetCodec() {
\treturn flutter::StandardMessageCodec::GetInstance(&$codecName::GetInstance());
}
''');
indent.writeln(
- '/** Sets up an instance of `${api.name}` to handle messages through the `binary_messenger`. */');
+ '$_commentPrefix Sets up an instance of `${api.name}` to handle messages through the `binary_messenger`.');
indent.write(
'void ${api.name}::SetUp(flutter::BinaryMessenger* binary_messenger, ${api.name}* api) ');
indent.scoped('{', '}', () {
@@ -679,8 +701,12 @@
void _writeFlutterApiHeader(Indent indent, Api api) {
assert(api.location == ApiLocation.flutter);
- indent.writeln(
- '/* Generated class from Pigeon that represents Flutter messages that can be called from C++. */');
+
+ const List<String> generatedMessages = <String>[
+ ' Generated class from Pigeon that represents Flutter messages that can be called from C++.'
+ ];
+ addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
+ generatorComments: generatedMessages);
indent.write('class ${api.name} ');
indent.scoped('{', '};', () {
indent.scoped(' private:', '', () {
@@ -695,6 +721,8 @@
? 'void'
: _nullSafeCppTypeForDartType(func.returnType);
final String callback = 'std::function<void($returnType)>&& callback';
+ addDocumentationComments(
+ indent, func.documentationComments, _docCommentSpec);
if (func.arguments.isEmpty) {
indent.writeln('void ${func.name}($callback);');
} else {
@@ -715,7 +743,7 @@
void _writeFlutterApiSource(Indent indent, Api api) {
assert(api.location == ApiLocation.flutter);
indent.writeln(
- '/* Generated class from Pigeon that represents Flutter messages that can be called from C++. */');
+ '$_commentPrefix Generated class from Pigeon that represents Flutter messages that can be called from C++.');
indent.write(
'${api.name}::${api.name}(flutter::BinaryMessenger* binary_messenger) ');
indent.scoped('{', '}', () {
@@ -988,8 +1016,8 @@
if (options.copyrightHeader != null) {
addLines(indent, options.copyrightHeader!, linePrefix: '// ');
}
- indent.writeln('// $generatedCodeWarning');
- indent.writeln('// $seeAlsoWarning');
+ indent.writeln('$_commentPrefix $generatedCodeWarning');
+ indent.writeln('$_commentPrefix $seeAlsoWarning');
indent.addln('');
final String guardName = _getGuardName(headerFileName, options.namespace);
indent.writeln('#ifndef $guardName');
@@ -1024,10 +1052,12 @@
}
indent.addln('');
- indent.writeln('/* Generated class from Pigeon. */');
+ 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('{', '};', () {
int index = 0;
@@ -1074,8 +1104,8 @@
if (options.copyrightHeader != null) {
addLines(indent, options.copyrightHeader!, linePrefix: '// ');
}
- indent.writeln('// $generatedCodeWarning');
- indent.writeln('// $seeAlsoWarning');
+ indent.writeln('$_commentPrefix $generatedCodeWarning');
+ indent.writeln('$_commentPrefix $seeAlsoWarning');
indent.addln('');
indent.addln('#undef _HAS_EXCEPTIONS');
indent.addln('');
diff --git a/packages/pigeon/lib/dart_generator.dart b/packages/pigeon/lib/dart_generator.dart
index f13c7e7..4b2ff9d 100644
--- a/packages/pigeon/lib/dart_generator.dart
+++ b/packages/pigeon/lib/dart_generator.dart
@@ -11,6 +11,13 @@
import 'functional.dart';
import 'generator_tools.dart';
+/// Documentation comment open symbol.
+const String _docCommentPrefix = '///';
+
+/// Documentation comment spec.
+const DocumentCommentSpecification _docCommentSpec =
+ DocumentCommentSpecification(_docCommentPrefix);
+
/// Options that control how Dart code will be generated.
class DartOptions {
/// Constructor for DartOptions.
@@ -154,6 +161,7 @@
_writeCodec(indent, codecName, api, root);
indent.addln('');
bool first = true;
+ addDocumentationComments(indent, api.documentationComments, _docCommentSpec);
indent.write('class ${api.name} ');
indent.scoped('{', '}', () {
indent.format('''
@@ -173,6 +181,8 @@
} else {
first = false;
}
+ addDocumentationComments(
+ indent, func.documentationComments, _docCommentSpec);
String argSignature = '';
String sendArgument = 'null';
if (func.arguments.isNotEmpty) {
@@ -264,11 +274,16 @@
assert(api.location == ApiLocation.flutter);
final String codecName = _getCodecName(api);
_writeCodec(indent, codecName, api, root);
+ addDocumentationComments(indent, api.documentationComments, _docCommentSpec);
+
indent.write('abstract class ${api.name} ');
indent.scoped('{', '}', () {
indent.writeln('static const MessageCodec<Object?> codec = $codecName();');
indent.addln('');
for (final Method func in api.methods) {
+ addDocumentationComments(
+ indent, func.documentationComments, _docCommentSpec);
+
final bool isAsync = func.isAsynchronous;
final String returnType = isAsync
? 'Future<${_addGenericTypesNullable(func.returnType)}>'
@@ -433,6 +448,8 @@
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 String member in anEnum.members) {
@@ -555,11 +572,17 @@
});
}
+ addDocumentationComments(
+ indent, klass.documentationComments, _docCommentSpec);
+
indent.write('class ${klass.name} ');
indent.scoped('{', '}', () {
writeConstructor();
indent.addln('');
for (final NamedType field in klass.fields) {
+ addDocumentationComments(
+ indent, field.documentationComments, _docCommentSpec);
+
final String datatype = _addGenericTypesNullable(field.type);
indent.writeln('$datatype ${field.name};');
}
@@ -696,6 +719,7 @@
methods: api.methods,
location: ApiLocation.flutter,
dartHostTestHandler: api.dartHostTestHandler,
+ documentationComments: api.documentationComments,
);
indent.writeln('');
_writeFlutterApi(
diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart
index a0607a9..0e6e659 100644
--- a/packages/pigeon/lib/generator_tools.dart
+++ b/packages/pigeon/lib/generator_tools.dart
@@ -9,7 +9,7 @@
import 'ast.dart';
/// The current version of pigeon. This must match the version in pubspec.yaml.
-const String pigeonVersion = '4.0.3';
+const String pigeonVersion = '4.1.0';
/// Read all the content from [stdin] to a String.
String readStdin() {
@@ -432,3 +432,59 @@
/// Returns true if the [TypeDeclaration] represents an enum.
bool isEnum(Root root, TypeDeclaration type) =>
root.enums.map((Enum e) => e.name).contains(type.baseName);
+
+/// Describes how to format a document comment.
+class DocumentCommentSpecification {
+ /// Constructor for [DocumentationCommentSpecification]
+ const DocumentCommentSpecification(
+ this.openCommentToken, {
+ this.closeCommentToken = '',
+ this.blockContinuationToken = '',
+ });
+
+ /// Token that represents the open symbol for a documentation comment.
+ final String openCommentToken;
+
+ /// Token that represents the closing symbol for a documentation comment.
+ final String closeCommentToken;
+
+ /// Token that represents the continuation symbol for a block of documentation comments.
+ final String blockContinuationToken;
+}
+
+/// Formats documentation comments and adds them to current Indent.
+///
+/// The [comments] list is meant for comments written in the input dart file.
+/// The [generatorComments] list is meant for comments added by the generators.
+/// Include white space for all tokens when called, no assumptions are made.
+void addDocumentationComments(
+ Indent indent,
+ List<String> comments,
+ DocumentCommentSpecification commentSpec, {
+ List<String> generatorComments = const <String>[],
+}) {
+ final List<String> allComments = <String>[
+ ...comments,
+ if (comments.isNotEmpty && generatorComments.isNotEmpty) '',
+ ...generatorComments,
+ ];
+ String currentLineOpenToken = commentSpec.openCommentToken;
+ if (allComments.length > 1) {
+ if (commentSpec.closeCommentToken != '') {
+ indent.writeln(commentSpec.openCommentToken);
+ currentLineOpenToken = commentSpec.blockContinuationToken;
+ }
+ for (final String line in allComments) {
+ indent.writeln(
+ '$currentLineOpenToken$line',
+ );
+ }
+ if (commentSpec.closeCommentToken != '') {
+ indent.writeln(commentSpec.closeCommentToken);
+ }
+ } else if (allComments.length == 1) {
+ indent.writeln(
+ '$currentLineOpenToken${allComments.first}${commentSpec.closeCommentToken}',
+ );
+ }
+}
diff --git a/packages/pigeon/lib/java_generator.dart b/packages/pigeon/lib/java_generator.dart
index e414d36..f820036 100644
--- a/packages/pigeon/lib/java_generator.dart
+++ b/packages/pigeon/lib/java_generator.dart
@@ -7,6 +7,23 @@
import 'generator_tools.dart';
import 'pigeon_lib.dart' show TaskQueueType;
+/// Documentation open symbol.
+const String _docCommentPrefix = '/**';
+
+/// Documentation continuation symbol.
+const String _docCommentContinuation = ' *';
+
+/// Documentation close symbol.
+const String _docCommentSuffix = ' */';
+
+/// Documentation comment spec.
+const DocumentCommentSpecification _docCommentSpec =
+ DocumentCommentSpecification(
+ _docCommentPrefix,
+ closeCommentToken: _docCommentSuffix,
+ blockContinuationToken: _docCommentContinuation,
+);
+
/// Options that control how Java code will be generated.
class JavaOptions {
/// Creates a [JavaOptions] object
@@ -159,6 +176,9 @@
: _javaTypeForDartType(method.returnType);
argSignature.add('Result<$resultType> result');
}
+ addDocumentationComments(
+ indent, method.documentationComments, _docCommentSpec);
+
indent.writeln('$returnType ${method.name}(${argSignature.join(', ')});');
}
@@ -278,8 +298,12 @@
});
}
- indent.writeln(
- '/** Generated interface from Pigeon that represents a handler of messages from Flutter.*/');
+ const List<String> generatedMessages = <String>[
+ ' Generated interface from Pigeon that represents a handler of messages from Flutter.'
+ ];
+ addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
+ generatorComments: generatedMessages);
+
indent.write('public interface ${api.name} ');
indent.scoped('{', '}', () {
api.methods.forEach(writeInterfaceMethod);
@@ -292,7 +316,7 @@
}
''');
indent.writeln(
- '/** Sets up an instance of `${api.name}` to handle messages through the `binaryMessenger`. */');
+ '${_docCommentPrefix}Sets up an instance of `${api.name}` to handle messages through the `binaryMessenger`.$_docCommentSuffix');
indent.write(
'static void setup(BinaryMessenger binaryMessenger, ${api.name} api) ');
indent.scoped('{', '}', () {
@@ -319,8 +343,12 @@
/// }
void _writeFlutterApi(Indent indent, Api api) {
assert(api.location == ApiLocation.flutter);
- indent.writeln(
- '/** Generated class from Pigeon that represents Flutter messages that can be called from Java.*/');
+ const List<String> generatedMessages = <String>[
+ ' Generated class from Pigeon that represents Flutter messages that can be called from Java.'
+ ];
+ addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
+ generatorComments: generatedMessages);
+
indent.write('public static class ${api.name} ');
indent.scoped('{', '}', () {
indent.writeln('private final BinaryMessenger binaryMessenger;');
@@ -344,6 +372,8 @@
? 'Void'
: _javaTypeForDartType(func.returnType);
String sendArgument;
+ addDocumentationComments(
+ indent, func.documentationComments, _docCommentSpec);
if (func.arguments.isEmpty) {
indent.write('public void ${func.name}(Reply<$returnType> callback) ');
sendArgument = 'null';
@@ -511,6 +541,9 @@
}
void writeEnum(Enum anEnum) {
+ addDocumentationComments(
+ indent, anEnum.documentationComments, _docCommentSpec);
+
indent.write('public enum ${anEnum.name} ');
indent.scoped('{', '}', () {
int index = 0;
@@ -541,6 +574,9 @@
(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(
@@ -639,8 +675,13 @@
});
}
- indent.writeln(
- '/** Generated class from Pigeon that represents data sent in messages. */');
+ const List<String> generatedMessages = <String>[
+ ' 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 klass.fields) {
@@ -652,7 +693,7 @@
.map((NamedType e) => !e.type.isNullable)
.any((bool e) => e)) {
indent.writeln(
- '/** Constructor is private to enforce null safety; use Builder. */');
+ '${_docCommentPrefix}Constructor is private to enforce null safety; use Builder.$_docCommentSuffix');
indent.writeln('private ${klass.name}() {}');
}
@@ -697,7 +738,8 @@
indent.addln('');
writeImports();
indent.addln('');
- indent.writeln('/** Generated class from Pigeon. */');
+ indent.writeln(
+ '${_docCommentPrefix}Generated class from Pigeon.$_docCommentSuffix');
indent.writeln(
'@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"})');
if (options.useGeneratedAnnotation ?? false) {
diff --git a/packages/pigeon/lib/objc_generator.dart b/packages/pigeon/lib/objc_generator.dart
index 088f9e4..af8edd4 100644
--- a/packages/pigeon/lib/objc_generator.dart
+++ b/packages/pigeon/lib/objc_generator.dart
@@ -7,6 +7,13 @@
import 'generator_tools.dart';
import 'pigeon_lib.dart' show Error, TaskQueueType;
+/// Documentation comment open symbol.
+const String _docCommentPrefix = '///';
+
+/// Documentation comment spec.
+const DocumentCommentSpecification _docCommentSpec =
+ DocumentCommentSpecification(_docCommentPrefix);
+
/// Options that control how Objective-C code will be generated.
class ObjcOptions {
/// Parametric constructor for ObjcOptions.
@@ -195,13 +202,16 @@
Indent indent, List<Class> classes, List<Enum> enums, String? prefix) {
final List<String> 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 (klass.fields.isNotEmpty) {
if (klass.fields
.map((NamedType e) => !e.type.isNullable)
.any((bool e) => e)) {
indent.writeln(
- '/// `init` unavailable to enforce nonnull fields, see the `make` class method.');
+ '$_docCommentPrefix `init` unavailable to enforce nonnull fields, see the `make` class method.');
indent.writeln('- (instancetype)init NS_UNAVAILABLE;');
}
_writeInitializerDeclaration(indent, klass, classes, enums, prefix);
@@ -217,6 +227,8 @@
? (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 {
@@ -415,6 +427,8 @@
void _writeHostApiDeclaration(
Indent indent, Api api, ObjcOptions options, Root root) {
final String apiName = _className(options.prefix, api.name);
+ addDocumentationComments(indent, api.documentationComments, _docCommentSpec);
+
indent.writeln('@protocol $apiName');
for (final Method func in api.methods) {
final _ObjcPtr returnTypeName =
@@ -443,8 +457,12 @@
if (!func.returnType.isNullable &&
!func.returnType.isVoid &&
!func.isAsynchronous) {
- indent.writeln('/// @return `nil` only when `error != nil`.');
+ indent.writeln(
+ '$_docCommentPrefix @return `nil` only when `error != nil`.');
}
+ addDocumentationComments(
+ indent, func.documentationComments, _docCommentSpec);
+
final String signature = _makeObjcSignature(
func: func,
options: options,
@@ -473,6 +491,8 @@
void _writeFlutterApiDeclaration(
Indent indent, Api api, ObjcOptions options, Root root) {
final String apiName = _className(options.prefix, api.name);
+ addDocumentationComments(indent, api.documentationComments, _docCommentSpec);
+
indent.writeln('@interface $apiName : NSObject');
indent.writeln(
'- (instancetype)initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;');
@@ -480,6 +500,9 @@
final _ObjcPtr returnType =
_objcTypeForDartType(options.prefix, func.returnType);
final String callbackType = _callbackForType(func.returnType, returnType);
+ addDocumentationComments(
+ indent, func.documentationComments, _docCommentSpec);
+
indent.writeln('${_makeObjcSignature(
func: func,
options: options,
@@ -518,6 +541,9 @@
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('{', '};', () {
int index = 0;
@@ -553,7 +579,7 @@
for (final Api api in root.apis) {
indent.writeln(
- '/// The codec used by ${_className(options.prefix, api.name)}.');
+ '${_docCommentPrefix}The codec used by ${_className(options.prefix, api.name)}.');
indent.writeln(
'NSObject<FlutterMessageCodec> *${_getCodecGetterName(options.prefix, api.name)}(void);');
indent.addln('');
@@ -724,6 +750,9 @@
indent.scoped('{', '}', () {
for (final Method func in api.methods) {
indent.write('');
+ addDocumentationComments(
+ indent, func.documentationComments, _docCommentSpec);
+
indent.scoped('{', '}', () {
String? taskQueue;
if (func.taskQueueType != TaskQueueType.serial) {
diff --git a/packages/pigeon/lib/pigeon_lib.dart b/packages/pigeon/lib/pigeon_lib.dart
index 0e282c6..32c6122 100644
--- a/packages/pigeon/lib/pigeon_lib.dart
+++ b/packages/pigeon/lib/pigeon_lib.dart
@@ -17,6 +17,7 @@
import 'package:analyzer/dart/ast/ast.dart' as dart_ast;
import 'package:analyzer/dart/ast/syntactic_entity.dart'
as dart_ast_syntactic_entity;
+import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart' as dart_ast_visitor;
import 'package:analyzer/error/error.dart' show AnalysisError;
import 'package:args/args.dart';
@@ -866,22 +867,42 @@
location: ApiLocation.host,
methods: <Method>[],
dartHostTestHandler: dartHostTestHandler,
+ documentationComments:
+ _documentationCommentsParser(node.documentationComment?.tokens),
);
} else if (_hasMetadata(node.metadata, 'FlutterApi')) {
_currentApi = Api(
name: node.name2.lexeme,
location: ApiLocation.flutter,
methods: <Method>[],
+ documentationComments:
+ _documentationCommentsParser(node.documentationComment?.tokens),
);
}
} else {
- _currentClass = Class(name: node.name2.lexeme, fields: <NamedType>[]);
+ _currentClass = Class(
+ name: node.name2.lexeme,
+ fields: <NamedType>[],
+ documentationComments:
+ _documentationCommentsParser(node.documentationComment?.tokens),
+ );
}
node.visitChildren(this);
return null;
}
+ /// Converts Token's to Strings and removes documentation comment symbol.
+ List<String> _documentationCommentsParser(List<Token>? comments) {
+ const String docCommentPrefix = '///';
+ return comments
+ ?.map((Token line) => line.length > docCommentPrefix.length
+ ? line.toString().substring(docCommentPrefix.length)
+ : '')
+ .toList() ??
+ <String>[];
+ }
+
NamedType formalParameterToField(dart_ast.FormalParameter parameter) {
final dart_ast.NamedType? namedType =
getFirstChildOfType<dart_ast.NamedType>(parameter);
@@ -952,12 +973,14 @@
final TaskQueueType taskQueueType =
_stringToEnum(TaskQueueType.values, taskQueueTypeName) ??
TaskQueueType.serial;
+
if (_currentApi != null) {
// Methods without named return types aren't supported.
final dart_ast.TypeAnnotation returnType = node.returnType!;
final dart_ast.SimpleIdentifier returnTypeIdentifier =
getFirstChildOfType<dart_ast.SimpleIdentifier>(returnType)!;
- _currentApi!.methods.add(Method(
+ _currentApi!.methods.add(
+ Method(
name: node.name2.lexeme,
returnType: TypeDeclaration(
baseName: returnTypeIdentifier.name,
@@ -968,7 +991,11 @@
isAsynchronous: isAsynchronous,
objcSelector: objcSelector,
offset: node.offset,
- taskQueueType: taskQueueType));
+ taskQueueType: taskQueueType,
+ documentationComments:
+ _documentationCommentsParser(node.documentationComment?.tokens),
+ ),
+ );
} else if (_currentClass != null) {
_errors.add(Error(
message:
@@ -982,10 +1009,13 @@
@override
Object? visitEnumDeclaration(dart_ast.EnumDeclaration node) {
_enums.add(Enum(
- name: node.name2.lexeme,
- members: node.constants
- .map((dart_ast.EnumConstantDeclaration e) => e.name2.lexeme)
- .toList()));
+ name: node.name2.lexeme,
+ members: node.constants
+ .map((dart_ast.EnumConstantDeclaration e) => e.name2.lexeme)
+ .toList(),
+ documentationComments:
+ _documentationCommentsParser(node.documentationComment?.tokens),
+ ));
node.visitChildren(this);
return null;
}
@@ -1026,12 +1056,16 @@
} else {
final dart_ast.TypeArgumentList? typeArguments = type.typeArguments;
_currentClass!.fields.add(NamedType(
- type: TypeDeclaration(
- baseName: type.name.name,
- isNullable: type.question != null,
- typeArguments: typeAnnotationsToTypeArguments(typeArguments)),
- name: node.fields.variables[0].name2.lexeme,
- offset: node.offset));
+ type: TypeDeclaration(
+ baseName: type.name.name,
+ isNullable: type.question != null,
+ typeArguments: typeAnnotationsToTypeArguments(typeArguments),
+ ),
+ name: node.fields.variables[0].name2.lexeme,
+ offset: node.offset,
+ documentationComments:
+ _documentationCommentsParser(node.documentationComment?.tokens),
+ ));
}
} else {
_errors.add(Error(
diff --git a/packages/pigeon/lib/swift_generator.dart b/packages/pigeon/lib/swift_generator.dart
index aaff9ee..7719b05 100644
--- a/packages/pigeon/lib/swift_generator.dart
+++ b/packages/pigeon/lib/swift_generator.dart
@@ -6,6 +6,13 @@
import 'functional.dart';
import 'generator_tools.dart';
+/// Documentation comment open symbol.
+const String _docCommentPrefix = '///';
+
+/// Documentation comment spec.
+const DocumentCommentSpecification _docCommentSpec =
+ DocumentCommentSpecification(_docCommentPrefix);
+
/// Options that control how Swift code will be generated.
class SwiftOptions {
/// Creates a [SwiftOptions] object
@@ -136,8 +143,12 @@
final String apiName = api.name;
- indent.writeln(
- '/// Generated protocol from Pigeon that represents a handler of messages from Flutter.');
+ const List<String> generatedComments = <String>[
+ 'Generated protocol from Pigeon that represents a handler of messages from Flutter.'
+ ];
+ addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
+ generatorComments: generatedComments);
+
indent.write('protocol $apiName ');
indent.scoped('{', '}', () {
for (final Method method in api.methods) {
@@ -156,6 +167,9 @@
final String returnType = method.returnType.isVoid
? ''
: _nullsafeSwiftTypeForDartType(method.returnType);
+ addDocumentationComments(
+ indent, method.documentationComments, _docCommentSpec);
+
if (method.isAsynchronous) {
argSignature.add('completion: @escaping ($returnType) -> Void');
indent.writeln('func ${method.name}(${argSignature.join(', ')})');
@@ -170,21 +184,23 @@
indent.addln('');
indent.writeln(
- '/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.');
+ '$_docCommentPrefix Generated setup class from Pigeon to handle messages through the `binaryMessenger`.');
indent.write('class ${apiName}Setup ');
indent.scoped('{', '}', () {
final String codecName = _getCodecName(api);
- indent.writeln('/// The codec used by $apiName.');
+ indent.writeln('$_docCommentPrefix The codec used by $apiName.');
indent.writeln(
'static var codec: FlutterStandardMessageCodec { $codecName.shared }');
indent.writeln(
- '/// Sets up an instance of `$apiName` to handle messages through the `binaryMessenger`.');
+ '$_docCommentPrefix Sets up an instance of `$apiName` to handle messages through the `binaryMessenger`.');
indent.write(
'static func setUp(binaryMessenger: FlutterBinaryMessenger, api: $apiName?) ');
indent.scoped('{', '}', () {
for (final Method method in api.methods) {
final String channelName = makeChannelName(api, method);
final String varChannelName = '${method.name}Channel';
+ addDocumentationComments(
+ indent, method.documentationComments, _docCommentSpec);
indent.writeln(
'let $varChannelName = FlutterBasicMessageChannel(name: "$channelName", binaryMessenger: binaryMessenger, codec: codec)');
@@ -260,8 +276,12 @@
/// }
void _writeFlutterApi(Indent indent, Api api, Root root) {
assert(api.location == ApiLocation.flutter);
- indent.writeln(
- '/// Generated class from Pigeon that represents Flutter messages that can be called from Swift.');
+ const List<String> generatedComments = <String>[
+ 'Generated class from Pigeon that represents Flutter messages that can be called from Swift.'
+ ];
+ addDocumentationComments(indent, api.documentationComments, _docCommentSpec,
+ generatorComments: generatedComments);
+
indent.write('class ${api.name} ');
indent.scoped('{', '}', () {
indent.writeln('private let binaryMessenger: FlutterBinaryMessenger');
@@ -280,6 +300,9 @@
? ''
: _nullsafeSwiftTypeForDartType(func.returnType);
String sendArgument;
+ addDocumentationComments(
+ indent, func.documentationComments, _docCommentSpec);
+
if (func.arguments.isEmpty) {
indent.write(
'func ${func.name}(completion: @escaping ($returnType) -> Void) ');
@@ -433,6 +456,9 @@
}
void writeEnum(Enum anEnum) {
+ addDocumentationComments(
+ indent, anEnum.documentationComments, _docCommentSpec);
+
indent.write('enum ${anEnum.name}: Int ');
indent.scoped('{', '}', () {
// We use explicit indexing here as use of the ordinal() method is
@@ -449,6 +475,9 @@
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' : '';
@@ -542,8 +571,13 @@
});
}
- indent.writeln(
- '/// Generated class from Pigeon that represents data sent in messages.');
+ const List<String> generatedComments = <String>[
+ 'Generated class from Pigeon that represents data sent in messages.'
+ ];
+ addDocumentationComments(
+ indent, klass.documentationComments, _docCommentSpec,
+ generatorComments: generatedComments);
+
indent.write('struct ${klass.name} ');
indent.scoped('{', '}', () {
klass.fields.forEach(writeField);
@@ -589,7 +623,7 @@
indent.addln('');
writeImports();
indent.addln('');
- indent.writeln('/// Generated class from Pigeon.');
+ indent.writeln('$_docCommentPrefix Generated class from Pigeon.');
for (final Enum anEnum in root.enums) {
indent.writeln('');
writeEnum(anEnum);
diff --git a/packages/pigeon/pigeons/enum.dart b/packages/pigeon/pigeons/enum.dart
index 8b35176..7552ac1 100644
--- a/packages/pigeon/pigeons/enum.dart
+++ b/packages/pigeon/pigeons/enum.dart
@@ -4,22 +4,31 @@
import 'package:pigeon/pigeon.dart';
+/// This comment is to test enum documentation comments.
enum EnumState {
Pending,
Success,
Error,
}
+/// This comment is to test class documentation comments.
class DataWithEnum {
+ /// This comment is to test field documentation comments.
EnumState? state;
}
@HostApi()
+
+/// This comment is to test api documentation comments.
abstract class EnumApi2Host {
+ /// This comment is to test method documentation comments.
DataWithEnum echo(DataWithEnum data);
}
@FlutterApi()
+
+/// This comment is to test api documentation comments.
abstract class EnumApi2Flutter {
+ /// This comment is to test method documentation comments.
DataWithEnum echo(DataWithEnum data);
}
diff --git a/packages/pigeon/pigeons/message.dart b/packages/pigeon/pigeons/message.dart
index 7ffe172..644031c 100644
--- a/packages/pigeon/pigeons/message.dart
+++ b/packages/pigeon/pigeons/message.dart
@@ -16,40 +16,79 @@
prefix: 'AC',
),
))
+
+/// This comment is to test enum documentation comments.
+///
+/// This comment also tests multiple line comments.
enum MessageRequestState {
pending,
success,
failure,
}
+/// This comment is to test class documentation comments.
+///
+/// This comment also tests multiple line comments.
class MessageSearchRequest {
+ /// This comment is to test field documentation comments.
String? query;
+
+ /// This comment is to test field documentation comments.
int? anInt;
+
+ /// This comment is to test field documentation comments.
bool? aBool;
}
+/// This comment is to test class documentation comments.
class MessageSearchReply {
+ /// This comment is to test field documentation comments.
+ ///
+ /// This comment also tests multiple line comments.
String? result;
+
+ /// This comment is to test field documentation comments.
String? error;
+
+ /// This comment is to test field documentation comments.
MessageRequestState? state;
}
@HostApi(dartHostTestHandler: 'TestHostApi')
+
+/// This comment is to test api documentation comments.
+///
+/// This comment also tests multiple line comments.
abstract class MessageApi {
+ /// This comment is to test documentation comments.
+ ///
+ /// This comment also tests multiple line comments.
void initialize();
+
+ /// This comment is to test method documentation comments.
MessageSearchReply search(MessageSearchRequest request);
}
+/// This comment is to test class documentation comments.
class MessageNested {
+ /// This comment is to test field documentation comments.
MessageSearchRequest? request;
}
@HostApi(dartHostTestHandler: 'TestNestedApi')
+
+/// This comment is to test api documentation comments.
abstract class MessageNestedApi {
+ /// This comment is to test method documentation comments.
+ ///
+ /// This comment also tests multiple line comments.
MessageSearchReply search(MessageNested nested);
}
@FlutterApi()
+
+/// This comment is to test api documentation comments.
abstract class MessageFlutterSearchApi {
+ /// This comment is to test method documentation comments.
MessageSearchReply search(MessageSearchRequest request);
}
diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml
index d677d9e..72f260d 100644
--- a/packages/pigeon/pubspec.yaml
+++ b/packages/pigeon/pubspec.yaml
@@ -2,7 +2,7 @@
description: Code generator tool to make communication between Flutter and the host platform type-safe and easier.
repository: https://github.com/flutter/packages/tree/main/packages/pigeon
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3Apigeon
-version: 4.0.3 # This must match the version in lib/generator_tools.dart
+version: 4.1.0 # 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 14b09e9..8b36e46 100644
--- a/packages/pigeon/test/cpp_generator_test.dart
+++ b/packages/pigeon/test/cpp_generator_test.dart
@@ -1051,4 +1051,75 @@
final List<Error> errors = validateCpp(const CppOptions(), root);
expect(errors.length, 1);
});
+
+ test('transfers documentation comments', () {
+ final List<String> comments = <String>[
+ ' api comment',
+ ' api method comment',
+ ' class comment',
+ ' class field comment',
+ ' enum comment',
+ ];
+ int count = 0;
+
+ final Root root = Root(
+ apis: <Api>[
+ Api(
+ name: 'Api',
+ location: ApiLocation.flutter,
+ documentationComments: <String>[comments[count++]],
+ methods: <Method>[
+ Method(
+ name: 'method',
+ returnType: const TypeDeclaration.voidDeclaration(),
+ documentationComments: <String>[comments[count++]],
+ arguments: <NamedType>[
+ NamedType(
+ name: 'field',
+ type: const TypeDeclaration(
+ baseName: 'int',
+ isNullable: true,
+ ),
+ ),
+ ],
+ )
+ ],
+ )
+ ],
+ classes: <Class>[
+ Class(
+ name: 'class',
+ documentationComments: <String>[comments[count++]],
+ fields: <NamedType>[
+ NamedType(
+ documentationComments: <String>[comments[count++]],
+ type: const TypeDeclaration(
+ baseName: 'Map',
+ isNullable: true,
+ typeArguments: <TypeDeclaration>[
+ TypeDeclaration(baseName: 'String', isNullable: true),
+ TypeDeclaration(baseName: 'int', isNullable: true),
+ ]),
+ name: 'field1'),
+ ],
+ ),
+ ],
+ enums: <Enum>[
+ Enum(
+ name: 'enum',
+ documentationComments: <String>[comments[count++]],
+ members: <String>[
+ 'one',
+ 'two',
+ ],
+ ),
+ ],
+ );
+ final StringBuffer sink = StringBuffer();
+ generateCppHeader('foo', const CppOptions(), root, sink);
+ final String code = sink.toString();
+ for (final String comment in comments) {
+ expect(code, contains('//$comment'));
+ }
+ });
}
diff --git a/packages/pigeon/test/dart_generator_test.dart b/packages/pigeon/test/dart_generator_test.dart
index ba30219..cf467d2 100644
--- a/packages/pigeon/test/dart_generator_test.dart
+++ b/packages/pigeon/test/dart_generator_test.dart
@@ -1164,4 +1164,74 @@
tempDir.deleteSync(recursive: true);
}
});
+
+ test('transfers documentation comments', () {
+ final List<String> comments = <String>[
+ ' api comment',
+ ' api method comment',
+ ' class comment',
+ ' class field comment',
+ ' enum comment',
+ ];
+ int count = 0;
+ final Root root = Root(
+ apis: <Api>[
+ Api(
+ name: 'Api',
+ location: ApiLocation.flutter,
+ documentationComments: <String>[comments[count++]],
+ methods: <Method>[
+ Method(
+ name: 'method',
+ returnType: const TypeDeclaration.voidDeclaration(),
+ documentationComments: <String>[comments[count++]],
+ arguments: <NamedType>[
+ NamedType(
+ name: 'field',
+ type: const TypeDeclaration(
+ baseName: 'int',
+ isNullable: true,
+ ),
+ ),
+ ],
+ )
+ ],
+ )
+ ],
+ classes: <Class>[
+ Class(
+ name: 'class',
+ documentationComments: <String>[comments[count++]],
+ fields: <NamedType>[
+ NamedType(
+ documentationComments: <String>[comments[count++]],
+ type: const TypeDeclaration(
+ baseName: 'Map',
+ isNullable: true,
+ typeArguments: <TypeDeclaration>[
+ TypeDeclaration(baseName: 'String', isNullable: true),
+ TypeDeclaration(baseName: 'int', isNullable: true),
+ ]),
+ name: 'field1'),
+ ],
+ ),
+ ],
+ enums: <Enum>[
+ Enum(
+ name: 'enum',
+ documentationComments: <String>[comments[count++]],
+ members: <String>[
+ 'one',
+ 'two',
+ ],
+ ),
+ ],
+ );
+ final StringBuffer sink = StringBuffer();
+ generateDart(const DartOptions(), root, sink);
+ final String code = sink.toString();
+ for (final String comment in comments) {
+ expect(code, contains('///$comment'));
+ }
+ });
}
diff --git a/packages/pigeon/test/java_generator_test.dart b/packages/pigeon/test/java_generator_test.dart
index b2eca32..da68603 100644
--- a/packages/pigeon/test/java_generator_test.dart
+++ b/packages/pigeon/test/java_generator_test.dart
@@ -1069,4 +1069,81 @@
expect(code,
isNot(contains('@javax.annotation.Generated("dev.flutter.pigeon")')));
});
+
+ test('transfers documentation comments', () {
+ final List<String> comments = <String>[
+ ' api comment',
+ ' api method comment',
+ ' class comment',
+ ' class field comment',
+ ' enum comment',
+ ];
+ int count = 0;
+
+ final Root root = Root(
+ apis: <Api>[
+ Api(
+ name: 'api',
+ location: ApiLocation.flutter,
+ documentationComments: <String>[comments[count++]],
+ methods: <Method>[
+ Method(
+ name: 'method',
+ returnType: const TypeDeclaration.voidDeclaration(),
+ documentationComments: <String>[comments[count++]],
+ arguments: <NamedType>[
+ NamedType(
+ name: 'field',
+ type: const TypeDeclaration(
+ baseName: 'int',
+ isNullable: true,
+ ),
+ ),
+ ],
+ )
+ ],
+ )
+ ],
+ classes: <Class>[
+ Class(
+ name: 'class',
+ documentationComments: <String>[comments[count++]],
+ fields: <NamedType>[
+ NamedType(
+ documentationComments: <String>[comments[count++]],
+ type: const TypeDeclaration(
+ baseName: 'Map',
+ isNullable: true,
+ typeArguments: <TypeDeclaration>[
+ TypeDeclaration(baseName: 'String', isNullable: true),
+ TypeDeclaration(baseName: 'int', isNullable: true),
+ ]),
+ name: 'field1',
+ ),
+ ],
+ ),
+ ],
+ enums: <Enum>[
+ Enum(
+ name: 'enum',
+ documentationComments: <String>[comments[count++]],
+ members: <String>[
+ 'one',
+ 'two',
+ ],
+ ),
+ ],
+ );
+ final StringBuffer sink = StringBuffer();
+ const JavaOptions javaOptions = JavaOptions(className: 'Messages');
+ generateJava(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
+ expect(
+ RegExp(r'(?<=\/\*\*.*?)' + comment + r'(?=.*?\*\/)', dotAll: true)
+ .hasMatch(code),
+ true);
+ }
+ });
}
diff --git a/packages/pigeon/test/objc_generator_test.dart b/packages/pigeon/test/objc_generator_test.dart
index 5754601..ff698b3 100644
--- a/packages/pigeon/test/objc_generator_test.dart
+++ b/packages/pigeon/test/objc_generator_test.dart
@@ -1740,4 +1740,76 @@
'NSObject<FlutterTaskQueue> *taskQueue = [binaryMessenger makeBackgroundTaskQueue];'));
expect(code, contains('taskQueue:taskQueue'));
});
+
+ test('transfers documentation comments', () {
+ final List<String> comments = <String>[
+ ' api comment',
+ ' api method comment',
+ ' class comment',
+ ' class field comment',
+ ' enum comment',
+ ];
+ int count = 0;
+
+ final Root root = Root(
+ apis: <Api>[
+ Api(
+ name: 'api',
+ location: ApiLocation.flutter,
+ documentationComments: <String>[comments[count++]],
+ methods: <Method>[
+ Method(
+ name: 'method',
+ returnType: const TypeDeclaration.voidDeclaration(),
+ documentationComments: <String>[comments[count++]],
+ arguments: <NamedType>[
+ NamedType(
+ name: 'field',
+ type: const TypeDeclaration(
+ baseName: 'int',
+ isNullable: true,
+ ),
+ ),
+ ],
+ )
+ ],
+ )
+ ],
+ classes: <Class>[
+ Class(
+ name: 'class',
+ documentationComments: <String>[comments[count++]],
+ fields: <NamedType>[
+ NamedType(
+ documentationComments: <String>[comments[count++]],
+ type: const TypeDeclaration(
+ baseName: 'Map',
+ isNullable: true,
+ typeArguments: <TypeDeclaration>[
+ TypeDeclaration(baseName: 'String', isNullable: true),
+ TypeDeclaration(baseName: 'int', isNullable: true),
+ ]),
+ name: 'field1',
+ ),
+ ],
+ ),
+ ],
+ enums: <Enum>[
+ Enum(
+ name: 'enum',
+ documentationComments: <String>[comments[count++]],
+ members: <String>[
+ 'one',
+ 'two',
+ ],
+ ),
+ ],
+ );
+ final StringBuffer sink = StringBuffer();
+ generateObjcHeader(const ObjcOptions(), root, sink);
+ final String code = sink.toString();
+ for (final String comment in comments) {
+ expect(code, contains('///$comment'));
+ }
+ });
}
diff --git a/packages/pigeon/test/swift_generator_test.dart b/packages/pigeon/test/swift_generator_test.dart
index 319054f..c40d85a 100644
--- a/packages/pigeon/test/swift_generator_test.dart
+++ b/packages/pigeon/test/swift_generator_test.dart
@@ -947,4 +947,77 @@
final String code = sink.toString();
expect(code, contains('var input: String\n'));
});
+
+ test('transfers documentation comments', () {
+ final List<String> comments = <String>[
+ ' api comment',
+ ' api method comment',
+ ' class comment',
+ ' class field comment',
+ ' enum comment',
+ ];
+ int count = 0;
+
+ final Root root = Root(
+ apis: <Api>[
+ Api(
+ name: 'api',
+ location: ApiLocation.flutter,
+ documentationComments: <String>[comments[count++]],
+ methods: <Method>[
+ Method(
+ name: 'method',
+ returnType: const TypeDeclaration.voidDeclaration(),
+ documentationComments: <String>[comments[count++]],
+ arguments: <NamedType>[
+ NamedType(
+ name: 'field',
+ type: const TypeDeclaration(
+ baseName: 'int',
+ isNullable: true,
+ ),
+ ),
+ ],
+ )
+ ],
+ )
+ ],
+ classes: <Class>[
+ Class(
+ name: 'class',
+ documentationComments: <String>[comments[count++]],
+ fields: <NamedType>[
+ NamedType(
+ documentationComments: <String>[comments[count++]],
+ type: const TypeDeclaration(
+ baseName: 'Map',
+ isNullable: true,
+ typeArguments: <TypeDeclaration>[
+ TypeDeclaration(baseName: 'String', isNullable: true),
+ TypeDeclaration(baseName: 'int', isNullable: true),
+ ]),
+ name: 'field1',
+ ),
+ ],
+ ),
+ ],
+ enums: <Enum>[
+ Enum(
+ name: 'enum',
+ documentationComments: <String>[comments[count++]],
+ members: <String>[
+ 'one',
+ 'two',
+ ],
+ ),
+ ],
+ );
+ final StringBuffer sink = StringBuffer();
+ const SwiftOptions swiftOptions = SwiftOptions();
+ generateSwift(swiftOptions, root, sink);
+ final String code = sink.toString();
+ for (final String comment in comments) {
+ expect(code, contains('///$comment'));
+ }
+ });
}