[ffigen] Add C++ public inheritance support (single, multiple, diamond) - #3542
[ffigen] Add C++ public inheritance support (single, multiple, diamond)#3542Hassnaa9 wants to merge 3 commits into
Conversation
| s.write(makeDartDoc(dartDoc)); | ||
| // Build the implements clause: ffi.Finalizable + public base classes. | ||
| final baseNames = bases.map((b) => b.name).join(', '); | ||
| final implementsClause = bases.isEmpty |
There was a problem hiding this comment.
nit: if you combine '$ffiPrefix.Finalizable' into a list literal with the iterable returned by bases.map, then you can just rely on the .join and don't need this conditional.
| '''); | ||
|
|
||
| // Inherited method delegation (Dart side) | ||
| final inheritedToDelegate = getInheritedMethodsToDelegate(ctx); |
There was a problem hiding this comment.
Rather than have this huge amount of duplicated code, just add the super type's methods to this class's methods. That way there's nothing special about these methods at all.
It probably makes sense to do that in lib/src/visitor/copy_methods_from_super_type.dart. When copying across the method, make an actual copy of it, like we do for ObjC methods.
There was a problem hiding this comment.
Done. Could you check if this is what you had in mind, or if there are any further improvements needed?
| public: | ||
| DiamondBase(); | ||
| virtual ~DiamondBase(); | ||
| int baseVal() const; |
There was a problem hiding this comment.
Add a virtual method test?
liamappelbe
left a comment
There was a problem hiding this comment.
Looks like there's some formatting errors on CI. The bot is using the most recent stable Dart, which was just released (and makes some small changes to the formatter), so make sure you update to the latest version.
| final bool isConstant; | ||
| final bool isStatic; | ||
| final CppMethodKind kind; | ||
| final String? originatingClass; |
There was a problem hiding this comment.
Better to store a reference to the CppClass object.
| return bases; | ||
| } | ||
|
|
||
| String methodSignatureKey(CppMethod method, Context context) { |
There was a problem hiding this comment.
This should be a method on CppMethod.
| CppMethod cloneForClass(CppClass targetClass, CppClass baseClass) { | ||
| return CppMethod( | ||
| name: Symbol( | ||
| '${targetClass.originalName}_$originalName', |
There was a problem hiding this comment.
I was pretty confused about this name mangling until I realised that you're using originalName instead of name when generating the Dart method. That means that users won't be able to rename methods, and the name collision resolution logic won't work.
You don't need to fix that in this PR, but I filed a bug so we don't forget: #3552
| if (method.originatingClass != null) { | ||
| final origClass = method.originatingClass; | ||
| final castTarget = | ||
| 'static_cast<$constPrefix$origClass*>(self)'; |
There was a problem hiding this comment.
Why is the static_cast necessary?
|
|
||
| String methodSignatureKey(CppMethod method, Context context) { | ||
| final paramTypes = method.parameters | ||
| .map((p) => p.type.getNativeType(context)) |
There was a problem hiding this comment.
getNativeType is only supposed to be used at codegen time. In general, these getters that are used in codegen may refer to things that are filled in during the transformation stage (all those visitors in the visitor dir), such as a Symbol's name. That would cause an NPE or assertion failure.
It's the kind of bug that you only catch if you have very good test coverage. Eg, writing a C++ class with a method for every possible return type and arg type (primitives, structs, unions, classes, function pointers etc etc etc).
You should use cacheKey instead. Let me know if that method gives you problems. I have a bug I've been meaning to fix to improve it.
| .map((m) => methodSignatureKey(m, node.context)) | ||
| .toSet(); | ||
|
|
||
| for (final base in node.bases) { |
There was a problem hiding this comment.
Dedupe this for loop with the for (final grandBase in base.bases) { loop below. You can refactor _copyCppMethodsFromBase so you only need one .bases loop.
No description provided.