[ffigen] Separate getDartType and getUserType (#623)
* Separate getDartType and getUserType
* Fix analysis
* Document instancetype special casing
* s/getDartType/getFfiDartType
* s/getUserType/getDartType
diff --git a/pkgs/ffigen/lib/src/code_generator/compound.dart b/pkgs/ffigen/lib/src/code_generator/compound.dart
index db75582..c3eb55e 100644
--- a/pkgs/ffigen/lib/src/code_generator/compound.dart
+++ b/pkgs/ffigen/lib/src/code_generator/compound.dart
@@ -120,7 +120,7 @@
/// Marking type names because dart doesn't allow class member to have the
/// same name as a type name used internally.
for (final m in members) {
- localUniqueNamer.markUsed(m.type.getDartType(w));
+ localUniqueNamer.markUsed(m.type.getFfiDartType(w));
}
/// Write @Packed(X) annotation if struct is packed.
@@ -148,7 +148,7 @@
if (!sameDartAndCType(m.type, w)) {
s.write('$depth@${m.type.getCType(w)}()\n');
}
- s.write('${depth}external ${m.type.getDartType(w)} ${m.name};\n\n');
+ s.write('${depth}external ${m.type.getFfiDartType(w)} ${m.name};\n\n');
}
}
s.write('}\n\n');
diff --git a/pkgs/ffigen/lib/src/code_generator/enum_class.dart b/pkgs/ffigen/lib/src/code_generator/enum_class.dart
index 081c864..70d142b 100644
--- a/pkgs/ffigen/lib/src/code_generator/enum_class.dart
+++ b/pkgs/ffigen/lib/src/code_generator/enum_class.dart
@@ -84,7 +84,7 @@
String getCType(Writer w) => nativeType.getCType(w);
@override
- String getDartType(Writer w) => nativeType.getDartType(w);
+ String getFfiDartType(Writer w) => nativeType.getFfiDartType(w);
@override
String? getDefaultValue(Writer w, String nativeLib) => '0';
diff --git a/pkgs/ffigen/lib/src/code_generator/func.dart b/pkgs/ffigen/lib/src/code_generator/func.dart
index f8d32e2..f8a8177 100644
--- a/pkgs/ffigen/lib/src/code_generator/func.dart
+++ b/pkgs/ffigen/lib/src/code_generator/func.dart
@@ -120,7 +120,7 @@
: functionType.getCType(w, writeArgumentNames: false);
final dartType = exposeFunctionTypedefs
? _exposedDartFunctionTypealias!.name
- : functionType.getDartType(w, writeArgumentNames: false);
+ : functionType.getFfiDartType(w, writeArgumentNames: false);
if (ffiNativeConfig.enabled) {
final assetString = ffiNativeConfig.asset != null
@@ -131,17 +131,17 @@
"@${w.ffiLibraryPrefix}.Native<$cType>(symbol: '$originalName'$assetString$isLeafString)\n");
s.write(
- 'external ${functionType.returnType.getDartType(w)} $enclosingFuncName(\n');
+ 'external ${functionType.returnType.getFfiDartType(w)} $enclosingFuncName(\n');
for (final p in functionType.dartTypeParameters) {
- s.write(' ${p.type.getDartType(w)} ${p.name},\n');
+ s.write(' ${p.type.getFfiDartType(w)} ${p.name},\n');
}
s.write(');\n\n');
} else {
// Write enclosing function.
s.write(
- '${functionType.returnType.getDartType(w)} $enclosingFuncName(\n');
+ '${functionType.returnType.getFfiDartType(w)} $enclosingFuncName(\n');
for (final p in functionType.dartTypeParameters) {
- s.write(' ${p.type.getDartType(w)} ${p.name},\n');
+ s.write(' ${p.type.getFfiDartType(w)} ${p.name},\n');
}
s.write(') {\n');
s.write('return $funcVarName');
diff --git a/pkgs/ffigen/lib/src/code_generator/func_type.dart b/pkgs/ffigen/lib/src/code_generator/func_type.dart
index 675c85b..3ee17d5 100644
--- a/pkgs/ffigen/lib/src/code_generator/func_type.dart
+++ b/pkgs/ffigen/lib/src/code_generator/func_type.dart
@@ -65,16 +65,16 @@
}
@override
- String getDartType(Writer w, {bool writeArgumentNames = true}) {
+ String getFfiDartType(Writer w, {bool writeArgumentNames = true}) {
final sb = StringBuffer();
// Write return Type.
- sb.write(returnType.getDartType(w));
+ sb.write(returnType.getFfiDartType(w));
// Write Function.
sb.write(' Function(');
sb.write(dartTypeParameters.map<String>((p) {
- return '${p.type.getDartType(w)} ${writeArgumentNames ? p.name : ""}';
+ return '${p.type.getFfiDartType(w)} ${writeArgumentNames ? p.name : ""}';
}).join(', '));
sb.write(')');
@@ -137,7 +137,7 @@
'${w.ffiLibraryPrefix}.NativeFunction<${_type.getCType(w)}>';
@override
- String getDartType(Writer w) => getCType(w);
+ String getFfiDartType(Writer w) => getCType(w);
@override
String toString() => 'NativeFunction<${_type.toString()}>';
diff --git a/pkgs/ffigen/lib/src/code_generator/global.dart b/pkgs/ffigen/lib/src/code_generator/global.dart
index 579d8dd..5f2e639 100644
--- a/pkgs/ffigen/lib/src/code_generator/global.dart
+++ b/pkgs/ffigen/lib/src/code_generator/global.dart
@@ -45,7 +45,7 @@
s.write(makeDartDoc(dartDoc!));
}
final pointerName = w.wrapperLevelUniqueNamer.makeUnique('_$globalVarName');
- final dartType = type.getDartType(w);
+ final dartType = type.getFfiDartType(w);
final cType = type.getCType(w);
s.write(
diff --git a/pkgs/ffigen/lib/src/code_generator/handle.dart b/pkgs/ffigen/lib/src/code_generator/handle.dart
index a1b2d47..c3817f2 100644
--- a/pkgs/ffigen/lib/src/code_generator/handle.dart
+++ b/pkgs/ffigen/lib/src/code_generator/handle.dart
@@ -16,7 +16,7 @@
String getCType(Writer w) => '${w.ffiLibraryPrefix}.Handle';
@override
- String getDartType(Writer w) => 'Object';
+ String getFfiDartType(Writer w) => 'Object';
@override
String toString() => 'Handle';
diff --git a/pkgs/ffigen/lib/src/code_generator/imports.dart b/pkgs/ffigen/lib/src/code_generator/imports.dart
index 93af5ad..f75a267 100644
--- a/pkgs/ffigen/lib/src/code_generator/imports.dart
+++ b/pkgs/ffigen/lib/src/code_generator/imports.dart
@@ -40,7 +40,7 @@
}
@override
- String getDartType(Writer w) => cType == dartType ? getCType(w) : dartType;
+ String getFfiDartType(Writer w) => cType == dartType ? getCType(w) : dartType;
@override
String toString() => '${libraryImport.name}.$cType';
@@ -62,7 +62,7 @@
String getCType(Writer w) => cType;
@override
- String getDartType(Writer w) => dartType;
+ String getFfiDartType(Writer w) => dartType;
@override
String toString() => cType;
diff --git a/pkgs/ffigen/lib/src/code_generator/native_type.dart b/pkgs/ffigen/lib/src/code_generator/native_type.dart
index dfb43a5..19425ba 100644
--- a/pkgs/ffigen/lib/src/code_generator/native_type.dart
+++ b/pkgs/ffigen/lib/src/code_generator/native_type.dart
@@ -54,7 +54,7 @@
String getCType(Writer w) => '${w.ffiLibraryPrefix}.$_cType';
@override
- String getDartType(Writer w) => _dartType;
+ String getFfiDartType(Writer w) => _dartType;
@override
String toString() => _cType;
@@ -67,7 +67,6 @@
}
class BooleanType extends NativeType {
- // Booleans are treated as uint8.
const BooleanType._() : super._('Bool', 'bool', 'false');
static const _boolean = BooleanType._();
factory BooleanType() => _boolean;
diff --git a/pkgs/ffigen/lib/src/code_generator/objc_block.dart b/pkgs/ffigen/lib/src/code_generator/objc_block.dart
index 7bbb4c0..4c82a91 100644
--- a/pkgs/ffigen/lib/src/code_generator/objc_block.dart
+++ b/pkgs/ffigen/lib/src/code_generator/objc_block.dart
@@ -82,15 +82,15 @@
'${w.ffiLibraryPrefix}.NativeCallable<${trampFuncType.getCType(w)}>';
// Write the function pointer based trampoline function.
- s.write(returnType.getDartType(w));
+ s.write(returnType.getFfiDartType(w));
s.write(' $funcPtrTrampoline(${blockPtr.getCType(w)} block');
for (int i = 0; i < params.length; ++i) {
- s.write(', ${params[i].type.getDartType(w)} ${params[i].name}');
+ s.write(', ${params[i].type.getFfiDartType(w)} ${params[i].name}');
}
s.write(') {\n');
s.write(' ${isVoid ? '' : 'return '}block.ref.target.cast<'
- '${natFnType.getDartType(w)}>().asFunction<'
- '${funcType.getDartType(w)}>()(');
+ '${natFnType.getFfiDartType(w)}>().asFunction<'
+ '${funcType.getFfiDartType(w)}>()(');
for (int i = 0; i < params.length; ++i) {
s.write('${i == 0 ? '' : ', '}${params[i].name}');
}
@@ -109,17 +109,17 @@
''');
// Write the closure based trampoline function.
- s.write(returnType.getDartType(w));
+ s.write(returnType.getFfiDartType(w));
s.write(' $closureTrampoline(${blockPtr.getCType(w)} block');
for (int i = 0; i < params.length; ++i) {
- s.write(', ${params[i].type.getDartType(w)} ${params[i].name}');
+ s.write(', ${params[i].type.getFfiDartType(w)} ${params[i].name}');
}
s.write(') {\n');
s.write(' ${isVoid ? '' : 'return '}');
s.write('($closureRegistry[block.ref.target.address]');
- s.write(' as ${returnType.getDartType(w)} Function(');
+ s.write(' as ${returnType.getFfiDartType(w)} Function(');
for (int i = 0; i < params.length; ++i) {
- s.write('${i == 0 ? '' : ', '}${params[i].type.getDartType(w)}');
+ s.write('${i == 0 ? '' : ', '}${params[i].type.getFfiDartType(w)}');
}
s.write('))');
s.write('(');
@@ -154,7 +154,7 @@
/// This block must be invoked by native code running on the same thread as
/// the isolate that registered it. Invoking the block on the wrong thread
/// will result in a crash.
- $name.fromFunction(${w.className} lib, ${funcType.getDartType(w)} fn) :
+ $name.fromFunction(${w.className} lib, ${funcType.getFfiDartType(w)} fn) :
this._(lib.${builtInFunctions.newBlock.name}(
_dartFuncTrampoline ??= ${w.ffiLibraryPrefix}.Pointer.fromFunction<
${trampFuncType.getCType(w)}>($closureTrampoline
@@ -175,7 +175,7 @@
///
/// Note that unlike the default behavior of NativeCallable.listener, listener
/// blocks do not keep the isolate alive.
- $name.listener(${w.className} lib, ${funcType.getDartType(w)} fn) :
+ $name.listener(${w.className} lib, ${funcType.getFfiDartType(w)} fn) :
this._(lib.${builtInFunctions.newBlock.name}(
(_dartFuncListenerTrampoline ??= $nativeCallableType.listener($closureTrampoline
$exceptionalReturn)..keepIsolateAlive = false).nativeFunction.cast(),
@@ -186,15 +186,15 @@
}
// Call method.
- s.write(' ${returnType.getDartType(w)} call(');
+ s.write(' ${returnType.getFfiDartType(w)} call(');
for (int i = 0; i < params.length; ++i) {
- s.write('${i == 0 ? '' : ', '}${params[i].type.getDartType(w)}');
+ s.write('${i == 0 ? '' : ', '}${params[i].type.getFfiDartType(w)}');
s.write(' ${params[i].name}');
}
s.write(''') {
${isVoid ? '' : 'return '}_id.ref.invoke.cast<
${natTrampFnType.getCType(w)}>().asFunction<
- ${trampFuncType.getDartType(w)}>()(_id''');
+ ${trampFuncType.getFfiDartType(w)}>()(_id''');
for (int i = 0; i < params.length; ++i) {
s.write(', ${params[i].name}');
}
@@ -223,5 +223,8 @@
PointerType(builtInFunctions.blockStruct).getCType(w);
@override
+ String getDartType(Writer w) => name;
+
+ @override
String toString() => '($returnType (^)(${argTypes.join(', ')}))';
}
diff --git a/pkgs/ffigen/lib/src/code_generator/objc_interface.dart b/pkgs/ffigen/lib/src/code_generator/objc_interface.dart
index 782d75c..12ebd14 100644
--- a/pkgs/ffigen/lib/src/code_generator/objc_interface.dart
+++ b/pkgs/ffigen/lib/src/code_generator/objc_interface.dart
@@ -5,7 +5,6 @@
import 'package:ffigen/src/code_generator.dart';
import 'package:logging/logging.dart';
-import '../strings.dart' as strings;
import 'binding_string.dart';
import 'utils.dart';
import 'writer.dart';
@@ -281,7 +280,7 @@
if (m.isClass &&
!_excludedNSObjectClassMethods.contains(m.originalName)) {
addMethod(m);
- } else if (_isInstanceType(m.returnType)) {
+ } else if (m.returnType is ObjCInstanceType) {
addMethod(m);
}
}
@@ -355,13 +354,8 @@
@override
String getCType(Writer w) => PointerType(objCObjectType).getCType(w);
- bool _isObject(Type type) =>
- type is PointerType && type.child == objCObjectType;
-
- bool _isInstanceType(Type type) =>
- type is Typealias &&
- type.originalName == strings.objcInstanceType &&
- _isObject(type.type);
+ @override
+ String getDartType(Writer w) => name;
// Utils for converting between the internal types passed to native code, and
// the external types visible to the user. For example, ObjCInterfaces are
@@ -370,15 +364,11 @@
bool _needsConverting(Type type) =>
type is ObjCInterface ||
type is ObjCBlock ||
- _isObject(type) ||
- _isInstanceType(type);
+ type is ObjCObjectPointer ||
+ type is ObjCInstanceType;
String _getConvertedType(Type type, Writer w, String enclosingClass) {
- if (type is BooleanType) return 'bool';
- if (type is ObjCInterface) return type.name;
- if (type is ObjCBlock) return type.name;
- if (_isObject(type)) return 'NSObject';
- if (_isInstanceType(type)) return enclosingClass;
+ if (type is ObjCInstanceType) return enclosingClass;
return type.getDartType(w);
}
@@ -393,8 +383,8 @@
String _doArgConversion(ObjCMethodParam arg) {
if (arg.type is ObjCInterface ||
- _isObject(arg.type) ||
- _isInstanceType(arg.type) ||
+ arg.type is ObjCObjectPointer ||
+ arg.type is ObjCInstanceType ||
arg.type is ObjCBlock) {
if (arg.isNullable) {
return '${arg.name}?._id ?? ffi.nullptr';
@@ -415,10 +405,10 @@
if (type is ObjCBlock) {
return '$prefix${type.name}._($value, $library)';
}
- if (_isObject(type)) {
+ if (type is ObjCObjectPointer) {
return '${prefix}NSObject._($value, $library, $ownerFlags)';
}
- if (_isInstanceType(type)) {
+ if (type is ObjCInstanceType) {
return '$prefix$enclosingClass._($value, $library, $ownerFlags)';
}
return prefix + value;
diff --git a/pkgs/ffigen/lib/src/code_generator/pointer.dart b/pkgs/ffigen/lib/src/code_generator/pointer.dart
index cacb5b2..f99ee53 100644
--- a/pkgs/ffigen/lib/src/code_generator/pointer.dart
+++ b/pkgs/ffigen/lib/src/code_generator/pointer.dart
@@ -9,7 +9,15 @@
/// Represents a pointer.
class PointerType extends Type {
final Type child;
- PointerType(this.child);
+
+ PointerType._(this.child);
+
+ factory PointerType(Type child) {
+ if (child == objCObjectType) {
+ return ObjCObjectPointer();
+ }
+ return PointerType._(child);
+ }
@override
void addDependencies(Set<Binding> dependencies) {
@@ -33,7 +41,7 @@
/// Represents a constant array, which has a fixed size.
class ConstantArray extends PointerType {
final int length;
- ConstantArray(this.length, Type child) : super(child);
+ ConstantArray(this.length, Type child) : super._(child);
@override
Type get baseArrayType => child.baseArrayType;
@@ -50,7 +58,7 @@
/// Represents an incomplete array, which has an unknown size.
class IncompleteArray extends PointerType {
- IncompleteArray(Type child) : super(child);
+ IncompleteArray(Type child) : super._(child);
@override
Type get baseArrayType => child.baseArrayType;
@@ -61,3 +69,14 @@
@override
String cacheKey() => '${child.cacheKey()}[]';
}
+
+/// A pointer to an NSObject.
+class ObjCObjectPointer extends PointerType {
+ factory ObjCObjectPointer() => _inst;
+
+ static final _inst = ObjCObjectPointer._();
+ ObjCObjectPointer._() : super._(objCObjectType);
+
+ @override
+ String getDartType(Writer w) => 'NSObject';
+}
diff --git a/pkgs/ffigen/lib/src/code_generator/type.dart b/pkgs/ffigen/lib/src/code_generator/type.dart
index 8468eca..1a69b60 100644
--- a/pkgs/ffigen/lib/src/code_generator/type.dart
+++ b/pkgs/ffigen/lib/src/code_generator/type.dart
@@ -39,9 +39,14 @@
/// passed to native code.
String getCType(Writer w) => throw 'No mapping for type: $this';
- /// Returns the Dart type of the Type. This is the user visible type that is
- /// passed to Dart code.
- String getDartType(Writer w) => getCType(w);
+ /// Returns the Dart type of the Type. This is the type that is passed from
+ /// FFI to Dart code.
+ String getFfiDartType(Writer w) => getCType(w);
+
+ /// Returns the user type of the Type. This is the type that is presented to
+ /// users by the ffigened API to users. For C bindings this is always the same
+ /// as getFfiDartType. For ObjC bindings this refers to the wrapper object.
+ String getDartType(Writer w) => getFfiDartType(w);
/// Returns the string representation of the Type, for debugging purposes
/// only. This string should not be printed as generated code.
@@ -62,7 +67,7 @@
}
/// Function to check if the dart and C type string are same.
-bool sameDartAndCType(Type t, Writer w) => t.getCType(w) == t.getDartType(w);
+bool sameDartAndCType(Type t, Writer w) => t.getCType(w) == t.getFfiDartType(w);
/// Base class for all Type bindings.
///
@@ -97,7 +102,10 @@
bool get isIncompleteCompound => false;
@override
- String getDartType(Writer w) => getCType(w);
+ String getFfiDartType(Writer w) => getCType(w);
+
+ @override
+ String getDartType(Writer w) => getFfiDartType(w);
@override
String toString() => originalName;
diff --git a/pkgs/ffigen/lib/src/code_generator/typealias.dart b/pkgs/ffigen/lib/src/code_generator/typealias.dart
index c7d95ca..469a40b 100644
--- a/pkgs/ffigen/lib/src/code_generator/typealias.dart
+++ b/pkgs/ffigen/lib/src/code_generator/typealias.dart
@@ -4,6 +4,7 @@
import 'package:ffigen/src/code_generator.dart';
+import '../strings.dart' as strings;
import 'binding_string.dart';
import 'utils.dart';
import 'writer.dart';
@@ -40,6 +41,18 @@
isInternal: isInternal,
)));
}
+ if ((originalName ?? name) == strings.objcInstanceType &&
+ type is ObjCObjectPointer) {
+ return ObjCInstanceType._(
+ usr: usr,
+ originalName: originalName,
+ dartDoc: dartDoc,
+ name: name,
+ type: type,
+ useDartType: useDartType,
+ isInternal: isInternal,
+ );
+ }
return Typealias._(
usr: usr,
originalName: originalName,
@@ -90,7 +103,7 @@
sb.write(makeDartDoc(dartDoc!));
}
sb.write('typedef $name = ');
- sb.write('${_useDartType ? type.getDartType(w) : type.getCType(w)};\n');
+ sb.write('${_useDartType ? type.getFfiDartType(w) : type.getCType(w)};\n');
return BindingString(
type: BindingStringType.typeDef, string: sb.toString());
}
@@ -105,13 +118,13 @@
String getCType(Writer w) => name;
@override
- String getDartType(Writer w) {
+ String getFfiDartType(Writer w) {
// Typealias cannot be used by name in Dart types unless both the C and Dart
// type of the underlying types are same.
if (sameDartAndCType(type, w)) {
return name;
} else {
- return type.getDartType(w);
+ return type.getFfiDartType(w);
}
}
@@ -122,3 +135,32 @@
String? getDefaultValue(Writer w, String nativeLib) =>
type.getDefaultValue(w, nativeLib);
}
+
+/// Objective C's instancetype.
+///
+/// This is an alias for an NSObject* that is special cased in code generation.
+/// It's only valid as the return type of a method, and always appears as the
+/// enclosing class's type, even in inherited methods.
+class ObjCInstanceType extends Typealias {
+ ObjCInstanceType._({
+ String? usr,
+ String? originalName,
+ String? dartDoc,
+ required String name,
+ required Type type,
+
+ /// If true, the binding string uses Dart type instead of C type.
+ ///
+ /// E.g if C type is ffi.Void func(ffi.Int32), Dart type is void func(int).
+ bool useDartType = false,
+ bool isInternal = false,
+ }) : super._(
+ usr: usr,
+ originalName: originalName,
+ dartDoc: dartDoc,
+ name: name,
+ type: type,
+ useDartType: useDartType,
+ isInternal: isInternal,
+ );
+}