[ffigen] Typedefs for Dart types (#625)
* WIP fix #386
* Fix tests
* fmt
* Update test expectations
* Update test expectations
* Fix analysis
* fmt
* Fix more tests
* WIP refactor
* Refactor `sameFfiDartAndCType` to not require a `Writer`
* Fix tests
* Fix analysis
* Update test expectations
* Format
* Fix typedef_test.dart
* Fix nits
* Fix tests
* Fmt
* Regenerate more test files
* Regen more tests
* Remove accidental commit
diff --git a/pkgs/ffigen/example/c_json/cjson_generated_bindings.dart b/pkgs/ffigen/example/c_json/cjson_generated_bindings.dart
index fa9e56e..38bc263 100644
--- a/pkgs/ffigen/example/c_json/cjson_generated_bindings.dart
+++ b/pkgs/ffigen/example/c_json/cjson_generated_bindings.dart
@@ -1268,6 +1268,7 @@
}
typedef cJSON_bool = ffi.Int;
+typedef DartcJSON_bool = int;
const int CJSON_VERSION_MAJOR = 1;
diff --git a/pkgs/ffigen/example/libclang-example/generated_bindings.dart b/pkgs/ffigen/example/libclang-example/generated_bindings.dart
index a0ae7a2..7cf663e 100644
--- a/pkgs/ffigen/example/libclang-example/generated_bindings.dart
+++ b/pkgs/ffigen/example/libclang-example/generated_bindings.dart
@@ -9748,8 +9748,10 @@
/// The visitor should return one of the \c CXChildVisitResult values
/// to direct clang_visitCursorChildren().
typedef CXCursorVisitor
- = ffi.Pointer<ffi.NativeFunction<CXCursorVisitor_function>>;
-typedef CXCursorVisitor_function = ffi.Int32 Function(
+ = ffi.Pointer<ffi.NativeFunction<CXCursorVisitorFunction>>;
+typedef CXCursorVisitorFunction = ffi.Int32 Function(
+ CXCursor cursor, CXCursor parent, CXClientData client_data);
+typedef DartCXCursorVisitorFunction = int Function(
CXCursor cursor, CXCursor parent, CXClientData client_data);
/// Describes how the traversal of the children of a particular
@@ -10426,12 +10428,17 @@
/// array is sorted in order of immediate inclusion. For example,
/// the first element refers to the location that included 'included_file'.
typedef CXInclusionVisitor
- = ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor_function>>;
-typedef CXInclusionVisitor_function = ffi.Void Function(
+ = ffi.Pointer<ffi.NativeFunction<CXInclusionVisitorFunction>>;
+typedef CXInclusionVisitorFunction = ffi.Void Function(
CXFile included_file,
ffi.Pointer<CXSourceLocation> inclusion_stack,
ffi.UnsignedInt include_len,
CXClientData client_data);
+typedef DartCXInclusionVisitorFunction = void Function(
+ CXFile included_file,
+ ffi.Pointer<CXSourceLocation> inclusion_stack,
+ int include_len,
+ CXClientData client_data);
typedef NativeClang_getInclusions = ffi.Void Function(
CXTranslationUnit tu, CXInclusionVisitor visitor, CXClientData client_data);
typedef DartClang_getInclusions = void Function(
@@ -11104,8 +11111,10 @@
/// The visitor should return one of the \c CXVisitorResult values
/// to direct \c clang_Type_visitFields.
typedef CXFieldVisitor
- = ffi.Pointer<ffi.NativeFunction<CXFieldVisitor_function>>;
-typedef CXFieldVisitor_function = ffi.Int32 Function(
+ = ffi.Pointer<ffi.NativeFunction<CXFieldVisitorFunction>>;
+typedef CXFieldVisitorFunction = ffi.Int32 Function(
+ CXCursor C, CXClientData client_data);
+typedef DartCXFieldVisitorFunction = int Function(
CXCursor C, CXClientData client_data);
typedef NativeClang_Type_visitFields = ffi.UnsignedInt Function(
CXType T, CXFieldVisitor visitor, CXClientData client_data);
diff --git a/pkgs/ffigen/lib/src/code_generator/func.dart b/pkgs/ffigen/lib/src/code_generator/func.dart
index f8a8177..b3141ae 100644
--- a/pkgs/ffigen/lib/src/code_generator/func.dart
+++ b/pkgs/ffigen/lib/src/code_generator/func.dart
@@ -46,8 +46,7 @@
late final String funcPointerName;
/// Contains typealias for function type if [exposeFunctionTypedefs] is true.
- Typealias? _exposedCFunctionTypealias;
- Typealias? _exposedDartFunctionTypealias;
+ Typealias? _exposedFunctionTypealias;
/// [originalName] is looked up in dynamic library, if not
/// provided, takes the value of [name].
@@ -85,15 +84,10 @@
// Get function name with first letter in upper case.
final upperCaseName = name[0].toUpperCase() + name.substring(1);
if (exposeFunctionTypedefs) {
- _exposedCFunctionTypealias = Typealias(
- name: 'Native$upperCaseName',
+ _exposedFunctionTypealias = Typealias(
+ name: upperCaseName,
type: functionType,
- isInternal: true,
- );
- _exposedDartFunctionTypealias = Typealias(
- name: 'Dart$upperCaseName',
- type: functionType,
- useDartType: true,
+ genFfiDartType: true,
isInternal: true,
);
}
@@ -115,12 +109,10 @@
p.name = paramNamer.makeUnique(p.name);
}
- final cType = exposeFunctionTypedefs
- ? _exposedCFunctionTypealias!.name
- : functionType.getCType(w, writeArgumentNames: false);
- final dartType = exposeFunctionTypedefs
- ? _exposedDartFunctionTypealias!.name
- : functionType.getFfiDartType(w, writeArgumentNames: false);
+ final cType = _exposedFunctionTypealias?.getCType(w) ??
+ functionType.getCType(w, writeArgumentNames: false);
+ final dartType = _exposedFunctionTypealias?.getFfiDartType(w) ??
+ functionType.getFfiDartType(w, writeArgumentNames: false);
if (ffiNativeConfig.enabled) {
final assetString = ffiNativeConfig.asset != null
@@ -180,8 +172,7 @@
dependencies.add(this);
functionType.addDependencies(dependencies);
if (exposeFunctionTypedefs) {
- _exposedCFunctionTypealias!.addDependencies(dependencies);
- _exposedDartFunctionTypealias!.addDependencies(dependencies);
+ _exposedFunctionTypealias!.addDependencies(dependencies);
}
}
}
diff --git a/pkgs/ffigen/lib/src/code_generator/objc_interface.dart b/pkgs/ffigen/lib/src/code_generator/objc_interface.dart
index 421a508..c79ccca 100644
--- a/pkgs/ffigen/lib/src/code_generator/objc_interface.dart
+++ b/pkgs/ffigen/lib/src/code_generator/objc_interface.dart
@@ -314,9 +314,11 @@
}
}
- static bool _isInstanceType(Type type) =>
- type is ObjCInstanceType ||
- (type is ObjCNullable && type.child is ObjCInstanceType);
+ static bool _isInstanceType(Type type) {
+ if (type is ObjCInstanceType) return true;
+ final baseType = type.typealiasType;
+ return baseType is ObjCNullable && baseType.child is ObjCInstanceType;
+ }
void addMethod(ObjCMethod method) {
final oldMethod = methods[method.originalName];
@@ -400,27 +402,29 @@
// passed to native as Pointer<ObjCObject>, but the user sees the Dart wrapper
// class. These methods need to be kept in sync.
bool _needsConverting(Type type) =>
- type is ObjCInterface ||
- type is ObjCBlock ||
- type is ObjCObjectPointer ||
type is ObjCInstanceType ||
- type is ObjCNullable;
+ type.typealiasType is ObjCInterface ||
+ type.typealiasType is ObjCBlock ||
+ type.typealiasType is ObjCObjectPointer ||
+ type.typealiasType is ObjCNullable;
String _getConvertedType(Type type, Writer w, String enclosingClass) {
if (type is ObjCInstanceType) return enclosingClass;
- if (type is ObjCNullable && type.child is ObjCInstanceType) {
+ final baseType = type.typealiasType;
+ if (baseType is ObjCNullable && baseType.child is ObjCInstanceType) {
return '$enclosingClass?';
}
return type.getDartType(w);
}
String _doArgConversion(ObjCMethodParam arg) {
- if (arg.type is ObjCNullable) {
+ final baseType = arg.type.typealiasType;
+ if (baseType is ObjCNullable) {
return '${arg.name}?._id ?? ffi.nullptr';
- } else if (arg.type is ObjCInterface ||
- arg.type is ObjCObjectPointer ||
- arg.type is ObjCInstanceType ||
- arg.type is ObjCBlock) {
+ } else if (arg.type is ObjCInstanceType ||
+ baseType is ObjCInterface ||
+ baseType is ObjCObjectPointer ||
+ baseType is ObjCBlock) {
return '${arg.name}._id';
}
return arg.name;
@@ -429,23 +433,25 @@
String _doReturnConversion(Type type, String value, String enclosingClass,
String library, bool isOwnedReturn) {
var prefix = '';
- if (type is ObjCNullable) {
+ var baseType = type.typealiasType;
+ if (baseType is ObjCNullable) {
prefix = '$value.address == 0 ? null : ';
- type = type.child;
+ type = baseType.child;
+ baseType = type.typealiasType;
}
final ownerFlags = 'retain: ${!isOwnedReturn}, release: true';
- if (type is ObjCInterface) {
- return '$prefix${type.name}._($value, $library, $ownerFlags)';
- }
- if (type is ObjCBlock) {
- return '$prefix${type.name}._($value, $library)';
- }
- if (type is ObjCObjectPointer) {
- return '${prefix}NSObject._($value, $library, $ownerFlags)';
- }
if (type is ObjCInstanceType) {
return '$prefix$enclosingClass._($value, $library, $ownerFlags)';
}
+ if (baseType is ObjCInterface) {
+ return '$prefix${baseType.name}._($value, $library, $ownerFlags)';
+ }
+ if (baseType is ObjCBlock) {
+ return '$prefix${baseType.name}._($value, $library)';
+ }
+ if (baseType is ObjCObjectPointer) {
+ return '${prefix}NSObject._($value, $library, $ownerFlags)';
+ }
return prefix + value;
}
}
diff --git a/pkgs/ffigen/lib/src/code_generator/typealias.dart b/pkgs/ffigen/lib/src/code_generator/typealias.dart
index 5c5cc44..ec9430e 100644
--- a/pkgs/ffigen/lib/src/code_generator/typealias.dart
+++ b/pkgs/ffigen/lib/src/code_generator/typealias.dart
@@ -17,27 +17,28 @@
/// ```
class Typealias extends BindingType {
final Type type;
- final bool _useDartType;
+ String? _ffiDartAliasName;
+ String? _dartAliasName;
+ /// Creates a Typealias.
+ ///
+ /// If [genFfiDartType] is true, a binding is generated for the Ffi Dart type
+ /// in addition to the C type. See [Type.getFfiDartType].
factory Typealias({
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 genFfiDartType = false,
bool isInternal = false,
}) {
final funcType = _getFunctionTypeFromPointer(type);
if (funcType != null) {
type = PointerType(NativeFunc(Typealias._(
- name: '${name}_function',
+ name: '${name}Function',
type: funcType,
- useDartType: useDartType,
+ genFfiDartType: genFfiDartType,
isInternal: isInternal,
)));
}
@@ -49,7 +50,7 @@
dartDoc: dartDoc,
name: name,
type: type,
- useDartType: useDartType,
+ genFfiDartType: genFfiDartType,
isInternal: isInternal,
);
}
@@ -59,7 +60,7 @@
dartDoc: dartDoc,
name: name,
type: type,
- useDartType: useDartType,
+ genFfiDartType: genFfiDartType,
isInternal: isInternal,
);
}
@@ -70,12 +71,16 @@
String? dartDoc,
required String name,
required this.type,
- bool useDartType = false,
+ bool genFfiDartType = false,
bool isInternal = false,
- }) : _useDartType = useDartType,
+ }) : _ffiDartAliasName = genFfiDartType ? 'Dart$name' : null,
+ _dartAliasName =
+ (!genFfiDartType && type is! Typealias && !type.sameDartAndCType)
+ ? 'Dart$name'
+ : null,
super(
usr: usr,
- name: name,
+ name: genFfiDartType ? 'Native$name' : name,
dartDoc: dartDoc,
originalName: originalName,
isInternal: isInternal,
@@ -98,12 +103,24 @@
@override
BindingString toBindingString(Writer w) {
+ if (_ffiDartAliasName != null) {
+ _ffiDartAliasName = w.topLevelUniqueNamer.makeUnique(_ffiDartAliasName!);
+ }
+ if (_dartAliasName != null) {
+ _dartAliasName = w.topLevelUniqueNamer.makeUnique(_dartAliasName!);
+ }
+
final sb = StringBuffer();
if (dartDoc != null) {
sb.write(makeDartDoc(dartDoc!));
}
- sb.write('typedef $name = ');
- sb.write('${_useDartType ? type.getFfiDartType(w) : type.getCType(w)};\n');
+ sb.write('typedef $name = ${type.getCType(w)};\n');
+ if (_ffiDartAliasName != null) {
+ sb.write('typedef $_ffiDartAliasName = ${type.getFfiDartType(w)};\n');
+ }
+ if (_dartAliasName != null) {
+ sb.write('typedef $_dartAliasName = ${type.getDartType(w)};\n');
+ }
return BindingString(
type: BindingStringType.typeDef, string: sb.toString());
}
@@ -119,9 +136,9 @@
@override
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 (type.sameFfiDartAndCType) {
+ if (_ffiDartAliasName != null) {
+ return _ffiDartAliasName!;
+ } else if (type.sameFfiDartAndCType) {
return name;
} else {
return type.getFfiDartType(w);
@@ -129,6 +146,9 @@
}
@override
+ String getDartType(Writer w) => _dartAliasName ?? type.getDartType(w);
+
+ @override
bool get sameFfiDartAndCType => type.sameFfiDartAndCType;
@override
@@ -154,11 +174,7 @@
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 genFfiDartType = false,
bool isInternal = false,
}) : super._(
usr: usr,
@@ -166,7 +182,7 @@
dartDoc: dartDoc,
name: name,
type: type,
- useDartType: useDartType,
+ genFfiDartType: genFfiDartType,
isInternal: isInternal,
);
}
diff --git a/pkgs/ffigen/test/collision_tests/decl_decl_collision_test.dart b/pkgs/ffigen/test/collision_tests/decl_decl_collision_test.dart
index 4529f29..1edcaeb 100644
--- a/pkgs/ffigen/test/collision_tests/decl_decl_collision_test.dart
+++ b/pkgs/ffigen/test/collision_tests/decl_decl_collision_test.dart
@@ -13,7 +13,7 @@
logWarnings(Level.SEVERE);
});
test('declaration conflict', () {
- final l1 = Library(name: 'Bindings', bindings: [
+ final library = Library(name: 'Bindings', bindings: [
Struct(name: 'TestStruct'),
Struct(name: 'TestStruct'),
EnumClass(name: 'TestEnum'),
@@ -53,49 +53,13 @@
Struct(name: 'ffi'),
Func(name: 'ffi1', returnType: NativeType(SupportedNativeType.Void)),
]);
- final l2 = Library(name: 'Bindings', bindings: [
- Struct(name: 'TestStruct'),
- Struct(name: 'TestStruct1'),
- EnumClass(name: 'TestEnum'),
- EnumClass(name: 'TestEnum1'),
- Func(
- name: 'testFunc',
- originalName: 'testFunc',
- returnType: NativeType(SupportedNativeType.Void)),
- Func(
- name: 'testFunc1',
- originalName: 'testFunc',
- returnType: NativeType(SupportedNativeType.Void)),
- Constant(
- originalName: 'Test_Macro',
- name: 'Test_Macro',
- rawType: 'int',
- rawValue: '0',
- ),
- Constant(
- originalName: 'Test_Macro',
- name: 'Test_Macro1',
- rawType: 'int',
- rawValue: '0',
- ),
- Typealias(
- name: 'testAlias', type: NativeType(SupportedNativeType.Void)),
- Typealias(
- name: 'testAlias1', type: NativeType(SupportedNativeType.Void)),
- Struct(name: 'testCrossDecl', originalName: 'testCrossDecl'),
- Func(
- name: 'testCrossDecl1',
- originalName: 'testCrossDecl',
- returnType: NativeType(SupportedNativeType.Void)),
- Constant(name: 'testCrossDecl2', rawValue: '0', rawType: 'int'),
- EnumClass(name: 'testCrossDecl3'),
- Typealias(
- name: 'testCrossDecl4', type: NativeType(SupportedNativeType.Void)),
- Struct(name: 'ffi'),
- Func(name: 'ffi1', returnType: NativeType(SupportedNativeType.Void)),
+ matchLibraryWithExpected(
+ library, 'decl_decl_collision_test_output.dart', [
+ 'test',
+ 'collision_tests',
+ 'expected_bindings',
+ '_expected_decl_decl_collision_bindings.dart',
]);
-
- expect(l1.generate(), l2.generate());
});
});
}
diff --git a/pkgs/ffigen/test/collision_tests/expected_bindings/_expected_decl_decl_collision_bindings.dart b/pkgs/ffigen/test/collision_tests/expected_bindings/_expected_decl_decl_collision_bindings.dart
new file mode 100644
index 0000000..32388b6
--- /dev/null
+++ b/pkgs/ffigen/test/collision_tests/expected_bindings/_expected_decl_decl_collision_bindings.dart
@@ -0,0 +1,80 @@
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+// ignore_for_file: type=lint
+import 'dart:ffi' as ffi;
+
+class Bindings {
+ /// Holds the symbol lookup function.
+ final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
+ _lookup;
+
+ /// The symbols are looked up in [dynamicLibrary].
+ Bindings(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup;
+
+ /// The symbols are looked up with [lookup].
+ Bindings.fromLookup(
+ ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
+ lookup)
+ : _lookup = lookup;
+
+ void testFunc() {
+ return _testFunc();
+ }
+
+ late final _testFuncPtr =
+ _lookup<ffi.NativeFunction<ffi.Void Function()>>('testFunc');
+ late final _testFunc = _testFuncPtr.asFunction<void Function()>();
+
+ void testFunc1() {
+ return _testFunc1();
+ }
+
+ late final _testFunc1Ptr =
+ _lookup<ffi.NativeFunction<ffi.Void Function()>>('testFunc');
+ late final _testFunc1 = _testFunc1Ptr.asFunction<void Function()>();
+
+ void testCrossDecl1() {
+ return _testCrossDecl1();
+ }
+
+ late final _testCrossDecl1Ptr =
+ _lookup<ffi.NativeFunction<ffi.Void Function()>>('testCrossDecl');
+ late final _testCrossDecl1 = _testCrossDecl1Ptr.asFunction<void Function()>();
+
+ void ffi1() {
+ return _ffi1();
+ }
+
+ late final _ffi1Ptr =
+ _lookup<ffi.NativeFunction<ffi.Void Function()>>('ffi1');
+ late final _ffi1 = _ffi1Ptr.asFunction<void Function()>();
+}
+
+final class TestStruct extends ffi.Opaque {}
+
+final class TestStruct1 extends ffi.Opaque {}
+
+abstract class TestEnum {}
+
+abstract class TestEnum1 {}
+
+const int Test_Macro = 0;
+
+const int Test_Macro1 = 0;
+
+typedef testAlias = ffi.Void;
+typedef DarttestAlias = void;
+typedef testAlias1 = ffi.Void;
+typedef DarttestAlias1 = void;
+
+final class testCrossDecl extends ffi.Opaque {}
+
+const int testCrossDecl2 = 0;
+
+abstract class testCrossDecl3 {}
+
+typedef testCrossDecl4 = ffi.Void;
+typedef DarttestCrossDecl = void;
+
+final class ffi extends ffi.Opaque {}
diff --git a/pkgs/ffigen/test/collision_tests/expected_bindings/_expected_reserved_keyword_collision_bindings.dart b/pkgs/ffigen/test/collision_tests/expected_bindings/_expected_reserved_keyword_collision_bindings.dart
new file mode 100644
index 0000000..c788b49
--- /dev/null
+++ b/pkgs/ffigen/test/collision_tests/expected_bindings/_expected_reserved_keyword_collision_bindings.dart
@@ -0,0 +1,61 @@
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+// ignore_for_file: type=lint
+import 'dart:ffi' as ffi;
+
+class Bindings {
+ /// Holds the symbol lookup function.
+ final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
+ _lookup;
+
+ /// The symbols are looked up in [dynamicLibrary].
+ Bindings(ffi.DynamicLibrary dynamicLibrary) : _lookup = dynamicLibrary.lookup;
+
+ /// The symbols are looked up with [lookup].
+ Bindings.fromLookup(
+ ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
+ lookup)
+ : _lookup = lookup;
+
+ void show1() {
+ return _show1();
+ }
+
+ late final _show1Ptr =
+ _lookup<ffi.NativeFunction<ffi.Void Function()>>('show');
+ late final _show1 = _show1Ptr.asFunction<void Function()>();
+
+ void implements1(
+ int if1,
+ int abstract1,
+ int in1,
+ ) {
+ return _implements1(
+ if1,
+ abstract1,
+ in1,
+ );
+ }
+
+ late final _implements1Ptr =
+ _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int, ffi.Int, ffi.Int)>>(
+ 'implements');
+ late final _implements1 =
+ _implements1Ptr.asFunction<void Function(int, int, int)>();
+}
+
+final class abstract1 extends ffi.Opaque {}
+
+final class abstract2 extends ffi.Opaque {}
+
+final class if1 extends ffi.Opaque {}
+
+abstract class return1 {}
+
+abstract class export1 {}
+
+const int else1 = 0;
+
+typedef var1 = ffi.Void;
+typedef Dartvar = void;
diff --git a/pkgs/ffigen/test/collision_tests/reserved_keyword_collision_test.dart b/pkgs/ffigen/test/collision_tests/reserved_keyword_collision_test.dart
index c6873f2..88f353a 100644
--- a/pkgs/ffigen/test/collision_tests/reserved_keyword_collision_test.dart
+++ b/pkgs/ffigen/test/collision_tests/reserved_keyword_collision_test.dart
@@ -14,7 +14,7 @@
logWarnings(Level.SEVERE);
});
test('reserved keyword collision', () {
- final l1 = Library(name: 'Bindings', bindings: [
+ final library = Library(name: 'Bindings', bindings: [
Struct(name: 'abstract'),
Struct(name: 'abstract'),
Struct(name: 'if'),
@@ -45,42 +45,13 @@
),
Typealias(name: 'var', type: NativeType(SupportedNativeType.Void)),
]);
- final l2 = Library(name: 'Bindings', bindings: [
- Struct(name: 'abstract1'),
- Struct(name: 'abstract2'),
- Struct(name: 'if1'),
- EnumClass(name: 'return1'),
- EnumClass(name: 'export1'),
- Func(
- name: 'show1',
- originalName: 'show',
- returnType: NativeType(SupportedNativeType.Void)),
- Func(
- name: 'implements1',
- originalName: 'implements',
- parameters: [
- Parameter(
- type: intType,
- name: 'if1',
- ),
- Parameter(
- type: intType,
- name: 'abstract1',
- ),
- Parameter(
- type: intType,
- name: 'in1',
- ),
- ],
- returnType: NativeType(SupportedNativeType.Void)),
- Constant(
- name: 'else1',
- rawType: 'int',
- rawValue: '0',
- ),
- Typealias(name: 'var1', type: NativeType(SupportedNativeType.Void)),
+ matchLibraryWithExpected(
+ library, 'reserved_keyword_collision_test_output.dart', [
+ 'test',
+ 'collision_tests',
+ 'expected_bindings',
+ '_expected_reserved_keyword_collision_bindings.dart',
]);
- expect(l1.generate(), l2.generate());
});
});
}
diff --git a/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_dart_handle_bindings.dart b/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_dart_handle_bindings.dart
index a6f4456..6106985 100644
--- a/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_dart_handle_bindings.dart
+++ b/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_dart_handle_bindings.dart
@@ -68,8 +68,9 @@
late final _func4 = _func4Ptr.asFunction<void Function(Typedef1)>();
}
-typedef Typedef1 = ffi.Pointer<ffi.NativeFunction<Typedef1_function>>;
-typedef Typedef1_function = ffi.Void Function(ffi.Handle);
+typedef Typedef1 = ffi.Pointer<ffi.NativeFunction<Typedef1Function>>;
+typedef Typedef1Function = ffi.Void Function(ffi.Handle);
+typedef DartTypedef1Function = void Function(Object);
final class Struct1 extends ffi.Opaque {}
diff --git a/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_native_func_typedef_bindings.dart b/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_native_func_typedef_bindings.dart
index ca4e5e6..b3063c4 100644
--- a/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_native_func_typedef_bindings.dart
+++ b/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_native_func_typedef_bindings.dart
@@ -73,16 +73,18 @@
}
typedef WithTypedefReturnType
- = ffi.Pointer<ffi.NativeFunction<WithTypedefReturnType_function>>;
-typedef WithTypedefReturnType_function = InsideReturnType Function();
+ = ffi.Pointer<ffi.NativeFunction<WithTypedefReturnTypeFunction>>;
+typedef WithTypedefReturnTypeFunction = InsideReturnType Function();
typedef InsideReturnType
- = ffi.Pointer<ffi.NativeFunction<InsideReturnType_function>>;
-typedef InsideReturnType_function = ffi.Void Function();
+ = ffi.Pointer<ffi.NativeFunction<InsideReturnTypeFunction>>;
+typedef InsideReturnTypeFunction = ffi.Void Function();
+typedef DartInsideReturnTypeFunction = void Function();
final class Struct2 extends ffi.Struct {
external VoidFuncPointer constFuncPointer;
}
typedef VoidFuncPointer
- = ffi.Pointer<ffi.NativeFunction<VoidFuncPointer_function>>;
-typedef VoidFuncPointer_function = ffi.Void Function();
+ = ffi.Pointer<ffi.NativeFunction<VoidFuncPointerFunction>>;
+typedef VoidFuncPointerFunction = ffi.Void Function();
+typedef DartVoidFuncPointerFunction = void Function();
diff --git a/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_struct_fptr_fields_bindings.dart b/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_struct_fptr_fields_bindings.dart
index 8dc7297..f5af81f 100644
--- a/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_struct_fptr_fields_bindings.dart
+++ b/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_struct_fptr_fields_bindings.dart
@@ -69,5 +69,6 @@
}
typedef ArithmeticOperation
- = ffi.Pointer<ffi.NativeFunction<ArithmeticOperation_function>>;
-typedef ArithmeticOperation_function = ffi.Int Function(ffi.Int a, ffi.Int b);
+ = ffi.Pointer<ffi.NativeFunction<ArithmeticOperationFunction>>;
+typedef ArithmeticOperationFunction = ffi.Int Function(ffi.Int a, ffi.Int b);
+typedef DartArithmeticOperationFunction = int Function(int a, int b);
diff --git a/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_typedef_bindings.dart b/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_typedef_bindings.dart
index b0b171a..a33e9c8 100644
--- a/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_typedef_bindings.dart
+++ b/pkgs/ffigen/test/header_parser_tests/expected_bindings/_expected_typedef_bindings.dart
@@ -92,8 +92,9 @@
}
typedef NamedFunctionProto
- = ffi.Pointer<ffi.NativeFunction<NamedFunctionProto_function>>;
-typedef NamedFunctionProto_function = ffi.Void Function();
+ = ffi.Pointer<ffi.NativeFunction<NamedFunctionProtoFunction>>;
+typedef NamedFunctionProtoFunction = ffi.Void Function();
+typedef DartNamedFunctionProtoFunction = void Function();
final class AnonymousStructInTypedef extends ffi.Opaque {}
@@ -113,6 +114,7 @@
}
typedef NestingASpecifiedType = ffi.IntPtr;
+typedef DartNestingASpecifiedType = int;
final class Struct2 extends ffi.Opaque {}
diff --git a/pkgs/ffigen/test/large_integration_tests/_expected_cjson_bindings.dart b/pkgs/ffigen/test/large_integration_tests/_expected_cjson_bindings.dart
index f4edb59..cc66670 100644
--- a/pkgs/ffigen/test/large_integration_tests/_expected_cjson_bindings.dart
+++ b/pkgs/ffigen/test/large_integration_tests/_expected_cjson_bindings.dart
@@ -1249,6 +1249,7 @@
}
typedef cJSON_bool = ffi.Int;
+typedef DartcJSON_bool = int;
const int CJSON_VERSION_MAJOR = 1;
diff --git a/pkgs/ffigen/test/large_integration_tests/_expected_libclang_bindings.dart b/pkgs/ffigen/test/large_integration_tests/_expected_libclang_bindings.dart
index d30109c..3d27499 100644
--- a/pkgs/ffigen/test/large_integration_tests/_expected_libclang_bindings.dart
+++ b/pkgs/ffigen/test/large_integration_tests/_expected_libclang_bindings.dart
@@ -7431,8 +7431,10 @@
/// Visitor invoked for each cursor found by a traversal.
typedef CXCursorVisitor
- = ffi.Pointer<ffi.NativeFunction<CXCursorVisitor_function>>;
-typedef CXCursorVisitor_function = ffi.Int32 Function(
+ = ffi.Pointer<ffi.NativeFunction<CXCursorVisitorFunction>>;
+typedef CXCursorVisitorFunction = ffi.Int32 Function(
+ CXCursor cursor, CXCursor parent, CXClientData client_data);
+typedef DartCXCursorVisitorFunction = int Function(
CXCursor cursor, CXCursor parent, CXClientData client_data);
/// Opaque pointer representing client data that will be passed through to
@@ -7762,12 +7764,17 @@
/// Visitor invoked for each file in a translation unit (used with
/// clang_getInclusions()).
typedef CXInclusionVisitor
- = ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor_function>>;
-typedef CXInclusionVisitor_function = ffi.Void Function(
+ = ffi.Pointer<ffi.NativeFunction<CXInclusionVisitorFunction>>;
+typedef CXInclusionVisitorFunction = ffi.Void Function(
CXFile included_file,
ffi.Pointer<CXSourceLocation> inclusion_stack,
ffi.UnsignedInt include_len,
CXClientData client_data);
+typedef DartCXInclusionVisitorFunction = void Function(
+ CXFile included_file,
+ ffi.Pointer<CXSourceLocation> inclusion_stack,
+ int include_len,
+ CXClientData client_data);
abstract class CXEvalResultKind {
static const int CXEval_Int = 1;
@@ -8225,8 +8232,10 @@
/// Visitor invoked for each field found by a traversal.
typedef CXFieldVisitor
- = ffi.Pointer<ffi.NativeFunction<CXFieldVisitor_function>>;
-typedef CXFieldVisitor_function = ffi.Int32 Function(
+ = ffi.Pointer<ffi.NativeFunction<CXFieldVisitorFunction>>;
+typedef CXFieldVisitorFunction = ffi.Int32 Function(
+ CXCursor C, CXClientData client_data);
+typedef DartCXFieldVisitorFunction = int Function(
CXCursor C, CXClientData client_data);
const int CINDEX_VERSION_MAJOR = 0;
diff --git a/pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart b/pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart
index 492da42..5c6de76 100644
--- a/pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart
+++ b/pkgs/ffigen/test/large_integration_tests/_expected_sqlite_bindings.dart
@@ -10854,9 +10854,11 @@
typedef sqlite3_int64 = sqlite_int64;
typedef sqlite_int64 = ffi.LongLong;
+typedef Dartsqlite_int64 = int;
typedef sqlite3_syscall_ptr
- = ffi.Pointer<ffi.NativeFunction<sqlite3_syscall_ptr_function>>;
-typedef sqlite3_syscall_ptr_function = ffi.Void Function();
+ = ffi.Pointer<ffi.NativeFunction<sqlite3_syscall_ptrFunction>>;
+typedef sqlite3_syscall_ptrFunction = ffi.Void Function();
+typedef Dartsqlite3_syscall_ptrFunction = void Function();
final class sqlite3_mem_methods extends ffi.Struct {
/// Memory allocation function
@@ -10899,6 +10901,7 @@
typedef sqlite3_uint64 = sqlite_uint64;
typedef sqlite_uint64 = ffi.UnsignedLongLong;
+typedef Dartsqlite_uint64 = int;
final class sqlite3_stmt extends ffi.Opaque {}
@@ -11507,6 +11510,7 @@
}
typedef sqlite3_rtree_dbl = ffi.Double;
+typedef Dartsqlite3_rtree_dbl = double;
/// A pointer to a structure of the following type is passed as the
/// argument to scored geometry callback registered using
@@ -12010,13 +12014,19 @@
}
typedef fts5_extension_function
- = ffi.Pointer<ffi.NativeFunction<fts5_extension_function_function>>;
-typedef fts5_extension_function_function = ffi.Void Function(
+ = ffi.Pointer<ffi.NativeFunction<fts5_extension_functionFunction>>;
+typedef fts5_extension_functionFunction = ffi.Void Function(
ffi.Pointer<Fts5ExtensionApi> pApi,
ffi.Pointer<Fts5Context> pFts,
ffi.Pointer<sqlite3_context> pCtx,
ffi.Int nVal,
ffi.Pointer<ffi.Pointer<sqlite3_value>> apVal);
+typedef Dartfts5_extension_functionFunction = void Function(
+ ffi.Pointer<Fts5ExtensionApi> pApi,
+ ffi.Pointer<Fts5Context> pFts,
+ ffi.Pointer<sqlite3_context> pCtx,
+ int nVal,
+ ffi.Pointer<ffi.Pointer<sqlite3_value>> apVal);
const String SQLITE_VERSION = '3.32.3';
diff --git a/pkgs/ffigen/test/native_objc_test/typedef_config.yaml b/pkgs/ffigen/test/native_objc_test/typedef_config.yaml
new file mode 100644
index 0000000..f375bfc
--- /dev/null
+++ b/pkgs/ffigen/test/native_objc_test/typedef_config.yaml
@@ -0,0 +1,17 @@
+name: TypedefTestObjCLibrary
+description: 'Tests typedef'
+language: objc
+output: 'typedef_bindings.dart'
+exclude-all-by-default: true
+objc-interfaces:
+ include:
+ - SomeClass
+ - AnotherClass
+typedefs:
+ include:
+ - SomeClassPtr
+headers:
+ entry-points:
+ - 'typedef_test.m'
+preamble: |
+ // ignore_for_file: camel_case_types, non_constant_identifier_names, unused_element, unused_field
diff --git a/pkgs/ffigen/test/native_objc_test/typedef_test.dart b/pkgs/ffigen/test/native_objc_test/typedef_test.dart
new file mode 100644
index 0000000..7a47fdb
--- /dev/null
+++ b/pkgs/ffigen/test/native_objc_test/typedef_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2023, 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.
+
+// Objective C support is only available on mac.
+@TestOn('mac-os')
+
+import 'dart:ffi';
+import 'dart:io';
+
+import 'package:test/test.dart';
+import '../test_utils.dart';
+import 'typedef_bindings.dart';
+import 'util.dart';
+
+void main() {
+ late TypedefTestObjCLibrary lib;
+
+ group('typedef', () {
+ setUpAll(() {
+ logWarnings();
+ final dylib = File('test/native_objc_test/typedef_test.dylib');
+ verifySetupFile(dylib);
+ lib = TypedefTestObjCLibrary(DynamicLibrary.open(dylib.absolute.path));
+ generateBindingsForCoverage('typedef');
+ });
+
+ test('Regression test for #386', () {
+ // https://github.com/dart-lang/ffigen/issues/386
+ // Make sure that the typedef DartSomeClassPtr is for SomeClass.
+ final DartSomeClassPtr instance = SomeClass.new1(lib);
+ expect(instance.pointer, isNot(nullptr));
+ });
+ });
+}
diff --git a/pkgs/ffigen/test/native_objc_test/typedef_test.m b/pkgs/ffigen/test/native_objc_test/typedef_test.m
new file mode 100644
index 0000000..c5972ab
--- /dev/null
+++ b/pkgs/ffigen/test/native_objc_test/typedef_test.m
@@ -0,0 +1,20 @@
+// Copyright (c) 2023, 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.
+
+#import <Foundation/NSObject.h>
+
+@interface SomeClass : NSObject {}
+@end
+
+@implementation SomeClass
+@end
+
+typedef SomeClass* SomeClassPtr;
+
+@interface AnotherClass : NSObject {}
+@property SomeClassPtr property;
+@end
+
+@implementation AnotherClass
+@end
diff --git a/pkgs/ffigen/test/regen.dart b/pkgs/ffigen/test/regen.dart
index 1617eda..ec52964 100644
--- a/pkgs/ffigen/test/regen.dart
+++ b/pkgs/ffigen/test/regen.dart
@@ -8,7 +8,7 @@
import 'package:args/args.dart';
import 'package:ffigen/ffigen.dart';
import 'package:logging/logging.dart';
-import './test_utils.dart';
+import 'test_utils.dart';
const usage = r'''Regenerates the Dart FFI bindings used in tests and examples.
@@ -18,12 +18,14 @@
$ dart run test/setup.dart && dart run test/regen.dart && dart test
''';
-Future<void> _regenConfig(File yamlConfig, File bindingOutput) async {
- yamlConfig = yamlConfig.absolute;
- bindingOutput = bindingOutput.absolute;
- final config = testConfigFromPath(yamlConfig.path);
- final library = parse(config);
- library.generateFile(bindingOutput);
+void _regenConfig(String yamlConfigPath, String bindingOutputPath) {
+ final yamlConfig = File(yamlConfigPath).absolute;
+ final bindingOutput = File(bindingOutputPath).absolute;
+ withChDir(yamlConfig.path, () {
+ final config = testConfigFromPath(yamlConfig.path);
+ final library = parse(config);
+ library.generateFile(bindingOutput);
+ });
}
Future<void> main(List<String> args) async {
@@ -50,25 +52,12 @@
print('${record.level.name}: ${record.time}: ${record.message}');
});
- final nativeTestConfig = File('test/native_test/config.yaml').absolute;
- final nativeTestOut =
- File('test/native_test/_expected_native_test_bindings.dart').absolute;
- await withChDir(nativeTestConfig.path,
- () => _regenConfig(nativeTestConfig, nativeTestOut));
-
- final libclangConfig = File('example/libclang-example/config.yaml').absolute;
- final libclangOut =
- File('example/libclang-example/generated_bindings.dart').absolute;
- await withChDir(
- libclangConfig.path, () => _regenConfig(libclangConfig, libclangOut));
-
- final simpleConfig = File('example/simple/config.yaml').absolute;
- final simpleOut = File('example/simple/generated_bindings.dart').absolute;
- await withChDir(
- simpleConfig.path, () => _regenConfig(simpleConfig, simpleOut));
-
- final cJsonConfig = File('example/c_json/config.yaml').absolute;
- final cJsonOut =
- File('example/c_json/cjson_generated_bindings.dart').absolute;
- await withChDir(cJsonConfig.path, () => _regenConfig(cJsonConfig, cJsonOut));
+ _regenConfig('test/native_test/config.yaml',
+ 'test/native_test/_expected_native_test_bindings.dart');
+ _regenConfig('example/libclang-example/config.yaml',
+ 'example/libclang-example/generated_bindings.dart');
+ _regenConfig(
+ 'example/simple/config.yaml', 'example/simple/generated_bindings.dart');
+ _regenConfig('example/c_json/config.yaml',
+ 'example/c_json/cjson_generated_bindings.dart');
}
diff --git a/pkgs/ffigen/test/test_utils.dart b/pkgs/ffigen/test/test_utils.dart
index 95434ff..9482b9c 100644
--- a/pkgs/ffigen/test/test_utils.dart
+++ b/pkgs/ffigen/test/test_utils.dart
@@ -47,7 +47,7 @@
// Remove '\r' for Windows compatibility, then apply user's normalizer.
String _normalizeGeneratedCode(
String generated, String Function(String)? codeNormalizer) {
- final noCR = generated.replaceAll('\r', '').replaceAll(RegExp(r'\n+'), '\n');
+ final noCR = generated.replaceAll('\r', '');
if (codeNormalizer == null) return noCR;
return codeNormalizer(noCR);
}
@@ -103,7 +103,7 @@
_normalizeGeneratedCode(file.readAsStringSync(), codeNormalizer);
final expected = _normalizeGeneratedCode(
File(path.joinAll(pathToExpected)).readAsStringSync(), codeNormalizer);
- expect(actual, expected);
+ expect(actual.split('\n'), expected.split('\n'));
if (file.existsSync()) {
file.delete();
}