Repository navigation
Fix numeric suffix rename - #1530
Conversation
PR HealthChangelog Entry ✔️
Changes to files need to be accounted for in their respective changelogs.
Coverage
|
| File | Coverage |
|---|---|
| pkgs/jnigen/example/in_app_java/lib/android_utils.dart | 💔 Not covered |
| pkgs/jnigen/example/in_app_java/lib/main.dart | 💔 Not covered |
| pkgs/jnigen/example/kotlin_plugin/lib/kotlin_bindings.dart | 💔 Not covered |
| pkgs/jnigen/example/notification_plugin/lib/notifications.dart | 💔 Not covered |
| pkgs/jnigen/example/pdfbox_plugin/dart_example/bin/pdf_info.dart | 💔 Not covered |
| pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/PDDocument.dart | 💔 Not covered |
| pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/PDDocumentInformation.dart | 💔 Not covered |
| pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/text/PDFTextStripper.dart | 💔 Not covered |
| pkgs/jnigen/lib/src/bindings/dart_generator.dart | 💔 Not covered |
| pkgs/jnigen/lib/src/bindings/excluder.dart | 💔 Not covered |
| pkgs/jnigen/lib/src/bindings/renamer.dart | 💔 Not covered |
| pkgs/jnigen/lib/src/bindings/unnester.dart | 💔 Not covered |
| pkgs/jnigen/lib/src/elements/elements.dart | 💔 Not covered |
This check for test coverage is informational (issues shown here will not fail the PR).
This check can be disabled by tagging the PR with skip-coverage-check.
License Headers ⚠️
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
| Files |
|---|
| pkgs/jnigen/example/in_app_java/lib/android_utils.dart |
| pkgs/jnigen/example/kotlin_plugin/lib/kotlin_bindings.dart |
| pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/PDDocument.dart |
| pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/PDDocumentInformation.dart |
| pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/text/PDFTextStripper.dart |
| pkgs/jnigen/test/renamer_test.dart |
All source files should start with a license header.
Unrelated files missing license headers
| Files |
|---|
| pkgs/ffigen/example/libclang-example/generated_bindings.dart |
| pkgs/ffigen/example/shared_bindings/generate.dart |
| pkgs/ffigen/example/shared_bindings/lib/generated/a_gen.dart |
| pkgs/ffigen/example/shared_bindings/lib/generated/a_shared_b_gen.dart |
| pkgs/ffigen/example/shared_bindings/lib/generated/base_gen.dart |
| pkgs/ffigen/example/simple/generated_bindings.dart |
| pkgs/ffigen/lib/src/header_parser/clang_bindings/clang_bindings.dart |
| pkgs/ffigen/test/collision_tests/expected_bindings/_expected_decl_decl_collision_bindings.dart |
| pkgs/ffigen/test/collision_tests/expected_bindings/_expected_decl_symbol_address_collision_bindings.dart |
| pkgs/ffigen/test/collision_tests/expected_bindings/_expected_decl_type_name_collision_bindings.dart |
| pkgs/ffigen/test/collision_tests/expected_bindings/_expected_reserved_keyword_collision_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_comment_markup_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_dart_handle_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_enum_int_mimic_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_forward_decl_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_functions_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_imported_types_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_native_func_typedef_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_opaque_dependencies_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_packed_structs_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_regress_384_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_struct_fptr_fields_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_typedef_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_unions_bindings.dart |
| pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_varargs_bindings.dart |
| pkgs/ffigen/test/large_integration_tests/_expected_cjson_bindings.dart |
| pkgs/ffigen/test/large_integration_tests/_expected_libclang_bindings.dart |
| pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart |
| pkgs/ffigen/test/native_test/_expected_native_test_bindings.dart |
| pkgs/jni/lib/src/lang/jcharacter.dart |
| pkgs/jni/lib/src/third_party/generated_bindings.dart |
| pkgs/jni/lib/src/third_party/global_env_extensions.dart |
| pkgs/jni/lib/src/third_party/jni_bindings_generated.dart |
| pkgs/jnigen/android_test_runner/lib/main.dart |
| pkgs/jnigen/example/kotlin_plugin/example/lib/main.dart |
| pkgs/jnigen/example/kotlin_plugin/lib/kotlin_plugin.dart |
| pkgs/jnigen/example/pdfbox_plugin/lib/pdfbox_plugin.dart |
| pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/pdmodel/_package.dart |
| pkgs/jnigen/example/pdfbox_plugin/lib/src/third_party/org/apache/pdfbox/text/_package.dart |
| pkgs/jnigen/lib/src/bindings/descriptor.dart |
| pkgs/jnigen/lib/src/elements/elements.g.dart |
| pkgs/jnigen/test/jackson_core_test/third_party/bindings/com/fasterxml/jackson/core/_package.dart |
| pkgs/jnigen/tool/command_runner.dart |
| pkgs/native_assets_builder/test_data/native_dynamic_linking/bin/native_dynamic_linking.dart |
| pkgs/swift2objc/lib/src/config.dart |
| pkgs/swift2objc/lib/src/generate_wrapper.dart |
| pkgs/swift2objc/lib/src/generator/_core/utils.dart |
| pkgs/swift2objc/lib/src/generator/generator.dart |
| pkgs/swift2objc/lib/src/generator/generators/class_generator.dart |
| pkgs/swift2objc/lib/src/parser/parsers/declaration_parsers/parse_property_declaration.dart |
| pkgs/swift2objc/lib/src/transformer/_core/unique_namer.dart |
| pkgs/swift2objc/lib/src/transformer/_core/utils.dart |
| pkgs/swift2objc/lib/src/transformer/transformers/transform_property.dart |
This check can be disabled by tagging the PR with skip-license-check.
Package publish validation ✔️
| Package | Version | Status |
|---|---|---|
| package:ffi | 2.1.3 | already published at pub.dev |
| package:ffigen | 14.0.0 | already published at pub.dev |
| package:jni | 0.11.0 | already published at pub.dev |
| package:jnigen | 0.12.0-wip | WIP (no publish necessary) |
| package:native_assets_cli | 0.8.0-wip | WIP (no publish necessary) |
| package:objective_c | 2.0.0 | already published at pub.dev |
| package:swift2objc | 0.0.1-wip | WIP (no publish necessary) |
| package:swiftgen | 0.0.1-wip | WIP (no publish necessary) |
Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.
|
Oops, I misread this suggestion in the bug. I thought you were going to add a |
No you correctly read it. It also was one of the options. I then made another comment: #571 (comment)
My argument was the fact that methods ending with a number are fewer than the methods that have overloads. This way users don't have to write a ton of |
I might align more with @liamappelbe here. Appending (Side note: If possible with transformers, we should implement some heuristic renamers which for example check if there's a single argument difference, and if yes use |
I agree, it may be subjective but aesthetically the code is going to look cryptic as overloadings are quite common. @lrhn @mkustermann wdyt? |
|
@dcharkes @liamappelbe I changed the renaming strategy to use |
Both |
We already discussed the numeric vs non numeric in another issue: #585 Maybe the ugliness is a feature, not a bug! Having Also a lot of method overloading in Java happens because Java does not have default parameter values like Dart has. The user could transform such family of functions to use default parameters in Dart instead. Here's an example of such case: https://github.com/dart-lang/native/blob/main/pkgs/jni/lib/src/nio/jbyte_buffer.dart#L136-L155 |
IMHO it makes sense to have the first part of the name be the same, then some separator making it clear to users what comes afterwards is to select the overloaded method. Separator could be a The last part being a number is probably fine as users have code-completion and see signatures in their completion window. Otherwise one could combine the argument type names - which is more verbose (especially if one wants guarantee to avoid collisions). One could think of making this pluggable - so there's an option for users to manually name them. @HosseinYousefi Is there a strategy to avoid breaking APIs when new overloads are added (and therefore cause change in numbering)? e.g. the generator could not just output bindings but also the naming choice it used. When running the generator again in future (with possibly updated jars), the generator could initialize it's chosen names from that naming choice and new overloads will get seperate names. That is also beneficial for code across packages: If one uses JNIgen to generate |
We so far have not tried to prevent renumbering (see the discussion in #585 (comment)). In previous discussions we preferred conciseness over the risk of renumbering (which can be avoided by appending a hash of the types/params or the types themselves). |
👍 I opened an issue for this a few days ago: #1529 (The mechanism already exists for interop between generated code.) |
In a world where bindings are not single-file, single-package but across packages that import each other - or where bindings are part of the public API (e.g. us publishing packages with bindings like Yes, using a hash is the default and simplest solution to this problem (also utilized by e.g. kotlin to java compiler) - but that would require adding the hash to all names, even if there's only one method - which makes it not very ergonomic. An alternative would be to make the generator "remember" the naming choices it made before and bootstrap from that naming choice when generating dependent code or code for updated JARs - making the choice sticky and therefore much less breaking. |
|
I also worry about renumbering. If there are overloadings, it's not unreasonable that there will be more. I do prefer We could give users a way to control the naming. It could be the same functionality we use for avoiding renumbering. Say ffigen/jnigen reads a file before doing the renaming, a file which contains the result of prior renamings, so that it always gives the same name to a declaration that it has already seen once, and it writes the file back when it has seen any changes to declarations. Then users can check the file into source control to preserve the naming, and they can hand edit the file to give a specific different naming to a function. Using a hash of the signature makes for long names (or higher risk of conflict if we truncate to fewer bits). (Do we have a way to choose a name today when using xxigen, or is that something you're expected to do at the Dart end, with a |
|
|
||
| You might wonder why the method isn't renamed to `add1` instead of `add$1`. The | ||
| reason is that a method named `add1` could already exist in the Java class. On | ||
| the other hand, Java identifiers cannot contain dollar signs. |
There was a problem hiding this comment.
Java identifiers can contain $: https://docs.oracle.com/javase/specs/jls/se11/html/jls-3.html#jls-3.8
They shouldn't, and the character is morally reserved for code generation and referencing legacy code that blatantly used $.
However, Dart code may be used to interact with code-generated Java code, so it cannot assume that there are no $s in the source names.
I recommend either changing existing $s to $$, or always adding a suffix to names containing $, starting with $0 where you would otherwise hav done nothing. Then any Dart name that ends with $<digits>, (or if using the $-doubling, one that is not preceded by an odd number of $s) is a JNIGen rename, and cannot conflict with an un-renamed name.
There was a problem hiding this comment.
🤦♂️ I didn't know this! Will add the logic, thanks
|
|
||
| /// The type which includes information such as the signature of this class. | ||
| static const type = $ExampleType(); | ||
| static final _id_new0 = _class.constructorId( |
There was a problem hiding this comment.
This does not look consistent with the description above, it's not $+digits?
There are several cases for 0 -> $ above and below. Is there some extra rule not mentioned in the documentation?
Found it. This is a "keyword rename", which adds $ after words that may conflict with Dart names or keywords.
Not sure why _id_new is one, but I guess it is derived from new, and therefore from new$, somehow.
(We don't need to add the keyword-$ on names that are made private by prefixing _. Don't know if it's better to be consistent, though.)
There was a problem hiding this comment.
As it's private, I didn't add a special case for it.
| classes.decls.values.map((c) => c.finalName).toList(); | ||
| expect(renamedClasses, [ | ||
| 'Foo', | ||
| 'Foo\$1', |
There was a problem hiding this comment.
I'd use raw strings here. It's safer.
| ]); | ||
|
|
||
| final renamedMethods = | ||
| classes.decls['Foo']!.methods.map((m) => m.finalName).toList(); |
There was a problem hiding this comment.
(The .map((m) => m.finalName).toList() happens a lot. Consider a helper function:
List<String> finalNames(List<Declaration> declarations) =>
declarations.map((d) => d.finalName).toList();(If it can be typed like that.)
|
|
||
| int add1(int a) { /* ... */ } | ||
|
|
||
| double add1$2(double a) { /* ... */ } |
| }; | ||
|
|
||
| /// Appends 0 to [name] if [name] is a keyword. | ||
| /// Appends $ to [name] if [name] is a keyword. |
There was a problem hiding this comment.
Is it a Dart or Java keywords. (Very related, not exactly the same. Looks like it's Dart "keyword", aka. reserved word, built-in identifier or contextual keyword. We don't necessarily need to add $ to these in all cases, like built-in identifiers are not reserved for non-type names, but I guess it's simpler to just always add it.)
| /// | ||
| /// Examples: | ||
| /// * `int` -> `int0` | ||
| /// * `int` -> `int$` |
There was a problem hiding this comment.
Not a good example, since int is not a Dart keyword, and is also not in the keywords set.
There was a problem hiding this comment.
Already merged, will address in a another PR.
|
Closes #571.
Adding a
$Kto the end of theK–th overload of a method.To be consistent, instead of adding a zero to the end of the keywords such as
newwe add a$.In short, the renaming becomes:
foo,foo, foo1, foo1->foo,foo$1,foo1,foo1$1yield,yield, ->yield$,yield$1Wrote a doc in
java_differences.mdexplaining the renaming for method overloading.