Skip to content

Commit 1ece664

Browse files
authored
[ffigen] Migrate method filtering to the visitor (#1684)
1 parent 8a8603b commit 1ece664

16 files changed

+262
-182
lines changed

pkgs/ffigen/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
- Ensure all protocols referenced in bindings are available at runtime.
44
- Use package:objective_c 4.0.0
5+
- Fix various small bugs todo with config filters:
6+
- https://github.com/dart-lang/native/issues/1582
7+
- https://github.com/dart-lang/native/issues/1594
8+
- https://github.com/dart-lang/native/issues/1595
59

610
## 15.0.0
711

pkgs/ffigen/lib/src/code_generator/imports.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,6 @@ final wCharType = ImportedType(ffiImport, 'WChar', 'int', 'wchar_t', '0');
135135
final objCObjectType =
136136
ImportedType(objcPkgImport, 'ObjCObject', 'ObjCObject', 'void');
137137
final objCSelType = ImportedType(
138-
objcPkgImport, 'ObjCSelector', 'ObjCSelector', 'objc_selector');
138+
objcPkgImport, 'ObjCSelector', 'ObjCSelector', 'struct objc_selector');
139139
final objCBlockType =
140140
ImportedType(objcPkgImport, 'ObjCBlockImpl', 'ObjCBlockImpl', 'id');

pkgs/ffigen/lib/src/code_generator/objc_interface.dart

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,18 @@ class ObjCInterface extends BindingType with ObjCMethods {
154154
s.write(' {\n');
155155

156156
// Implementation.
157+
final target = isStatic
158+
? _classObject.name
159+
: convertDartTypeToFfiDartType(
160+
w,
161+
'this',
162+
objCRetain: m.consumesSelf,
163+
objCAutorelease: false,
164+
);
157165
final sel = m.selObject.name;
158166
if (m.isOptional) {
159167
s.write('''
160-
if (!${ObjCBuiltInFunctions.respondsToSelector.gen(w)}(ref.pointer, $sel)) {
168+
if (!${ObjCBuiltInFunctions.respondsToSelector.gen(w)}($target, $sel)) {
161169
throw ${ObjCBuiltInFunctions.unimplementedOptionalMethodException.gen(w)}(
162170
'$originalName', '${m.originalName}');
163171
}
@@ -166,14 +174,6 @@ class ObjCInterface extends BindingType with ObjCMethods {
166174
final convertReturn = m.kind != ObjCMethodKind.propertySetter &&
167175
!returnType.sameDartAndFfiDartType;
168176

169-
final target = isStatic
170-
? _classObject.name
171-
: convertDartTypeToFfiDartType(
172-
w,
173-
'this',
174-
objCRetain: m.consumesSelf,
175-
objCAutorelease: false,
176-
);
177177
final msgSendParams =
178178
m.params.map((p) => p.type.convertDartTypeToFfiDartType(
179179
w,

pkgs/ffigen/lib/src/code_generator/objc_methods.dart

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import 'writer.dart';
1515
final _logger = Logger('ffigen.code_generator.objc_methods');
1616

1717
mixin ObjCMethods {
18-
final _methods = <String, ObjCMethod>{};
19-
final _order = <String>[];
18+
Map<String, ObjCMethod> _methods = <String, ObjCMethod>{};
19+
List<String> _order = <String>[];
2020

2121
Iterable<ObjCMethod> get methods =>
2222
_order.map((name) => _methods[name]).nonNulls;
@@ -97,6 +97,20 @@ mixin ObjCMethods {
9797
parent: w.topLevelUniqueNamer);
9898

9999
void sortMethods() => _order.sort();
100+
101+
void filterMethods(bool Function(ObjCMethod method) predicate) {
102+
final newOrder = <String>[];
103+
final newMethods = <String, ObjCMethod>{};
104+
for (final name in _order) {
105+
final method = _methods[name];
106+
if (method != null && predicate(method)) {
107+
newMethods[name] = method;
108+
newOrder.add(name);
109+
}
110+
}
111+
_order = newOrder;
112+
_methods = newMethods;
113+
}
100114
}
101115

102116
enum ObjCMethodKind {

pkgs/ffigen/lib/src/header_parser/sub_parsers/objcinterfacedecl_parser.dart

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,6 @@ void _parseProperty(
131131
return;
132132
}
133133

134-
if (!config.objcInterfaces.shouldIncludeMember(itfDecl, fieldName)) {
135-
return;
136-
}
137-
138134
final dartDoc = getCursorDocComment(cursor);
139135

140136
final propertyAttributes =
@@ -221,10 +217,6 @@ ObjCMethod? parseObjCMethod(clang_types.CXCursor cursor, Declaration itfDecl,
221217
return null;
222218
}
223219

224-
if (!filters.shouldIncludeMember(itfDecl, methodName)) {
225-
return null;
226-
}
227-
228220
final method = ObjCMethod(
229221
builtInFunctions: objCBuiltInFunctions,
230222
originalName: methodName,

pkgs/ffigen/lib/src/visitor/apply_config_filters.dart

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,25 @@ class ApplyConfigFiltersVisitation extends Visitation {
3636
_visitImpl(node, config.macroDecl);
3737

3838
@override
39-
void visitObjCInterface(ObjCInterface node) =>
40-
_visitImpl(node, config.objcInterfaces);
39+
void visitObjCInterface(ObjCInterface node) {
40+
node.filterMethods(
41+
(m) => config.objcInterfaces.shouldIncludeMember(node, m.originalName));
42+
_visitImpl(node, config.objcInterfaces);
43+
}
4144

4245
@override
43-
void visitObjCProtocol(ObjCProtocol node) =>
44-
_visitImpl(node, config.objcProtocols);
46+
void visitObjCProtocol(ObjCProtocol node) {
47+
node.filterMethods((m) {
48+
// TODO(https://github.com/dart-lang/native/issues/1149): Support class
49+
// methods on protocols if there's a use case. For now filter them. We
50+
// filter here instead of during parsing so that these methods are still
51+
// copied to any interfaces that implement the protocol.
52+
if (m.isClassMethod) return false;
53+
54+
return config.objcProtocols.shouldIncludeMember(node, m.originalName);
55+
});
56+
_visitImpl(node, config.objcProtocols);
57+
}
4558

4659
@override
4760
void visitUnnamedEnumConstant(UnnamedEnumConstant node) =>

pkgs/ffigen/test/native_objc_test/block_config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ typedefs:
1414
- FloatBlock
1515
- DoubleBlock
1616
- Vec4Block
17+
- SelectorBlock
1718
- VoidBlock
1819
- ObjectBlock
1920
- NullableObjectBlock

pkgs/ffigen/test/native_objc_test/block_test.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ typedef ListenerBlock = ObjCBlock_ffiVoid_IntBlock;
2727
typedef FloatBlock = ObjCBlock_ffiFloat_ffiFloat;
2828
typedef DoubleBlock = ObjCBlock_ffiDouble_ffiDouble;
2929
typedef Vec4Block = ObjCBlock_Vec4_Vec4;
30+
typedef SelectorBlock = ObjCBlock_ffiVoid_objcObjCSelector;
3031
typedef ObjectBlock = ObjCBlock_DummyObject_DummyObject;
3132
typedef NullableObjectBlock = ObjCBlock_DummyObject_DummyObject1;
3233
typedef NullableStringBlock = ObjCBlock_NSString_NSString;
@@ -162,6 +163,19 @@ void main() {
162163
});
163164
});
164165

166+
test('Selector block', () {
167+
late String sel;
168+
final block = SelectorBlock.fromFunction((Pointer<ObjCSelector> x) {
169+
sel = x.toDartString();
170+
});
171+
172+
block('Hello'.toSelector());
173+
expect(sel, 'Hello');
174+
175+
BlockTester.callSelectorBlock_(block);
176+
expect(sel, 'Select');
177+
});
178+
165179
test('Object block', () {
166180
bool isCalled = false;
167181
final block = ObjectBlock.fromFunction((DummyObject x) {

pkgs/ffigen/test/native_objc_test/block_test.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ typedef float (^FloatBlock)(float);
3535
typedef double (^DoubleBlock)(double);
3636
typedef Vec4 (^Vec4Block)(Vec4);
3737
typedef void (^VoidBlock)();
38+
typedef void (^SelectorBlock)(SEL);
3839
typedef DummyObject* (^ObjectBlock)(DummyObject*);
3940
typedef DummyObject* _Nullable (^NullableObjectBlock)(DummyObject* _Nullable);
4041
typedef NSString* _Nullable (^NullableStringBlock)(NSString* _Nullable);
@@ -64,6 +65,7 @@ typedef void (^NoTrampolineListenerBlock)(int32_t, Vec4, const char*);
6465
+ (float)callFloatBlock:(FloatBlock)block;
6566
+ (double)callDoubleBlock:(DoubleBlock)block;
6667
+ (Vec4)callVec4Block:(Vec4Block)block;
68+
+ (void)callSelectorBlock:(SelectorBlock)block;
6769
+ (DummyObject*)callObjectBlock:(ObjectBlock)block NS_RETURNS_RETAINED;
6870
+ (nullable DummyObject*)callNullableObjectBlock:(NullableObjectBlock)block
6971
NS_RETURNS_RETAINED;

pkgs/ffigen/test/native_objc_test/block_test.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ + (Vec4)callVec4Block:(Vec4Block)block {
153153
return block(vec4);
154154
}
155155

156+
+ (void)callSelectorBlock:(SelectorBlock)block {
157+
block(sel_registerName("Select"));
158+
}
159+
156160
+ (DummyObject*)callObjectBlock:(ObjectBlock)block NS_RETURNS_RETAINED {
157161
return block([DummyObject new]);
158162
}

pkgs/ffigen/test/native_objc_test/method_filtering_test.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ void main() {
4545
expect(bindings, contains('includedProtocolMethod'));
4646
expect(bindings, isNot(contains('excludedProtocolMethod')));
4747
});
48+
49+
test('transitive deps', () {
50+
expect(bindings, isNot(contains('TransitiveInterface')));
51+
expect(bindings, isNot(contains('someTransitiveMethod')));
52+
});
4853
});
4954
});
5055
}

pkgs/ffigen/test/native_objc_test/method_filtering_test.m

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@
44

55
#import <Foundation/NSObject.h>
66

7+
@interface TransitiveInterface : NSObject {}
8+
+ (instancetype)someTransitiveMethod: (double)arg;
9+
@end
10+
711
@interface MethodFilteringTestInterface : NSObject {}
812
+ (instancetype)includedStaticMethod;
913
+ (instancetype)excludedStaticMethod;
1014
- (instancetype)includedInstanceMethod: (int32_t)arg with: (int32_t)otherArg;
11-
- (instancetype)excludedInstanceMethod: (int32_t)arg with: (int32_t)otherArg;
15+
- (instancetype)excludedInstanceMethod: (int32_t)arg
16+
with: (TransitiveInterface*)otherArg;
1217
@property (assign) NSObject* includedProperty;
1318
@property (assign) NSObject* excludedProperty;
1419
@end

pkgs/ffigen/test/native_objc_test/protocol_test.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ void main() {
7373

7474
// Method from a protocol that isn't included by the filters.
7575
expect(protocolImpl.fooMethod(), 2468);
76+
77+
// Class methods.
78+
expect(ObjCProtocolImpl.requiredClassMethod(), 9876);
79+
expect(ObjCProtocolImpl.optionalClassMethod(), 5432);
7680
});
7781

7882
test('Unimplemented method', () {
@@ -94,6 +98,9 @@ void main() {
9498
expect(() => protocolImpl.optionalMethod_(structPtr.ref),
9599
throwsA(isA<UnimplementedOptionalMethodException>()));
96100
calloc.free(structPtr);
101+
102+
expect(() => ObjCProtocolImpl.unimplementedOtionalClassMethod(),
103+
throwsA(isA<UnimplementedOptionalMethodException>()));
97104
});
98105
});
99106

pkgs/ffigen/test/native_objc_test/protocol_test.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ typedef struct {
2525
@optional
2626
- (void)voidMethod:(int32_t)x;
2727

28+
// Class methods aren't supported in protocol implementation from Dart, but they
29+
// are still codegenned for any native interfaces that implement this protocol.
30+
@required
31+
+ (int32_t)requiredClassMethod;
32+
33+
@optional
34+
+ (int32_t)optionalClassMethod;
35+
36+
@optional
37+
+ (int32_t)unimplementedOtionalClassMethod;
38+
2839
@end
2940

3041

pkgs/ffigen/test/native_objc_test/protocol_test.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ - (int32_t)fooMethod {
4949
return 2468;
5050
}
5151

52+
+ (int32_t)requiredClassMethod {
53+
return 9876;
54+
}
55+
56+
+ (int32_t)optionalClassMethod {
57+
return 5432;
58+
}
59+
5260
@end
5361

5462

0 commit comments

Comments
 (0)