Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/pigeon/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 27.2.0

* Adds support for empty data classes.

## 27.1.2

* Reports a clear error when an input file uses an enhanced enum (one with a
Expand Down
2 changes: 2 additions & 0 deletions packages/pigeon/lib/src/ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,8 @@ class Root extends Node {
return Root(apis: <Api>[], classes: <Class>[], enums: <Enum>[]);
}

// TODO(tarrinneal): Ensure classes are sorted in topological dependency order; see
// https://github.com/flutter/flutter/issues/128330.
/// All the classes contained in the AST.
List<Class> classes;

Expand Down
18 changes: 12 additions & 6 deletions packages/pigeon/lib/src/dart/dart_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -222,17 +222,19 @@ class DartGenerator extends StructuredGenerator<InternalDartOptions> {

indent.write('${sealed}class ${classDefinition.name} $implements');
indent.addScoped('{', '}', () {
if (classDefinition.fields.isEmpty) {
if (classDefinition.isSealed) {
return;
}
_writeConstructor(indent, classDefinition);
indent.newln();
for (final NamedType field in getFieldsInSerializationOrder(classDefinition)) {
addDocumentationComments(indent, field.documentationComments, docCommentSpec);
if (classDefinition.fields.isNotEmpty) {
for (final NamedType field in getFieldsInSerializationOrder(classDefinition)) {
addDocumentationComments(indent, field.documentationComments, docCommentSpec);

final String datatype = addGenericTypes(field.type);
indent.writeln('$datatype ${field.name};');
indent.newln();
final String datatype = addGenericTypes(field.type);
indent.writeln('$datatype ${field.name};');
indent.newln();
}
}
Comment thread
tarrinneal marked this conversation as resolved.
_writeToList(indent, classDefinition);
indent.newln();
Expand Down Expand Up @@ -264,6 +266,10 @@ class DartGenerator extends StructuredGenerator<InternalDartOptions> {

void _writeConstructor(Indent indent, Class classDefinition) {
indent.write(classDefinition.name);
if (classDefinition.fields.isEmpty) {
indent.addln('();');
return;
}
indent.addScoped('({', '});', () {
for (final NamedType field in getFieldsInSerializationOrder(classDefinition)) {
final required = !field.type.isNullable && field.defaultValue == null ? 'required ' : '';
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/lib/src/generator_tools.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import 'generator.dart';
/// The current version of pigeon.
///
/// This must match the version in pubspec.yaml.
const String pigeonVersion = '27.1.2';
const String pigeonVersion = '27.2.0';

/// Default plugin package name.
const String defaultPluginPackageName = 'dev.flutter.pigeon';
Expand Down
14 changes: 9 additions & 5 deletions packages/pigeon/lib/src/java/java_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -345,11 +345,15 @@ class JavaGenerator extends StructuredGenerator<InternalJavaOptions> {
indent.writeScoped('public boolean equals(Object o) {', '}', () {
indent.writeln('if (this == o) { return true; }');
indent.writeln('if (o == null || getClass() != o.getClass()) { return false; }');
indent.writeln('${classDefinition.name} that = (${classDefinition.name}) o;');
final Iterable<String> checks = classDefinition.fields.map((NamedType field) {
return 'pigeonDeepEquals(${field.name}, that.${field.name})';
});
indent.writeln('return ${checks.join(' && ')};');
if (classDefinition.fields.isEmpty) {
indent.writeln('return true;');
} else {
indent.writeln('${classDefinition.name} that = (${classDefinition.name}) o;');
final Iterable<String> checks = classDefinition.fields.map((NamedType field) {
return 'pigeonDeepEquals(${field.name}, that.${field.name})';
});
indent.writeln('return ${checks.join(' && ')};');
}
});
indent.newln();

Expand Down
35 changes: 23 additions & 12 deletions packages/pigeon/lib/src/kotlin/kotlin_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,11 @@ class KotlinGenerator extends StructuredGenerator<InternalKotlinOptions> {
indent.writeln('return true');
});

indent.writeln('val other = other as ${classDefinition.name}');
final Iterable<NamedType> fields = getFieldsInSerializationOrder(classDefinition);
if (fields.isEmpty) {
indent.writeln('return true');
} else {
indent.writeln('val other = other as ${classDefinition.name}');
final String utils = _getUtilsClassName(generatorOptions);
final String comparisons = fields
.map((NamedType field) => '$utils.deepEquals(this.${field.name}, other.${field.name})')
Expand Down Expand Up @@ -399,24 +399,35 @@ class KotlinGenerator extends StructuredGenerator<InternalKotlinOptions> {

void _writeDataClassSignature(Indent indent, Class classDefinition, {bool private = false}) {
final privateString = private ? 'private ' : '';
final classType = classDefinition.isSealed ? 'sealed' : 'data';
final String classType;
if (classDefinition.isSealed) {
classType = 'sealed ';
} else if (classDefinition.fields.isEmpty) {
classType = '';
} else {
classType = 'data ';
}
final inheritance = classDefinition.superClass != null
? ' : ${classDefinition.superClassName}()'
: '';
indent.write('$privateString$classType class ${classDefinition.name} ');
indent.write('$privateString${classType}class ${classDefinition.name} ');
if (classDefinition.isSealed) {
return;
}
indent.addScoped('(', ')$inheritance', () {
for (final NamedType element in getFieldsInSerializationOrder(classDefinition)) {
_writeClassField(indent, element);
if (getFieldsInSerializationOrder(classDefinition).last != element) {
indent.addln(',');
} else {
indent.newln();
if (classDefinition.fields.isEmpty) {
indent.add(inheritance);
} else {
indent.addScoped('(', ')$inheritance', () {
for (final NamedType element in getFieldsInSerializationOrder(classDefinition)) {
_writeClassField(indent, element);
if (getFieldsInSerializationOrder(classDefinition).last != element) {
indent.addln(',');
} else {
indent.newln();
}
}
}
});
});
}
}

@override
Expand Down
36 changes: 18 additions & 18 deletions packages/pigeon/lib/src/objc/objc_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,9 @@ class ObjcSourceGenerator extends StructuredGenerator<InternalObjcOptions> {
final String className = _className(generatorOptions.prefix, classDefinition.name);

indent.writeln('@implementation $className');
_writeObjcSourceClassInitializer(generatorOptions, root, indent, classDefinition, className);
if (classDefinition.fields.isNotEmpty) {
_writeObjcSourceClassInitializer(generatorOptions, root, indent, classDefinition, className);
}
writeClassDecode(
generatorOptions,
root,
Expand Down Expand Up @@ -554,21 +556,21 @@ class ObjcSourceGenerator extends StructuredGenerator<InternalObjcOptions> {
indent.writeScoped('if (![object isKindOfClass:[self class]]) {', '}', () {
indent.writeln('return NO;');
});
indent.writeln('$className *other = ($className *)object;');
final Iterable<String> checks = classDefinition.fields.map((NamedType field) {
final String name = field.name;
if (_usesPrimitive(field.type)) {
if (field.type.baseName == 'double') {
return '(self.$name == other.$name || (isnan(self.$name) && isnan(other.$name)))';
}
return 'self.$name == other.$name';
} else {
return 'FLTPigeonDeepEquals(self.$name, other.$name)';
}
});
if (checks.isEmpty) {
if (classDefinition.fields.isEmpty) {
indent.writeln('return YES;');
} else {
indent.writeln('$className *other = ($className *)object;');
final Iterable<String> checks = classDefinition.fields.map((NamedType field) {
final String name = field.name;
if (_usesPrimitive(field.type)) {
if (field.type.baseName == 'double') {
return '(self.$name == other.$name || (isnan(self.$name) && isnan(other.$name)))';
}
return 'self.$name == other.$name';
} else {
return 'FLTPigeonDeepEquals(self.$name, other.$name)';
}
});
indent.writeln('return ${checks.join(' && ')};');
}
});
Expand Down Expand Up @@ -1900,10 +1902,8 @@ void _writeDataClassDeclaration(
addDocumentationComments(indent, classDefinition.documentationComments, _docCommentSpec);

indent.writeln('@interface ${_className(prefix, classDefinition.name)} : NSObject');
if (getFieldsInSerializationOrder(classDefinition).isNotEmpty) {
if (getFieldsInSerializationOrder(
classDefinition,
).map((NamedType e) => !e.type.isNullable).any((bool e) => e)) {
if (classDefinition.fields.isNotEmpty) {
if (classDefinition.fields.any((NamedType e) => !e.type.isNullable)) {
indent.writeln(
'$_docCommentPrefix `init` unavailable to enforce nonnull fields, see the `make` class method.',
);
Expand Down
5 changes: 5 additions & 0 deletions packages/pigeon/pigeons/core_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ class AllNullableTypesWithoutRecursion {
Map<int?, Map<Object?, Object?>?>? mapMap;
}

/// A data class without fields for testing empty classes.
class AnEmptyClass {}

/// A class for testing nested class handling.
///
/// This is needed to test nested nullable and non-nullable classes,
Expand All @@ -265,6 +268,7 @@ class AllClassesWrapper {
this.classMap,
this.nullableClassList,
this.nullableClassMap,
this.anEmptyClass,
);
AllNullableTypes allNullableTypes;
AllNullableTypesWithoutRecursion? allNullableTypesWithoutRecursion;
Expand All @@ -273,6 +277,7 @@ class AllClassesWrapper {
List<AllNullableTypesWithoutRecursion?>? nullableClassList;
Map<int?, AllTypes?> classMap;
Map<int?, AllNullableTypesWithoutRecursion?>? nullableClassMap;
AnEmptyClass? anEmptyClass;
}

/// The core interface that each host language plugin must implement in
Expand Down
2 changes: 2 additions & 0 deletions packages/pigeon/pigeons/event_channel_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ class ClassEvent extends PlatformEvent {
final EventAllNullableTypes value;
}

class EmptyEvent extends PlatformEvent {}

@EventChannelApi()
abstract class EventChannelMethods {
int streamInts();
Expand Down
Loading
Loading