Fix error caused by duplicate declaration names and collision with ffi library prefix (#200)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index b037c39..1b811cc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+# 2.4.2
+- Fix issues due to declarations having duplicate names.
+- Fix name conflict of declaration with ffi library prefix.
+- Fix `char` not being recognized on platforms where it's unsigned by default.
+
 # 2.4.1
 - Added `/usr/lib` to default dynamic library location for linux.
 
diff --git a/lib/src/code_generator/library.dart b/lib/src/code_generator/library.dart
index d83a19d..e37a062 100644
--- a/lib/src/code_generator/library.dart
+++ b/lib/src/code_generator/library.dart
@@ -31,24 +31,17 @@
   }) {
     if (sort) _sort();
 
+    /// Handle any declaration-declaration name conflicts.
+    final declConflictHandler = UniqueNamer({});
+    for (final b in bindings) {
+      _warnIfPrivateDeclaration(b);
+      _resolveIfNameConflicts(declConflictHandler, b);
+    }
+
     // Seperate bindings which require lookup.
     final lookUpBindings = bindings.whereType<LookUpBinding>().toList();
     final noLookUpBindings = bindings.whereType<NoLookUpBinding>().toList();
 
-    /// Handle any declaration-declaration name conflict in [lookUpBindings].
-    final lookUpDeclConflictHandler = UniqueNamer({});
-    for (final b in lookUpBindings) {
-      _warnIfPrivateDeclaration(b);
-      _resolveIfNameConflicts(lookUpDeclConflictHandler, b);
-    }
-
-    /// Handle any declaration-declaration name conflict in [noLookUpBindings].
-    final noLookUpDeclConflictHandler = UniqueNamer({});
-    for (final b in noLookUpBindings) {
-      _warnIfPrivateDeclaration(b);
-      _resolveIfNameConflicts(noLookUpDeclConflictHandler, b);
-    }
-
     _writer = Writer(
       lookUpBindings: lookUpBindings,
       noLookUpBindings: noLookUpBindings,
diff --git a/lib/src/code_generator/writer.dart b/lib/src/code_generator/writer.dart
index 03c3647..10d1d57 100644
--- a/lib/src/code_generator/writer.dart
+++ b/lib/src/code_generator/writer.dart
@@ -70,23 +70,42 @@
     final allLevelsUniqueNamer = UniqueNamer(allNameSet);
 
     /// Wrapper class name must be unique among all names.
-    _className = allLevelsUniqueNamer.makeUnique(className);
-    _initialWrapperLevelUniqueNamer.markUsed(_className);
-    _initialTopLevelUniqueNamer.markUsed(_className);
+    _className = _resolveNameConflict(
+      name: className,
+      makeUnique: allLevelsUniqueNamer,
+      markUsed: [_initialWrapperLevelUniqueNamer, _initialTopLevelUniqueNamer],
+    );
 
-    /// [_ffiLibraryPrefix] should be unique in top level.
-    _ffiLibraryPrefix = _initialTopLevelUniqueNamer.makeUnique('ffi');
+    /// [_ffiLibraryPrefix] should be unique unique among all names.
+    _ffiLibraryPrefix = _resolveNameConflict(
+      name: 'ffi',
+      makeUnique: allLevelsUniqueNamer,
+      markUsed: [_initialWrapperLevelUniqueNamer, _initialTopLevelUniqueNamer],
+    );
 
     /// [_lookupFuncIdentifier] should be unique in top level.
-    _lookupFuncIdentifier = _initialTopLevelUniqueNamer.makeUnique('_lookup');
+    _lookupFuncIdentifier = _resolveNameConflict(
+      name: '_lookup',
+      makeUnique: _initialTopLevelUniqueNamer,
+      markUsed: [_initialTopLevelUniqueNamer],
+    );
 
     /// Resolve name conflicts of identifiers used for SymbolAddresses.
-    _symbolAddressClassName =
-        allLevelsUniqueNamer.makeUnique('_SymbolAddresses');
-    _symbolAddressVariableName =
-        _initialWrapperLevelUniqueNamer.makeUnique('addresses');
-    _symbolAddressLibraryVarName =
-        _initialWrapperLevelUniqueNamer.makeUnique('_library');
+    _symbolAddressClassName = _resolveNameConflict(
+      name: '_SymbolAddresses',
+      makeUnique: allLevelsUniqueNamer,
+      markUsed: [_initialWrapperLevelUniqueNamer, _initialTopLevelUniqueNamer],
+    );
+    _symbolAddressVariableName = _resolveNameConflict(
+      name: 'addresses',
+      makeUnique: _initialWrapperLevelUniqueNamer,
+      markUsed: [_initialWrapperLevelUniqueNamer],
+    );
+    _symbolAddressLibraryVarName = _resolveNameConflict(
+      name: '_library',
+      makeUnique: _initialWrapperLevelUniqueNamer,
+      markUsed: [_initialWrapperLevelUniqueNamer],
+    );
 
     /// Finding a unique prefix for Array Helper Classes and store into
     /// [_arrayHelperClassPrefix].
@@ -105,6 +124,20 @@
     _resetUniqueNamersNamers();
   }
 
+  /// Resolved name conflict using [makeUnique] and marks the result as used in
+  /// all [markUsed].
+  String _resolveNameConflict({
+    required String name,
+    required UniqueNamer makeUnique,
+    List<UniqueNamer> markUsed = const [],
+  }) {
+    final s = makeUnique.makeUnique(name);
+    for (final un in markUsed) {
+      un.markUsed(s);
+    }
+    return s;
+  }
+
   /// Resets the namers to initial state. Namers are reset before generating.
   void _resetUniqueNamersNamers() {
     _topLevelUniqueNamer = _initialTopLevelUniqueNamer.clone();
diff --git a/pubspec.yaml b/pubspec.yaml
index deb1c68..d5ad721 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: 2.4.1
+version: 2.4.2
 homepage: https://github.com/dart-lang/ffigen
 description: Generator for FFI bindings, using LibClang to parse C header files.
 
diff --git a/test/collision_tests/decl_decl_collision_test.dart b/test/collision_tests/decl_decl_collision_test.dart
index 554795e..fb6645f 100644
--- a/test/collision_tests/decl_decl_collision_test.dart
+++ b/test/collision_tests/decl_decl_collision_test.dart
@@ -36,6 +36,20 @@
           rawType: 'int',
           rawValue: '0',
         ),
+
+        /// Conflicts across declarations.
+        Struc(name: 'testCrossDecl'),
+        Func(
+            name: 'testCrossDecl',
+            returnType: Type.nativeType(SupportedNativeType.Void)),
+        Constant(name: 'testCrossDecl', rawValue: '0', rawType: 'int'),
+        EnumClass(name: 'testCrossDecl'),
+
+        /// Conflicts with ffi library prefix, name of prefix is changed.
+        Struc(name: 'ffi'),
+        Func(
+            name: 'ffi_1',
+            returnType: Type.nativeType(SupportedNativeType.Void)),
       ]);
       final l2 = Library(name: 'Bindings', bindings: [
         Struc(name: 'TestStruc'),
@@ -62,6 +76,17 @@
           rawType: 'int',
           rawValue: '0',
         ),
+        Struc(name: 'testCrossDecl', originalName: 'testCrossDecl'),
+        Func(
+            name: 'testCrossDecl_1',
+            originalName: 'testCrossDecl',
+            returnType: Type.nativeType(SupportedNativeType.Void)),
+        Constant(name: 'testCrossDecl_2', rawValue: '0', rawType: 'int'),
+        EnumClass(name: 'testCrossDecl_3'),
+        Struc(name: 'ffi'),
+        Func(
+            name: 'ffi_1',
+            returnType: Type.nativeType(SupportedNativeType.Void)),
       ]);
 
       expect(l1.generate(), l2.generate());