Skip to content

Commit 2965c48

Browse files
authored
[ffigen] Support default constructor (#2030)
1 parent 13e1341 commit 2965c48

27 files changed

+201
-99
lines changed

pkgs/ffigen/CHANGELOG.md

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

33
- Add variable substitutions that can be used in the `headers.entry-points` to
44
locate Apple APIs: `$XCODE`, `$IOS_SDK`, and `$MACOS_SDK`.
5+
- Add an empty constructor to all ObjC interfaces that have a `new` method,
6+
which just calls that method.
57
- __Breaking change__: Change the `usrTypeMappings` field of `Config`'s factory
68
constructor from a `List<ImportedType>` to a `Map<String, ImportedType>`.
79
- Add a `keepIsolateAlive` parameter to the block and protocol constructors that

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,20 @@ ${generateAsStub ? '' : _generateMethods(w)}
127127
''');
128128
s.write(generateMethodBindings(w, this));
129129

130+
final newMethod = methods
131+
.where((ObjCMethod m) =>
132+
m.isClassMethod &&
133+
m.family == ObjCMethodFamily.new_ &&
134+
m.params.isEmpty &&
135+
m.originalName == 'new')
136+
.firstOrNull;
137+
if (newMethod != null && originalName != 'NSString') {
138+
s.write('''
139+
/// Returns a new instance of $name constructed with the default `new` method.
140+
factory $name() => ${newMethod.dartMethodName}();
141+
''');
142+
}
143+
130144
return s.toString();
131145
}
132146

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ class ObjCMethod extends AstNode {
194194
final String? dartDoc;
195195
final String originalName;
196196
final String name;
197+
String? dartMethodName;
197198
final ObjCProperty? property;
198199
Type returnType;
199200
final List<Parameter> params;
@@ -338,7 +339,8 @@ class ObjCMethod extends AstNode {
338339

339340
String generateBindings(
340341
Writer w, ObjCInterface target, UniqueNamer methodNamer) {
341-
final methodName = getDartMethodName(methodNamer);
342+
dartMethodName ??= getDartMethodName(methodNamer);
343+
final methodName = dartMethodName!;
342344
final upperName = methodName[0].toUpperCase() + methodName.substring(1);
343345
final s = StringBuffer();
344346

pkgs/ffigen/test/native_objc_test/arc_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ void main() {
3838

3939
(Pointer<ObjCObject>, Pointer<ObjCObject>) newMethodsInner(
4040
Pointer<Int32> counter) {
41-
final obj1 = ArcTestObject.new1();
41+
final obj1 = ArcTestObject();
4242
obj1.setCounter_(counter);
4343
expect(counter.value, 1);
4444
final obj2 = ArcTestObject.newWithCounter_(counter);

pkgs/ffigen/test/native_objc_test/bad_method_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ void main() {
2525
});
2626

2727
test("Test incomplete struct methods that weren't skipped", () {
28-
final obj = BadMethodTestObject.new1();
28+
final obj = BadMethodTestObject();
2929
final structPtr = obj.incompletePointerReturn();
3030
expect(structPtr.address, 1234);
3131
expect(obj.incompletePointerParam_(structPtr), 1234);
3232
});
3333

3434
test("Test bit field methods that weren't skipped", () {
35-
final obj = BadMethodTestObject.new1();
35+
final obj = BadMethodTestObject();
3636
final bitFieldPtr = obj.bitFieldPointerReturn();
3737
expect(bitFieldPtr.address, 5678);
3838
expect(obj.bitFieldPointerParam_(bitFieldPtr), 5678);

pkgs/ffigen/test/native_objc_test/bad_override_test.dart

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,48 +31,48 @@ void main() {
3131
// method in some classes of the heirarchy, and a property in others. This
3232
// isn't allowed in Dart, so we change all such conflicts to properties.
3333
// https://github.com/dart-lang/native/issues/1220
34-
expect(BadOverrideParent.new1().methodVsGetter, 1);
35-
expect(BadOverrideChild.new1().methodVsGetter, 11);
36-
expect(BadOverrideSibbling.new1().methodVsGetter, 12);
37-
expect(BadOverrideGrandchild.new1().methodVsGetter, 111);
34+
expect(BadOverrideParent().methodVsGetter, 1);
35+
expect(BadOverrideChild().methodVsGetter, 11);
36+
expect(BadOverrideSibbling().methodVsGetter, 12);
37+
expect(BadOverrideGrandchild().methodVsGetter, 111);
3838

39-
var inst = BadOverrideParent.new1();
39+
var inst = BadOverrideParent();
4040
expect(inst.methodVsGetter, 1);
41-
inst = BadOverrideChild.new1();
41+
inst = BadOverrideChild();
4242
expect(inst.methodVsGetter, 11);
43-
inst = BadOverrideSibbling.new1();
43+
inst = BadOverrideSibbling();
4444
expect(inst.methodVsGetter, 12);
45-
inst = BadOverrideGrandchild.new1();
45+
inst = BadOverrideGrandchild();
4646
expect(inst.methodVsGetter, 111);
4747

4848
// Uncle isn't affected by the transform, so has an ordinary method.
49-
expect(BadOverrideUncle.new1().methodVsGetter(), 2);
49+
expect(BadOverrideUncle().methodVsGetter(), 2);
5050
});
5151

5252
test('Contravariant returns', () {
5353
// Return types are supposed to be covariant, but ObjC allows them to be
5454
// contravariant.
5555
// https://github.com/dart-lang/native/issues/1220
56-
Polygon parentResult = BadOverrideParent.new1().contravariantReturn();
56+
Polygon parentResult = BadOverrideParent().contravariantReturn();
5757
expect(parentResult.name().toDartString(), 'Rectangle');
5858

59-
Polygon childResult = BadOverrideChild.new1().contravariantReturn();
59+
Polygon childResult = BadOverrideChild().contravariantReturn();
6060
expect(childResult.name().toDartString(), 'Triangle');
6161
});
6262

6363
test('Covariant args', () {
6464
// Arg types are supposed to be contravariant, but ObjC allows them to be
6565
// covariant.
6666
// https://github.com/dart-lang/native/issues/1220
67-
final square = Square.new1();
68-
final triangle = Triangle.new1();
67+
final square = Square();
68+
final triangle = Triangle();
6969

70-
var parent = BadOverrideParent.new1();
70+
var parent = BadOverrideParent();
7171
expect(parent.covariantArg_(square).toDartString(), 'Polygon: Square');
7272
expect(
7373
parent.covariantArg_(triangle).toDartString(), 'Polygon: Triangle');
7474

75-
parent = BadOverrideChild.new1();
75+
parent = BadOverrideChild();
7676
expect(parent.covariantArg_(square).toDartString(), 'Rectangle: Square');
7777
expect(() => parent.covariantArg_(triangle), throwsA(isA<TypeError>()));
7878
});

pkgs/ffigen/test/native_objc_test/block_inherit_test.dart

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,18 @@ void main() {
3131
});
3232

3333
test('BlockInheritTestBase', () {
34-
final BlockInheritTestBase baseObj = BlockInheritTestBase.new1();
34+
final BlockInheritTestBase baseObj = BlockInheritTestBase();
3535
expect(baseObj.getAnimal().laysEggs(), false);
36-
expect(baseObj.acceptAnimal_(Platypus.new1()), true);
36+
expect(baseObj.acceptAnimal_(Platypus()), true);
3737

3838
final ObjCBlock<Mammal Function()> returner = baseObj.getReturner();
3939
final Mammal returnerResult = returner();
4040
expect(returnerResult.laysEggs(), false);
4141

4242
final ObjCBlock<Bool Function(Platypus)> accepter = baseObj.getAccepter();
43-
expect(accepter(Platypus.new1()), true);
43+
expect(accepter(Platypus()), true);
4444

45-
final platypus = Platypus.new1();
45+
final platypus = Platypus();
4646
final ObjCBlock<Platypus Function()> platypusReturner =
4747
ObjCBlock_Platypus.fromFunction(() => platypus);
4848
expect(baseObj.invokeReturner_(platypusReturner).laysEggs(), true);
@@ -54,11 +54,11 @@ void main() {
5454
});
5555

5656
test('BlockInheritTestChild', () {
57-
final BlockInheritTestChild childObj = BlockInheritTestChild.new1();
57+
final BlockInheritTestChild childObj = BlockInheritTestChild();
5858
final BlockInheritTestBase baseObj = childObj;
5959
expect(baseObj.getAnimal().laysEggs(), true);
60-
expect(baseObj.acceptAnimal_(Platypus.new1()), true);
61-
expect(childObj.acceptAnimal_(Mammal.new1()), false);
60+
expect(baseObj.acceptAnimal_(Platypus()), true);
61+
expect(childObj.acceptAnimal_(Mammal()), false);
6262

6363
final ObjCBlock<Mammal Function()> baseReturner = baseObj.getReturner();
6464
final Mammal baseReturnerResult = baseReturner();
@@ -71,19 +71,19 @@ void main() {
7171

7272
final ObjCBlock<Bool Function(Platypus)> baseAccepter =
7373
baseObj.getAccepter();
74-
expect(baseAccepter(Platypus.new1()), true);
74+
expect(baseAccepter(Platypus()), true);
7575

7676
final ObjCBlock<Bool Function(Mammal)> childAccepter =
7777
childObj.getAccepter();
78-
expect(childAccepter(Mammal.new1()), false);
79-
expect(childAccepter(Platypus.new1()), true);
78+
expect(childAccepter(Mammal()), false);
79+
expect(childAccepter(Platypus()), true);
8080

81-
final platypus = Platypus.new1();
81+
final platypus = Platypus();
8282
final ObjCBlock<Platypus Function()> platypusReturner =
8383
ObjCBlock_Platypus.fromFunction(() => platypus);
8484
expect(baseObj.invokeReturner_(platypusReturner).laysEggs(), true);
8585

86-
final mammal = Mammal.new1();
86+
final mammal = Mammal();
8787
final ObjCBlock<Mammal Function()> mammalReturner =
8888
ObjCBlock_Mammal.fromFunction(() => mammal);
8989
expect(childObj.invokeReturner_(mammalReturner).laysEggs(), false);

pkgs/ffigen/test/native_objc_test/block_test.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ void main() {
250250
return x;
251251
});
252252

253-
final obj = DummyObject.new1();
253+
final obj = DummyObject();
254254
final result1 = block(obj);
255255
expect(result1, obj);
256256
expect(isCalled, isTrue);
@@ -269,7 +269,7 @@ void main() {
269269
return x;
270270
});
271271

272-
final obj = DummyObject.new1();
272+
final obj = DummyObject();
273273
final result1 = block(obj);
274274
expect(result1, obj);
275275
expect(isCalled, isTrue);
@@ -732,7 +732,7 @@ void main() {
732732
}, skip: !canDoGC);
733733

734734
test('Blocking block ref counting same thread', () async {
735-
DummyObject? dummyObject = DummyObject.new1();
735+
DummyObject? dummyObject = DummyObject();
736736
DartObjectListenerBlock? block =
737737
ObjectListenerBlock.blocking((DummyObject obj) {
738738
// Object passed as argument.
@@ -762,7 +762,7 @@ void main() {
762762

763763
test('Blocking block ref counting new thread', () async {
764764
final completer = Completer<void>();
765-
DummyObject? dummyObject = DummyObject.new1();
765+
DummyObject? dummyObject = DummyObject();
766766
DartObjectListenerBlock? block =
767767
ObjectListenerBlock.blocking((DummyObject obj) {
768768
// Object passed as argument.
@@ -828,7 +828,7 @@ void main() {
828828

829829
(BlockTester, Pointer<ObjCBlockImpl>, Pointer<ObjCObject>) regress1571Inner(
830830
Completer<void> completer) {
831-
final dummyObject = DummyObject.new1();
831+
final dummyObject = DummyObject();
832832
DartObjectListenerBlock? block =
833833
ObjectListenerBlock.listener((DummyObject obj) {
834834
expect(objectRetainCount(obj.ref.pointer), greaterThan(0));

pkgs/ffigen/test/native_objc_test/cast_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void main() {
2525
final dylib = File('test/native_objc_test/objc_test.dylib');
2626
verifySetupFile(dylib);
2727
DynamicLibrary.open(dylib.absolute.path);
28-
testInstance = Castaway.new1();
28+
testInstance = Castaway();
2929
generateBindingsForCoverage('cast');
3030
});
3131

@@ -57,7 +57,7 @@ void main() {
5757
final meAsInt = testInstance!.meAsInt();
5858
final fromCast =
5959
Castaway.castFromPointer(Pointer<ObjCObject>.fromAddress(meAsInt));
60-
expect(fromCast, isNot(equals(NSObject.new1())));
60+
expect(fromCast, isNot(equals(NSObject())));
6161
});
6262
});
6363
}

pkgs/ffigen/test/native_objc_test/category_test.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ void main() {
2727
});
2828

2929
test('Category methods', () {
30-
final thing = Thing.new1();
30+
final thing = Thing();
3131
expect(thing.add_Y_(1000, 234), 1234);
3232
expect(thing.sub_Y_(1234, 1000), 234);
3333
expect(thing.mul_Y_(1234, 1000), 1234000);
@@ -38,13 +38,13 @@ void main() {
3838
});
3939

4040
test('Protocol methods', () {
41-
final thing = Thing.new1();
41+
final thing = Thing();
4242
expect(thing.protoMethod(), 987);
4343
expect(CatImplementsProto.staticProtoMethod(), 654);
4444
});
4545

4646
test('Instancetype', () {
47-
Thing thing1 = Thing.new1();
47+
Thing thing1 = Thing();
4848
expect(Thing.isInstance(thing1), isTrue);
4949
expect(ChildOfThing.isInstance(thing1), isFalse);
5050

@@ -53,7 +53,7 @@ void main() {
5353
expect(Thing.isInstance(thing2), isTrue);
5454
expect(ChildOfThing.isInstance(thing2), isFalse);
5555

56-
ChildOfThing child1 = ChildOfThing.new1();
56+
ChildOfThing child1 = ChildOfThing();
5757
expect(Thing.isInstance(child1), isTrue);
5858
expect(ChildOfThing.isInstance(child1), isTrue);
5959

0 commit comments

Comments
 (0)