[ffigen] Fix ObjC @class declarations (#352)

* WIP: NSData bug repro

* Fix forward declaration bug

* Remove unused clang_isDeclaration function

* Format
diff --git a/pkgs/ffigen/lib/src/header_parser/sub_parsers/objcinterfacedecl_parser.dart b/pkgs/ffigen/lib/src/header_parser/sub_parsers/objcinterfacedecl_parser.dart
index f30abe5..03d7325 100644
--- a/pkgs/ffigen/lib/src/header_parser/sub_parsers/objcinterfacedecl_parser.dart
+++ b/pkgs/ffigen/lib/src/header_parser/sub_parsers/objcinterfacedecl_parser.dart
@@ -58,6 +58,12 @@
 
 void fillObjCInterfaceMethodsIfNeeded(
     ObjCInterface itf, clang_types.CXCursor cursor) {
+  if (_isClassDeclaration(cursor)) {
+    // @class declarations are ObjC's way of forward declaring classes. In that
+    // case there's nothing to fill yet.
+    return;
+  }
+
   if (itf.filled) return;
   itf.filled = true; // Break cycles.
 
@@ -75,6 +81,27 @@
       'Name: ${itf.originalName}, ${cursor.completeStringRepr()}');
 }
 
+bool _isClassDeclarationResult = false;
+bool _isClassDeclaration(clang_types.CXCursor cursor) {
+  // It's a class declaration if it has no children other than ObjCClassRef.
+  _isClassDeclarationResult = true;
+  clang.clang_visitChildren(
+      cursor,
+      Pointer.fromFunction(
+          _isClassDeclarationVisitor, exceptional_visitor_return),
+      nullptr);
+  return _isClassDeclarationResult;
+}
+
+int _isClassDeclarationVisitor(clang_types.CXCursor cursor,
+    clang_types.CXCursor parent, Pointer<Void> clientData) {
+  if (cursor.kind == clang_types.CXCursorKind.CXCursor_ObjCClassRef) {
+    return clang_types.CXChildVisitResult.CXChildVisit_Continue;
+  }
+  _isClassDeclarationResult = false;
+  return clang_types.CXChildVisitResult.CXChildVisit_Break;
+}
+
 int _parseInterfaceVisitor(clang_types.CXCursor cursor,
     clang_types.CXCursor parent, Pointer<Void> clientData) {
   switch (cursor.kind) {
diff --git a/pkgs/ffigen/test/native_objc_test/forward_decl_bindings.dart b/pkgs/ffigen/test/native_objc_test/forward_decl_bindings.dart
new file mode 100644
index 0000000..f998344
--- /dev/null
+++ b/pkgs/ffigen/test/native_objc_test/forward_decl_bindings.dart
@@ -0,0 +1,1464 @@
+// ignore_for_file: camel_case_types, non_constant_identifier_names, unused_element, unused_field
+
+// AUTO GENERATED FILE, DO NOT EDIT.
+//
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+import 'package:ffi/ffi.dart' as pkg_ffi;
+
+/// Test that forward declared ObjC classes are correctly filled
+class ForwardDeclTestObjCLibrary {
+  /// Holds the symbol lookup function.
+  final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
+      _lookup;
+
+  /// The symbols are looked up in [dynamicLibrary].
+  ForwardDeclTestObjCLibrary(ffi.DynamicLibrary dynamicLibrary)
+      : _lookup = dynamicLibrary.lookup;
+
+  /// The symbols are looked up with [lookup].
+  ForwardDeclTestObjCLibrary.fromLookup(
+      ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
+          lookup)
+      : _lookup = lookup;
+
+  late final ffi.Pointer<ffi.Double> _NSFoundationVersionNumber =
+      _lookup<ffi.Double>('NSFoundationVersionNumber');
+
+  double get NSFoundationVersionNumber => _NSFoundationVersionNumber.value;
+
+  set NSFoundationVersionNumber(double value) =>
+      _NSFoundationVersionNumber.value = value;
+
+  late final ffi.Pointer<NSInteger> _NSNotFound =
+      _lookup<NSInteger>('NSNotFound');
+
+  int get NSNotFound => _NSNotFound.value;
+
+  set NSNotFound(int value) => _NSNotFound.value = value;
+
+  late final ffi.Pointer<ffi.Double> _kCFCoreFoundationVersionNumber =
+      _lookup<ffi.Double>('kCFCoreFoundationVersionNumber');
+
+  double get kCFCoreFoundationVersionNumber =>
+      _kCFCoreFoundationVersionNumber.value;
+
+  set kCFCoreFoundationVersionNumber(double value) =>
+      _kCFCoreFoundationVersionNumber.value = value;
+
+  late final ffi.Pointer<CFIndex> _kCFNotFound =
+      _lookup<CFIndex>('kCFNotFound');
+
+  int get kCFNotFound => _kCFNotFound.value;
+
+  set kCFNotFound(int value) => _kCFNotFound.value = value;
+
+  late final ffi.Pointer<CFNullRef> _kCFNull = _lookup<CFNullRef>('kCFNull');
+
+  CFNullRef get kCFNull => _kCFNull.value;
+
+  set kCFNull(CFNullRef value) => _kCFNull.value = value;
+
+  late final ffi.Pointer<CFAllocatorRef> _kCFAllocatorDefault =
+      _lookup<CFAllocatorRef>('kCFAllocatorDefault');
+
+  CFAllocatorRef get kCFAllocatorDefault => _kCFAllocatorDefault.value;
+
+  set kCFAllocatorDefault(CFAllocatorRef value) =>
+      _kCFAllocatorDefault.value = value;
+
+  late final ffi.Pointer<CFAllocatorRef> _kCFAllocatorSystemDefault =
+      _lookup<CFAllocatorRef>('kCFAllocatorSystemDefault');
+
+  CFAllocatorRef get kCFAllocatorSystemDefault =>
+      _kCFAllocatorSystemDefault.value;
+
+  set kCFAllocatorSystemDefault(CFAllocatorRef value) =>
+      _kCFAllocatorSystemDefault.value = value;
+
+  late final ffi.Pointer<CFAllocatorRef> _kCFAllocatorMalloc =
+      _lookup<CFAllocatorRef>('kCFAllocatorMalloc');
+
+  CFAllocatorRef get kCFAllocatorMalloc => _kCFAllocatorMalloc.value;
+
+  set kCFAllocatorMalloc(CFAllocatorRef value) =>
+      _kCFAllocatorMalloc.value = value;
+
+  late final ffi.Pointer<CFAllocatorRef> _kCFAllocatorMallocZone =
+      _lookup<CFAllocatorRef>('kCFAllocatorMallocZone');
+
+  CFAllocatorRef get kCFAllocatorMallocZone => _kCFAllocatorMallocZone.value;
+
+  set kCFAllocatorMallocZone(CFAllocatorRef value) =>
+      _kCFAllocatorMallocZone.value = value;
+
+  late final ffi.Pointer<CFAllocatorRef> _kCFAllocatorNull =
+      _lookup<CFAllocatorRef>('kCFAllocatorNull');
+
+  CFAllocatorRef get kCFAllocatorNull => _kCFAllocatorNull.value;
+
+  set kCFAllocatorNull(CFAllocatorRef value) => _kCFAllocatorNull.value = value;
+
+  late final ffi.Pointer<CFAllocatorRef> _kCFAllocatorUseContext =
+      _lookup<CFAllocatorRef>('kCFAllocatorUseContext');
+
+  CFAllocatorRef get kCFAllocatorUseContext => _kCFAllocatorUseContext.value;
+
+  set kCFAllocatorUseContext(CFAllocatorRef value) =>
+      _kCFAllocatorUseContext.value = value;
+
+  ffi.Pointer<ObjCSel> _registerName1(String name) {
+    final cstr = name.toNativeUtf8();
+    final sel = _sel_registerName(cstr.cast());
+    pkg_ffi.calloc.free(cstr);
+    return sel;
+  }
+
+  ffi.Pointer<ObjCSel> _sel_registerName(
+    ffi.Pointer<pkg_ffi.Char> str,
+  ) {
+    return __sel_registerName(
+      str,
+    );
+  }
+
+  late final __sel_registerNamePtr = _lookup<
+      ffi.NativeFunction<
+          ffi.Pointer<ObjCSel> Function(
+              ffi.Pointer<pkg_ffi.Char>)>>('sel_registerName');
+  late final __sel_registerName = __sel_registerNamePtr
+      .asFunction<ffi.Pointer<ObjCSel> Function(ffi.Pointer<pkg_ffi.Char>)>();
+
+  ffi.Pointer<ObjCObject> _getClass1(String name) {
+    final cstr = name.toNativeUtf8();
+    final clazz = _objc_getClass(cstr.cast());
+    pkg_ffi.calloc.free(cstr);
+    return clazz;
+  }
+
+  ffi.Pointer<ObjCObject> _objc_getClass(
+    ffi.Pointer<pkg_ffi.Char> str,
+  ) {
+    return __objc_getClass(
+      str,
+    );
+  }
+
+  late final __objc_getClassPtr = _lookup<
+      ffi.NativeFunction<
+          ffi.Pointer<ObjCObject> Function(
+              ffi.Pointer<pkg_ffi.Char>)>>('objc_getClass');
+  late final __objc_getClass = __objc_getClassPtr.asFunction<
+      ffi.Pointer<ObjCObject> Function(ffi.Pointer<pkg_ffi.Char>)>();
+
+  late final ffi.Pointer<ObjCObject> _class_NSObject1 = _getClass1("NSObject");
+  late final ffi.Pointer<ObjCSel> _sel_load1 = _registerName1("load");
+  void _objc_msgSend_0(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+  ) {
+    return __objc_msgSend_0(
+      obj,
+      sel,
+    );
+  }
+
+  late final __objc_msgSend_0Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Void Function(
+              ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_0 = __objc_msgSend_0Ptr.asFunction<
+      void Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_initialize1 =
+      _registerName1("initialize");
+  late final ffi.Pointer<ObjCSel> _sel_init1 = _registerName1("init");
+  instancetype _objc_msgSend_1(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+  ) {
+    return __objc_msgSend_1(
+      obj,
+      sel,
+    );
+  }
+
+  late final __objc_msgSend_1Ptr = _lookup<
+      ffi.NativeFunction<
+          instancetype Function(
+              ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_1 = __objc_msgSend_1Ptr.asFunction<
+      instancetype Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_new1 = _registerName1("new");
+  late final ffi.Pointer<ObjCSel> _sel_allocWithZone_1 =
+      _registerName1("allocWithZone:");
+  instancetype _objc_msgSend_2(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+    ffi.Pointer<_NSZone> zone,
+  ) {
+    return __objc_msgSend_2(
+      obj,
+      sel,
+      zone,
+    );
+  }
+
+  late final __objc_msgSend_2Ptr = _lookup<
+      ffi.NativeFunction<
+          instancetype Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+              ffi.Pointer<_NSZone>)>>('objc_msgSend');
+  late final __objc_msgSend_2 = __objc_msgSend_2Ptr.asFunction<
+      instancetype Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+          ffi.Pointer<_NSZone>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_alloc1 = _registerName1("alloc");
+  late final ffi.Pointer<ObjCSel> _sel_dealloc1 = _registerName1("dealloc");
+  late final ffi.Pointer<ObjCSel> _sel_finalize1 = _registerName1("finalize");
+  late final ffi.Pointer<ObjCSel> _sel_copy1 = _registerName1("copy");
+  late final ffi.Pointer<ObjCSel> _sel_mutableCopy1 =
+      _registerName1("mutableCopy");
+  late final ffi.Pointer<ObjCSel> _sel_copyWithZone_1 =
+      _registerName1("copyWithZone:");
+  late final ffi.Pointer<ObjCSel> _sel_mutableCopyWithZone_1 =
+      _registerName1("mutableCopyWithZone:");
+  late final ffi.Pointer<ObjCSel> _sel_instancesRespondToSelector_1 =
+      _registerName1("instancesRespondToSelector:");
+  bool _objc_msgSend_3(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+    ffi.Pointer<ObjCSel> aSelector,
+  ) {
+    return __objc_msgSend_3(
+          obj,
+          sel,
+          aSelector,
+        ) !=
+        0;
+  }
+
+  late final __objc_msgSend_3Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Uint8 Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+              ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_3 = __objc_msgSend_3Ptr.asFunction<
+      int Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+          ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_conformsToProtocol_1 =
+      _registerName1("conformsToProtocol:");
+  bool _objc_msgSend_4(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+    ffi.Pointer<ObjCObject> protocol,
+  ) {
+    return __objc_msgSend_4(
+          obj,
+          sel,
+          protocol,
+        ) !=
+        0;
+  }
+
+  late final __objc_msgSend_4Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Uint8 Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+              ffi.Pointer<ObjCObject>)>>('objc_msgSend');
+  late final __objc_msgSend_4 = __objc_msgSend_4Ptr.asFunction<
+      int Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+          ffi.Pointer<ObjCObject>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_methodForSelector_1 =
+      _registerName1("methodForSelector:");
+  IMP _objc_msgSend_5(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+    ffi.Pointer<ObjCSel> aSelector,
+  ) {
+    return __objc_msgSend_5(
+      obj,
+      sel,
+      aSelector,
+    );
+  }
+
+  late final __objc_msgSend_5Ptr = _lookup<
+      ffi.NativeFunction<
+          IMP Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+              ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_5 = __objc_msgSend_5Ptr.asFunction<
+      IMP Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+          ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_instanceMethodForSelector_1 =
+      _registerName1("instanceMethodForSelector:");
+  late final ffi.Pointer<ObjCSel> _sel_doesNotRecognizeSelector_1 =
+      _registerName1("doesNotRecognizeSelector:");
+  void _objc_msgSend_6(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+    ffi.Pointer<ObjCSel> aSelector,
+  ) {
+    return __objc_msgSend_6(
+      obj,
+      sel,
+      aSelector,
+    );
+  }
+
+  late final __objc_msgSend_6Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Void Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+              ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_6 = __objc_msgSend_6Ptr.asFunction<
+      void Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+          ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_forwardingTargetForSelector_1 =
+      _registerName1("forwardingTargetForSelector:");
+  ffi.Pointer<ObjCObject> _objc_msgSend_7(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+    ffi.Pointer<ObjCSel> aSelector,
+  ) {
+    return __objc_msgSend_7(
+      obj,
+      sel,
+      aSelector,
+    );
+  }
+
+  late final __objc_msgSend_7Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Pointer<ObjCObject> Function(ffi.Pointer<ObjCObject>,
+              ffi.Pointer<ObjCSel>, ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_7 = __objc_msgSend_7Ptr.asFunction<
+      ffi.Pointer<ObjCObject> Function(ffi.Pointer<ObjCObject>,
+          ffi.Pointer<ObjCSel>, ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_forwardInvocation_1 =
+      _registerName1("forwardInvocation:");
+  void _objc_msgSend_8(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+    ffi.Pointer<ObjCObject> anInvocation,
+  ) {
+    return __objc_msgSend_8(
+      obj,
+      sel,
+      anInvocation,
+    );
+  }
+
+  late final __objc_msgSend_8Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Void Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+              ffi.Pointer<ObjCObject>)>>('objc_msgSend');
+  late final __objc_msgSend_8 = __objc_msgSend_8Ptr.asFunction<
+      void Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+          ffi.Pointer<ObjCObject>)>();
+
+  late final ffi.Pointer<ObjCObject> _class_NSMethodSignature1 =
+      _getClass1("NSMethodSignature");
+  late final ffi.Pointer<ObjCSel> _sel_methodSignatureForSelector_1 =
+      _registerName1("methodSignatureForSelector:");
+  ffi.Pointer<ObjCObject> _objc_msgSend_9(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+    ffi.Pointer<ObjCSel> aSelector,
+  ) {
+    return __objc_msgSend_9(
+      obj,
+      sel,
+      aSelector,
+    );
+  }
+
+  late final __objc_msgSend_9Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Pointer<ObjCObject> Function(ffi.Pointer<ObjCObject>,
+              ffi.Pointer<ObjCSel>, ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_9 = __objc_msgSend_9Ptr.asFunction<
+      ffi.Pointer<ObjCObject> Function(ffi.Pointer<ObjCObject>,
+          ffi.Pointer<ObjCSel>, ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_instanceMethodSignatureForSelector_1 =
+      _registerName1("instanceMethodSignatureForSelector:");
+  late final ffi.Pointer<ObjCSel> _sel_allowsWeakReference1 =
+      _registerName1("allowsWeakReference");
+  bool _objc_msgSend_10(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+  ) {
+    return __objc_msgSend_10(
+          obj,
+          sel,
+        ) !=
+        0;
+  }
+
+  late final __objc_msgSend_10Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Uint8 Function(
+              ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_10 = __objc_msgSend_10Ptr.asFunction<
+      int Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_retainWeakReference1 =
+      _registerName1("retainWeakReference");
+  late final ffi.Pointer<ObjCSel> _sel_isSubclassOfClass_1 =
+      _registerName1("isSubclassOfClass:");
+  late final ffi.Pointer<ObjCSel> _sel_resolveClassMethod_1 =
+      _registerName1("resolveClassMethod:");
+  late final ffi.Pointer<ObjCSel> _sel_resolveInstanceMethod_1 =
+      _registerName1("resolveInstanceMethod:");
+  late final ffi.Pointer<ObjCSel> _sel_hash1 = _registerName1("hash");
+  int _objc_msgSend_11(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+  ) {
+    return __objc_msgSend_11(
+      obj,
+      sel,
+    );
+  }
+
+  late final __objc_msgSend_11Ptr = _lookup<
+      ffi.NativeFunction<
+          NSUInteger Function(
+              ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_11 = __objc_msgSend_11Ptr.asFunction<
+      int Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_superclass1 =
+      _registerName1("superclass");
+  late final ffi.Pointer<ObjCSel> _sel_class1 = _registerName1("class");
+  late final ffi.Pointer<ObjCObject> _class_NSString1 = _getClass1("NSString");
+  late final ffi.Pointer<ObjCSel> _sel_stringWithCString_encoding_1 =
+      _registerName1("stringWithCString:encoding:");
+  ffi.Pointer<ObjCObject> _objc_msgSend_12(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+    ffi.Pointer<pkg_ffi.Char> cString,
+    int enc,
+  ) {
+    return __objc_msgSend_12(
+      obj,
+      sel,
+      cString,
+      enc,
+    );
+  }
+
+  late final __objc_msgSend_12Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Pointer<ObjCObject> Function(
+              ffi.Pointer<ObjCObject>,
+              ffi.Pointer<ObjCSel>,
+              ffi.Pointer<pkg_ffi.Char>,
+              pkg_ffi.UnsignedInt)>>('objc_msgSend');
+  late final __objc_msgSend_12 = __objc_msgSend_12Ptr.asFunction<
+      ffi.Pointer<ObjCObject> Function(ffi.Pointer<ObjCObject>,
+          ffi.Pointer<ObjCSel>, ffi.Pointer<pkg_ffi.Char>, int)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_UTF8String1 =
+      _registerName1("UTF8String");
+  ffi.Pointer<pkg_ffi.Char> _objc_msgSend_13(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+  ) {
+    return __objc_msgSend_13(
+      obj,
+      sel,
+    );
+  }
+
+  late final __objc_msgSend_13Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Pointer<pkg_ffi.Char> Function(
+              ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_13 = __objc_msgSend_13Ptr.asFunction<
+      ffi.Pointer<pkg_ffi.Char> Function(
+          ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_description1 =
+      _registerName1("description");
+  ffi.Pointer<ObjCObject> _objc_msgSend_14(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+  ) {
+    return __objc_msgSend_14(
+      obj,
+      sel,
+    );
+  }
+
+  late final __objc_msgSend_14Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Pointer<ObjCObject> Function(
+              ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_14 = __objc_msgSend_14Ptr.asFunction<
+      ffi.Pointer<ObjCObject> Function(
+          ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_debugDescription1 =
+      _registerName1("debugDescription");
+  late final ffi.Pointer<ObjCSel> _sel_version1 = _registerName1("version");
+  int _objc_msgSend_15(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+  ) {
+    return __objc_msgSend_15(
+      obj,
+      sel,
+    );
+  }
+
+  late final __objc_msgSend_15Ptr = _lookup<
+      ffi.NativeFunction<
+          NSInteger Function(
+              ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_15 = __objc_msgSend_15Ptr.asFunction<
+      int Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_setVersion_1 =
+      _registerName1("setVersion:");
+  void _objc_msgSend_16(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+    int aVersion,
+  ) {
+    return __objc_msgSend_16(
+      obj,
+      sel,
+      aVersion,
+    );
+  }
+
+  late final __objc_msgSend_16Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Void Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>,
+              NSInteger)>>('objc_msgSend');
+  late final __objc_msgSend_16 = __objc_msgSend_16Ptr.asFunction<
+      void Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>, int)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_classForCoder1 =
+      _registerName1("classForCoder");
+  late final ffi.Pointer<ObjCSel> _sel_replacementObjectForCoder_1 =
+      _registerName1("replacementObjectForCoder:");
+  ffi.Pointer<ObjCObject> _objc_msgSend_17(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+    ffi.Pointer<ObjCObject> coder,
+  ) {
+    return __objc_msgSend_17(
+      obj,
+      sel,
+      coder,
+    );
+  }
+
+  late final __objc_msgSend_17Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Pointer<ObjCObject> Function(ffi.Pointer<ObjCObject>,
+              ffi.Pointer<ObjCSel>, ffi.Pointer<ObjCObject>)>>('objc_msgSend');
+  late final __objc_msgSend_17 = __objc_msgSend_17Ptr.asFunction<
+      ffi.Pointer<ObjCObject> Function(ffi.Pointer<ObjCObject>,
+          ffi.Pointer<ObjCSel>, ffi.Pointer<ObjCObject>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_awakeAfterUsingCoder_1 =
+      _registerName1("awakeAfterUsingCoder:");
+  late final ffi.Pointer<ObjCSel> _sel_poseAsClass_1 =
+      _registerName1("poseAsClass:");
+  late final ffi.Pointer<ObjCSel> _sel_autoContentAccessingProxy1 =
+      _registerName1("autoContentAccessingProxy");
+  late final ffi.Pointer<ObjCObject> _class_OtherClass1 =
+      _getClass1("OtherClass");
+  late final ffi.Pointer<ObjCObject> _class_ForwardDeclaredClass1 =
+      _getClass1("ForwardDeclaredClass");
+  late final ffi.Pointer<ObjCSel> _sel_get1231 = _registerName1("get123");
+  int _objc_msgSend_18(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+  ) {
+    return __objc_msgSend_18(
+      obj,
+      sel,
+    );
+  }
+
+  late final __objc_msgSend_18Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Int32 Function(
+              ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_18 = __objc_msgSend_18Ptr.asFunction<
+      int Function(ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>();
+
+  late final ffi.Pointer<ObjCSel> _sel_getTheThing1 =
+      _registerName1("getTheThing");
+  ffi.Pointer<ObjCObject> _objc_msgSend_19(
+    ffi.Pointer<ObjCObject> obj,
+    ffi.Pointer<ObjCSel> sel,
+  ) {
+    return __objc_msgSend_19(
+      obj,
+      sel,
+    );
+  }
+
+  late final __objc_msgSend_19Ptr = _lookup<
+      ffi.NativeFunction<
+          ffi.Pointer<ObjCObject> Function(
+              ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>>('objc_msgSend');
+  late final __objc_msgSend_19 = __objc_msgSend_19Ptr.asFunction<
+      ffi.Pointer<ObjCObject> Function(
+          ffi.Pointer<ObjCObject>, ffi.Pointer<ObjCSel>)>();
+}
+
+abstract class NSComparisonResult {
+  static const int NSOrderedAscending = -1;
+  static const int NSOrderedSame = 0;
+  static const int NSOrderedDescending = 1;
+}
+
+abstract class NSEnumerationOptions {
+  static const int NSEnumerationConcurrent = 1;
+  static const int NSEnumerationReverse = 2;
+}
+
+abstract class NSSortOptions {
+  static const int NSSortConcurrent = 1;
+  static const int NSSortStable = 16;
+}
+
+abstract class NSQualityOfService {
+  static const int NSQualityOfServiceUserInteractive = 33;
+  static const int NSQualityOfServiceUserInitiated = 25;
+  static const int NSQualityOfServiceUtility = 17;
+  static const int NSQualityOfServiceBackground = 9;
+  static const int NSQualityOfServiceDefault = -1;
+}
+
+typedef NSInteger = pkg_ffi.Long;
+
+class __CFString extends ffi.Opaque {}
+
+abstract class CFComparisonResult {
+  static const int kCFCompareLessThan = -1;
+  static const int kCFCompareEqualTo = 0;
+  static const int kCFCompareGreaterThan = 1;
+}
+
+typedef CFIndex = pkg_ffi.Long;
+
+class CFRange extends ffi.Struct {
+  @CFIndex()
+  external int location;
+
+  @CFIndex()
+  external int length;
+}
+
+class __CFNull extends ffi.Opaque {}
+
+typedef CFNullRef = ffi.Pointer<__CFNull>;
+
+class __CFAllocator extends ffi.Opaque {}
+
+typedef CFAllocatorRef = ffi.Pointer<__CFAllocator>;
+
+class CFAllocatorContext extends ffi.Struct {
+  @CFIndex()
+  external int version;
+
+  external ffi.Pointer<ffi.Void> info;
+
+  external CFAllocatorRetainCallBack retain;
+
+  external CFAllocatorReleaseCallBack release;
+
+  external CFAllocatorCopyDescriptionCallBack copyDescription;
+
+  external CFAllocatorAllocateCallBack allocate;
+
+  external CFAllocatorReallocateCallBack reallocate;
+
+  external CFAllocatorDeallocateCallBack deallocate;
+
+  external CFAllocatorPreferredSizeCallBack preferredSize;
+}
+
+typedef CFAllocatorRetainCallBack = ffi.Pointer<
+    ffi.NativeFunction<ffi.Pointer<ffi.Void> Function(ffi.Pointer<ffi.Void>)>>;
+typedef CFAllocatorReleaseCallBack
+    = ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>;
+typedef CFAllocatorCopyDescriptionCallBack = ffi
+    .Pointer<ffi.NativeFunction<CFStringRef Function(ffi.Pointer<ffi.Void>)>>;
+typedef CFStringRef = ffi.Pointer<__CFString>;
+typedef CFAllocatorAllocateCallBack = ffi.Pointer<
+    ffi.NativeFunction<
+        ffi.Pointer<ffi.Void> Function(
+            CFIndex, CFOptionFlags, ffi.Pointer<ffi.Void>)>>;
+typedef CFOptionFlags = pkg_ffi.UnsignedLong;
+typedef CFAllocatorReallocateCallBack = ffi.Pointer<
+    ffi.NativeFunction<
+        ffi.Pointer<ffi.Void> Function(ffi.Pointer<ffi.Void>, CFIndex,
+            CFOptionFlags, ffi.Pointer<ffi.Void>)>>;
+typedef CFAllocatorDeallocateCallBack = ffi.Pointer<
+    ffi.NativeFunction<
+        ffi.Void Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>)>>;
+typedef CFAllocatorPreferredSizeCallBack = ffi.Pointer<
+    ffi.NativeFunction<
+        CFIndex Function(CFIndex, CFOptionFlags, ffi.Pointer<ffi.Void>)>>;
+
+class _ObjCWrapper {
+  final ffi.Pointer<ObjCObject> _id;
+  final ForwardDeclTestObjCLibrary _lib;
+
+  _ObjCWrapper._(this._id, this._lib);
+
+  @override
+  bool operator ==(Object other) {
+    return other is _ObjCWrapper && _id == other._id;
+  }
+
+  @override
+  int get hashCode => _id.hashCode;
+}
+
+class NSObject extends _ObjCWrapper {
+  NSObject._(ffi.Pointer<ObjCObject> id, ForwardDeclTestObjCLibrary lib)
+      : super._(id, lib);
+
+  static NSObject castFrom<T extends _ObjCWrapper>(T other) {
+    return NSObject._(other._id, other._lib);
+  }
+
+  static NSObject castFromPointer(
+      ForwardDeclTestObjCLibrary lib, ffi.Pointer<ObjCObject> other) {
+    return NSObject._(other, lib);
+  }
+
+  static void load(ForwardDeclTestObjCLibrary _lib) {
+    _lib._objc_msgSend_0(_lib._class_NSObject1, _lib._sel_load1);
+  }
+
+  static void initialize(ForwardDeclTestObjCLibrary _lib) {
+    _lib._objc_msgSend_0(_lib._class_NSObject1, _lib._sel_initialize1);
+  }
+
+  NSObject init() {
+    final _ret = _lib._objc_msgSend_1(_id, _lib._sel_init1);
+    return NSObject._(_ret, _lib);
+  }
+
+  static NSObject new1(ForwardDeclTestObjCLibrary _lib) {
+    final _ret = _lib._objc_msgSend_1(_lib._class_NSObject1, _lib._sel_new1);
+    return NSObject._(_ret, _lib);
+  }
+
+  static NSObject allocWithZone(
+      ForwardDeclTestObjCLibrary _lib, ffi.Pointer<_NSZone> zone) {
+    final _ret = _lib._objc_msgSend_2(
+        _lib._class_NSObject1, _lib._sel_allocWithZone_1, zone);
+    return NSObject._(_ret, _lib);
+  }
+
+  static NSObject alloc(ForwardDeclTestObjCLibrary _lib) {
+    final _ret = _lib._objc_msgSend_1(_lib._class_NSObject1, _lib._sel_alloc1);
+    return NSObject._(_ret, _lib);
+  }
+
+  void dealloc() {
+    _lib._objc_msgSend_0(_id, _lib._sel_dealloc1);
+  }
+
+  void finalize() {
+    _lib._objc_msgSend_0(_id, _lib._sel_finalize1);
+  }
+
+  NSObject copy() {
+    final _ret = _lib._objc_msgSend_1(_id, _lib._sel_copy1);
+    return NSObject._(_ret, _lib);
+  }
+
+  NSObject mutableCopy() {
+    final _ret = _lib._objc_msgSend_1(_id, _lib._sel_mutableCopy1);
+    return NSObject._(_ret, _lib);
+  }
+
+  static NSObject copyWithZone(
+      ForwardDeclTestObjCLibrary _lib, ffi.Pointer<_NSZone> zone) {
+    final _ret = _lib._objc_msgSend_2(
+        _lib._class_NSObject1, _lib._sel_copyWithZone_1, zone);
+    return NSObject._(_ret, _lib);
+  }
+
+  static NSObject mutableCopyWithZone(
+      ForwardDeclTestObjCLibrary _lib, ffi.Pointer<_NSZone> zone) {
+    final _ret = _lib._objc_msgSend_2(
+        _lib._class_NSObject1, _lib._sel_mutableCopyWithZone_1, zone);
+    return NSObject._(_ret, _lib);
+  }
+
+  static bool instancesRespondToSelector(
+      ForwardDeclTestObjCLibrary _lib, ffi.Pointer<ObjCSel> aSelector) {
+    return _lib._objc_msgSend_3(_lib._class_NSObject1,
+        _lib._sel_instancesRespondToSelector_1, aSelector);
+  }
+
+  static bool conformsToProtocol(
+      ForwardDeclTestObjCLibrary _lib, NSObject? protocol) {
+    return _lib._objc_msgSend_4(_lib._class_NSObject1,
+        _lib._sel_conformsToProtocol_1, protocol?._id ?? ffi.nullptr);
+  }
+
+  IMP methodForSelector(ffi.Pointer<ObjCSel> aSelector) {
+    return _lib._objc_msgSend_5(_id, _lib._sel_methodForSelector_1, aSelector);
+  }
+
+  static IMP instanceMethodForSelector(
+      ForwardDeclTestObjCLibrary _lib, ffi.Pointer<ObjCSel> aSelector) {
+    return _lib._objc_msgSend_5(_lib._class_NSObject1,
+        _lib._sel_instanceMethodForSelector_1, aSelector);
+  }
+
+  void doesNotRecognizeSelector(ffi.Pointer<ObjCSel> aSelector) {
+    _lib._objc_msgSend_6(_id, _lib._sel_doesNotRecognizeSelector_1, aSelector);
+  }
+
+  NSObject forwardingTargetForSelector(ffi.Pointer<ObjCSel> aSelector) {
+    final _ret = _lib._objc_msgSend_7(
+        _id, _lib._sel_forwardingTargetForSelector_1, aSelector);
+    return NSObject._(_ret, _lib);
+  }
+
+  void forwardInvocation(NSObject? anInvocation) {
+    _lib._objc_msgSend_8(
+        _id, _lib._sel_forwardInvocation_1, anInvocation?._id ?? ffi.nullptr);
+  }
+
+  NSMethodSignature methodSignatureForSelector(ffi.Pointer<ObjCSel> aSelector) {
+    final _ret = _lib._objc_msgSend_9(
+        _id, _lib._sel_methodSignatureForSelector_1, aSelector);
+    return NSMethodSignature._(_ret, _lib);
+  }
+
+  static NSMethodSignature instanceMethodSignatureForSelector(
+      ForwardDeclTestObjCLibrary _lib, ffi.Pointer<ObjCSel> aSelector) {
+    final _ret = _lib._objc_msgSend_9(_lib._class_NSObject1,
+        _lib._sel_instanceMethodSignatureForSelector_1, aSelector);
+    return NSMethodSignature._(_ret, _lib);
+  }
+
+  bool allowsWeakReference() {
+    return _lib._objc_msgSend_10(_id, _lib._sel_allowsWeakReference1);
+  }
+
+  bool retainWeakReference() {
+    return _lib._objc_msgSend_10(_id, _lib._sel_retainWeakReference1);
+  }
+
+  static bool isSubclassOfClass(
+      ForwardDeclTestObjCLibrary _lib, NSObject aClass) {
+    return _lib._objc_msgSend_4(
+        _lib._class_NSObject1, _lib._sel_isSubclassOfClass_1, aClass._id);
+  }
+
+  static bool resolveClassMethod(
+      ForwardDeclTestObjCLibrary _lib, ffi.Pointer<ObjCSel> sel) {
+    return _lib._objc_msgSend_3(
+        _lib._class_NSObject1, _lib._sel_resolveClassMethod_1, sel);
+  }
+
+  static bool resolveInstanceMethod(
+      ForwardDeclTestObjCLibrary _lib, ffi.Pointer<ObjCSel> sel) {
+    return _lib._objc_msgSend_3(
+        _lib._class_NSObject1, _lib._sel_resolveInstanceMethod_1, sel);
+  }
+
+  static int hash(ForwardDeclTestObjCLibrary _lib) {
+    return _lib._objc_msgSend_11(_lib._class_NSObject1, _lib._sel_hash1);
+  }
+
+  static NSObject superclass(ForwardDeclTestObjCLibrary _lib) {
+    final _ret =
+        _lib._objc_msgSend_1(_lib._class_NSObject1, _lib._sel_superclass1);
+    return NSObject._(_ret, _lib);
+  }
+
+  static NSObject class1(ForwardDeclTestObjCLibrary _lib) {
+    final _ret = _lib._objc_msgSend_1(_lib._class_NSObject1, _lib._sel_class1);
+    return NSObject._(_ret, _lib);
+  }
+
+  static NSString description(ForwardDeclTestObjCLibrary _lib) {
+    final _ret =
+        _lib._objc_msgSend_14(_lib._class_NSObject1, _lib._sel_description1);
+    return NSString._(_ret, _lib);
+  }
+
+  static NSString debugDescription(ForwardDeclTestObjCLibrary _lib) {
+    final _ret = _lib._objc_msgSend_14(
+        _lib._class_NSObject1, _lib._sel_debugDescription1);
+    return NSString._(_ret, _lib);
+  }
+
+  static int version(ForwardDeclTestObjCLibrary _lib) {
+    return _lib._objc_msgSend_15(_lib._class_NSObject1, _lib._sel_version1);
+  }
+
+  static void setVersion(ForwardDeclTestObjCLibrary _lib, int aVersion) {
+    _lib._objc_msgSend_16(
+        _lib._class_NSObject1, _lib._sel_setVersion_1, aVersion);
+  }
+
+  NSObject get classForCoder {
+    final _ret = _lib._objc_msgSend_1(_id, _lib._sel_classForCoder1);
+    return NSObject._(_ret, _lib);
+  }
+
+  NSObject replacementObjectForCoder(NSObject? coder) {
+    final _ret = _lib._objc_msgSend_17(
+        _id, _lib._sel_replacementObjectForCoder_1, coder?._id ?? ffi.nullptr);
+    return NSObject._(_ret, _lib);
+  }
+
+  NSObject awakeAfterUsingCoder(NSObject? coder) {
+    final _ret = _lib._objc_msgSend_17(
+        _id, _lib._sel_awakeAfterUsingCoder_1, coder?._id ?? ffi.nullptr);
+    return NSObject._(_ret, _lib);
+  }
+
+  static void poseAsClass(ForwardDeclTestObjCLibrary _lib, NSObject aClass) {
+    _lib._objc_msgSend_8(
+        _lib._class_NSObject1, _lib._sel_poseAsClass_1, aClass._id);
+  }
+
+  NSObject get autoContentAccessingProxy {
+    final _ret =
+        _lib._objc_msgSend_1(_id, _lib._sel_autoContentAccessingProxy1);
+    return NSObject._(_ret, _lib);
+  }
+
+  static int version1(ForwardDeclTestObjCLibrary _lib) {
+    return _lib._objc_msgSend_15(_lib._class_NSObject1, _lib._sel_version1);
+  }
+
+  static void setVersion1(ForwardDeclTestObjCLibrary _lib, int aVersion) {
+    _lib._objc_msgSend_16(
+        _lib._class_NSObject1, _lib._sel_setVersion_1, aVersion);
+  }
+
+  NSObject get classForCoder1 {
+    final _ret = _lib._objc_msgSend_1(_id, _lib._sel_classForCoder1);
+    return NSObject._(_ret, _lib);
+  }
+
+  NSObject replacementObjectForCoder1(NSObject? coder) {
+    final _ret = _lib._objc_msgSend_17(
+        _id, _lib._sel_replacementObjectForCoder_1, coder?._id ?? ffi.nullptr);
+    return NSObject._(_ret, _lib);
+  }
+
+  NSObject awakeAfterUsingCoder1(NSObject? coder) {
+    final _ret = _lib._objc_msgSend_17(
+        _id, _lib._sel_awakeAfterUsingCoder_1, coder?._id ?? ffi.nullptr);
+    return NSObject._(_ret, _lib);
+  }
+
+  static void poseAsClass1(ForwardDeclTestObjCLibrary _lib, NSObject aClass) {
+    _lib._objc_msgSend_8(
+        _lib._class_NSObject1, _lib._sel_poseAsClass_1, aClass._id);
+  }
+
+  NSObject get autoContentAccessingProxy1 {
+    final _ret =
+        _lib._objc_msgSend_1(_id, _lib._sel_autoContentAccessingProxy1);
+    return NSObject._(_ret, _lib);
+  }
+}
+
+class ObjCSel extends ffi.Opaque {}
+
+class ObjCObject extends ffi.Opaque {}
+
+typedef instancetype = ffi.Pointer<ObjCObject>;
+
+class _NSZone extends ffi.Opaque {}
+
+typedef IMP = ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>;
+
+class NSMethodSignature extends _ObjCWrapper {
+  NSMethodSignature._(
+      ffi.Pointer<ObjCObject> id, ForwardDeclTestObjCLibrary lib)
+      : super._(id, lib);
+
+  static NSMethodSignature castFrom<T extends _ObjCWrapper>(T other) {
+    return NSMethodSignature._(other._id, other._lib);
+  }
+
+  static NSMethodSignature castFromPointer(
+      ForwardDeclTestObjCLibrary lib, ffi.Pointer<ObjCObject> other) {
+    return NSMethodSignature._(other, lib);
+  }
+}
+
+typedef NSUInteger = pkg_ffi.UnsignedLong;
+
+class NSString extends _ObjCWrapper {
+  NSString._(ffi.Pointer<ObjCObject> id, ForwardDeclTestObjCLibrary lib)
+      : super._(id, lib);
+
+  static NSString castFrom<T extends _ObjCWrapper>(T other) {
+    return NSString._(other._id, other._lib);
+  }
+
+  static NSString castFromPointer(
+      ForwardDeclTestObjCLibrary lib, ffi.Pointer<ObjCObject> other) {
+    return NSString._(other, lib);
+  }
+
+  factory NSString(ForwardDeclTestObjCLibrary _lib, String str) {
+    final cstr = str.toNativeUtf8();
+    final nsstr = stringWithCString_encoding(_lib, cstr.cast(), 4 /* UTF8 */);
+    pkg_ffi.calloc.free(cstr);
+    return nsstr;
+  }
+
+  @override
+  String toString() => (UTF8String).cast<pkg_ffi.Utf8>().toDartString();
+
+  static NSString stringWithCString_encoding(ForwardDeclTestObjCLibrary _lib,
+      ffi.Pointer<pkg_ffi.Char> cString, int enc) {
+    final _ret = _lib._objc_msgSend_12(_lib._class_NSString1,
+        _lib._sel_stringWithCString_encoding_1, cString, enc);
+    return NSString._(_ret, _lib);
+  }
+
+  ffi.Pointer<pkg_ffi.Char> get UTF8String {
+    return _lib._objc_msgSend_13(_id, _lib._sel_UTF8String1);
+  }
+}
+
+extension StringToNSString on String {
+  NSString toNSString(ForwardDeclTestObjCLibrary lib) => NSString(lib, this);
+}
+
+class OtherClass extends NSObject {
+  OtherClass._(ffi.Pointer<ObjCObject> id, ForwardDeclTestObjCLibrary lib)
+      : super._(id, lib);
+
+  static OtherClass castFrom<T extends _ObjCWrapper>(T other) {
+    return OtherClass._(other._id, other._lib);
+  }
+
+  static OtherClass castFromPointer(
+      ForwardDeclTestObjCLibrary lib, ffi.Pointer<ObjCObject> other) {
+    return OtherClass._(other, lib);
+  }
+
+  static ForwardDeclaredClass getTheThing(ForwardDeclTestObjCLibrary _lib) {
+    final _ret =
+        _lib._objc_msgSend_19(_lib._class_OtherClass1, _lib._sel_getTheThing1);
+    return ForwardDeclaredClass._(_ret, _lib);
+  }
+
+  static OtherClass new1(ForwardDeclTestObjCLibrary _lib) {
+    final _ret = _lib._objc_msgSend_1(_lib._class_OtherClass1, _lib._sel_new1);
+    return OtherClass._(_ret, _lib);
+  }
+
+  static OtherClass alloc(ForwardDeclTestObjCLibrary _lib) {
+    final _ret =
+        _lib._objc_msgSend_1(_lib._class_OtherClass1, _lib._sel_alloc1);
+    return OtherClass._(_ret, _lib);
+  }
+}
+
+class ForwardDeclaredClass extends NSObject {
+  ForwardDeclaredClass._(
+      ffi.Pointer<ObjCObject> id, ForwardDeclTestObjCLibrary lib)
+      : super._(id, lib);
+
+  static ForwardDeclaredClass castFrom<T extends _ObjCWrapper>(T other) {
+    return ForwardDeclaredClass._(other._id, other._lib);
+  }
+
+  static ForwardDeclaredClass castFromPointer(
+      ForwardDeclTestObjCLibrary lib, ffi.Pointer<ObjCObject> other) {
+    return ForwardDeclaredClass._(other, lib);
+  }
+
+  static int get123(ForwardDeclTestObjCLibrary _lib) {
+    return _lib._objc_msgSend_18(
+        _lib._class_ForwardDeclaredClass1, _lib._sel_get1231);
+  }
+
+  static ForwardDeclaredClass new1(ForwardDeclTestObjCLibrary _lib) {
+    final _ret =
+        _lib._objc_msgSend_1(_lib._class_ForwardDeclaredClass1, _lib._sel_new1);
+    return ForwardDeclaredClass._(_ret, _lib);
+  }
+
+  static ForwardDeclaredClass alloc(ForwardDeclTestObjCLibrary _lib) {
+    final _ret = _lib._objc_msgSend_1(
+        _lib._class_ForwardDeclaredClass1, _lib._sel_alloc1);
+    return ForwardDeclaredClass._(_ret, _lib);
+  }
+}
+
+const int NSScannedOption = 1;
+
+const int NSCollectorDisabledOption = 2;
+
+const int NS_BLOCKS_AVAILABLE = 1;
+
+const int __COREFOUNDATION_CFAVAILABILITY__ = 1;
+
+const int __CF_ENUM_FIXED_IS_AVAILABLE = 1;
+
+const double NSFoundationVersionNumber10_0 = 397.4;
+
+const double NSFoundationVersionNumber10_1 = 425.0;
+
+const double NSFoundationVersionNumber10_1_1 = 425.0;
+
+const double NSFoundationVersionNumber10_1_2 = 425.0;
+
+const double NSFoundationVersionNumber10_1_3 = 425.0;
+
+const double NSFoundationVersionNumber10_1_4 = 425.0;
+
+const double NSFoundationVersionNumber10_2 = 462.0;
+
+const double NSFoundationVersionNumber10_2_1 = 462.0;
+
+const double NSFoundationVersionNumber10_2_2 = 462.0;
+
+const double NSFoundationVersionNumber10_2_3 = 462.0;
+
+const double NSFoundationVersionNumber10_2_4 = 462.0;
+
+const double NSFoundationVersionNumber10_2_5 = 462.0;
+
+const double NSFoundationVersionNumber10_2_6 = 462.0;
+
+const double NSFoundationVersionNumber10_2_7 = 462.7;
+
+const double NSFoundationVersionNumber10_2_8 = 462.7;
+
+const double NSFoundationVersionNumber10_3 = 500.0;
+
+const double NSFoundationVersionNumber10_3_1 = 500.0;
+
+const double NSFoundationVersionNumber10_3_2 = 500.3;
+
+const double NSFoundationVersionNumber10_3_3 = 500.54;
+
+const double NSFoundationVersionNumber10_3_4 = 500.56;
+
+const double NSFoundationVersionNumber10_3_5 = 500.56;
+
+const double NSFoundationVersionNumber10_3_6 = 500.56;
+
+const double NSFoundationVersionNumber10_3_7 = 500.56;
+
+const double NSFoundationVersionNumber10_3_8 = 500.56;
+
+const double NSFoundationVersionNumber10_3_9 = 500.58;
+
+const double NSFoundationVersionNumber10_4 = 567.0;
+
+const double NSFoundationVersionNumber10_4_1 = 567.0;
+
+const double NSFoundationVersionNumber10_4_2 = 567.12;
+
+const double NSFoundationVersionNumber10_4_3 = 567.21;
+
+const double NSFoundationVersionNumber10_4_4_Intel = 567.23;
+
+const double NSFoundationVersionNumber10_4_4_PowerPC = 567.21;
+
+const double NSFoundationVersionNumber10_4_5 = 567.25;
+
+const double NSFoundationVersionNumber10_4_6 = 567.26;
+
+const double NSFoundationVersionNumber10_4_7 = 567.27;
+
+const double NSFoundationVersionNumber10_4_8 = 567.28;
+
+const double NSFoundationVersionNumber10_4_9 = 567.29;
+
+const double NSFoundationVersionNumber10_4_10 = 567.29;
+
+const double NSFoundationVersionNumber10_4_11 = 567.36;
+
+const double NSFoundationVersionNumber10_5 = 677.0;
+
+const double NSFoundationVersionNumber10_5_1 = 677.1;
+
+const double NSFoundationVersionNumber10_5_2 = 677.15;
+
+const double NSFoundationVersionNumber10_5_3 = 677.19;
+
+const double NSFoundationVersionNumber10_5_4 = 677.19;
+
+const double NSFoundationVersionNumber10_5_5 = 677.21;
+
+const double NSFoundationVersionNumber10_5_6 = 677.22;
+
+const double NSFoundationVersionNumber10_5_7 = 677.24;
+
+const double NSFoundationVersionNumber10_5_8 = 677.26;
+
+const double NSFoundationVersionNumber10_6 = 751.0;
+
+const double NSFoundationVersionNumber10_6_1 = 751.0;
+
+const double NSFoundationVersionNumber10_6_2 = 751.14;
+
+const double NSFoundationVersionNumber10_6_3 = 751.21;
+
+const double NSFoundationVersionNumber10_6_4 = 751.29;
+
+const double NSFoundationVersionNumber10_6_5 = 751.42;
+
+const double NSFoundationVersionNumber10_6_6 = 751.53;
+
+const double NSFoundationVersionNumber10_6_7 = 751.53;
+
+const double NSFoundationVersionNumber10_6_8 = 751.62;
+
+const double NSFoundationVersionNumber10_7 = 833.1;
+
+const double NSFoundationVersionNumber10_7_1 = 833.1;
+
+const double NSFoundationVersionNumber10_7_2 = 833.2;
+
+const double NSFoundationVersionNumber10_7_3 = 833.24;
+
+const double NSFoundationVersionNumber10_7_4 = 833.25;
+
+const double NSFoundationVersionNumber10_8 = 945.0;
+
+const double NSFoundationVersionNumber10_8_1 = 945.0;
+
+const double NSFoundationVersionNumber10_8_2 = 945.11;
+
+const double NSFoundationVersionNumber10_8_3 = 945.16;
+
+const double NSFoundationVersionNumber10_8_4 = 945.18;
+
+const int NSFoundationVersionNumber10_9 = 1056;
+
+const int NSFoundationVersionNumber10_9_1 = 1056;
+
+const double NSFoundationVersionNumber10_9_2 = 1056.13;
+
+const double NSFoundationVersionNumber10_10 = 1151.16;
+
+const double NSFoundationVersionNumber10_10_1 = 1151.16;
+
+const double NSFoundationVersionNumber10_10_2 = 1152.14;
+
+const double NSFoundationVersionNumber10_10_3 = 1153.2;
+
+const double NSFoundationVersionNumber10_10_4 = 1153.2;
+
+const int NSFoundationVersionNumber10_10_5 = 1154;
+
+const int NSFoundationVersionNumber10_10_Max = 1199;
+
+const int NSFoundationVersionNumber10_11 = 1252;
+
+const double NSFoundationVersionNumber10_11_1 = 1255.1;
+
+const double NSFoundationVersionNumber10_11_2 = 1256.1;
+
+const double NSFoundationVersionNumber10_11_3 = 1256.1;
+
+const int NSFoundationVersionNumber10_11_4 = 1258;
+
+const int NSFoundationVersionNumber10_11_Max = 1299;
+
+const int __COREFOUNDATION_CFBASE__ = 1;
+
+const int TRUE = 1;
+
+const int FALSE = 0;
+
+const double kCFCoreFoundationVersionNumber10_0 = 196.4;
+
+const double kCFCoreFoundationVersionNumber10_0_3 = 196.5;
+
+const double kCFCoreFoundationVersionNumber10_1 = 226.0;
+
+const double kCFCoreFoundationVersionNumber10_1_1 = 226.0;
+
+const double kCFCoreFoundationVersionNumber10_1_2 = 227.2;
+
+const double kCFCoreFoundationVersionNumber10_1_3 = 227.2;
+
+const double kCFCoreFoundationVersionNumber10_1_4 = 227.3;
+
+const double kCFCoreFoundationVersionNumber10_2 = 263.0;
+
+const double kCFCoreFoundationVersionNumber10_2_1 = 263.1;
+
+const double kCFCoreFoundationVersionNumber10_2_2 = 263.1;
+
+const double kCFCoreFoundationVersionNumber10_2_3 = 263.3;
+
+const double kCFCoreFoundationVersionNumber10_2_4 = 263.3;
+
+const double kCFCoreFoundationVersionNumber10_2_5 = 263.5;
+
+const double kCFCoreFoundationVersionNumber10_2_6 = 263.5;
+
+const double kCFCoreFoundationVersionNumber10_2_7 = 263.5;
+
+const double kCFCoreFoundationVersionNumber10_2_8 = 263.5;
+
+const double kCFCoreFoundationVersionNumber10_3 = 299.0;
+
+const double kCFCoreFoundationVersionNumber10_3_1 = 299.0;
+
+const double kCFCoreFoundationVersionNumber10_3_2 = 299.0;
+
+const double kCFCoreFoundationVersionNumber10_3_3 = 299.3;
+
+const double kCFCoreFoundationVersionNumber10_3_4 = 299.31;
+
+const double kCFCoreFoundationVersionNumber10_3_5 = 299.31;
+
+const double kCFCoreFoundationVersionNumber10_3_6 = 299.32;
+
+const double kCFCoreFoundationVersionNumber10_3_7 = 299.33;
+
+const double kCFCoreFoundationVersionNumber10_3_8 = 299.33;
+
+const double kCFCoreFoundationVersionNumber10_3_9 = 299.35;
+
+const double kCFCoreFoundationVersionNumber10_4 = 368.0;
+
+const double kCFCoreFoundationVersionNumber10_4_1 = 368.1;
+
+const double kCFCoreFoundationVersionNumber10_4_2 = 368.11;
+
+const double kCFCoreFoundationVersionNumber10_4_3 = 368.18;
+
+const double kCFCoreFoundationVersionNumber10_4_4_Intel = 368.26;
+
+const double kCFCoreFoundationVersionNumber10_4_4_PowerPC = 368.25;
+
+const double kCFCoreFoundationVersionNumber10_4_5_Intel = 368.26;
+
+const double kCFCoreFoundationVersionNumber10_4_5_PowerPC = 368.25;
+
+const double kCFCoreFoundationVersionNumber10_4_6_Intel = 368.26;
+
+const double kCFCoreFoundationVersionNumber10_4_6_PowerPC = 368.25;
+
+const double kCFCoreFoundationVersionNumber10_4_7 = 368.27;
+
+const double kCFCoreFoundationVersionNumber10_4_8 = 368.27;
+
+const double kCFCoreFoundationVersionNumber10_4_9 = 368.28;
+
+const double kCFCoreFoundationVersionNumber10_4_10 = 368.28;
+
+const double kCFCoreFoundationVersionNumber10_4_11 = 368.31;
+
+const double kCFCoreFoundationVersionNumber10_5 = 476.0;
+
+const double kCFCoreFoundationVersionNumber10_5_1 = 476.0;
+
+const double kCFCoreFoundationVersionNumber10_5_2 = 476.1;
+
+const double kCFCoreFoundationVersionNumber10_5_3 = 476.13;
+
+const double kCFCoreFoundationVersionNumber10_5_4 = 476.14;
+
+const double kCFCoreFoundationVersionNumber10_5_5 = 476.15;
+
+const double kCFCoreFoundationVersionNumber10_5_6 = 476.17;
+
+const double kCFCoreFoundationVersionNumber10_5_7 = 476.18;
+
+const double kCFCoreFoundationVersionNumber10_5_8 = 476.19;
+
+const double kCFCoreFoundationVersionNumber10_6 = 550.0;
+
+const double kCFCoreFoundationVersionNumber10_6_1 = 550.0;
+
+const double kCFCoreFoundationVersionNumber10_6_2 = 550.13;
+
+const double kCFCoreFoundationVersionNumber10_6_3 = 550.19;
+
+const double kCFCoreFoundationVersionNumber10_6_4 = 550.29;
+
+const double kCFCoreFoundationVersionNumber10_6_5 = 550.42;
+
+const double kCFCoreFoundationVersionNumber10_6_6 = 550.42;
+
+const double kCFCoreFoundationVersionNumber10_6_7 = 550.42;
+
+const double kCFCoreFoundationVersionNumber10_6_8 = 550.43;
+
+const double kCFCoreFoundationVersionNumber10_7 = 635.0;
+
+const double kCFCoreFoundationVersionNumber10_7_1 = 635.0;
+
+const double kCFCoreFoundationVersionNumber10_7_2 = 635.15;
+
+const double kCFCoreFoundationVersionNumber10_7_3 = 635.19;
+
+const double kCFCoreFoundationVersionNumber10_7_4 = 635.21;
+
+const double kCFCoreFoundationVersionNumber10_7_5 = 635.21;
+
+const double kCFCoreFoundationVersionNumber10_8 = 744.0;
+
+const double kCFCoreFoundationVersionNumber10_8_1 = 744.0;
+
+const double kCFCoreFoundationVersionNumber10_8_2 = 744.12;
+
+const double kCFCoreFoundationVersionNumber10_8_3 = 744.18;
+
+const double kCFCoreFoundationVersionNumber10_8_4 = 744.19;
+
+const double kCFCoreFoundationVersionNumber10_9 = 855.11;
+
+const double kCFCoreFoundationVersionNumber10_9_1 = 855.11;
+
+const double kCFCoreFoundationVersionNumber10_9_2 = 855.14;
+
+const double kCFCoreFoundationVersionNumber10_10 = 1151.16;
+
+const double kCFCoreFoundationVersionNumber10_10_1 = 1151.16;
+
+const int kCFCoreFoundationVersionNumber10_10_2 = 1152;
+
+const double kCFCoreFoundationVersionNumber10_10_3 = 1153.18;
+
+const double kCFCoreFoundationVersionNumber10_10_4 = 1153.18;
+
+const double kCFCoreFoundationVersionNumber10_10_5 = 1153.18;
+
+const int kCFCoreFoundationVersionNumber10_10_Max = 1199;
+
+const int kCFCoreFoundationVersionNumber10_11 = 1253;
+
+const double kCFCoreFoundationVersionNumber10_11_1 = 1255.1;
+
+const double kCFCoreFoundationVersionNumber10_11_2 = 1256.14;
+
+const double kCFCoreFoundationVersionNumber10_11_3 = 1256.14;
+
+const double kCFCoreFoundationVersionNumber10_11_4 = 1258.1;
+
+const int kCFCoreFoundationVersionNumber10_11_Max = 1299;
+
+const int ISA_PTRAUTH_DISCRIMINATOR = 27361;
diff --git a/pkgs/ffigen/test/native_objc_test/forward_decl_config.yaml b/pkgs/ffigen/test/native_objc_test/forward_decl_config.yaml
new file mode 100644
index 0000000..73b0aee
--- /dev/null
+++ b/pkgs/ffigen/test/native_objc_test/forward_decl_config.yaml
@@ -0,0 +1,13 @@
+name: ForwardDeclTestObjCLibrary
+description: 'Test that forward declared ObjC classes are correctly filled'
+language: objc
+output: 'test/native_objc_test/forward_decl_bindings.dart'
+functions:
+  exclude:
+    - '.*'
+headers:
+  entry-points:
+    - 'test/native_objc_test/forward_decl_test.h'
+    - 'test/native_objc_test/forward_decl_test.m'
+preamble: |
+  // ignore_for_file: camel_case_types, non_constant_identifier_names, unused_element, unused_field
diff --git a/pkgs/ffigen/test/native_objc_test/forward_decl_test.dart b/pkgs/ffigen/test/native_objc_test/forward_decl_test.dart
new file mode 100644
index 0000000..41b7181
--- /dev/null
+++ b/pkgs/ffigen/test/native_objc_test/forward_decl_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2022, 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:ffigen/ffigen.dart';
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+import 'package:yaml/yaml.dart';
+import '../test_utils.dart';
+import 'forward_decl_bindings.dart';
+
+void main() {
+  late ForwardDeclTestObjCLibrary lib;
+
+  group('forward decl', () {
+    setUpAll(() {
+      logWarnings();
+      final dylib = File('test/native_objc_test/forward_decl_test.dylib');
+      verifySetupFile(dylib);
+      lib =
+          ForwardDeclTestObjCLibrary(DynamicLibrary.open(dylib.absolute.path));
+    });
+
+    test('generate_bindings', () {
+      final config = Config.fromYaml(loadYaml(File(
+              path.join('test', 'native_objc_test', 'forward_decl_config.yaml'))
+          .readAsStringSync()) as YamlMap);
+      final library = parse(config);
+      final file = File(
+        path.join('test', 'debug_generated', 'forward_decl_test.dart'),
+      );
+      library.generateFile(file);
+
+      try {
+        final actual = file.readAsStringSync();
+        final expected = File(path.join(config.output)).readAsStringSync();
+        expect(actual, expected);
+        if (file.existsSync()) {
+          file.delete();
+        }
+      } catch (e) {
+        print('Failed test: Debug generated file: ${file.absolute.path}');
+        rethrow;
+      }
+    });
+
+    test('Forward declared class', () {
+      expect(ForwardDeclaredClass.get123(lib), 123);
+    });
+  });
+}
diff --git a/pkgs/ffigen/test/native_objc_test/forward_decl_test.h b/pkgs/ffigen/test/native_objc_test/forward_decl_test.h
new file mode 100644
index 0000000..4336b35
--- /dev/null
+++ b/pkgs/ffigen/test/native_objc_test/forward_decl_test.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2022, 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 <Foundation/NSObject.h>
+
+@class ForwardDeclaredClass;
+
+@interface OtherClass : NSObject
++ (ForwardDeclaredClass*) getTheThing;
+@end
diff --git a/pkgs/ffigen/test/native_objc_test/forward_decl_test.m b/pkgs/ffigen/test/native_objc_test/forward_decl_test.m
new file mode 100644
index 0000000..69c8f66
--- /dev/null
+++ b/pkgs/ffigen/test/native_objc_test/forward_decl_test.m
@@ -0,0 +1,15 @@
+// Copyright (c) 2022, 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 <Foundation/NSObject.h>
+
+@interface ForwardDeclaredClass : NSObject
++ (int32_t)get123;
+@end
+
+@implementation ForwardDeclaredClass
++ (int32_t)get123 {
+  return 123;
+}
+@end
diff --git a/pkgs/ffigen/test/native_objc_test/setup.dart b/pkgs/ffigen/test/native_objc_test/setup.dart
index 2681389..7485c91 100644
--- a/pkgs/ffigen/test/native_objc_test/setup.dart
+++ b/pkgs/ffigen/test/native_objc_test/setup.dart
@@ -38,6 +38,7 @@
   await _buildLib('method_test.m', 'method_test.dylib');
   await _buildLib('nullable_test.m', 'nullable_test.dylib');
   await _buildLib('property_test.m', 'property_test.dylib');
+  await _buildLib('forward_decl_test.m', 'forward_decl_test.dylib');
   await _buildLib('string_test.m', 'string_test.dylib');
   await _buildLib('block_test.m', 'block_test.dylib');
 }
diff --git a/pkgs/ffigen/test/regen.dart b/pkgs/ffigen/test/regen.dart
index d77d3ca..ff2909e 100644
--- a/pkgs/ffigen/test/regen.dart
+++ b/pkgs/ffigen/test/regen.dart
@@ -100,6 +100,11 @@
   );
 
   await _regenConfig(
+    File('test/native_objc_test/forward_decl_config.yaml'),
+    File('test/native_objc_test/forward_decl_bindings.dart'),
+  );
+
+  await _regenConfig(
     File('test/native_objc_test/string_config.yaml'),
     File('test/native_objc_test/string_bindings.dart'),
   );