diff --git a/pkgs/ffigen/CHANGELOG.md b/pkgs/ffigen/CHANGELOG.md index 34e67a4fe1..feb83557de 100644 --- a/pkgs/ffigen/CHANGELOG.md +++ b/pkgs/ffigen/CHANGELOG.md @@ -1,3 +1,5 @@ +## 19.1.0-wip + ## 19.0.0 - Use package:objective_c 8.0.0. diff --git a/pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart b/pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart index 9f89897133..6d0aa2330e 100644 --- a/pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart +++ b/pkgs/ffigen/lib/src/code_generator/objc_built_in_functions.dart @@ -2,13 +2,12 @@ // 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 'package:meta/meta.dart'; - import '../code_generator.dart'; import '../config_provider/config_types.dart'; import '../visitor/ast.dart'; import 'binding_string.dart'; +import 'objc_built_in_types.dart'; import 'utils.dart'; import 'writer.dart'; @@ -49,144 +48,18 @@ class ObjCBuiltInFunctions { ObjCImport('UnimplementedOptionalMethodException'); static const checkOsVersion = ObjCImport('checkOsVersionInternal'); - // Keep in sync with pkgs/objective_c/ffigen_objc.yaml. - - @visibleForTesting - static const builtInInterfaces = { - 'DartInputStreamAdapter', - 'DartProtocol', - 'DartProtocolBuilder', - 'NSArray', - 'NSCharacterSet', - 'NSCoder', - 'NSData', - 'NSDate', - 'NSDictionary', - 'NSEnumerator', - 'NSError', - 'NSIndexSet', - 'NSInputStream', - 'NSInvocation', - 'NSItemProvider', - 'NSLocale', - 'NSMethodSignature', - 'NSMutableArray', - 'NSMutableData', - 'NSMutableDictionary', - 'NSMutableIndexSet', - 'NSMutableOrderedSet', - 'NSMutableSet', - 'NSMutableString', - 'NSNotification', - 'NSNumber', - 'NSObject', - 'NSOrderedCollectionDifference', - 'NSOrderedSet', - 'NSOutputStream', - 'NSPort', - 'NSPortMessage', - 'NSRunLoop', - 'NSSet', - 'NSStream', - 'NSString', - 'NSTimer', - 'NSURL', - 'NSURLHandle', - 'NSValue', - 'Protocol', - }; - @visibleForTesting - static const builtInCompounds = { - 'AEDesc': 'AEDesc', - '__CFRunLoop': 'CFRunLoop', - '__CFString': 'CFString', - 'CGPoint': 'CGPoint', - 'CGRect': 'CGRect', - 'CGSize': 'CGSize', - 'NSEdgeInsets': 'NSEdgeInsets', - 'NSFastEnumerationState': 'NSFastEnumerationState', - '_NSRange': 'NSRange', - '_NSZone': 'NSZone', - 'OpaqueAEDataStorageType': 'OpaqueAEDataStorageType', - }; - @visibleForTesting - static const builtInEnums = { - 'NSAppleEventSendOptions', - 'NSBinarySearchingOptions', - 'NSComparisonResult', - 'NSDataBase64DecodingOptions', - 'NSDataBase64EncodingOptions', - 'NSDataCompressionAlgorithm', - 'NSDataReadingOptions', - 'NSDataSearchOptions', - 'NSDataWritingOptions', - 'NSDecodingFailurePolicy', - 'NSEnumerationOptions', - 'NSItemProviderFileOptions', - 'NSItemProviderRepresentationVisibility', - 'NSKeyValueChange', - 'NSKeyValueObservingOptions', - 'NSKeyValueSetMutationKind', - 'NSLinguisticTaggerOptions', - 'NSLocaleLanguageDirection', - 'NSOrderedCollectionDifferenceCalculationOptions', - 'NSPropertyListFormat', - 'NSQualityOfService', - 'NSSortOptions', - 'NSStreamEvent', - 'NSStreamStatus', - 'NSStringCompareOptions', - 'NSStringEncodingConversionOptions', - 'NSStringEnumerationOptions', - 'NSURLBookmarkCreationOptions', - 'NSURLBookmarkResolutionOptions', - 'NSURLHandleStatus', - }; - @visibleForTesting - static const builtInProtocols = { - 'NSCoding': 'NSCoding', - 'NSCopying': 'NSCopying', - 'NSFastEnumeration': 'NSFastEnumeration', - 'NSItemProviderReading': 'NSItemProviderReading', - 'NSItemProviderWriting': 'NSItemProviderWriting', - 'NSMutableCopying': 'NSMutableCopying', - 'NSObject': 'NSObjectProtocol', - 'NSPortDelegate': 'NSPortDelegate', - 'NSSecureCoding': 'NSSecureCoding', - 'NSStreamDelegate': 'NSStreamDelegate', - }; - @visibleForTesting - static const builtInCategories = { - 'NSDataCreation', - 'NSExtendedArray', - 'NSExtendedData', - 'NSExtendedDate', - 'NSExtendedDictionary', - 'NSExtendedEnumerator', - 'NSExtendedMutableArray', - 'NSExtendedMutableData', - 'NSExtendedMutableDictionary', - 'NSExtendedMutableOrderedSet', - 'NSExtendedMutableSet', - 'NSExtendedOrderedSet', - 'NSExtendedSet', - 'NSNumberCreation', - 'NSNumberIsFloat', - 'NSStringExtensionMethods', - }; - // TODO(https://github.com/dart-lang/native/issues/1173): Ideally this check // would be based on more than just the name. - bool isBuiltInInterface(String name) => - !generateForPackageObjectiveC && builtInInterfaces.contains(name); + String? getBuiltInInterfaceName(String name) => + generateForPackageObjectiveC ? null : objCBuiltInInterfaces[name]; String? getBuiltInCompoundName(String name) => - generateForPackageObjectiveC ? null : builtInCompounds[name]; + generateForPackageObjectiveC ? null : objCBuiltInCompounds[name]; bool isBuiltInEnum(String name) => - !generateForPackageObjectiveC && builtInEnums.contains(name); + !generateForPackageObjectiveC && objCBuiltInEnums.contains(name); String? getBuiltInProtocolName(String name) => - generateForPackageObjectiveC ? null : builtInProtocols[name]; + generateForPackageObjectiveC ? null : objCBuiltInProtocols[name]; bool isBuiltInCategory(String name) => - !generateForPackageObjectiveC && builtInCategories.contains(name); + !generateForPackageObjectiveC && objCBuiltInCategories.contains(name); static bool isNSObject(String name) => name == 'NSObject'; // We need to load a separate instance of objc_msgSend for each signature. If diff --git a/pkgs/ffigen/lib/src/code_generator/objc_built_in_types.dart b/pkgs/ffigen/lib/src/code_generator/objc_built_in_types.dart new file mode 100644 index 0000000000..329d186fc3 --- /dev/null +++ b/pkgs/ffigen/lib/src/code_generator/objc_built_in_types.dart @@ -0,0 +1,128 @@ +// Copyright (c) 2025, 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. + +// Generated by package:objective_c's tool/generate_code.dart. + +const objCBuiltInInterfaces = { + 'DOBJCDartInputStreamAdapter': 'DartInputStreamAdapter', + 'DOBJCDartProtocolBuilder': 'DartProtocolBuilder', + 'DOBJCDartProtocol': 'DartProtocol', + 'NSArray': 'NSArray', + 'NSCharacterSet': 'NSCharacterSet', + 'NSCoder': 'NSCoder', + 'NSData': 'NSData', + 'NSDate': 'NSDate', + 'NSDictionary': 'NSDictionary', + 'NSEnumerator': 'NSEnumerator', + 'NSError': 'NSError', + 'NSIndexSet': 'NSIndexSet', + 'NSInputStream': 'NSInputStream', + 'NSInvocation': 'NSInvocation', + 'NSItemProvider': 'NSItemProvider', + 'NSLocale': 'NSLocale', + 'NSMethodSignature': 'NSMethodSignature', + 'NSMutableArray': 'NSMutableArray', + 'NSMutableData': 'NSMutableData', + 'NSMutableDictionary': 'NSMutableDictionary', + 'NSMutableIndexSet': 'NSMutableIndexSet', + 'NSMutableOrderedSet': 'NSMutableOrderedSet', + 'NSMutableSet': 'NSMutableSet', + 'NSMutableString': 'NSMutableString', + 'NSNotification': 'NSNotification', + 'NSNumber': 'NSNumber', + 'NSObject': 'NSObject', + 'NSOutputStream': 'NSOutputStream', + 'NSOrderedCollectionDifference': 'NSOrderedCollectionDifference', + 'NSOrderedSet': 'NSOrderedSet', + 'NSPort': 'NSPort', + 'NSPortMessage': 'NSPortMessage', + 'NSRunLoop': 'NSRunLoop', + 'NSSet': 'NSSet', + 'NSStream': 'NSStream', + 'NSString': 'NSString', + 'NSTimer': 'NSTimer', + 'NSURL': 'NSURL', + 'NSURLHandle': 'NSURLHandle', + 'NSValue': 'NSValue', + 'Protocol': 'Protocol', +}; + +const objCBuiltInCompounds = { + 'AEDesc': 'AEDesc', + '__CFRunLoop': 'CFRunLoop', + '__CFString': 'CFString', + 'CGPoint': 'CGPoint', + 'CGRect': 'CGRect', + 'CGSize': 'CGSize', + 'NSEdgeInsets': 'NSEdgeInsets', + 'NSFastEnumerationState': 'NSFastEnumerationState', + '_NSRange': 'NSRange', + '_NSZone': 'NSZone', + 'OpaqueAEDataStorageType': 'OpaqueAEDataStorageType', +}; + +const objCBuiltInEnums = { + 'NSAppleEventSendOptions', + 'NSBinarySearchingOptions', + 'NSComparisonResult', + 'NSDataBase64DecodingOptions', + 'NSDataBase64EncodingOptions', + 'NSDataCompressionAlgorithm', + 'NSDataReadingOptions', + 'NSDataSearchOptions', + 'NSDataWritingOptions', + 'NSDecodingFailurePolicy', + 'NSEnumerationOptions', + 'NSItemProviderFileOptions', + 'NSItemProviderRepresentationVisibility', + 'NSKeyValueChange', + 'NSKeyValueObservingOptions', + 'NSKeyValueSetMutationKind', + 'NSLinguisticTaggerOptions', + 'NSLocaleLanguageDirection', + 'NSOrderedCollectionDifferenceCalculationOptions', + 'NSPropertyListFormat', + 'NSQualityOfService', + 'NSSortOptions', + 'NSStreamEvent', + 'NSStreamStatus', + 'NSStringCompareOptions', + 'NSStringEncodingConversionOptions', + 'NSStringEnumerationOptions', + 'NSURLBookmarkCreationOptions', + 'NSURLBookmarkResolutionOptions', + 'NSURLHandleStatus', +}; + +const objCBuiltInProtocols = { + 'NSCoding': 'NSCoding', + 'NSCopying': 'NSCopying', + 'NSFastEnumeration': 'NSFastEnumeration', + 'NSItemProviderReading': 'NSItemProviderReading', + 'NSItemProviderWriting': 'NSItemProviderWriting', + 'NSMutableCopying': 'NSMutableCopying', + 'NSObject': 'NSObjectProtocol', + 'NSPortDelegate': 'NSPortDelegate', + 'NSSecureCoding': 'NSSecureCoding', + 'NSStreamDelegate': 'NSStreamDelegate', +}; + +const objCBuiltInCategories = { + 'NSDataCreation', + 'NSExtendedArray', + 'NSExtendedData', + 'NSExtendedDate', + 'NSExtendedDictionary', + 'NSExtendedEnumerator', + 'NSExtendedMutableArray', + 'NSExtendedMutableData', + 'NSExtendedMutableDictionary', + 'NSExtendedMutableOrderedSet', + 'NSExtendedMutableSet', + 'NSExtendedOrderedSet', + 'NSExtendedSet', + 'NSNumberCreation', + 'NSNumberIsFloat', + 'NSStringExtensionMethods', +}; diff --git a/pkgs/ffigen/lib/src/code_generator/objc_interface.dart b/pkgs/ffigen/lib/src/code_generator/objc_interface.dart index f496c9847e..06c41d41ea 100644 --- a/pkgs/ffigen/lib/src/code_generator/objc_interface.dart +++ b/pkgs/ffigen/lib/src/code_generator/objc_interface.dart @@ -38,7 +38,10 @@ class ObjCInterface extends BindingType with ObjCMethods { required this.builtInFunctions, required this.apiAvailability, }) : lookupName = lookupName ?? originalName, - super(name: name ?? originalName) { + super( + name: builtInFunctions.getBuiltInInterfaceName(originalName) ?? + name ?? + originalName) { classObject = ObjCInternalGlobal('_class_$originalName', (Writer w) => '${ObjCBuiltInFunctions.getClass.gen(w)}("$lookupName")'); _isKindOfClass = builtInFunctions.getSelObject('isKindOfClass:'); @@ -56,7 +59,8 @@ class ObjCInterface extends BindingType with ObjCMethods { } @override - bool get isObjCImport => builtInFunctions.isBuiltInInterface(originalName); + bool get isObjCImport => + builtInFunctions.getBuiltInInterfaceName(originalName) != null; @override void sort() => sortMethods(); diff --git a/pkgs/ffigen/pubspec.yaml b/pkgs/ffigen/pubspec.yaml index 0501a72984..bbcb20dcd8 100644 --- a/pkgs/ffigen/pubspec.yaml +++ b/pkgs/ffigen/pubspec.yaml @@ -3,7 +3,7 @@ # BSD-style license that can be found in the LICENSE file. name: ffigen -version: 19.0.0 +version: 19.1.0-wip description: > Generator for FFI bindings, using LibClang to parse C, Objective-C, and Swift files. diff --git a/pkgs/objective_c/CHANGELOG.md b/pkgs/objective_c/CHANGELOG.md index 9fccabdf81..3266d92e2d 100644 --- a/pkgs/objective_c/CHANGELOG.md +++ b/pkgs/objective_c/CHANGELOG.md @@ -1,3 +1,5 @@ +## 8.1.0-wip + ## 8.0.0 - Use ffigen 19.0.0 diff --git a/pkgs/objective_c/lib/objective_c.dart b/pkgs/objective_c/lib/objective_c.dart index b36ac46f84..2664c8fbf7 100644 --- a/pkgs/objective_c/lib/objective_c.dart +++ b/pkgs/objective_c/lib/objective_c.dart @@ -28,117 +28,7 @@ export 'src/ns_input_stream.dart'; export 'src/ns_mutable_data.dart'; export 'src/ns_number.dart'; export 'src/ns_string.dart'; -// Keep in sync with pkgs/objective_c/ffigen_objc.yaml. -export 'src/objective_c_bindings_generated.dart' - show - AEDesc, - CFRunLoop, - CFString, - CFStringRef, - CGPoint, - CGRect, - CGSize, - DartProtocol, - DartProtocolBuilder, - NSAppleEventSendOptions, - NSArray, - NSBinarySearchingOptions, - NSCharacterSet, - NSCoder, - NSCoding, - NSComparisonResult, - NSCopying, - NSData, - NSDataBase64DecodingOptions, - NSDataBase64EncodingOptions, - NSDataCompressionAlgorithm, - NSDataCreation, - NSDataReadingOptions, - NSDataSearchOptions, - NSDataWritingOptions, - NSDate, - NSDecodingFailurePolicy, - NSDictionary, - NSEdgeInsets, - NSEnumerationOptions, - NSEnumerator, - NSError, - NSExtendedArray, - NSExtendedData, - NSExtendedDate, - NSExtendedDictionary, - NSExtendedEnumerator, - NSExtendedMutableArray, - NSExtendedMutableData, - NSExtendedMutableDictionary, - NSExtendedMutableOrderedSet, - NSExtendedMutableSet, - NSExtendedOrderedSet, - NSExtendedSet, - NSFastEnumeration, - NSFastEnumerationState, - NSIndexSet, - NSInputStream, - NSInvocation, - NSItemProvider, - NSItemProviderFileOptions, - NSItemProviderReading, - NSItemProviderRepresentationVisibility, - NSItemProviderWriting, - NSKeyValueChange, - NSKeyValueObservingOptions, - NSKeyValueSetMutationKind, - NSLinguisticTaggerOptions, - NSLocale, - NSLocaleLanguageDirection, - NSMethodSignature, - NSMutableArray, - NSMutableCopying, - NSMutableData, - NSMutableDictionary, - NSMutableIndexSet, - NSMutableOrderedSet, - NSMutableSet, - NSMutableString, - NSNotification, - NSNumber, - NSNumberCreation, - NSNumberIsFloat, - NSObject, - NSObjectProtocol, - NSOrderedCollectionDifference, - NSOrderedCollectionDifferenceCalculationOptions, - NSOrderedSet, - NSOutputStream, - NSPort, - NSPortDelegate, - NSPortMessage, - NSPropertyListFormat, - NSQualityOfService, - NSRange, - NSRunLoop, - NSSecureCoding, - NSSet, - NSSortOptions, - NSStream, - NSStreamDelegate, - NSStreamEvent, - NSStreamStatus, - NSString, - NSStringCompareOptions, - NSStringEncodingConversionOptions, - NSStringEnumerationOptions, - NSStringExtensionMethods, - NSTimer, - NSURL, - NSURLBookmarkCreationOptions, - NSURLBookmarkResolutionOptions, - NSURLHandle, - NSURLHandleStatus, - NSValue, - NSZone, - OpaqueAEDataStorageType, - Protocol; +export 'src/objective_c_bindings_generated.dart'; export 'src/os_version.dart'; export 'src/protocol_builder.dart'; export 'src/selector.dart'; diff --git a/pkgs/objective_c/pubspec.yaml b/pkgs/objective_c/pubspec.yaml index c73a25071f..f52ac6f4b4 100644 --- a/pkgs/objective_c/pubspec.yaml +++ b/pkgs/objective_c/pubspec.yaml @@ -4,7 +4,7 @@ name: objective_c description: 'A library to access Objective C from Flutter that acts as a support library for package:ffigen.' -version: 8.0.0 +version: 8.1.0-wip repository: https://github.com/dart-lang/native/tree/main/pkgs/objective_c issue_tracker: https://github.com/dart-lang/native/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aobjective_c diff --git a/pkgs/objective_c/test/interface_lists_test.dart b/pkgs/objective_c/test/interface_lists_test.dart index 5b03607d05..dca254944d 100644 --- a/pkgs/objective_c/test/interface_lists_test.dart +++ b/pkgs/objective_c/test/interface_lists_test.dart @@ -8,191 +8,69 @@ library; import 'dart:io'; -import 'package:ffigen/src/code_generator/objc_built_in_functions.dart'; +import 'package:ffigen/src/code_generator/objc_built_in_types.dart'; import 'package:path/path.dart' as p; import 'package:test/test.dart'; -import 'package:yaml/yaml.dart'; import 'util.dart'; -const privateObjectiveCClasses = ['DartInputStreamAdapter']; +// The default expect error message for sets isn't very useful. In the common +// case where the sets are different lengths, the default matcher just says the +// lengths don't match. This function says exactly what the difference is. +void expectSetsEqual(String name, Set expected, Set actual) { + expect(expected.difference(actual), {}, + reason: 'Found elements that are missing from $name'); + expect(actual.difference(expected), {}, + reason: "Found extra elements that shouldn't be in $name"); +} void main() { group('Verify interface lists', () { - late List yamlInterfaces; - late List yamlStructs; - late List yamlEnums; - late List yamlProtocols; - late List yamlCategories; - late String exportFile; - late List bindings; - + late final List bindings; setUpAll(() { - final yaml = - loadYaml(File(p.join(pkgDir, 'ffigen_objc.yaml')).readAsStringSync()) - as YamlMap; - - final interfaceRenames = - (yaml['objc-interfaces'] as YamlMap)['rename'] as YamlMap; - yamlInterfaces = ((yaml['objc-interfaces'] as YamlMap)['include'] - as YamlList) - .map( - (dynamic name) => (interfaceRenames[name] ?? name) as String) - .toList() - ..sort(); - - final structRenames = (yaml['structs'] as YamlMap)['rename'] as YamlMap; - yamlStructs = ((yaml['structs'] as YamlMap)['include'] as YamlList) - .map( - (dynamic name) => (structRenames[name] ?? name) as String) - .toList() - ..sort(); - - yamlEnums = ((yaml['enums'] as YamlMap)['include'] as YamlList) - .map((dynamic i) => i as String) - .toList() - ..sort(); - - final protocolRenames = - (yaml['objc-protocols'] as YamlMap)['rename'] as YamlMap; - yamlProtocols = ((yaml['objc-protocols'] as YamlMap)['include'] - as YamlList) - .map( - (dynamic name) => (protocolRenames[name] ?? name) as String) - .toList() - ..sort(); - - yamlCategories = ((yaml['objc-categories'] as YamlMap)['include'] - as YamlList) - .map((dynamic i) => i as String) - .toList() - ..sort(); - - exportFile = - File(p.join(pkgDir, 'lib', 'objective_c.dart')).readAsStringSync(); bindings = File(p.join( pkgDir, 'lib', 'src', 'objective_c_bindings_generated.dart')) .readAsLinesSync() .toList(); }); - test('ObjCBuiltInFunctions.builtInInterfaces', () { - expect(ObjCBuiltInFunctions.builtInInterfaces, yamlInterfaces); - }); - - test('ObjCBuiltInFunctions.builtInCompounds', () { - expect(ObjCBuiltInFunctions.builtInCompounds.values, yamlStructs); - }); - - test('ObjCBuiltInFunctions.builtInEnums', () { - expect(ObjCBuiltInFunctions.builtInEnums, yamlEnums); - }); - - test('ObjCBuiltInFunctions.builtInProtocols', () { - expect(ObjCBuiltInFunctions.builtInProtocols.values, yamlProtocols); - }); - - test('ObjCBuiltInFunctions.builtInCategories', () { - expect(ObjCBuiltInFunctions.builtInCategories, yamlCategories); - }); - - test('package:objective_c exports all the interfaces', () { - for (final intf in yamlInterfaces) { - if (!privateObjectiveCClasses.contains(intf)) { - expect(exportFile, contains(RegExp('\\W$intf\\W'))); - } - } - }); - - test('package:objective_c exports all the structs', () { - for (final struct in yamlStructs) { - expect(exportFile, contains(RegExp('\\W$struct\\W'))); - } - }); - - test('package:objective_c exports all the enums', () { - for (final enum_ in yamlEnums) { - expect(exportFile, contains(RegExp('\\W$enum_\\W'))); - } - }); - - test('package:objective_c exports all the protocols', () { - for (final protocol in yamlProtocols) { - expect(exportFile, contains(RegExp('\\W$protocol\\W'))); - } - }); - - test('package:objective_c exports all the categories', () { - for (final category in yamlCategories) { - expect(exportFile, contains(RegExp('\\W$category\\W'))); - } - }); + Set findBindings(RegExp re) => + bindings.map(re.firstMatch).nonNulls.map((match) => match[1]!).toSet(); test('All code genned interfaces are included in the list', () { - final classNameRegExp = RegExp(r'^class ([^_]\w*) '); - final allClassNames = []; - for (final line in bindings) { - final match = classNameRegExp.firstMatch(line); - if (match != null) { - allClassNames.add(match[1]!); - } - } - allClassNames.sort(); - expect(allClassNames, yamlInterfaces); + final allClassNames = findBindings(RegExp(r'^class ([^_]\w*) ')); + expectSetsEqual('generated classes', objCBuiltInInterfaces.values.toSet(), + allClassNames); }); test('All code genned structs are included in the list', () { - final structNameRegExp = - RegExp(r'^final class (\w+) extends ffi\.(Struct|Opaque)'); - final allStructNames = []; - for (final line in bindings) { - final match = structNameRegExp.firstMatch(line); - if (match != null) { - allStructNames.add(match[1]!); - } - } - allStructNames.sort(); - expect(allStructNames, yamlStructs); + final allStructNames = findBindings( + RegExp(r'^final class (\w+) extends ffi\.(Struct|Opaque)')); + expectSetsEqual('generated structs', objCBuiltInCompounds.values.toSet(), + allStructNames); }); test('All code genned enums are included in the list', () { - final enumNameRegExp = RegExp(r'^enum (\w+) {'); - final allEnumNames = []; - for (final line in bindings) { - final match = enumNameRegExp.firstMatch(line); - if (match != null) { - allEnumNames.add(match[1]!); - } - } - expect(allEnumNames, unorderedEquals(yamlEnums)); + final allEnumNames = findBindings(RegExp(r'^enum (\w+) {')); + expectSetsEqual('generated enums', objCBuiltInEnums, allEnumNames); }); test('All code genned protocols are included in the list', () { - final protocolNameRegExp = RegExp(r'^interface class (\w+) '); - final allProtocolNames = []; - for (final line in bindings) { - final match = protocolNameRegExp.firstMatch(line); - if (match != null) { - allProtocolNames.add(match[1]!); - } - } - expect(allProtocolNames, unorderedEquals(yamlProtocols)); + final allProtocolNames = findBindings(RegExp(r'^interface class (\w+) ')); + expectSetsEqual('generated protocols', + objCBuiltInProtocols.values.toSet(), allProtocolNames); }); test('All code genned categories are included in the list', () { - final categoryNameRegExp = RegExp(r'^extension (\w+) on \w+ {'); - final allCategoryNames = []; - for (final line in bindings) { - final match = categoryNameRegExp.firstMatch(line); - if (match != null) { - allCategoryNames.add(match[1]!); - } - } - expect(allCategoryNames, unorderedEquals(yamlCategories)); + final allCategoryNames = + findBindings(RegExp(r'^extension (\w+) on \w+ {')); + expectSetsEqual( + 'generated categories', objCBuiltInCategories, allCategoryNames); }); test('No stubs', () { - expect(bindings.join('\n'), isNot(contains(RegExp(r'\Wstub\W')))); + final stubRegExp = RegExp(r'\Wstub\W'); + expect(bindings.where(stubRegExp.hasMatch).toList(), []); }); }); } diff --git a/pkgs/objective_c/test/ns_input_stream_test.dart b/pkgs/objective_c/test/ns_input_stream_test.dart index 006dde9192..dc695d80ec 100644 --- a/pkgs/objective_c/test/ns_input_stream_test.dart +++ b/pkgs/objective_c/test/ns_input_stream_test.dart @@ -14,7 +14,6 @@ import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'package:objective_c/objective_c.dart'; -import 'package:objective_c/src/objective_c_bindings_generated.dart'; import 'package:test/test.dart'; import 'util.dart'; diff --git a/pkgs/objective_c/tool/generate_code.dart b/pkgs/objective_c/tool/generate_code.dart index fcd40e4e0b..9271c8a57d 100644 --- a/pkgs/objective_c/tool/generate_code.dart +++ b/pkgs/objective_c/tool/generate_code.dart @@ -11,12 +11,16 @@ import 'dart:io'; import 'package:args/args.dart'; import 'package:ffigen/src/executables/ffigen.dart' as ffigen; +import 'package:yaml/yaml.dart'; const cConfig = 'ffigen_c.yaml'; const objcConfig = 'ffigen_objc.yaml'; const cBindings = 'lib/src/c_bindings_generated.dart'; const objcBindings = 'lib/src/objective_c_bindings_generated.dart'; const extraMethodsFile = 'tool/data/extra_methods.dart.in'; +const builtInTypes = + '../ffigen/lib/src/code_generator/objc_built_in_types.dart'; +const interfaceListTest = 'test/interface_lists_test.dart'; void dartCmd(List args) { final exec = Platform.resolvedExecutable; @@ -112,6 +116,50 @@ void mergeExtraMethods( File(filename).writeAsStringSync(out.toString()); } +void writeBuiltInTypes(String config, String out) { + final yaml = loadYaml(File(config).readAsStringSync()) as YamlMap; + + final s = StringBuffer(); + + s.write(''' +// Copyright (c) 2025, 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. + +// Generated by package:objective_c's tool/generate_code.dart. +'''); + + void writeDecls(String name, String key) { + final decls = yaml[key] as YamlMap; + final renames = decls['rename'] as YamlMap? ?? YamlMap(); + final includes = decls['include'] as YamlList; + + final names = { + for (final inc in includes.map((i) => i as String)) + inc: renames[inc] as String? ?? inc, + }; + final anyRenames = names.entries.any((kv) => kv.key != kv.value); + final elements = anyRenames + ? names.entries.map((kv) => " '${kv.key}': '${kv.value}',") + : names.keys.map((key) => " '$key',"); + + s.write(''' + +const $name = { +${elements.join('\n')} +}; +'''); + } + + writeDecls('objCBuiltInInterfaces', 'objc-interfaces'); + writeDecls('objCBuiltInCompounds', 'structs'); + writeDecls('objCBuiltInEnums', 'enums'); + writeDecls('objCBuiltInProtocols', 'objc-protocols'); + writeDecls('objCBuiltInCategories', 'objc-categories'); + + File(out).writeAsStringSync(s.toString()); +} + Future run({required bool format}) async { print('Generating C bindings...'); await ffigen.main(['--no-format', '-v', 'severe', '--config', cConfig]); @@ -120,10 +168,16 @@ Future run({required bool format}) async { await ffigen.main(['--no-format', '-v', 'severe', '--config', objcConfig]); mergeExtraMethods(objcBindings, parseExtraMethods(extraMethodsFile)); + print('Generating objc_built_in_types.dart...'); + writeBuiltInTypes(objcConfig, builtInTypes); + if (format) { print('Formatting bindings...'); - dartCmd(['format', cBindings, objcBindings]); + dartCmd(['format', cBindings, objcBindings, builtInTypes]); } + + print('Running tests...'); + dartCmd(['test', interfaceListTest]); } Future main(List args) async {