[ffigen] Better block names (#606)

* Better Block names

* Test

* Move swift_api.h to third_party

* merge cruft
diff --git a/pkgs/ffigen/example/swift/README.md b/pkgs/ffigen/example/swift/README.md
index d53778e..caa482e 100644
--- a/pkgs/ffigen/example/swift/README.md
+++ b/pkgs/ffigen/example/swift/README.md
@@ -8,9 +8,9 @@
 `-emit-objc-header-path filename.h`:
 
 ```shell
-swiftc -c swift_api.swift               \
-    -module-name swift_module           \
-    -emit-objc-header-path swift_api.h  \
+swiftc -c swift_api.swift                           \
+    -module-name swift_module                       \
+    -emit-objc-header-path third_party/swift_api.h  \
     -emit-library -o libswiftapi.dylib
 ```
 
@@ -43,7 +43,7 @@
 language: objc
 headers:
   entry-points:
-    - 'swift_api.h'
+    - 'third_party/swift_api.h'
 ```
 
 Swift classes become Objective-C interfaces, so include them like this:
diff --git a/pkgs/ffigen/example/swift/config.yaml b/pkgs/ffigen/example/swift/config.yaml
index 6082e97..7f820ba 100644
--- a/pkgs/ffigen/example/swift/config.yaml
+++ b/pkgs/ffigen/example/swift/config.yaml
@@ -12,10 +12,10 @@
     'SwiftClass': 'swift_module'
 headers:
   entry-points:
-    - 'swift_api.h'
+    - 'third_party/swift_api.h'
 preamble: |
   // ignore_for_file: camel_case_types, non_constant_identifier_names
   // ignore_for_file: unused_element, unused_field, return_of_invalid_type
   // ignore_for_file: void_checks, annotate_overrides
   // ignore_for_file: no_leading_underscores_for_local_identifiers
-  // ignore_for_file: library_private_types_in_public_api
\ No newline at end of file
+  // ignore_for_file: library_private_types_in_public_api
diff --git a/pkgs/ffigen/example/swift/swift_api.h b/pkgs/ffigen/example/swift/third_party/swift_api.h
similarity index 100%
rename from pkgs/ffigen/example/swift/swift_api.h
rename to pkgs/ffigen/example/swift/third_party/swift_api.h
diff --git a/pkgs/ffigen/lib/src/code_generator/objc_block.dart b/pkgs/ffigen/lib/src/code_generator/objc_block.dart
index ba028d6..7bbb4c0 100644
--- a/pkgs/ffigen/lib/src/code_generator/objc_block.dart
+++ b/pkgs/ffigen/lib/src/code_generator/objc_block.dart
@@ -14,6 +14,19 @@
 
   ObjCBlock({
     required String usr,
+    required Type returnType,
+    required List<Type> argTypes,
+    required ObjCBuiltInFunctions builtInFunctions,
+  }) : this._(
+          usr: usr,
+          name: _getBlockName(returnType, argTypes),
+          returnType: returnType,
+          argTypes: argTypes,
+          builtInFunctions: builtInFunctions,
+        );
+
+  ObjCBlock._({
+    required String usr,
     required String name,
     required this.returnType,
     required this.argTypes,
@@ -24,6 +37,16 @@
           name: name,
         );
 
+  // Generates a human readable name for the block based on the args and return
+  // type. These names will be pretty verbose and unweildy, but they're at least
+  // sensible and stable. Users can always add their own typedef with a simpler
+  // name if necessary.
+  static String _getBlockName(Type returnType, List<Type> argTypes) =>
+      'ObjCBlock_${[returnType, ...argTypes].map(_typeName).join('_')}';
+  static String _typeName(Type type) =>
+      type.toString().replaceAll(_illegalNameChar, '');
+  static final _illegalNameChar = RegExp(r'[^0-9a-zA-Z]');
+
   @override
   BindingString toBindingString(Writer w) {
     final s = StringBuffer();
diff --git a/pkgs/ffigen/lib/src/header_parser/sub_parsers/objc_block_parser.dart b/pkgs/ffigen/lib/src/header_parser/sub_parsers/objc_block_parser.dart
index f7ac662..313de4e 100644
--- a/pkgs/ffigen/lib/src/header_parser/sub_parsers/objc_block_parser.dart
+++ b/pkgs/ffigen/lib/src/header_parser/sub_parsers/objc_block_parser.dart
@@ -32,7 +32,6 @@
 
   return ObjCBlock(
     usr: usr.toString(),
-    name: 'ObjCBlock',
     returnType: returnType,
     argTypes: argTypes,
     builtInFunctions: objCBuiltInFunctions,
diff --git a/pkgs/ffigen/test/example_tests/swift_example_test.dart b/pkgs/ffigen/test/example_tests/swift_example_test.dart
index 02ed00a..a4ac61e 100644
--- a/pkgs/ffigen/test/example_tests/swift_example_test.dart
+++ b/pkgs/ffigen/test/example_tests/swift_example_test.dart
@@ -31,7 +31,7 @@
             '-module-name',
             'swift_module',
             '-emit-objc-header-path',
-            'swift_api.h',
+            'third_party/swift_api.h',
             '-emit-library',
             '-o',
             'libswiftapi.dylib',
diff --git a/pkgs/ffigen/test/native_objc_test/block_test.dart b/pkgs/ffigen/test/native_objc_test/block_test.dart
index 908e8fc..0253eaf 100644
--- a/pkgs/ffigen/test/native_objc_test/block_test.dart
+++ b/pkgs/ffigen/test/native_objc_test/block_test.dart
@@ -15,6 +15,13 @@
 import 'block_bindings.dart';
 import 'util.dart';
 
+// The generated block names are stable but verbose, so typedef them.
+typedef IntBlock = ObjCBlock_Int32_Int32;
+typedef FloatBlock = ObjCBlock_ffiFloat_ffiFloat;
+typedef DoubleBlock = ObjCBlock_ffiDouble_ffiDouble;
+typedef Vec4Block = ObjCBlock_Vec4_Vec4;
+typedef VoidBlock = ObjCBlock_ffiVoid;
+
 void main() {
   late BlockTestObjCLibrary lib;
   late void Function(Pointer<Char>, Pointer<Void>) executeInternalCommand;
@@ -52,8 +59,8 @@
     });
 
     test('Block from function pointer', () {
-      final block = ObjCBlock1.fromFunctionPointer(
-          lib, Pointer.fromFunction(_add100, 999));
+      final block =
+          IntBlock.fromFunctionPointer(lib, Pointer.fromFunction(_add100, 999));
       final blockTester = BlockTester.makeFromBlock_(lib, block);
       blockTester.pokeBlock();
       expect(blockTester.call_(123), 223);
@@ -65,7 +72,7 @@
     }
 
     test('Block from function', () {
-      final block = ObjCBlock1.fromFunction(lib, makeAdder(4000));
+      final block = IntBlock.fromFunction(lib, makeAdder(4000));
       final blockTester = BlockTester.makeFromBlock_(lib, block);
       blockTester.pokeBlock();
       expect(blockTester.call_(123), 4123);
@@ -75,7 +82,7 @@
     test('Listener block same thread', () async {
       final hasRun = Completer();
       int value = 0;
-      final block = ObjCBlock.listener(lib, () {
+      final block = VoidBlock.listener(lib, () {
         value = 123;
         hasRun.complete();
       });
@@ -89,7 +96,7 @@
     test('Listener block new thread', () async {
       final hasRun = Completer();
       int value = 0;
-      final block = ObjCBlock.listener(lib, () {
+      final block = VoidBlock.listener(lib, () {
         value = 123;
         hasRun.complete();
       });
@@ -102,7 +109,7 @@
     });
 
     test('Float block', () {
-      final block = ObjCBlock2.fromFunction(lib, (double x) {
+      final block = FloatBlock.fromFunction(lib, (double x) {
         return x + 4.56;
       });
       expect(block(1.23), closeTo(5.79, 1e-6));
@@ -110,7 +117,7 @@
     });
 
     test('Double block', () {
-      final block = ObjCBlock3.fromFunction(lib, (double x) {
+      final block = DoubleBlock.fromFunction(lib, (double x) {
         return x + 4.56;
       });
       expect(block(1.23), closeTo(5.79, 1e-6));
@@ -127,7 +134,7 @@
 
       final tempPtr = calloc<Vec4>();
       final temp = tempPtr.ref;
-      final block = ObjCBlock4.fromFunction(lib, (Vec4 v) {
+      final block = Vec4Block.fromFunction(lib, (Vec4 v) {
         // Twiddle the Vec4 components.
         temp.x = v.y;
         temp.y = v.z;
@@ -156,8 +163,8 @@
     });
 
     Pointer<Void> funcPointerBlockRefCountTest() {
-      final block = ObjCBlock1.fromFunctionPointer(
-          lib, Pointer.fromFunction(_add100, 999));
+      final block =
+          IntBlock.fromFunctionPointer(lib, Pointer.fromFunction(_add100, 999));
       expect(BlockTester.getBlockRetainCount_(lib, block.pointer.cast()), 1);
       return block.pointer.cast();
     }
@@ -169,7 +176,7 @@
     });
 
     Pointer<Void> funcBlockRefCountTest() {
-      final block = ObjCBlock1.fromFunction(lib, makeAdder(4000));
+      final block = IntBlock.fromFunction(lib, makeAdder(4000));
       expect(BlockTester.getBlockRetainCount_(lib, block.pointer.cast()), 1);
       return block.pointer.cast();
     }
@@ -181,7 +188,7 @@
     });
 
     test('Block fields have sensible values', () {
-      final block = ObjCBlock1.fromFunction(lib, makeAdder(4000));
+      final block = IntBlock.fromFunction(lib, makeAdder(4000));
       final blockPtr = block.pointer;
       expect(blockPtr.ref.isa, isNot(0));
       expect(blockPtr.ref.flags, isNot(0)); // Set by Block_copy.