diff --git a/pkgs/ffigen/lib/src/code_generator/enum_class.dart b/pkgs/ffigen/lib/src/code_generator/enum_class.dart index 8e1ea9822e..9c24c6b6ad 100644 --- a/pkgs/ffigen/lib/src/code_generator/enum_class.dart +++ b/pkgs/ffigen/lib/src/code_generator/enum_class.dart @@ -264,10 +264,7 @@ class EnumClass extends BindingType { } @override - String getCType(Writer w) { - w.usedEnumCTypes.add(this); - return nativeType.getCType(w); - } + String getCType(Writer w) => nativeType.getCType(w); @override String getFfiDartType(Writer w) => nativeType.getFfiDartType(w); diff --git a/pkgs/ffigen/lib/src/code_generator/writer.dart b/pkgs/ffigen/lib/src/code_generator/writer.dart index f35c0c1916..b070898a01 100644 --- a/pkgs/ffigen/lib/src/code_generator/writer.dart +++ b/pkgs/ffigen/lib/src/code_generator/writer.dart @@ -7,6 +7,7 @@ import 'package:path/path.dart' as p; import '../code_generator.dart'; import '../context.dart'; import '../strings.dart' as strings; +import '../visitor/visitor.dart'; import 'unique_namer.dart'; import 'utils.dart'; @@ -39,10 +40,6 @@ class Writer { final List nativeEntryPoints; - /// Tracks the enums for which enumType.getCType is called. Reset everytime - /// [generate] is called. - final usedEnumCTypes = {}; - String? _ffiLibraryPrefix; String get ffiLibraryPrefix { if (_ffiLibraryPrefix != null) { @@ -228,9 +225,6 @@ class Writer { // Reset unique namers to initial state. _resetUniqueNamers(); - // Reset [usedEnumCTypes]. - usedEnumCTypes.clear(); - // Write file header (if any). if (header != null) { result.writeln(header); @@ -325,17 +319,23 @@ class Writer { result.write(s); // Warn about Enum usage in API surface. - if (!silenceEnumWarning && usedEnumCTypes.isNotEmpty) { - final names = usedEnumCTypes.map((e) => e.originalName).toList()..sort(); - context.logger.severe( - 'The integer type used for enums is ' - 'implementation-defined. FFIgen tries to mimic the integer sizes ' - 'chosen by the most common compilers for the various OS and ' - 'architecture combinations. To prevent any crashes, remove the ' - 'enums from your API surface. To rely on the (unsafe!) mimicking, ' - 'you can silence this warning by adding silence-enum-warning: true ' - 'to the FFIgen config. Affected enums:\n\t${names.join('\n\t')}', + if (!silenceEnumWarning) { + final notEnums = _allBindings.where( + (b) => b is! Type || (b as Type).typealiasType is! EnumClass, ); + final usedEnums = visit(context, _FindEnumsVisitation(), notEnums).enums; + if (usedEnums.isNotEmpty) { + final names = usedEnums.map((e) => e.originalName).toList()..sort(); + context.logger.severe( + 'The integer type used for enums is ' + 'implementation-defined. FFIgen tries to mimic the integer sizes ' + 'chosen by the most common compilers for the various OS and ' + 'architecture combinations. To prevent any crashes, remove the ' + 'enums from your API surface. To rely on the (unsafe!) mimicking, ' + 'you can silence this warning by adding silence-enum-warning: true ' + 'to the FFIgen config. Affected enums:\n\t${names.join('\n\t')}', + ); + } } _canGenerateSymbolOutput = true; @@ -583,3 +583,13 @@ class _SymbolAddressUnit { _SymbolAddressUnit(this.type, this.name, this.ptrName, this.native); } + +class _FindEnumsVisitation extends Visitation { + final enums = {}; + + @override + void visitEnumClass(EnumClass node) { + node.visitChildren(visitor); + enums.add(node); + } +} diff --git a/pkgs/ffigen/test/large_integration_tests/large_test.dart b/pkgs/ffigen/test/large_integration_tests/large_test.dart index 13e1d8ab09..919fe661e0 100644 --- a/pkgs/ffigen/test/large_integration_tests/large_test.dart +++ b/pkgs/ffigen/test/large_integration_tests/large_test.dart @@ -24,8 +24,10 @@ void main() { 'libclang', 'include', ); + final logArr = []; + final logger = logToArray(logArr, Level.SEVERE); final config = FfiGen( - Logger.root, + logger, wrapperName: 'LibClang', wrapperDocComment: 'Bindings to LibClang.', output: Uri.file('unused'), @@ -75,6 +77,44 @@ void main() { codeNormalizer: (code) => code.replaceAll(RegExp('[^\n]*///[^\n]*@[^\n]*\n'), ''), ); + + const expectedEnumWarnings = [ + 'CXAvailabilityKind', + 'CXCallingConv', + 'CXChildVisitResult', + 'CXCompletionChunkKind', + 'CXCursorKind', + 'CXDiagnosticSeverity', + 'CXErrorCode', + 'CXEvalResultKind', + 'CXIdxAttrKind', + 'CXIdxEntityCXXTemplateKind', + 'CXIdxEntityKind', + 'CXIdxEntityLanguage', + 'CXIdxEntityRefKind', + 'CXIdxObjCContainerKind', + 'CXLanguageKind', + 'CXLinkageKind', + 'CXLoadDiag_Error', + 'CXPrintingPolicyProperty', + 'CXRefQualifierKind', + 'CXResult', + 'CXSymbolRole', + 'CXTLSKind', + 'CXTUResourceUsageKind', + 'CXTemplateArgumentKind', + 'CXTokenKind', + 'CXTypeKind', + 'CXTypeNullabilityKind', + 'CXVisibilityKind', + 'CXVisitorResult', + 'CX_CXXAccessSpecifier', + 'CX_StorageClass', + ]; + final actualLogs = logArr.join('\n'); + for (final e in expectedEnumWarnings) { + expect(actualLogs, contains(e)); + } }); test('CJSON test', () {