Skip to content

[pigeon] add support for top level consts#12032

Open
tarrinneal wants to merge 3 commits into
flutter:mainfrom
tarrinneal:consts
Open

[pigeon] add support for top level consts#12032
tarrinneal wants to merge 3 commits into
flutter:mainfrom
tarrinneal:consts

Conversation

@tarrinneal

@tarrinneal tarrinneal commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Add Top-level Constants Support to Pigeon

This PR adds support for defining and generating top-level constants across all target languages supported by Pigeon (Dart, Kotlin, Java, Swift, Objective-C, C++, and GObject).

Resolves: flutter/flutter#188642

Summary of Changes

1. AST & Parser

  • Added a Constant node type to the AST representing top-level constants.
  • Updated pigeon_lib_internal.dart to parse const declarations.
  • Restrained constant types to: String, int, double, and bool.
  • Implemented validation for explicit type annotations, type matching, and initialization values (unsupported types, binary expressions, and string interpolations will trigger compilation errors).

2. Code Generation

Added constant generation to all target languages:

  • Dart: Generates top-level const variables.
  • Java: Generates public static final fields inside the main generated class.
  • Kotlin: Generates companion object const val properties (using val for double/boolean where JVM const is not supported).
  • Swift: Generates global public let constants.
  • Objective-C: Generates global static const / static NSString *const variables in the header file.
  • C++: Generates global inline constexpr variables in the header.
  • GObject: Generates global #define macros in the header.

3. Tests & Documentation

  • Added parsing validation tests in test/pigeon_lib_test.dart.
  • Added generator unit tests (test/*_generator_test.dart) for each language verifying the syntax of generated constants.
  • Updated pigeons/core_tests.dart with constant declarations, and added corresponding unit tests verifying their correctness in each target platform project.
  • Added an integration test in platform_tests/shared_test_plugin_code/lib/integration_tests.dart to assert constant values at runtime.
  • Updated packages/pigeon/README.md to document the new feature, using code excerpts linked to example/app/pigeons/messages.dart.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for generating top-level constants across all supported platforms in Pigeon. Feedback on the changes suggests resolving compilation issues by avoiding the escaping of the $ character in the shared double-quote escaping helper and instead handling it specifically in Kotlin. Additionally, double constants initialized with integer literals should be explicitly parsed as doubles to prevent type mismatch errors in Java and Kotlin, and Java constants should be generated as primitive types rather than boxed types to ensure they function as true compile-time constants.

Comment thread packages/pigeon/lib/src/generator_tools.dart
Comment thread packages/pigeon/lib/src/kotlin/kotlin_generator.dart
Comment thread packages/pigeon/lib/src/pigeon_lib_internal.dart Outdated
Comment thread packages/pigeon/lib/src/java/java_generator.dart
Comment thread packages/pigeon/test/java_generator_test.dart Outdated
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 27, 2026
@tarrinneal

Copy link
Copy Markdown
Contributor Author

/gemini

@tarrinneal tarrinneal added the CICD Run CI/CD label Jun 30, 2026
@tarrinneal

Copy link
Copy Markdown
Contributor Author

/gemini


NS_ASSUME_NONNULL_BEGIN

static NSString *const PGNaStringConstant = @"stringConstantValue";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of the prefixing, the variable name needs to be converted to UpperCamelCase. E.g., PGNAStringConstant.

return _makeDartStringLiteral(value.toString());
} else {
return value.toString();
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Consider a single return statement with a ternary.


String _makeDartStringLiteral(String valStr) {
final bool hasSpecial =
// ignore: use_raw_strings

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just use a raw string for this one?

if (!valStr.contains('"')) {
return '"$valStr"';
}
return "r'''$valStr'''";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the string contains '''s? I think you'll need to make the fallback escaping ' instead of using '''.

return '${value}L';
} else {
return value.toString();
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: consider return switch (type) {...}


NS_ASSUME_NONNULL_BEGIN

static NSString *const PGNaStringConstant = @"stringConstantValue";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consts should not be inlined into headers in C. These should be extern declarations, and the definitions should be in the .g.m file.

/// Escapes special characters in a string for use in double-quoted string literals.
String escapeStringDoubleQuotes(String value) {
return value
.replaceAll('\\', r'\\') // ignore: use_raw_strings

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and below, why not just use raw strings?

),
);
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be able to shrink down to:

Map allowedValueTypes = <String, Type>{
  'String': String,
  'int': int,
  'double': num,
  'bool': bool,
};
for (final Constant constant in _constants) {
  final String typeName = constant.type.baseName;
  final Type? expectedValueType = allowedValueTypes[typeName];
  if (expectedValueType == null) {
    ... (existing error message from what is currently a 4-condition if)
  }
  if (constant.value is! expectedValueType) {
    ...
      message: 'Constant ${constant.name}" type is ${typeName} but value type is ${constant.value.runtimeType}.'
  }
}

(This is freehand in the text field so there may be minor mistakes, but I think it's pretty much correct.)

_errors.add(
Error(
message:
'Unsupported expression type ${expression.runtimeType} for constant initializer.',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may get requests for bit-shift operator support, but we can cross that bridge if we come to it.

import 'package:pigeon/pigeon.dart';

const String aStringConstant = 'stringConstantValue';
const String aStringConstantWithEscapes = r'string\\$ConstantValue';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't ' and " be included in this string as well?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[pigeon] Add support for sharing constants across platforms

2 participants