[ffigen] Cpp unique ptr ownership - #3513
Conversation
| final numTemplateArgs = clang.clang_Type_getNumTemplateArguments(cxtype); | ||
| if (numTemplateArgs >= 1) { | ||
| final spelling = clang.clang_getTypeSpelling(cxtype).toStringAndDispose(); | ||
| if (spelling.contains('unique_ptr<')) { |
There was a problem hiding this comment.
Are you able to do this check using the USR instead? If you use the type spelling, then a custom type name containing "unique_ptr" would be parsed as a std::unique_ptr. If the USR varies depending on what types the template is instantiated with, maybe you could get the USR of the underlying template definition?
| throw StateError('This object has already been disposed.'); | ||
| } | ||
|
|
||
| if (node._ptr == ffi.nullptr) { |
There was a problem hiding this comment.
DRY. This is mostly the same stuff that node.releaseOwnership() does, so you should call that util here rather than duplicating code.
The only extra thing you're doing here is setting node._ptr to null and getting the pointer first. You could consider adding a new util that does those things. Or maybe releaseOwnership should do those things? WDYT?
| if (method.isConstructor) { | ||
| returnTypeString = '$originalName*'; | ||
| params = method.parameters.map(paramDecl).join(', '); | ||
| final callArgs = method.parameters.map((p) => p.name).join(', '); |
There was a problem hiding this comment.
A constructor can take a std::unique_ptr too. Can you add a test for this case?
|
|
||
| final callArgs = method.parameters | ||
| .map((p) { | ||
| if (p.type is CppClassPointerType && |
There was a problem hiding this comment.
This is complicated enough that it should probably be a separate private util function, for readability.
|
|
||
| // Check if any method uses unique_ptr (owned ownership) so we can emit | ||
| // #include <memory> conditionally rather than always. | ||
| final needsMemoryHeader = methods.any( |
There was a problem hiding this comment.
There's no real harm in unconditionally including <memory>. I'd rather keep things simple.
| params = ['$selfType* self', ...otherParams].join(', '); | ||
| body = '${returnPrefix}self->${method.originalName}($callArgs);'; | ||
| final isUniquePtrReturn = | ||
| method.returnType is CppClassPointerType && |
There was a problem hiding this comment.
DRY. You're using this pattern of checking whether something is a unique_ptr often enough that it should be a util. Code duplication adds a maintenance burden over time.
| final m = method.originalName; | ||
| body = '${returnPrefix}self->$m($callArgs).release();'; | ||
| } else { | ||
| body = |
There was a problem hiding this comment.
DRY. These two cases are almost identical. A cleaner approach would be something like:
final methodName = method.originalName;
final suffix = isUniquePtrReturn ? 'release()' : '';
body = '${returnPrefix}self->$methodName($callArgs)$suffix;'| final innerType = getCodeGenType(context, innerCXType); | ||
|
|
||
| if (innerType is CppClass) { | ||
| final className = innerType.symbol.isFilled |
There was a problem hiding this comment.
The symbol is never filled at this stage of the pipeline. Symbol renaming doesn't happen until much later.
| } | ||
| } | ||
|
|
||
| enum OwnershipKind { unowned, owned } |
There was a problem hiding this comment.
Call this CppOwnershipKind. Also, rename owned to unique_ptr, because it's specific to std::unique_ptr (you're hard coding std::unique_ptr in the C++ glue code). If we add more kinds of smart pointer later, we'll need more options here.
| String? objCEnclosingClass, | ||
| }) => '${cppClass.name}.fromPointer($value)'; | ||
| }) { | ||
| if (ownership == OwnershipKind.owned) { |
There was a problem hiding this comment.
Since so many methods have different behavior based on the OwnershipKind, you should consider making a separate class for this. Eg, CppUniquePointerType. That would also simplify some of the other type checks you do in cpp_class.dart.
No description provided.