Added workaround to map typedef names to a NativeType. (#119)
* Iterate over all typedefs rather than jumping to the base type.
* Added typedef-map to config.
* Updated version, changelog, and readme.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d24647f..38c346e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 1.1.0
+- `typedef-map` can now be used to map a typedef name to a native type directly.
+
# 1.0.6
- Fixed missing typedefs nested in another typedef's return types.
diff --git a/README.md b/README.md
index 4c5f335..2bc7aa6 100644
--- a/README.md
+++ b/README.md
@@ -244,6 +244,20 @@
</td>
</tr>
<tr>
+ <td>typedef-map</td>
+ <td>Map typedefs to Native Types.<br> Values can only be
+ <i>Void, Uint8, Int8, Uint16, Int16, Uint32, Int32, Uint64, Int64, IntPtr, Float and Double.</i>
+ </td>
+ <td>
+
+```yaml
+typedef-map:
+ 'my_custom_type': 'IntPtr'
+ 'size_t': 'Int64'
+```
+ </td>
+ </tr>
+ <tr>
<td>size-map</td>
<td>Size of integers to use (in bytes).<br>
<b>The defaults (see example) <i>may</i> not be portable on all OS.
diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart
index ad8db21..eae3edc 100644
--- a/lib/src/config_provider/config.dart
+++ b/lib/src/config_provider/config.dart
@@ -59,6 +59,11 @@
bool get useSupportedTypedefs => _useSupportedTypedefs;
bool _useSupportedTypedefs;
+ /// Stores typedef name to NativeType mappings specified by user.
+ Map<String, SupportedNativeType> get typedefNativeTypeMappings =>
+ _typedefNativeTypeMappings;
+ Map<String, SupportedNativeType> _typedefNativeTypeMappings;
+
/// Extracted Doc comment type.
CommentType get commentType => _commentType;
CommentType _commentType;
@@ -223,6 +228,13 @@
}
},
),
+ strings.typedefmap: Specification<Map<String, SupportedNativeType>>(
+ validator: typedefmapValidator,
+ extractor: typedefmapExtractor,
+ defaultValue: () => <String, SupportedNativeType>{},
+ extractedResult: (dynamic result) => _typedefNativeTypeMappings =
+ result as Map<String, SupportedNativeType>,
+ ),
strings.sort: Specification<bool>(
requirement: Requirement.no,
validator: booleanValidator,
diff --git a/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart
index 1400c2f..3ed5767 100644
--- a/lib/src/config_provider/spec_utils.dart
+++ b/lib/src/config_provider/spec_utils.dart
@@ -71,6 +71,37 @@
return true;
}
+Map<String, SupportedNativeType> typedefmapExtractor(dynamic yamlConfig) {
+ final resultMap = <String, SupportedNativeType>{};
+ final typedefmap = yamlConfig as YamlMap;
+ if (typedefmap != null) {
+ for (final typeName in typedefmap.keys) {
+ if (typedefmap[typeName] is String &&
+ strings.supportedNativeType_mappings
+ .containsKey(typedefmap[typeName])) {
+ // Map this typename to specified supportedNativeType.
+ resultMap[typeName as String] =
+ strings.supportedNativeType_mappings[typedefmap[typeName]];
+ }
+ }
+ }
+ return resultMap;
+}
+
+bool typedefmapValidator(String name, dynamic yamlConfig) {
+ if (!checkType<YamlMap>([name], yamlConfig)) {
+ return false;
+ }
+ for (final value in (yamlConfig as YamlMap).values) {
+ if (value is! String ||
+ !strings.supportedNativeType_mappings.containsKey(value)) {
+ _logger.severe("Unknown value of subkey '$value' in '$name'.");
+ }
+ }
+
+ return true;
+}
+
List<String> compilerOptsExtractor(dynamic value) =>
(value as String)?.split(' ');
diff --git a/lib/src/header_parser/type_extractor/extractor.dart b/lib/src/header_parser/type_extractor/extractor.dart
index f2ec345..eedb119 100644
--- a/lib/src/header_parser/type_extractor/extractor.dart
+++ b/lib/src/header_parser/type_extractor/extractor.dart
@@ -30,9 +30,13 @@
pt.dispose();
return Type.pointer(s);
case clang_types.CXTypeKind.CXType_Typedef:
- // Get name from typedef name if config allows.
+ final spelling = cxtype.spelling();
+ if (config.typedefNativeTypeMappings.containsKey(spelling)) {
+ _logger.fine(' Type Mapped from typedef-map');
+ return Type.nativeType(config.typedefNativeTypeMappings[spelling]);
+ }
+ // Get name from supported typedef name if config allows.
if (config.useSupportedTypedefs) {
- final spelling = cxtype.spelling();
if (suportedTypedefToSuportedNativeType.containsKey(spelling)) {
_logger.fine(' Type Mapped from supported typedef');
return Type.nativeType(suportedTypedefToSuportedNativeType[spelling]);
@@ -40,7 +44,8 @@
}
// This is important or we get stuck in infinite recursion.
- final ct = clang.clang_getCanonicalType_wrap(cxtype);
+ final ct = clang.clang_getTypedefDeclUnderlyingType_wrap(
+ clang.clang_getTypeDeclaration_wrap(cxtype));
final s = getCodeGenType(ct, parentName: parentName ?? cxtype.spelling());
ct.dispose();
diff --git a/lib/src/strings.dart b/lib/src/strings.dart
index 5a81450..60981bc 100644
--- a/lib/src/strings.dart
+++ b/lib/src/strings.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:io';
+import 'package:ffigen/src/code_generator/type.dart';
import 'package:ffigen/src/find_resource.dart';
import 'package:ffigen/src/header_parser/clang_bindings/clang_bindings.dart'
as clang;
@@ -49,6 +50,7 @@
const rename = 'rename';
const memberRename = 'member-rename';
const sizemap = 'size-map';
+const typedefmap = 'typedef-map';
// Sizemap values.
const SChar = 'char';
@@ -78,6 +80,21 @@
Enum: clang.CXTypeKind.CXType_Enum
};
+const supportedNativeType_mappings = <String, SupportedNativeType>{
+ 'Void': SupportedNativeType.Void,
+ 'Uint8': SupportedNativeType.Uint8,
+ 'Uint16': SupportedNativeType.Uint16,
+ 'Uint32': SupportedNativeType.Uint32,
+ 'Uint64': SupportedNativeType.Uint64,
+ 'Int8': SupportedNativeType.Int8,
+ 'Int16': SupportedNativeType.Int16,
+ 'Int32': SupportedNativeType.Int32,
+ 'Int64': SupportedNativeType.Int64,
+ 'IntPtr': SupportedNativeType.IntPtr,
+ 'Float': SupportedNativeType.Float,
+ 'Double': SupportedNativeType.Double,
+};
+
// Boolean flags.
const sort = 'sort';
const useSupportedTypedefs = 'use-supported-typedefs';
diff --git a/pubspec.yaml b/pubspec.yaml
index 2d21dc5..b0f6b4b 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: 1.0.6
+version: 1.1.0
homepage: https://github.com/dart-lang/ffigen
description: Experimental generator for FFI bindings, using LibClang to parse C header files.
diff --git a/test/header_parser_tests/native_func_typedef_test.dart b/test/header_parser_tests/native_func_typedef_test.dart
index 1676817..c1f2d37 100644
--- a/test/header_parser_tests/native_func_typedef_test.dart
+++ b/test/header_parser_tests/native_func_typedef_test.dart
@@ -98,10 +98,10 @@
ffi.Pointer<ffi.NativeFunction<_typedefC_4>> unnamed1,
);
-typedef _typedefC_5 = ffi.Void Function(
+typedef insideReturnType = ffi.Void Function(
);
-typedef withTypedefReturnType = ffi.Pointer<ffi.NativeFunction<_typedefC_5>> Function(
+typedef withTypedefReturnType = ffi.Pointer<ffi.NativeFunction<insideReturnType>> Function(
);
typedef _c_funcWithNativeFunc = ffi.Void Function(
diff --git a/test/header_parser_tests/typedef.h b/test/header_parser_tests/typedef.h
index 9dda096..68ad426 100644
--- a/test/header_parser_tests/typedef.h
+++ b/test/header_parser_tests/typedef.h
@@ -48,3 +48,9 @@
{
b=0
} NamedEnumInTypedef;
+
+// Should be treated as IntPtr when used.
+typedef char specified_type_as_IntPtr;
+typedef specified_type_as_IntPtr nesting_a_specified_type;
+
+void func3(specified_type_as_IntPtr, nesting_a_specified_type b);
diff --git a/test/header_parser_tests/typedef_test.dart b/test/header_parser_tests/typedef_test.dart
index 6b3b971..eeeb37c 100644
--- a/test/header_parser_tests/typedef_test.dart
+++ b/test/header_parser_tests/typedef_test.dart
@@ -31,6 +31,8 @@
${strings.exclude}:
- ExcludedStruct
- _ExcludedStruct
+${strings.typedefmap}:
+ 'specified_type_as_IntPtr': 'IntPtr'
''') as yaml.YamlMap),
);
});
@@ -109,6 +111,17 @@
EnumConstant(name: 'b', value: 0),
],
),
+ Func(
+ name: 'func3',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ parameters: [
+ Parameter(type: Type.nativeType(SupportedNativeType.IntPtr)),
+ Parameter(
+ type: Type.nativeType(SupportedNativeType.IntPtr),
+ name: 'b',
+ ),
+ ],
+ ),
],
);
}