Fix missing typedef dependencies (#90)

* Fix missing typedef dependencies of func and struct

* added tests

* update version, changelog
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f496c70..5db8023 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 0.2.3+1
+- Fixed missing typedefs of nested function pointers.
+
 # 0.2.3
 - Fixed parsing structs with bitfields, all members of structs with bit field members will now be removed. See [#84](https://github.com/dart-lang/ffigen/issues/84)
 
diff --git a/lib/src/code_generator/binding.dart b/lib/src/code_generator/binding.dart
index b4267b8..4f24d58 100644
--- a/lib/src/code_generator/binding.dart
+++ b/lib/src/code_generator/binding.dart
@@ -31,7 +31,7 @@
   });
 
   /// Return typedef dependencies.
-  List<Typedef> getTypedefDependencies(Writer w);
+  List<Typedef> getTypedefDependencies(Writer w) => const [];
 
   /// Converts a Binding to its actual string representation.
   ///
diff --git a/lib/src/code_generator/constant.dart b/lib/src/code_generator/constant.dart
index 41572ab..617f2d7 100644
--- a/lib/src/code_generator/constant.dart
+++ b/lib/src/code_generator/constant.dart
@@ -2,7 +2,6 @@
 // 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:ffigen/src/code_generator/typedef.dart';
 import 'package:meta/meta.dart';
 
 import 'binding.dart';
@@ -58,7 +57,4 @@
     return BindingString(
         type: BindingStringType.constant, string: s.toString());
   }
-
-  @override
-  List<Typedef> getTypedefDependencies(Writer w) => const [];
 }
diff --git a/lib/src/code_generator/enum_class.dart b/lib/src/code_generator/enum_class.dart
index 9404c4b..867133a 100644
--- a/lib/src/code_generator/enum_class.dart
+++ b/lib/src/code_generator/enum_class.dart
@@ -2,7 +2,6 @@
 // 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:ffigen/src/code_generator/typedef.dart';
 import 'package:meta/meta.dart';
 
 import 'binding.dart';
@@ -71,9 +70,6 @@
     return BindingString(
         type: BindingStringType.enumClass, string: s.toString());
   }
-
-  @override
-  List<Typedef> getTypedefDependencies(Writer w) => const [];
 }
 
 /// Represents a single value in an enum.
diff --git a/lib/src/code_generator/func.dart b/lib/src/code_generator/func.dart
index d29abcb..c1f444b 100644
--- a/lib/src/code_generator/func.dart
+++ b/lib/src/code_generator/func.dart
@@ -66,14 +66,15 @@
       // Add typedef's required by return type.
       final returnTypeBase = returnType.getBaseType();
       if (returnTypeBase.broadType == BroadType.NativeFunction) {
-        _typedefDependencies.add(returnTypeBase.nativeFunc);
+        _typedefDependencies
+            .addAll(returnTypeBase.nativeFunc.getDependencies());
       }
 
       // Add typedef's required by parameters.
       for (final p in parameters) {
         final base = p.type.getBaseType();
         if (base.broadType == BroadType.NativeFunction) {
-          _typedefDependencies.add(base.nativeFunc);
+          _typedefDependencies.addAll(base.nativeFunc.getDependencies());
         }
       }
       // Add C function typedef.
diff --git a/lib/src/code_generator/global.dart b/lib/src/code_generator/global.dart
index 79478fa..817844d 100644
--- a/lib/src/code_generator/global.dart
+++ b/lib/src/code_generator/global.dart
@@ -2,7 +2,6 @@
 // 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:ffigen/src/code_generator/typedef.dart';
 import 'package:meta/meta.dart';
 
 import 'binding.dart';
@@ -54,7 +53,4 @@
 
     return BindingString(type: BindingStringType.global, string: s.toString());
   }
-
-  @override
-  List<Typedef> getTypedefDependencies(Writer w) => const [];
 }
diff --git a/lib/src/code_generator/struc.dart b/lib/src/code_generator/struc.dart
index 8cd6df3..a17649b 100644
--- a/lib/src/code_generator/struc.dart
+++ b/lib/src/code_generator/struc.dart
@@ -72,7 +72,7 @@
       for (final m in members) {
         final base = m.type.getBaseType();
         if (base.broadType == BroadType.NativeFunction) {
-          _typedefDependencies.add(base.nativeFunc);
+          _typedefDependencies.addAll(base.nativeFunc.getDependencies());
         }
       }
     }
diff --git a/lib/src/code_generator/typedef.dart b/lib/src/code_generator/typedef.dart
index 0cf7f84..e0c3c7a 100644
--- a/lib/src/code_generator/typedef.dart
+++ b/lib/src/code_generator/typedef.dart
@@ -38,6 +38,19 @@
     List<Parameter> parameters,
   }) : parameters = parameters ?? [];
 
+  /// Returns the [Typedef] dependencies required by this typedef including itself.
+  List<Typedef> getDependencies() {
+    final dep = <Typedef>[];
+    for (final p in parameters) {
+      final base = p.type.getBaseType();
+      if (base.broadType == BroadType.NativeFunction) {
+        dep.addAll(base.nativeFunc.getDependencies());
+      }
+    }
+    dep.add(this);
+    return dep;
+  }
+
   String toTypedefString(Writer w) {
     final s = StringBuffer();
     if (dartDoc != null) {
diff --git a/pubspec.yaml b/pubspec.yaml
index 9695da5..f87d8eb 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE file.
 
 name: ffigen
-version: 0.2.3
+version: 0.2.3+1
 homepage: https://github.com/dart-lang/ffigen
 description: Experimental generator for FFI bindings, using LibClang to parse C/C++ header files.
 
diff --git a/test/header_parser_tests/native_func_typedef.h b/test/header_parser_tests/native_func_typedef.h
new file mode 100644
index 0000000..38551e9
--- /dev/null
+++ b/test/header_parser_tests/native_func_typedef.h
@@ -0,0 +1,10 @@
+// Copyright (c) 2020, 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.
+
+struct struc
+{
+    void (*unnamed1)(void (*unnamed2)());
+};
+
+void func(void (*unnamed1)(void (*unnamed2)()));
diff --git a/test/header_parser_tests/native_func_typedef_test.dart b/test/header_parser_tests/native_func_typedef_test.dart
new file mode 100644
index 0000000..c2826d4
--- /dev/null
+++ b/test/header_parser_tests/native_func_typedef_test.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2020, 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 'dart:io';
+
+import 'package:ffigen/src/code_generator.dart';
+import 'package:ffigen/src/header_parser.dart' as parser;
+import 'package:ffigen/src/config_provider.dart';
+import 'package:test/test.dart';
+import 'package:yaml/yaml.dart' as yaml;
+import 'package:ffigen/src/strings.dart' as strings;
+
+import '../test_utils.dart';
+
+Library actual;
+void main() {
+  group('unnamed_enums_test', () {
+    setUpAll(() {
+      logWarnings();
+      actual = parser.parse(
+        Config.fromYaml(yaml.loadYaml('''
+${strings.name}: 'NativeLibrary'
+${strings.description}: 'Unnamed Enums Test'
+${strings.output}: 'unused'
+${strings.headers}:
+  ${strings.entryPoints}:
+    - 'test/header_parser_tests/native_func_typedef.h'
+        ''') as yaml.YamlMap),
+      );
+    });
+
+    test('Expected bindings', () {
+      final gen = actual.generate();
+      // Writing to file for debug purpose.
+      final file =
+          File('test/debug_generated/native_func_typedef_test-output.dart');
+
+      try {
+        expect(gen, '''// AUTO GENERATED FILE, DO NOT EDIT.
+// 
+// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+/// Unnamed Enums Test
+class NativeLibrary{
+/// Holds the Dynamic library.
+final ffi.DynamicLibrary _dylib;
+
+/// The symbols are looked up in [dynamicLibrary].
+NativeLibrary(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary;
+
+void func(
+  ffi.Pointer<ffi.NativeFunction<_typedefC_4>> unnamed1,
+) {
+_func ??= _dylib.lookupFunction<_c_func,_dart_func>('func');
+  return _func(
+    unnamed1,
+  );
+}
+_dart_func _func;
+
+}
+
+class struc extends ffi.Struct{
+  ffi.Pointer<ffi.NativeFunction<_typedefC_2>> unnamed1;
+
+}
+
+typedef _typedefC_3 = ffi.Void Function(
+);
+
+typedef _typedefC_4 = ffi.Void Function(
+  ffi.Pointer<ffi.NativeFunction<_typedefC_3>> ,
+);
+
+typedef _c_func = ffi.Void Function(
+  ffi.Pointer<ffi.NativeFunction<_typedefC_4>> unnamed1,
+);
+
+typedef _dart_func = void Function(
+  ffi.Pointer<ffi.NativeFunction<_typedefC_4>> unnamed1,
+);
+
+typedef _typedefC_1 = ffi.Void Function(
+);
+
+typedef _typedefC_2 = ffi.Void Function(
+  ffi.Pointer<ffi.NativeFunction<_typedefC_1>> ,
+);
+
+''');
+        if (file.existsSync()) {
+          file.delete();
+        }
+      } catch (e) {
+        file.writeAsStringSync(gen);
+        print('Failed test, Debug output: ${file.absolute?.path}');
+        rethrow;
+      }
+    });
+  });
+}