diff --git a/example/c_json/cjson_generated_bindings.dart b/example/c_json/cjson_generated_bindings.dart index fa9e56ef..38bc263f 100644 --- a/example/c_json/cjson_generated_bindings.dart +++ b/example/c_json/cjson_generated_bindings.dart @@ -1268,6 +1268,7 @@ final class cJSON_Hooks extends ffi.Struct { } typedef cJSON_bool = ffi.Int; +typedef DartcJSON_bool = int; const int CJSON_VERSION_MAJOR = 1; diff --git a/example/libclang-example/generated_bindings.dart b/example/libclang-example/generated_bindings.dart index a0ae7a2e..7cf663e3 100644 --- a/example/libclang-example/generated_bindings.dart +++ b/example/libclang-example/generated_bindings.dart @@ -9748,8 +9748,10 @@ typedef DartClang_getIBOutletCollectionType = CXType Function(CXCursor arg0); /// The visitor should return one of the \c CXChildVisitResult values /// to direct clang_visitCursorChildren(). typedef CXCursorVisitor - = ffi.Pointer>; -typedef CXCursorVisitor_function = ffi.Int32 Function( + = ffi.Pointer>; +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 @@ typedef DartClang_toggleCrashRecovery = void Function(int isEnabled); /// 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>; -typedef CXInclusionVisitor_function = ffi.Void Function( + = ffi.Pointer>; +typedef CXInclusionVisitorFunction = ffi.Void Function( CXFile included_file, ffi.Pointer inclusion_stack, ffi.UnsignedInt include_len, CXClientData client_data); +typedef DartCXInclusionVisitorFunction = void Function( + CXFile included_file, + ffi.Pointer 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 @@ typedef DartClang_indexLoc_getCXSourceLocation = CXSourceLocation Function( /// The visitor should return one of the \c CXVisitorResult values /// to direct \c clang_Type_visitFields. typedef CXFieldVisitor - = ffi.Pointer>; -typedef CXFieldVisitor_function = ffi.Int32 Function( + = ffi.Pointer>; +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/lib/src/code_generator/func.dart b/lib/src/code_generator/func.dart index f8a81773..b3141ae1 100644 --- a/lib/src/code_generator/func.dart +++ b/lib/src/code_generator/func.dart @@ -46,8 +46,7 @@ class Func extends LookUpBinding { 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 @@ class Func extends LookUpBinding { // 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 @@ class Func extends LookUpBinding { 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 @@ class Func extends LookUpBinding { dependencies.add(this); functionType.addDependencies(dependencies); if (exposeFunctionTypedefs) { - _exposedCFunctionTypealias!.addDependencies(dependencies); - _exposedDartFunctionTypealias!.addDependencies(dependencies); + _exposedFunctionTypealias!.addDependencies(dependencies); } } } diff --git a/lib/src/code_generator/objc_interface.dart b/lib/src/code_generator/objc_interface.dart index 421a508d..c79ccca1 100644 --- a/lib/src/code_generator/objc_interface.dart +++ b/lib/src/code_generator/objc_interface.dart @@ -314,9 +314,11 @@ class $name extends ${superType?.name ?? '_ObjCWrapper'} { } } - 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 @@ class $name extends ${superType?.name ?? '_ObjCWrapper'} { // passed to native as Pointer, 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,22 +433,24 @@ class $name extends ${superType?.name ?? '_ObjCWrapper'} { 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 ObjCInstanceType) { + return '$prefix$enclosingClass._($value, $library, $ownerFlags)'; } - if (type is ObjCBlock) { - return '$prefix${type.name}._($value, $library)'; + if (baseType is ObjCInterface) { + return '$prefix${baseType.name}._($value, $library, $ownerFlags)'; } - if (type is ObjCObjectPointer) { - return '${prefix}NSObject._($value, $library, $ownerFlags)'; + if (baseType is ObjCBlock) { + return '$prefix${baseType.name}._($value, $library)'; } - if (type is ObjCInstanceType) { - return '$prefix$enclosingClass._($value, $library, $ownerFlags)'; + if (baseType is ObjCObjectPointer) { + return '${prefix}NSObject._($value, $library, $ownerFlags)'; } return prefix + value; } diff --git a/lib/src/code_generator/typealias.dart b/lib/src/code_generator/typealias.dart index 5c5cc443..ec9430e2 100644 --- a/lib/src/code_generator/typealias.dart +++ b/lib/src/code_generator/typealias.dart @@ -17,27 +17,28 @@ import 'writer.dart'; /// ``` 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 @@ class Typealias extends BindingType { dartDoc: dartDoc, name: name, type: type, - useDartType: useDartType, + genFfiDartType: genFfiDartType, isInternal: isInternal, ); } @@ -59,7 +60,7 @@ class Typealias extends BindingType { dartDoc: dartDoc, name: name, type: type, - useDartType: useDartType, + genFfiDartType: genFfiDartType, isInternal: isInternal, ); } @@ -70,12 +71,16 @@ class Typealias extends BindingType { 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 @@ class Typealias extends BindingType { @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,15 +136,18 @@ class Typealias extends BindingType { @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); } } + @override + String getDartType(Writer w) => _dartAliasName ?? type.getDartType(w); + @override bool get sameFfiDartAndCType => type.sameFfiDartAndCType; @@ -154,11 +174,7 @@ class ObjCInstanceType extends Typealias { 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 @@ class ObjCInstanceType extends Typealias { dartDoc: dartDoc, name: name, type: type, - useDartType: useDartType, + genFfiDartType: genFfiDartType, isInternal: isInternal, ); } diff --git a/test/collision_tests/decl_decl_collision_test.dart b/test/collision_tests/decl_decl_collision_test.dart index 4529f290..1edcaeb1 100644 --- a/test/collision_tests/decl_decl_collision_test.dart +++ b/test/collision_tests/decl_decl_collision_test.dart @@ -13,7 +13,7 @@ void main() { 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 @@ void main() { 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/test/collision_tests/expected_bindings/_expected_decl_decl_collision_bindings.dart b/test/collision_tests/expected_bindings/_expected_decl_decl_collision_bindings.dart new file mode 100644 index 00000000..32388b61 --- /dev/null +++ b/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 Function(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 Function(String symbolName) + lookup) + : _lookup = lookup; + + void testFunc() { + return _testFunc(); + } + + late final _testFuncPtr = + _lookup>('testFunc'); + late final _testFunc = _testFuncPtr.asFunction(); + + void testFunc1() { + return _testFunc1(); + } + + late final _testFunc1Ptr = + _lookup>('testFunc'); + late final _testFunc1 = _testFunc1Ptr.asFunction(); + + void testCrossDecl1() { + return _testCrossDecl1(); + } + + late final _testCrossDecl1Ptr = + _lookup>('testCrossDecl'); + late final _testCrossDecl1 = _testCrossDecl1Ptr.asFunction(); + + void ffi1() { + return _ffi1(); + } + + late final _ffi1Ptr = + _lookup>('ffi1'); + late final _ffi1 = _ffi1Ptr.asFunction(); +} + +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/test/collision_tests/expected_bindings/_expected_reserved_keyword_collision_bindings.dart b/test/collision_tests/expected_bindings/_expected_reserved_keyword_collision_bindings.dart new file mode 100644 index 00000000..c788b49c --- /dev/null +++ b/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 Function(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 Function(String symbolName) + lookup) + : _lookup = lookup; + + void show1() { + return _show1(); + } + + late final _show1Ptr = + _lookup>('show'); + late final _show1 = _show1Ptr.asFunction(); + + void implements1( + int if1, + int abstract1, + int in1, + ) { + return _implements1( + if1, + abstract1, + in1, + ); + } + + late final _implements1Ptr = + _lookup>( + 'implements'); + late final _implements1 = + _implements1Ptr.asFunction(); +} + +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/test/collision_tests/reserved_keyword_collision_test.dart b/test/collision_tests/reserved_keyword_collision_test.dart index c6873f29..88f353a7 100644 --- a/test/collision_tests/reserved_keyword_collision_test.dart +++ b/test/collision_tests/reserved_keyword_collision_test.dart @@ -14,7 +14,7 @@ void main() { 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 @@ void main() { ), 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/test/header_parser_tests/expected_bindings/_expected_dart_handle_bindings.dart b/test/header_parser_tests/expected_bindings/_expected_dart_handle_bindings.dart index a6f44566..61069852 100644 --- a/test/header_parser_tests/expected_bindings/_expected_dart_handle_bindings.dart +++ b/test/header_parser_tests/expected_bindings/_expected_dart_handle_bindings.dart @@ -68,8 +68,9 @@ class NativeLibrary { late final _func4 = _func4Ptr.asFunction(); } -typedef Typedef1 = ffi.Pointer>; -typedef Typedef1_function = ffi.Void Function(ffi.Handle); +typedef Typedef1 = ffi.Pointer>; +typedef Typedef1Function = ffi.Void Function(ffi.Handle); +typedef DartTypedef1Function = void Function(Object); final class Struct1 extends ffi.Opaque {} diff --git a/test/header_parser_tests/expected_bindings/_expected_native_func_typedef_bindings.dart b/test/header_parser_tests/expected_bindings/_expected_native_func_typedef_bindings.dart index ca4e5e61..b3063c46 100644 --- a/test/header_parser_tests/expected_bindings/_expected_native_func_typedef_bindings.dart +++ b/test/header_parser_tests/expected_bindings/_expected_native_func_typedef_bindings.dart @@ -73,16 +73,18 @@ final class Struct extends ffi.Struct { } typedef WithTypedefReturnType - = ffi.Pointer>; -typedef WithTypedefReturnType_function = InsideReturnType Function(); + = ffi.Pointer>; +typedef WithTypedefReturnTypeFunction = InsideReturnType Function(); typedef InsideReturnType - = ffi.Pointer>; -typedef InsideReturnType_function = ffi.Void Function(); + = ffi.Pointer>; +typedef InsideReturnTypeFunction = ffi.Void Function(); +typedef DartInsideReturnTypeFunction = void Function(); final class Struct2 extends ffi.Struct { external VoidFuncPointer constFuncPointer; } typedef VoidFuncPointer - = ffi.Pointer>; -typedef VoidFuncPointer_function = ffi.Void Function(); + = ffi.Pointer>; +typedef VoidFuncPointerFunction = ffi.Void Function(); +typedef DartVoidFuncPointerFunction = void Function(); diff --git a/test/header_parser_tests/expected_bindings/_expected_struct_fptr_fields_bindings.dart b/test/header_parser_tests/expected_bindings/_expected_struct_fptr_fields_bindings.dart index 8dc72979..f5af81fc 100644 --- a/test/header_parser_tests/expected_bindings/_expected_struct_fptr_fields_bindings.dart +++ b/test/header_parser_tests/expected_bindings/_expected_struct_fptr_fields_bindings.dart @@ -69,5 +69,6 @@ final class S extends ffi.Struct { } typedef ArithmeticOperation - = ffi.Pointer>; -typedef ArithmeticOperation_function = ffi.Int Function(ffi.Int a, ffi.Int b); + = ffi.Pointer>; +typedef ArithmeticOperationFunction = ffi.Int Function(ffi.Int a, ffi.Int b); +typedef DartArithmeticOperationFunction = int Function(int a, int b); diff --git a/test/header_parser_tests/expected_bindings/_expected_typedef_bindings.dart b/test/header_parser_tests/expected_bindings/_expected_typedef_bindings.dart index b0b171a0..a33e9c8b 100644 --- a/test/header_parser_tests/expected_bindings/_expected_typedef_bindings.dart +++ b/test/header_parser_tests/expected_bindings/_expected_typedef_bindings.dart @@ -92,8 +92,9 @@ final class Struct1 extends ffi.Struct { } typedef NamedFunctionProto - = ffi.Pointer>; -typedef NamedFunctionProto_function = ffi.Void Function(); + = ffi.Pointer>; +typedef NamedFunctionProtoFunction = ffi.Void Function(); +typedef DartNamedFunctionProtoFunction = void Function(); final class AnonymousStructInTypedef extends ffi.Opaque {} @@ -113,6 +114,7 @@ abstract class _NamedEnumInTypedef { } typedef NestingASpecifiedType = ffi.IntPtr; +typedef DartNestingASpecifiedType = int; final class Struct2 extends ffi.Opaque {} diff --git a/test/large_integration_tests/_expected_cjson_bindings.dart b/test/large_integration_tests/_expected_cjson_bindings.dart index f4edb598..cc66670e 100644 --- a/test/large_integration_tests/_expected_cjson_bindings.dart +++ b/test/large_integration_tests/_expected_cjson_bindings.dart @@ -1249,6 +1249,7 @@ final class cJSON_Hooks extends ffi.Struct { } typedef cJSON_bool = ffi.Int; +typedef DartcJSON_bool = int; const int CJSON_VERSION_MAJOR = 1; diff --git a/test/large_integration_tests/_expected_libclang_bindings.dart b/test/large_integration_tests/_expected_libclang_bindings.dart index d30109c4..3d274994 100644 --- a/test/large_integration_tests/_expected_libclang_bindings.dart +++ b/test/large_integration_tests/_expected_libclang_bindings.dart @@ -7431,8 +7431,10 @@ abstract class CXChildVisitResult { /// Visitor invoked for each cursor found by a traversal. typedef CXCursorVisitor - = ffi.Pointer>; -typedef CXCursorVisitor_function = ffi.Int32 Function( + = ffi.Pointer>; +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 @@ abstract class CXCompletionContext { /// Visitor invoked for each file in a translation unit (used with /// clang_getInclusions()). typedef CXInclusionVisitor - = ffi.Pointer>; -typedef CXInclusionVisitor_function = ffi.Void Function( + = ffi.Pointer>; +typedef CXInclusionVisitorFunction = ffi.Void Function( CXFile included_file, ffi.Pointer inclusion_stack, ffi.UnsignedInt include_len, CXClientData client_data); +typedef DartCXInclusionVisitorFunction = void Function( + CXFile included_file, + ffi.Pointer inclusion_stack, + int include_len, + CXClientData client_data); abstract class CXEvalResultKind { static const int CXEval_Int = 1; @@ -8225,8 +8232,10 @@ abstract class CXIndexOptFlags { /// Visitor invoked for each field found by a traversal. typedef CXFieldVisitor - = ffi.Pointer>; -typedef CXFieldVisitor_function = ffi.Int32 Function( + = ffi.Pointer>; +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/test/large_integration_tests/_expected_sqlite_bindings.dart b/test/large_integration_tests/_expected_sqlite_bindings.dart index 492da429..5c6de762 100644 --- a/test/large_integration_tests/_expected_sqlite_bindings.dart +++ b/test/large_integration_tests/_expected_sqlite_bindings.dart @@ -10854,9 +10854,11 @@ final class sqlite3_vfs extends ffi.Struct { typedef sqlite3_int64 = sqlite_int64; typedef sqlite_int64 = ffi.LongLong; +typedef Dartsqlite_int64 = int; typedef sqlite3_syscall_ptr - = ffi.Pointer>; -typedef sqlite3_syscall_ptr_function = ffi.Void Function(); + = ffi.Pointer>; +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 @@ final class sqlite3_mem_methods extends ffi.Struct { 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 @@ final class sqlite3_rtree_geometry extends ffi.Struct { } 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 @@ final class fts5_api extends ffi.Struct { } typedef fts5_extension_function - = ffi.Pointer>; -typedef fts5_extension_function_function = ffi.Void Function( + = ffi.Pointer>; +typedef fts5_extension_functionFunction = ffi.Void Function( ffi.Pointer pApi, ffi.Pointer pFts, ffi.Pointer pCtx, ffi.Int nVal, ffi.Pointer> apVal); +typedef Dartfts5_extension_functionFunction = void Function( + ffi.Pointer pApi, + ffi.Pointer pFts, + ffi.Pointer pCtx, + int nVal, + ffi.Pointer> apVal); const String SQLITE_VERSION = '3.32.3'; diff --git a/test/native_objc_test/typedef_config.yaml b/test/native_objc_test/typedef_config.yaml new file mode 100644 index 00000000..f375bfc7 --- /dev/null +++ b/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/test/native_objc_test/typedef_test.dart b/test/native_objc_test/typedef_test.dart new file mode 100644 index 00000000..7a47fdb8 --- /dev/null +++ b/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/test/native_objc_test/typedef_test.m b/test/native_objc_test/typedef_test.m new file mode 100644 index 00000000..c5972ab4 --- /dev/null +++ b/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 + +@interface SomeClass : NSObject {} +@end + +@implementation SomeClass +@end + +typedef SomeClass* SomeClassPtr; + +@interface AnotherClass : NSObject {} +@property SomeClassPtr property; +@end + +@implementation AnotherClass +@end diff --git a/test/regen.dart b/test/regen.dart index 1617eda3..ec529644 100644 --- a/test/regen.dart +++ b/test/regen.dart @@ -8,7 +8,7 @@ import 'dart:io'; 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 @@ e.g. with this command: $ dart run test/setup.dart && dart run test/regen.dart && dart test '''; -Future _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 main(List args) async { @@ -50,25 +52,12 @@ Future main(List args) async { 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/test/test_utils.dart b/test/test_utils.dart index 95434ff7..9482b9cc 100644 --- a/test/test_utils.dart +++ b/test/test_utils.dart @@ -47,7 +47,7 @@ void verifySetupFile(File file) { // 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 @@ void _matchFileWithExpected({ _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(); }