Repository navigation
[ffigen] Generate bindings for C++ enums, structs and unions nested in namespaces and records - #3644
Conversation
…in namespaces; update qualified name handling
… types and add tests for scoped records and enums
| /// Whether the nested record at [cursor] may be parsed. | ||
| /// | ||
| /// Records in system headers are skipped: parsing one also parses its methods | ||
| /// and their types, which for the C++ standard library is unbounded, and |
There was a problem hiding this comment.
Why is the stdlib unbounded? Surely it's just large?
There was a problem hiding this comment.
Yeah, it's not unbounded, just a bad comment, sorry. I updated the comment
There was a problem hiding this comment.
What happens if you don't skip them? The default include behavior is to skip everything, so unless there's a severe performance overhead, I don't think it should be a problem.
There was a problem hiding this comment.
The default include behavior is to skip everything
In the Dart API yes, in the YAML no
I checked and it's not a performance overhead, but I did just discover a crash (#3691). It was primarily added because I've been using it for my work with a include-all config and it generated a huge amount of system stuff I didn't want. I was on the fence of if I should keep the check or remove it for the PR.
There was a problem hiding this comment.
The YAML format is deprecated, and I assume this whole PR only affects the new C++ mode? If it affects C as well, then filtering it makes sense (at least until I delete the YAML format in a couple of months).
There was a problem hiding this comment.
The check only matters in C++ mode. It runs on the C path too, but a nested C struct is always referenced by its parent's member, and referenced types are bound regardless, so C output is identical with or without it.
I removed the check
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3644 +/- ##
==========================================
+ Coverage 87.98% 88.00% +0.02%
==========================================
Files 311 311
Lines 19802 19840 +38
==========================================
+ Hits 17422 17460 +38
Misses 2380 2380
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
# Conflicts: # pkgs/ffigen/CHANGELOG.md
Revisions updated by `dart tools/rev_sdk_deps.dart`. native (https://github.com/dart-lang/native/compare/f628b26..27f7678): 27f767827 Mon Sep 28 14:51:28 2026 +0200 Daco Harkes [hooks_runner] Remove `KernelAssets` and `Target` (dart-lang/native#3703) ddc7d6deb Mon Sep 28 05:40:03 2026 +0200 Jakob Kordež [ffigen] Skip typedefs to function pointers with unsupported parameter types (dart-lang/native#3694) 177d283d9 Mon Sep 28 04:30:28 2026 +0200 Jakob Kordež [ffigen] Generate bindings for C++ enums, structs and unions nested in namespaces and records (dart-lang/native#3644) 5ee8f67d8 Mon Sep 28 11:39:14 2026 +1000 Liam Appelbe [objective_c] Clarify block isolate scoping (dart-lang/native#3692) 25f090116 Fri Sep 25 12:09:12 2026 +1000 Liam Appelbe [ffigen][jnigen] Deprecate YAML config (dart-lang/native#3654) 8364413eb Fri Sep 25 10:09:50 2026 +1000 Liam Appelbe [jnigen] Document nullability (dart-lang/native#3690) e8d518574 Thu Sep 24 18:02:46 2026 +1000 Liam Appelbe [ffigen] Code snippet-ify ffigen and objective_c (dart-lang/native#3685) 663385955 Thu Sep 24 03:21:53 2026 +0300 Manar Elhabbal [ffigen] prevent setting both cpp and objectiveC in ffigenerator (dart-lang/native#3687) 1cf40952a Thu Sep 24 09:27:09 2026 +1000 Liam Appelbe [objective_c] Remove arm64e build hack (dart-lang/native#3680) c44550b6e Wed Sep 23 13:01:33 2026 +0200 Simon Binder [web_assets] Scaffold package (dart-lang/native#3610) 57b4bad69 Wed Sep 23 16:21:27 2026 +1000 Liam Appelbe [swift2objc] Code snippet-ify swift2objc (dart-lang/native#3684) 5cee1d0be Wed Sep 23 10:16:29 2026 +0530 Rachit Vikram Singh [ffigen] Add Input.appendCompilerOptions to append clang args to defaults (`#3630`) (dart-lang/native#3676) 225a648df Wed Sep 23 14:37:13 2026 +1000 Liam Appelbe [jnigen] Code snippet-ify jnigen and co (dart-lang/native#3641) 2030decf9 Wed Sep 23 13:51:24 2026 +1000 Liam Appelbe [infra] Move snippets_tool to its own package (dart-lang/native#3683) 6fa2beea2 Wed Sep 23 12:14:28 2026 +1000 Liam Appelbe [objective_c] Revert `#3664` (dart-lang/native#3681) ed7605f8a Tue Sep 22 12:03:22 2026 +0530 Sivapriya [jni] Add deep conversion utils (dart-lang/native#3635) 8574b7422 Tue Sep 22 08:31:11 2026 +0200 Lukas Klingsbo [ffigen] Allow package:cli_util 0.5.x and 0.6.x (dart-lang/native#3673) test (https://github.com/dart-lang/test/compare/9946c95..4f92d53): 4f92d530 Fri Sep 25 16:46:22 2026 -0700 Nate Bosch Unskip a test on windows (dart-lang/test#2772) 7fb84866 Fri Sep 25 14:52:39 2026 -0700 Nate Bosch Bundle skips at the end of the GitHub reporter (dart-lang/test#2768) 603e5ec5 Thu Sep 24 14:00:41 2026 -0700 Nate Bosch Clean up the runner's temporary directories (dart-lang/test#2763) 4bf04d90 Thu Sep 24 12:41:15 2026 -0700 Nate Bosch Refactor signal handling in executable.dart (dart-lang/test#2765) 2c660a84 Tue Sep 22 15:33:34 2026 -0700 Nate Bosch Regenerate mono_repo output (dart-lang/test#2767) tools (https://github.com/dart-lang/tools/compare/3614ce0..d87eaf7): d87eaf79 Thu Sep 24 08:31:33 2026 -0700 Kevin Moore fix(benchmark_harness): migrate subprocess spawning to package:cli_util (dart-lang/tools#2585) 8ccf8ccf Wed Sep 23 05:09:10 2026 +0530 Aman Maurya [string_scanner] Extract a mixin for LineScanner and deduplicate eager scanning logic (dart-lang/tools#2569) afcdd6d9 Tue Sep 22 15:38:07 2026 +0200 Morgan :) Document that watch events converge on filesystem state. (dart-lang/tools#2607) f2157cbc Tue Sep 22 04:52:58 2026 +0300 Hasan Armoush [code_builder] Add null-aware cascades, cascade index, and fluent cascade helpers (dart-lang/tools#2540) web (https://github.com/dart-lang/web/compare/e5c6c02..ec71a4c): ec71a4c Mon Sep 28 10:07:01 2026 -0700 Kevin Moore [js_interop_gen] Require `code_builder: ^4.12.0` and update golden headers (dart-lang/web#576) [email protected] Change-Id: I766bc5b2b1297e3251990821bb73387ba685e39b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/556320 Commit-Queue: Nate Bosch <[email protected]> Reviewed-by: Brian Quinlan <[email protected]>
Most of this branch's C++ parsing work landed upstream as separate PRs (dart-lang#3591, dart-lang#3607, dart-lang#3608, dart-lang#3609, dart-lang#3644), so conflicts are resolved in favour of the upstream implementations. Branch-only features are kept on top: - constexpr variables and static data members: nested VarDecls are dispatched again, using qualifiedNameFromCursor, but only bound when they have a constant value (others would need a mangled-symbol lookup). - forward-declared / pointer-only classes are covered by upstream's class-as-struct fallback; the existing test still passes. - cpp_constexpr and cpp_opaque_class tests get per-test config files. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Description
ffigen only visited the direct children of the translation unit, so any C++
type declared inside a
namespaceor inside another record was neversurfaced as a binding. It could still be reached indirectly through a
function signature, but then it was named by its leaf name alone, so two
Colorenums in different namespaces collided.This PR makes the translation-unit visitor descend into namespaces and
records and generate bindings for the enums, structs, classes and unions it
finds there. Scoped types are named by their scope path:
originalNameis the qualified C++ name, e.g.outer::inner::Color, so aVisitororimportTypecallback can filter or rename by it.$, e.g.outer$inner$Color,which is a valid identifier and keeps same-leaf-name types distinct.
The scope path is built from the cursor's semantic parents (a new
clang_getCursorSemanticParentbinding), so an out-of-line definition suchas
struct ns::Fwd { ... }is still namedns::Fwd. Anonymous namespaces,anonymous records and
extern "C"blocks contribute no segment. Plain C isunaffected: Clang hoists C nested tags to file scope, so their semantic
parent is the translation unit and names are unchanged.
importTypenow receives the same qualifiedoriginalNameas aVisitor,so the two hooks agree on how a scoped type is identified.
Related Issues
PR Checklist
dart tool/ci.dart --alllocally and resolved all issues identified. This ensures the PR is formatted, has no lint errors, and ran all code generators. This applies to the packages part of the toplevelpubspec.yamlworkspace.CHANGELOG.mdfor the relevant packages. (Not needed for small changes such as doc typos).