Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a82b1c3
Add logic to add generated annotation in kotlin
jeffkwoh Feb 4, 2026
df74e39
Add flags for parsing use_generated_annotation
jeffkwoh Feb 4, 2026
a262475
Fix wrong parsing logic
jeffkwoh Feb 4, 2026
4267595
Fix test and remove unneeded code
jeffkwoh Feb 4, 2026
b9bd95f
Fix kotlin generator test
jeffkwoh Feb 4, 2026
f154dec
Fix test
jeffkwoh Feb 4, 2026
1afaa7b
Format dart files
jeffkwoh Feb 6, 2026
79ccc95
Address gemini-code-assist comments
jeffkwoh Feb 6, 2026
d33ccff
refactor: consolidate generated annotation constant and refactor test…
jeffkwoh Feb 6, 2026
449b597
Add kotlinUseGeneratedAnnotation parameter to generation tool
jeffkwoh Feb 9, 2026
5e2b71a
Add javaUseGeneratedAnnotation parameter and test case
jeffkwoh Feb 9, 2026
04214ed
Format generation.dart
jeffkwoh Feb 9, 2026
a9ee424
Merge branch 'main' into pigeon-gen
jeffkwoh Feb 9, 2026
34d41e1
Fix analyzer issues in generation.dart
jeffkwoh Feb 9, 2026
0944a99
Fix Kotlin @file: annotation prefix for @Generated
jeffkwoh Feb 9, 2026
a8254ba
Remove unrequired import
jeffkwoh Feb 9, 2026
275d85f
Remove java generated goldens as they don't seems to be passing at HEAD
jeffkwoh Feb 9, 2026
ee13f77
Merge branch 'main' into pigeon-gen
jeffkwoh Mar 2, 2026
9352877
Fix kotlin genrated code with annotation
jeffkwoh Mar 2, 2026
c937bc6
Fix rename constant that was missed in previous commit
jeffkwoh Mar 2, 2026
4993d2b
Fix broken java refactor of generatedAnnotation --> pluginPackageName
jeffkwoh Mar 2, 2026
2bf1c88
Fix Kotlin compilation errors in generated pigeon tests
jeffkwoh Mar 2, 2026
064d8f2
Format kotlin_generator.dart
jeffkwoh Mar 2, 2026
76c3cd5
Merge branch 'main' into pigeon-gen
jeffkwoh Mar 2, 2026
e99d324
Address PR review comments: Fix typos, unused args, and rename annota…
jeffkwoh Mar 3, 2026
125d903
Merge branch 'main' into pigeon-gen
jeffkwoh Mar 3, 2026
a173dfc
Update pubspec.yaml
jeffkwoh Mar 3, 2026
3f34435
Merge branch 'main' into pigeon-gen
jeffkwoh Mar 4, 2026
654b4dc
Merge branch 'main' into pigeon-gen
jeffkwoh Mar 5, 2026
6eb341d
Merge branch 'main' into pigeon-gen
jeffkwoh Mar 6, 2026
d433a77
Update Pigeon generator tools and package metadata
jeffkwoh Mar 9, 2026
52b5bce
Merge branch 'main' into pigeon-gen
jeffkwoh Mar 9, 2026
fab6e4f
Merge branch 'main' into pigeon-gen
jeffkwoh Mar 9, 2026
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 @@
## 26.2.0

* [kotlin] Adds option to add javax.annotation.Generated annotation.

## 26.1.10

* Dramatically reduces the number of File write operations sent to the operating
Expand Down
5 changes: 4 additions & 1 deletion packages/pigeon/lib/src/generator_tools.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import 'generator.dart';
/// The current version of pigeon.
///
/// This must match the version in pubspec.yaml.
const String pigeonVersion = '26.1.10';
const String pigeonVersion = '26.2.0';

/// Default plugin package name.
const String defaultPluginPackageName = 'dev.flutter.pigeon';

/// Read all the content from [stdin] to a String.
String readStdin() {
Expand Down
4 changes: 3 additions & 1 deletion packages/pigeon/lib/src/java/java_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,9 @@ class JavaGenerator extends StructuredGenerator<InternalJavaOptions> {
'@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression", "serial"})',
);
if (generatorOptions.useGeneratedAnnotation ?? false) {
indent.writeln('@javax.annotation.Generated("dev.flutter.pigeon")');
indent.writeln(
'@javax.annotation.Generated("$defaultPluginPackageName")',
);
}
indent.writeln('public class ${generatorOptions.className!} {');
indent.inc();
Expand Down
25 changes: 25 additions & 0 deletions packages/pigeon/lib/src/kotlin/kotlin_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ const String _pigeonMethodChannelCodec = 'PigeonMethodCodec';

const String _overflowClassName = '${classNamePrefix}CodecOverflow';

/// Kotlin file-level annotation for generated code.
const String kotlinGeneratedAnnotation =
'@file:Generated("$defaultPluginPackageName")';

/// Options that control how Kotlin code will be generated.
class KotlinOptions {
/// Creates a [KotlinOptions] object
Expand All @@ -44,6 +48,7 @@ class KotlinOptions {
this.errorClassName,
this.includeErrorClass = true,
this.fileSpecificClassNameComponent,
this.useGeneratedAnnotation = false,
});

/// The package where the generated class will live.
Expand All @@ -64,6 +69,11 @@ class KotlinOptions {
/// A String to augment class names to avoid cross file collisions.
final String? fileSpecificClassNameComponent;

/// Determines if the `javax.annotation.Generated` is used in the output. This
/// is false by default since that dependency isn't available in plugins by
/// default.
final bool useGeneratedAnnotation;

/// Creates a [KotlinOptions] from a Map representation where:
/// `x = KotlinOptions.fromMap(x.toMap())`.
static KotlinOptions fromMap(Map<String, Object> map) {
Expand All @@ -74,6 +84,7 @@ class KotlinOptions {
includeErrorClass: map['includeErrorClass'] as bool? ?? true,
fileSpecificClassNameComponent:
map['fileSpecificClassNameComponent'] as String?,
useGeneratedAnnotation: map['useGeneratedAnnotation'] as bool? ?? false,
);
}

Expand All @@ -87,6 +98,7 @@ class KotlinOptions {
'includeErrorClass': includeErrorClass,
if (fileSpecificClassNameComponent != null)
'fileSpecificClassNameComponent': fileSpecificClassNameComponent!,
'useGeneratedAnnotation': useGeneratedAnnotation,
};
return result;
}
Expand All @@ -108,6 +120,7 @@ class InternalKotlinOptions extends InternalOptions {
this.errorClassName,
this.includeErrorClass = true,
this.fileSpecificClassNameComponent,
this.useGeneratedAnnotation = false,
});

/// Creates InternalKotlinOptions from KotlinOptions.
Expand All @@ -119,6 +132,7 @@ class InternalKotlinOptions extends InternalOptions {
copyrightHeader = options.copyrightHeader ?? copyrightHeader,
errorClassName = options.errorClassName,
includeErrorClass = options.includeErrorClass,
useGeneratedAnnotation = options.useGeneratedAnnotation,
fileSpecificClassNameComponent =
options.fileSpecificClassNameComponent ??
kotlinOut.split('/').lastOrNull?.split('.').first;
Expand All @@ -143,6 +157,11 @@ class InternalKotlinOptions extends InternalOptions {

/// A String to augment class names to avoid cross file collisions.
final String? fileSpecificClassNameComponent;

/// Determines if the `javax.annotation.Generated` is used in the output. This
/// is false by default since that dependency isn't available in plugins by
/// default.
final bool useGeneratedAnnotation;
}

/// Options that control how Kotlin code will be generated for a specific
Expand Down Expand Up @@ -192,6 +211,9 @@ class KotlinGenerator extends StructuredGenerator<InternalKotlinOptions> {
indent.writeln('// ${getGeneratedCodeWarning()}');
indent.writeln('// $seeAlsoWarning');
indent.writeln('@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")');
if (generatorOptions.useGeneratedAnnotation) {
indent.writeln(kotlinGeneratedAnnotation);
}
}

@override
Expand All @@ -215,6 +237,9 @@ class KotlinGenerator extends StructuredGenerator<InternalKotlinOptions> {
indent.writeln('import io.flutter.plugin.common.StandardMessageCodec');
indent.writeln('import java.io.ByteArrayOutputStream');
indent.writeln('import java.nio.ByteBuffer');
if (generatorOptions.useGeneratedAnnotation) {
indent.writeln('import javax.annotation.Generated');
}
}

@override
Expand Down
6 changes: 6 additions & 0 deletions packages/pigeon/lib/src/pigeon_lib.dart
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,10 @@ ${_argParser.usage}''';
help: 'The package that generated Kotlin code will be in.',
aliases: const <String>['experimental_kotlin_package'],
)
..addFlag(
'kotlin_use_generated_annotation',
help: 'Adds javax.annotation.Generated annotation to the output.',
)
..addOption(
'cpp_header_out',
help: 'Path to generated C++ header file (.h).',
Expand Down Expand Up @@ -638,6 +642,8 @@ ${_argParser.usage}''';
kotlinOut: results['kotlin_out'] as String?,
kotlinOptions: KotlinOptions(
package: results['kotlin_package'] as String?,
useGeneratedAnnotation:
results['kotlin_use_generated_annotation'] as bool? ?? false,
),
cppHeaderOut: results['cpp_header_out'] as String?,
cppSourceOut: results['cpp_source_out'] as String?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ android {
}

dependencies {
compileOnly 'javax.annotation:javax.annotation-api:1.3.2'
testImplementation("junit:junit:4.13.2")
testImplementation("io.mockk:mockk:1.14.9")
// org.jetbrains.kotlin:kotlin-bom artifact purpose is to align kotlin stdlib and related code versions.
Expand Down
2 changes: 1 addition & 1 deletion packages/pigeon/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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%3A%22p%3A+pigeon%22
version: 26.1.10 # This must match the version in lib/src/generator_tools.dart
version: 26.2.0 # This must match the version in lib/src/generator_tools.dart

environment:
sdk: ^3.9.0
Expand Down
93 changes: 49 additions & 44 deletions packages/pigeon/test/java_generator_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'package:pigeon/pigeon.dart';
import 'package:pigeon/src/ast.dart';
import 'package:pigeon/src/generator_tools.dart';
import 'package:pigeon/src/java/java_generator.dart';
import 'package:test/test.dart';

Expand Down Expand Up @@ -1611,51 +1612,55 @@ void main() {
);
});

test('generated annotation', () {
final classDefinition = Class(name: 'Foobar', fields: <NamedType>[]);
final root = Root(
apis: <Api>[],
classes: <Class>[classDefinition],
enums: <Enum>[],
);
final sink = StringBuffer();
const javaOptions = InternalJavaOptions(
className: 'Messages',
useGeneratedAnnotation: true,
javaOut: '',
);
const generator = JavaGenerator();
generator.generate(
javaOptions,
root,
sink,
dartPackageName: DEFAULT_PACKAGE_NAME,
);
final code = sink.toString();
expect(code, contains('@javax.annotation.Generated("dev.flutter.pigeon")'));
});
group('generated annotation', () {
late Class classDefinition;
late Root root;
late StringBuffer sink;
late JavaGenerator generator;
const generatedAnnotation =
'@javax.annotation.Generated("$defaultPluginPackageName")';

test('no generated annotation', () {
final classDefinition = Class(name: 'Foobar', fields: <NamedType>[]);
final root = Root(
apis: <Api>[],
classes: <Class>[classDefinition],
enums: <Enum>[],
);
final sink = StringBuffer();
const javaOptions = InternalJavaOptions(className: 'Messages', javaOut: '');
const generator = JavaGenerator();
generator.generate(
javaOptions,
root,
sink,
dartPackageName: DEFAULT_PACKAGE_NAME,
);
final code = sink.toString();
expect(
code,
isNot(contains('@javax.annotation.Generated("dev.flutter.pigeon")')),
);
setUp(() {
classDefinition = Class(name: 'Foobar', fields: <NamedType>[]);
root = Root(
apis: <Api>[],
classes: <Class>[classDefinition],
enums: <Enum>[],
);
sink = StringBuffer();
generator = const JavaGenerator();
});

test('with generated annotation', () {
const javaOptions = InternalJavaOptions(
className: 'Messages',
useGeneratedAnnotation: true,
javaOut: '',
);
generator.generate(
javaOptions,
root,
sink,
dartPackageName: DEFAULT_PACKAGE_NAME,
);
final code = sink.toString();
expect(code, contains(generatedAnnotation));
});

test('without generated annotation', () {
const javaOptions = InternalJavaOptions(
className: 'Messages',
javaOut: '',
);
generator.generate(
javaOptions,
root,
sink,
dartPackageName: DEFAULT_PACKAGE_NAME,
);
final code = sink.toString();
expect(code, isNot(contains(generatedAnnotation)));
});
});

test('transfers documentation comments', () {
Expand Down
43 changes: 43 additions & 0 deletions packages/pigeon/test/kotlin_generator_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,49 @@ void main() {
expect(code, startsWith('// hello world'));
});

group('generated annotation', () {
late Root root;
late KotlinGenerator generator;
late StringBuffer sink;

setUp(() {
root = Root(apis: <Api>[], classes: <Class>[], enums: <Enum>[]);
generator = const KotlinGenerator();
sink = StringBuffer();
});

test('with generated annotation', () {
final kotlinOptions = InternalKotlinOptions(
copyrightHeader: makeIterable('hello world'),
kotlinOut: '',
useGeneratedAnnotation: true,
);
generator.generate(
kotlinOptions,
root,
sink,
dartPackageName: DEFAULT_PACKAGE_NAME,
);
final code = sink.toString();
expect(code, contains(kotlinGeneratedAnnotation));
});

test('without generated annotation', () {
final kotlinOptions = InternalKotlinOptions(
copyrightHeader: makeIterable('hello world'),
kotlinOut: '',
);
generator.generate(
kotlinOptions,
root,
sink,
dartPackageName: DEFAULT_PACKAGE_NAME,
);
final code = sink.toString();
expect(code, isNot(contains(kotlinGeneratedAnnotation)));
});
});

test('generics - list', () {
final classDefinition = Class(
name: 'Foobar',
Expand Down
7 changes: 7 additions & 0 deletions packages/pigeon/test/pigeon_lib_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ void main() {
expect(opts.kotlinOptions?.package, equals('com.google.foo'));
});

test('parse args - kotlin_use_generated_annotation', () {
final PigeonOptions opts = Pigeon.parseArgs(<String>[
'--kotlin_use_generated_annotation',
]);
expect(opts.kotlinOptions!.useGeneratedAnnotation, isTrue);
});

test('parse args - cpp_header_out', () {
final PigeonOptions opts = Pigeon.parseArgs(<String>[
'--cpp_header_out',
Expand Down
17 changes: 17 additions & 0 deletions packages/pigeon/tool/shared/generation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,21 @@ Future<int> generateTestPigeons({
return generateCode;
}
}

// Test case for useGeneratedAnnotation feature with core_tests
final String corePascalCaseName = _snakeToPascalCase('core_tests');
final int generateCodeWithAnnotation = await runPigeon(
input: './pigeons/core_tests.dart',
kotlinOut:
'$outputBase/android/src/main/kotlin/com/example/test_plugin/annotation/${corePascalCaseName}WithAnnotation.gen.kt',
kotlinPackage: 'com.example.test_plugin.annotation',
kotlinErrorClassName: 'FlutterError',
kotlinUseGeneratedAnnotation: true,
);
if (generateCodeWithAnnotation != 0) {
return generateCodeWithAnnotation;
}

Comment thread
jeffkwoh marked this conversation as resolved.
return 0;
}

Expand All @@ -217,6 +232,7 @@ Future<int> runPigeon({
String? kotlinPackage,
String? kotlinErrorClassName,
bool kotlinIncludeErrorClass = true,
bool kotlinUseGeneratedAnnotation = false,
bool swiftIncludeErrorClass = true,
String? swiftOut,
String? swiftErrorClassName,
Expand Down Expand Up @@ -291,6 +307,7 @@ Future<int> runPigeon({
package: kotlinPackage,
errorClassName: kotlinErrorClassName,
includeErrorClass: kotlinIncludeErrorClass,
useGeneratedAnnotation: kotlinUseGeneratedAnnotation,
),
objcHeaderOut: objcHeaderOut,
objcSourceOut: objcSourceOut,
Expand Down