Skip to content

Commit

Permalink
[pigeon] Documentation comments (#2578)
Browse files Browse the repository at this point in the history
  • Loading branch information
tarrinneal authored Sep 19, 2022
1 parent b2a4157 commit 392a454
Show file tree
Hide file tree
Showing 17 changed files with 768 additions and 60 deletions.
4 changes: 4 additions & 0 deletions packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
56 changes: 50 additions & 6 deletions packages/pigeon/lib/ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class Method extends Node {
this.offset,
this.objcSelector = '',
this.taskQueueType = TaskQueueType.serial,
this.documentationComments = const <String>[],
});

/// The name of the method.
Expand All @@ -56,11 +57,18 @@ class Method extends Node {
/// 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)';
}
}

Expand All @@ -72,6 +80,7 @@ class Api extends Node {
required this.location,
required this.methods,
this.dartHostTestHandler,
this.documentationComments = const <String>[],
});

/// The name of the API.
Expand All @@ -86,9 +95,16 @@ class Api extends Node {
/// 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)';
}
}

Expand Down Expand Up @@ -156,7 +172,12 @@ class TypeDeclaration {
/// 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;
Expand All @@ -167,9 +188,16 @@ class NamedType extends Node {
/// 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)';
}
}

Expand All @@ -179,6 +207,7 @@ class Class extends Node {
Class({
required this.name,
required this.fields,
this.documentationComments = const <String>[],
});

/// The name of the class.
Expand All @@ -187,9 +216,16 @@ class Class extends Node {
/// 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)';
}
}

Expand All @@ -199,6 +235,7 @@ class Enum extends Node {
Enum({
required this.name,
required this.members,
this.documentationComments = const <String>[],
});

/// The name of the enum.
Expand All @@ -207,9 +244,16 @@ class Enum extends Node {
/// 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)';
}
}

Expand Down
64 changes: 47 additions & 17 deletions packages/pigeon/lib/cpp_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ import 'functional.dart';
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
Expand Down Expand Up @@ -188,13 +195,21 @@ $friendLines
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,
Expand Down Expand Up @@ -261,7 +276,7 @@ void _writeDataClassImplementation(Indent indent, Class klass, Root root) {
root.enums.map((Enum x) => x.name).toSet();

indent.addln('');
indent.writeln('/* ${klass.name} */');
indent.writeln('$_commentPrefix ${klass.name}');
indent.addln('');

// Getters and setters.
Expand Down Expand Up @@ -398,8 +413,11 @@ else if (const int64_t* ${pointerFieldName}_64 = std::get_if<int64_t>(&$encodabl
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:', '', () {
Expand Down Expand Up @@ -432,6 +450,10 @@ void _writeHostApiHeader(Indent indent, Api api, Root root) {
return '$argType $argName';
}));
}

addDocumentationComments(
indent, method.documentationComments, _docCommentSpec);

if (method.isAsynchronous) {
argSignature.add('std::function<void($returnTypeName reply)> result');
indent.writeln(
Expand All @@ -442,10 +464,10 @@ void _writeHostApiHeader(Indent indent, Api api, Root root) {
}
}
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(
Expand All @@ -464,13 +486,13 @@ void _writeHostApiSource(Indent indent, Api api, Root root) {

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('{', '}', () {
Expand Down Expand Up @@ -679,8 +701,12 @@ String _getSafeArgumentName(int count, NamedType argument) =>

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:', '', () {
Expand All @@ -695,6 +721,8 @@ void _writeFlutterApiHeader(Indent indent, Api api) {
? '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 {
Expand All @@ -715,7 +743,7 @@ void _writeFlutterApiHeader(Indent indent, Api api) {
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('{', '}', () {
Expand Down Expand Up @@ -988,8 +1016,8 @@ void generateCppHeader(
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');
Expand Down Expand Up @@ -1024,10 +1052,12 @@ void generateCppHeader(
}

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;
Expand Down Expand Up @@ -1074,8 +1104,8 @@ void generateCppSource(CppOptions options, Root root, StringSink sink) {
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('');
Expand Down
24 changes: 24 additions & 0 deletions packages/pigeon/lib/dart_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ import 'ast.dart';
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.
Expand Down Expand Up @@ -154,6 +161,7 @@ void _writeHostApi(DartOptions opt, Indent indent, Api api, Root root) {
_writeCodec(indent, codecName, api, root);
indent.addln('');
bool first = true;
addDocumentationComments(indent, api.documentationComments, _docCommentSpec);
indent.write('class ${api.name} ');
indent.scoped('{', '}', () {
indent.format('''
Expand All @@ -173,6 +181,8 @@ final BinaryMessenger? _binaryMessenger;
} else {
first = false;
}
addDocumentationComments(
indent, func.documentationComments, _docCommentSpec);
String argSignature = '';
String sendArgument = 'null';
if (func.arguments.isNotEmpty) {
Expand Down Expand Up @@ -264,11 +274,16 @@ void _writeFlutterApi(
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)}>'
Expand Down Expand Up @@ -433,6 +448,8 @@ void generateDart(DartOptions opt, Root root, StringSink sink) {
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) {
Expand Down Expand Up @@ -555,11 +572,17 @@ pigeonMap['${field.name}'] != null
});
}

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};');
}
Expand Down Expand Up @@ -696,6 +719,7 @@ void generateTestDart(
methods: api.methods,
location: ApiLocation.flutter,
dartHostTestHandler: api.dartHostTestHandler,
documentationComments: api.documentationComments,
);
indent.writeln('');
_writeFlutterApi(
Expand Down
Loading

0 comments on commit 392a454

Please sign in to comment.