[ffigen] Fix error caused by duplicate declaration names and collision with ffi library prefix (#200)
diff --git a/pkgs/ffigen/CHANGELOG.md b/pkgs/ffigen/CHANGELOG.md index b037c39..1b811cc 100644 --- a/pkgs/ffigen/CHANGELOG.md +++ b/pkgs/ffigen/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/pkgs/ffigen/lib/src/code_generator/library.dart b/pkgs/ffigen/lib/src/code_generator/library.dart index d83a19d..e37a062 100644 --- a/pkgs/ffigen/lib/src/code_generator/library.dart +++ b/pkgs/ffigen/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/pkgs/ffigen/lib/src/code_generator/writer.dart b/pkgs/ffigen/lib/src/code_generator/writer.dart index 03c3647..10d1d57 100644 --- a/pkgs/ffigen/lib/src/code_generator/writer.dart +++ b/pkgs/ffigen/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/pkgs/ffigen/pubspec.yaml b/pkgs/ffigen/pubspec.yaml index deb1c68..d5ad721 100644 --- a/pkgs/ffigen/pubspec.yaml +++ b/pkgs/ffigen/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/pkgs/ffigen/test/collision_tests/decl_decl_collision_test.dart b/pkgs/ffigen/test/collision_tests/decl_decl_collision_test.dart index 554795e..fb6645f 100644 --- a/pkgs/ffigen/test/collision_tests/decl_decl_collision_test.dart +++ b/pkgs/ffigen/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());