Support for Prefix and Names in config. (#20)
- Support for global prefix and prefix replacement in functions/structs/enums
- Handles all internal name collisions (such as those between - dylib identifier, ffi import prefix, any typedefs generated, array helper classes, expanded array items, declarations, init function) if a collision occurs its suffixed by `_cr<int>`
- Added tests for prefixing and collisions
diff --git a/example/c_json/cjson_generated_bindings.dart b/example/c_json/cjson_generated_bindings.dart
index 1cf00a3..e26ed6a 100644
--- a/example/c_json/cjson_generated_bindings.dart
+++ b/example/c_json/cjson_generated_bindings.dart
@@ -7,8 +7,8 @@
ffi.DynamicLibrary _dylib;
/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib) {
- _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary) {
+ _dylib = dynamicLibrary;
}
class cJSON extends ffi.Struct {
@@ -32,18 +32,18 @@
ffi.Pointer<ffi.Int8> string;
}
-typedef _typedefC_noname_1 = ffi.Pointer<ffi.Void> Function(
+typedef _typedefC_1 = ffi.Pointer<ffi.Void> Function(
ffi.Uint64,
);
-typedef _typedefC_noname_2 = ffi.Void Function(
+typedef _typedefC_2 = ffi.Void Function(
ffi.Pointer<ffi.Void>,
);
class cJSON_Hooks extends ffi.Struct {
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_1>> malloc_fn;
+ ffi.Pointer<ffi.NativeFunction<_typedefC_1>> malloc_fn;
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_2>> free_fn;
+ ffi.Pointer<ffi.NativeFunction<_typedefC_2>> free_fn;
}
ffi.Pointer<ffi.Int8> cJSON_Version() {
diff --git a/example/libclang-example/generated_bindings.dart b/example/libclang-example/generated_bindings.dart
index 4fbfac3..6a0d1d3 100644
--- a/example/libclang-example/generated_bindings.dart
+++ b/example/libclang-example/generated_bindings.dart
@@ -1,14 +1,15 @@
/// AUTO GENERATED FILE, DO NOT EDIT.
///
/// Generated by `package:ffigen`.
+
import 'dart:ffi' as ffi;
/// Holds the Dynamic library.
ffi.DynamicLibrary _dylib;
/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib) {
- _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary) {
+ _dylib = dynamicLibrary;
}
/// Contains the results of code-completion.
@@ -67,9 +68,9 @@
@ffi.Int32()
int xdata;
- ffi.Pointer<ffi.Void> _data_item_0;
- ffi.Pointer<ffi.Void> _data_item_1;
- ffi.Pointer<ffi.Void> _data_item_2;
+ ffi.Pointer<ffi.Void> _exp_workaround_data_item_0;
+ ffi.Pointer<ffi.Void> _exp_workaround_data_item_1;
+ ffi.Pointer<ffi.Void> _exp_workaround_data_item_2;
/// Helper for array `data`.
ArrayHelper_CXCursor_data_level0 get data =>
@@ -96,11 +97,11 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- return _struct._data_item_0;
+ return _struct._exp_workaround_data_item_0;
case 1:
- return _struct._data_item_1;
+ return _struct._exp_workaround_data_item_1;
case 2:
- return _struct._data_item_2;
+ return _struct._exp_workaround_data_item_2;
default:
throw Exception('Invalid Array Helper generated.');
}
@@ -110,13 +111,13 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- _struct._data_item_0 = value;
+ _struct._exp_workaround_data_item_0 = value;
break;
case 1:
- _struct._data_item_1 = value;
+ _struct._exp_workaround_data_item_1 = value;
break;
case 2:
- _struct._data_item_2 = value;
+ _struct._exp_workaround_data_item_2 = value;
break;
default:
throw Exception('Invalid Array Helper generated.');
@@ -124,34 +125,19 @@
}
}
-class CXCursorAndRangeVisitor extends ffi.Struct {
- ffi.Pointer<ffi.Void> context;
-
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_2>> visit;
-}
+class CXCursorAndRangeVisitor extends ffi.Struct {}
class CXCursorSetImpl extends ffi.Struct {}
-typedef CXCursorVisitor = ffi.Int32 Function(
- CXCursor,
- CXCursor,
- ffi.Pointer<ffi.Void>,
-);
-
-typedef CXFieldVisitor = ffi.Int32 Function(
- CXCursor,
- ffi.Pointer<ffi.Void>,
-);
-
/// Uniquely identifies a CXFile, that refers to the same underlying file,
/// across an indexing session.
class CXFileUniqueID extends ffi.Struct {
@ffi.Uint64()
- int _data_item_0;
+ int _exp_workaround_data_item_0;
@ffi.Uint64()
- int _data_item_1;
+ int _exp_workaround_data_item_1;
@ffi.Uint64()
- int _data_item_2;
+ int _exp_workaround_data_item_2;
/// Helper for array `data`.
ArrayHelper_CXFileUniqueID_data_level0 get data =>
@@ -178,11 +164,11 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- return _struct._data_item_0;
+ return _struct._exp_workaround_data_item_0;
case 1:
- return _struct._data_item_1;
+ return _struct._exp_workaround_data_item_1;
case 2:
- return _struct._data_item_2;
+ return _struct._exp_workaround_data_item_2;
default:
throw Exception('Invalid Array Helper generated.');
}
@@ -192,13 +178,13 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- _struct._data_item_0 = value;
+ _struct._exp_workaround_data_item_0 = value;
break;
case 1:
- _struct._data_item_1 = value;
+ _struct._exp_workaround_data_item_1 = value;
break;
case 2:
- _struct._data_item_2 = value;
+ _struct._exp_workaround_data_item_2 = value;
break;
default:
throw Exception('Invalid Array Helper generated.');
@@ -261,8 +247,8 @@
/// Source location passed to index callbacks.
class CXIdxLoc extends ffi.Struct {
- ffi.Pointer<ffi.Void> _ptr_data_item_0;
- ffi.Pointer<ffi.Void> _ptr_data_item_1;
+ ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_0;
+ ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_1;
/// Helper for array `ptr_data`.
ArrayHelper_CXIdxLoc_ptr_data_level0 get ptr_data =>
@@ -291,9 +277,9 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- return _struct._ptr_data_item_0;
+ return _struct._exp_workaround_ptr_data_item_0;
case 1:
- return _struct._ptr_data_item_1;
+ return _struct._exp_workaround_ptr_data_item_1;
default:
throw Exception('Invalid Array Helper generated.');
}
@@ -303,10 +289,10 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- _struct._ptr_data_item_0 = value;
+ _struct._exp_workaround_ptr_data_item_0 = value;
break;
case 1:
- _struct._ptr_data_item_1 = value;
+ _struct._exp_workaround_ptr_data_item_1 = value;
break;
default:
throw Exception('Invalid Array Helper generated.');
@@ -348,13 +334,6 @@
int numProtocols;
}
-typedef CXInclusionVisitor = ffi.Void Function(
- ffi.Pointer<ffi.Void>,
- ffi.Pointer<CXSourceLocation>,
- ffi.Uint32,
- ffi.Pointer<ffi.Void>,
-);
-
/// Describes the availability of a given entity on a particular platform, e.g.,
/// a particular class might only be available on Mac OS 10.7 or newer.
class CXPlatformAvailability extends ffi.Struct {}
@@ -365,8 +344,8 @@
/// Use clang_getExpansionLocation() or clang_getSpellingLocation()
/// to map a source location to a particular file, line, and column.
class CXSourceLocation extends ffi.Struct {
- ffi.Pointer<ffi.Void> _ptr_data_item_0;
- ffi.Pointer<ffi.Void> _ptr_data_item_1;
+ ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_0;
+ ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_1;
/// Helper for array `ptr_data`.
ArrayHelper_CXSourceLocation_ptr_data_level0 get ptr_data =>
@@ -395,9 +374,9 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- return _struct._ptr_data_item_0;
+ return _struct._exp_workaround_ptr_data_item_0;
case 1:
- return _struct._ptr_data_item_1;
+ return _struct._exp_workaround_ptr_data_item_1;
default:
throw Exception('Invalid Array Helper generated.');
}
@@ -407,10 +386,10 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- _struct._ptr_data_item_0 = value;
+ _struct._exp_workaround_ptr_data_item_0 = value;
break;
case 1:
- _struct._ptr_data_item_1 = value;
+ _struct._exp_workaround_ptr_data_item_1 = value;
break;
default:
throw Exception('Invalid Array Helper generated.');
@@ -423,8 +402,8 @@
/// Use clang_getRangeStart() and clang_getRangeEnd() to retrieve the
/// starting and end locations from a source range, respectively.
class CXSourceRange extends ffi.Struct {
- ffi.Pointer<ffi.Void> _ptr_data_item_0;
- ffi.Pointer<ffi.Void> _ptr_data_item_1;
+ ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_0;
+ ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_1;
/// Helper for array `ptr_data`.
ArrayHelper_CXSourceRange_ptr_data_level0 get ptr_data =>
@@ -456,9 +435,9 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- return _struct._ptr_data_item_0;
+ return _struct._exp_workaround_ptr_data_item_0;
case 1:
- return _struct._ptr_data_item_1;
+ return _struct._exp_workaround_ptr_data_item_1;
default:
throw Exception('Invalid Array Helper generated.');
}
@@ -468,10 +447,10 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- _struct._ptr_data_item_0 = value;
+ _struct._exp_workaround_ptr_data_item_0 = value;
break;
case 1:
- _struct._ptr_data_item_1 = value;
+ _struct._exp_workaround_ptr_data_item_1 = value;
break;
default:
throw Exception('Invalid Array Helper generated.');
@@ -532,13 +511,13 @@
/// Describes a single preprocessing token.
class CXToken extends ffi.Struct {
@ffi.Uint32()
- int _int_data_item_0;
+ int _exp_workaround_int_data_item_0;
@ffi.Uint32()
- int _int_data_item_1;
+ int _exp_workaround_int_data_item_1;
@ffi.Uint32()
- int _int_data_item_2;
+ int _exp_workaround_int_data_item_2;
@ffi.Uint32()
- int _int_data_item_3;
+ int _exp_workaround_int_data_item_3;
/// Helper for array `int_data`.
ArrayHelper_CXToken_int_data_level0 get int_data =>
@@ -566,13 +545,13 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- return _struct._int_data_item_0;
+ return _struct._exp_workaround_int_data_item_0;
case 1:
- return _struct._int_data_item_1;
+ return _struct._exp_workaround_int_data_item_1;
case 2:
- return _struct._int_data_item_2;
+ return _struct._exp_workaround_int_data_item_2;
case 3:
- return _struct._int_data_item_3;
+ return _struct._exp_workaround_int_data_item_3;
default:
throw Exception('Invalid Array Helper generated.');
}
@@ -582,16 +561,16 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- _struct._int_data_item_0 = value;
+ _struct._exp_workaround_int_data_item_0 = value;
break;
case 1:
- _struct._int_data_item_1 = value;
+ _struct._exp_workaround_int_data_item_1 = value;
break;
case 2:
- _struct._int_data_item_2 = value;
+ _struct._exp_workaround_int_data_item_2 = value;
break;
case 3:
- _struct._int_data_item_3 = value;
+ _struct._exp_workaround_int_data_item_3 = value;
break;
default:
throw Exception('Invalid Array Helper generated.');
@@ -606,8 +585,8 @@
@ffi.Int32()
int kind;
- ffi.Pointer<ffi.Void> _data_item_0;
- ffi.Pointer<ffi.Void> _data_item_1;
+ ffi.Pointer<ffi.Void> _exp_workaround_data_item_0;
+ ffi.Pointer<ffi.Void> _exp_workaround_data_item_1;
/// Helper for array `data`.
ArrayHelper_CXType_data_level0 get data =>
@@ -634,9 +613,9 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- return _struct._data_item_0;
+ return _struct._exp_workaround_data_item_0;
case 1:
- return _struct._data_item_1;
+ return _struct._exp_workaround_data_item_1;
default:
throw Exception('Invalid Array Helper generated.');
}
@@ -646,10 +625,10 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- _struct._data_item_0 = value;
+ _struct._exp_workaround_data_item_0 = value;
break;
case 1:
- _struct._data_item_1 = value;
+ _struct._exp_workaround_data_item_1 = value;
break;
default:
throw Exception('Invalid Array Helper generated.');
@@ -828,18 +807,60 @@
/// A group of callbacks used by #clang_indexSourceFile and
/// #clang_indexTranslationUnit.
+typedef _typedefC_3 = ffi.Int32 Function(
+ ffi.Pointer<ffi.Void>,
+ ffi.Pointer<ffi.Void>,
+);
+
+typedef _typedefC_4 = ffi.Void Function(
+ ffi.Pointer<ffi.Void>,
+ ffi.Pointer<ffi.Void>,
+ ffi.Pointer<ffi.Void>,
+);
+
+typedef _typedefC_5 = ffi.Pointer<ffi.Void> Function(
+ ffi.Pointer<ffi.Void>,
+ ffi.Pointer<ffi.Void>,
+ ffi.Pointer<ffi.Void>,
+);
+
+typedef _typedefC_6 = ffi.Pointer<ffi.Void> Function(
+ ffi.Pointer<ffi.Void>,
+ ffi.Pointer<CXIdxIncludedFileInfo>,
+);
+
+typedef _typedefC_7 = ffi.Pointer<ffi.Void> Function(
+ ffi.Pointer<ffi.Void>,
+ ffi.Pointer<CXIdxImportedASTFileInfo>,
+);
+
+typedef _typedefC_8 = ffi.Pointer<ffi.Void> Function(
+ ffi.Pointer<ffi.Void>,
+ ffi.Pointer<ffi.Void>,
+);
+
+typedef _typedefC_9 = ffi.Void Function(
+ ffi.Pointer<ffi.Void>,
+ ffi.Pointer<CXIdxDeclInfo>,
+);
+
+typedef _typedefC_10 = ffi.Void Function(
+ ffi.Pointer<ffi.Void>,
+ ffi.Pointer<CXIdxEntityRefInfo>,
+);
+
class IndexerCallbacks extends ffi.Struct {
/// Called periodically to check whether indexing should be aborted.
/// Should return 0 to continue, and non-zero to abort.
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_3>> abortQuery;
+ ffi.Pointer<ffi.NativeFunction<_typedefC_3>> abortQuery;
/// Called at the end of indexing; passes the complete diagnostic set.
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_4>> diagnostic;
+ ffi.Pointer<ffi.NativeFunction<_typedefC_4>> diagnostic;
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_5>> enteredMainFile;
+ ffi.Pointer<ffi.NativeFunction<_typedefC_5>> enteredMainFile;
/// Called when a file gets \#included/\#imported.
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_6>> ppIncludedFile;
+ ffi.Pointer<ffi.NativeFunction<_typedefC_6>> ppIncludedFile;
/// Called when a AST file (PCH or module) gets imported.
///
@@ -847,75 +868,17 @@
/// the entities in an AST file). The recommended action is that, if the AST
/// file is not already indexed, to initiate a new indexing job specific to
/// the AST file.
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_7>> importedASTFile;
+ ffi.Pointer<ffi.NativeFunction<_typedefC_7>> importedASTFile;
/// Called at the beginning of indexing a translation unit.
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_8>> startedTranslationUnit;
+ ffi.Pointer<ffi.NativeFunction<_typedefC_8>> startedTranslationUnit;
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_9>> indexDeclaration;
+ ffi.Pointer<ffi.NativeFunction<_typedefC_9>> indexDeclaration;
/// Called to index a reference of an entity.
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_10>> indexEntityReference;
+ ffi.Pointer<ffi.NativeFunction<_typedefC_10>> indexEntityReference;
}
-typedef ModifiedCXCursorVisitor = ffi.Int32 Function(
- ffi.Pointer<CXCursor>,
- ffi.Pointer<CXCursor>,
- ffi.Pointer<ffi.Void>,
-);
-
-typedef _typedefC_noname_1 = ffi.Void Function(
- ffi.Pointer<ffi.Void>,
-);
-
-typedef _typedefC_noname_10 = ffi.Void Function(
- ffi.Pointer<ffi.Void>,
- ffi.Pointer<CXIdxEntityRefInfo>,
-);
-
-typedef _typedefC_noname_2 = ffi.Int32 Function(
- ffi.Pointer<ffi.Void>,
- CXCursor,
- CXSourceRange,
-);
-
-typedef _typedefC_noname_3 = ffi.Int32 Function(
- ffi.Pointer<ffi.Void>,
- ffi.Pointer<ffi.Void>,
-);
-
-typedef _typedefC_noname_4 = ffi.Void Function(
- ffi.Pointer<ffi.Void>,
- ffi.Pointer<ffi.Void>,
- ffi.Pointer<ffi.Void>,
-);
-
-typedef _typedefC_noname_5 = ffi.Pointer<ffi.Void> Function(
- ffi.Pointer<ffi.Void>,
- ffi.Pointer<ffi.Void>,
- ffi.Pointer<ffi.Void>,
-);
-
-typedef _typedefC_noname_6 = ffi.Pointer<ffi.Void> Function(
- ffi.Pointer<ffi.Void>,
- ffi.Pointer<CXIdxIncludedFileInfo>,
-);
-
-typedef _typedefC_noname_7 = ffi.Pointer<ffi.Void> Function(
- ffi.Pointer<ffi.Void>,
- ffi.Pointer<CXIdxImportedASTFileInfo>,
-);
-
-typedef _typedefC_noname_8 = ffi.Pointer<ffi.Void> Function(
- ffi.Pointer<ffi.Void>,
- ffi.Pointer<ffi.Void>,
-);
-
-typedef _typedefC_noname_9 = ffi.Void Function(
- ffi.Pointer<ffi.Void>,
- ffi.Pointer<CXIdxDeclInfo>,
-);
-
/// Gets the general options associated with a CXIndex.
///
/// \returns A bitmask of options, a bitwise OR of CXGlobalOpt_XXX flags that
@@ -2582,8 +2545,12 @@
ffi.Pointer<CXSourceRange> c2,
);
+typedef _typedefC_1 = ffi.Void Function(
+ ffi.Pointer<ffi.Void>,
+);
+
void clang_executeOnThread(
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_1>> fn,
+ ffi.Pointer<ffi.NativeFunction<_typedefC_1>> fn,
ffi.Pointer<ffi.Void> user_data,
int stack_size,
) {
@@ -2599,13 +2566,13 @@
'clang_executeOnThread');
typedef _c_clang_executeOnThread = ffi.Void Function(
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_1>> fn,
+ ffi.Pointer<ffi.NativeFunction<_typedefC_1>> fn,
ffi.Pointer<ffi.Void> user_data,
ffi.Uint32 stack_size,
);
typedef _dart_clang_executeOnThread = void Function(
- ffi.Pointer<ffi.NativeFunction<_typedefC_noname_1>> fn,
+ ffi.Pointer<ffi.NativeFunction<_typedefC_1>> fn,
ffi.Pointer<ffi.Void> user_data,
int stack_size,
);
@@ -3438,13 +3405,20 @@
ffi.Pointer<CXFileUniqueID> outID,
);
+typedef CXInclusionVisitor_1 = ffi.Void Function(
+ ffi.Pointer<ffi.Void>,
+ ffi.Pointer<CXSourceLocation>,
+ ffi.Uint32,
+ ffi.Pointer<ffi.Void>,
+);
+
/// Visit the set of preprocessor inclusions in a translation unit.
/// The visitor function is called with the provided data for every included
/// file. This does not include headers included by the PCH file (unless one
/// is inspecting the inclusions in the PCH file itself).
void clang_getInclusions(
ffi.Pointer<CXTranslationUnitImpl> tu,
- ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor>> visitor,
+ ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor_1>> visitor,
ffi.Pointer<ffi.Void> client_data,
) {
return _clang_getInclusions(
@@ -3460,13 +3434,13 @@
typedef _c_clang_getInclusions = ffi.Void Function(
ffi.Pointer<CXTranslationUnitImpl> tu,
- ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor>> visitor,
+ ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor_1>> visitor,
ffi.Pointer<ffi.Void> client_data,
);
typedef _dart_clang_getInclusions = void Function(
ffi.Pointer<CXTranslationUnitImpl> tu,
- ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor>> visitor,
+ ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor_1>> visitor,
ffi.Pointer<ffi.Void> client_data,
);
@@ -5112,11 +5086,17 @@
int isEnabled,
);
+typedef ModifiedCXCursorVisitor_1 = ffi.Int32 Function(
+ ffi.Pointer<CXCursor>,
+ ffi.Pointer<CXCursor>,
+ ffi.Pointer<ffi.Void>,
+);
+
/// Visitor is a function pointer with parameters having pointers to cxcursor
/// instead of cxcursor by default.
int clang_visitChildren_wrap(
ffi.Pointer<CXCursor> parent,
- ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
+ ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
ffi.Pointer<ffi.Void> clientData,
) {
return _clang_visitChildren_wrap(
@@ -5132,12 +5112,12 @@
typedef _c_clang_visitChildren_wrap = ffi.Uint32 Function(
ffi.Pointer<CXCursor> parent,
- ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
+ ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
ffi.Pointer<ffi.Void> clientData,
);
typedef _dart_clang_visitChildren_wrap = int Function(
ffi.Pointer<CXCursor> parent,
- ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
+ ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
ffi.Pointer<ffi.Void> clientData,
);
diff --git a/example/libclang-example/pubspec.yaml b/example/libclang-example/pubspec.yaml
index 832f111..c29adb8 100644
--- a/example/libclang-example/pubspec.yaml
+++ b/example/libclang-example/pubspec.yaml
@@ -59,8 +59,17 @@
unsigned long long: 8
enum: 4
+ # Default is 'init'
+ init-function-name: init
+
# False by default.
array-workaround: true
+ # The header of the file, this is pasted as it is.
+ preamble: |
+ /// AUTO GENERATED FILE, DO NOT EDIT.
+ ///
+ /// Generated by `package:ffigen`.
+
# Doc Comments for generated binings: Can be full, brief(default) or none.
comments: full
diff --git a/example/simple/generated_bindings.dart b/example/simple/generated_bindings.dart
index 6e3a97b..54409b1 100644
--- a/example/simple/generated_bindings.dart
+++ b/example/simple/generated_bindings.dart
@@ -7,8 +7,8 @@
ffi.DynamicLibrary _dylib;
/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib) {
- _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary) {
+ _dylib = dynamicLibrary;
}
/// Adds 2 integers.
diff --git a/lib/src/code_generator.dart b/lib/src/code_generator.dart
index 9eb01b6..9af6dbe 100644
--- a/lib/src/code_generator.dart
+++ b/lib/src/code_generator.dart
@@ -13,5 +13,5 @@
export 'code_generator/library.dart';
export 'code_generator/struc.dart';
export 'code_generator/type.dart';
-export 'code_generator/typedef.dart';
+export 'code_generator/typedefc.dart';
diff --git a/lib/src/code_generator/binding.dart b/lib/src/code_generator/binding.dart
index 127c0d2..f37c72c 100644
--- a/lib/src/code_generator/binding.dart
+++ b/lib/src/code_generator/binding.dart
@@ -9,11 +9,11 @@
/// Base class for all Bindings.
abstract class Binding {
- final String name;
+ String name;
final String dartDoc;
- const Binding({@required this.name, this.dartDoc});
+ Binding({@required this.name, this.dartDoc});
/// Converts a Binding to its actual string representation.
BindingString toBindingString(Writer w);
diff --git a/lib/src/code_generator/constant.dart b/lib/src/code_generator/constant.dart
index bef22d8..dd5c657 100644
--- a/lib/src/code_generator/constant.dart
+++ b/lib/src/code_generator/constant.dart
@@ -28,7 +28,7 @@
/// Put quotes if type is a string.
final String rawValue;
- const Constant({
+ Constant({
@required String name,
String dartDoc,
@required this.type,
@@ -38,6 +38,7 @@
@override
BindingString toBindingString(Writer w) {
final s = StringBuffer();
+ final constantName = name;
if (dartDoc != null) {
s.write('/// ');
@@ -45,7 +46,7 @@
s.write('\n');
}
- s.write('const ${type.getDartType(w)} $name = $rawValue;\n\n');
+ s.write('const ${type.getDartType(w)} $constantName = $rawValue;\n\n');
return BindingString(
type: BindingStringType.constant, string: s.toString());
diff --git a/lib/src/code_generator/enum_class.dart b/lib/src/code_generator/enum_class.dart
index 90faf5b..1baea18 100644
--- a/lib/src/code_generator/enum_class.dart
+++ b/lib/src/code_generator/enum_class.dart
@@ -6,6 +6,7 @@
import 'binding.dart';
import 'binding_string.dart';
+import 'utils.dart';
import 'writer.dart';
/// A binding for enums in C.
@@ -35,6 +36,7 @@
@override
BindingString toBindingString(Writer w) {
final s = StringBuffer();
+ final enclosingClassName = name;
if (dartDoc != null) {
s.write('/// ');
@@ -42,16 +44,22 @@
s.write('\n');
}
+ /// Adding [enclosingClassName] because dart doesn't allow class member
+ /// to have the same name as the class.
+ final localUniqueNamer = UniqueNamer({enclosingClassName});
+
// Print enclosing class.
- s.write('class $name {\n');
+ s.write('class $enclosingClassName {\n');
const depth = ' ';
for (final ec in enumConstants) {
+ final enum_value_name =
+ localUniqueNamer.makeUnique(ec.name);
if (ec.dartDoc != null) {
s.write(depth + '/// ');
s.writeAll(ec.dartDoc.split('\n'), '\n' + depth + '/// ');
s.write('\n');
}
- s.write(depth + 'static const int ${ec.name} = ${ec.value};\n');
+ s.write(depth + 'static const int ${enum_value_name} = ${ec.value};\n');
}
s.write('}\n\n');
diff --git a/lib/src/code_generator/func.dart b/lib/src/code_generator/func.dart
index 688c573..ffc1509 100644
--- a/lib/src/code_generator/func.dart
+++ b/lib/src/code_generator/func.dart
@@ -28,15 +28,19 @@
/// typedef _dart_sum = int Function(int a, int b);
/// ```
class Func extends Binding {
+ final String lookupSymbolName;
final Type returnType;
final List<Parameter> parameters;
+ /// [lookupSymbolName], if not provided, takes the value of [name].
Func({
@required String name,
+ String lookupSymbolName,
String dartDoc,
@required this.returnType,
List<Parameter> parameters,
}) : parameters = parameters ?? [],
+ lookupSymbolName = lookupSymbolName ?? name,
super(name: name, dartDoc: dartDoc) {
for (var i = 0; i < this.parameters.length; i++) {
if (this.parameters[i].name == null ||
@@ -49,10 +53,22 @@
@override
BindingString toBindingString(Writer w) {
final s = StringBuffer();
+ final enclosingFuncName = name;
- final funcVarName = '_$name';
- final typedefC = '_c_$name';
- final typedefDart = '_dart_$name';
+ // Ensure name conflicts are resolved for typedefs generated.
+ final funcVarName = w.uniqueNamer.makeUnique('_$name');
+ final typedefC = w.uniqueNamer.makeUnique('_c_$name');
+ final typedefDart = w.uniqueNamer.makeUnique('_dart_$name');
+
+ // Write typedef's required by parameters and resolve name conflicts.
+ for (final p in parameters) {
+ final base = p.type.getBaseType();
+ if (base.broadType == BroadType.NativeFunction) {
+ base.nativeFunc.name =
+ w.uniqueNamer.makeUnique(base.nativeFunc.name);
+ s.write(base.nativeFunc.toTypedefString(w));
+ }
+ }
if (dartDoc != null) {
s.write('/// ');
@@ -61,7 +77,7 @@
}
// Write enclosing function.
- s.write('${returnType.getDartType(w)} $name(\n');
+ s.write('${returnType.getDartType(w)} $enclosingFuncName(\n');
for (final p in parameters) {
s.write(' ${p.type.getDartType(w)} ${p.name},\n');
}
@@ -75,7 +91,7 @@
// Write function with dylib lookup.
s.write(
- "final $typedefDart $funcVarName = ${w.dylibIdentifier}.lookupFunction<$typedefC,$typedefDart>('$name');\n\n");
+ "final $typedefDart $funcVarName = ${w.dylibIdentifier}.lookupFunction<$typedefC,$typedefDart>('$lookupSymbolName');\n\n");
// Write typdef for C.
s.write('typedef $typedefC = ${returnType.getCType(w)} Function(\n');
diff --git a/lib/src/code_generator/global.dart b/lib/src/code_generator/global.dart
index 8729785..2e41d82 100644
--- a/lib/src/code_generator/global.dart
+++ b/lib/src/code_generator/global.dart
@@ -20,10 +20,12 @@
/// final int a = _dylib.lookup<ffi.Int32>('a').value;
/// ```
class Global extends Binding {
+ final String lookupSymbolName;
final Type type;
- const Global({
+ Global({
@required String name,
+ @required this.lookupSymbolName,
@required this.type,
String dartDoc,
}) : super(name: name, dartDoc: dartDoc);
@@ -31,7 +33,7 @@
@override
BindingString toBindingString(Writer w) {
final s = StringBuffer();
-
+ final globalVarName = name;
if (dartDoc != null) {
s.write('/// ');
s.writeAll(dartDoc.split('\n'), '\n/// ');
@@ -39,7 +41,7 @@
}
s.write(
- "final ${type.getDartType(w)} $name = ${w.dylibIdentifier}.lookup<${type.getCType(w)}>('$name').value;\n\n");
+ "final ${type.getDartType(w)} $globalVarName = ${w.dylibIdentifier}.lookup<${type.getCType(w)}>('$lookupSymbolName').value;\n\n");
return BindingString(type: BindingStringType.global, string: s.toString());
}
diff --git a/lib/src/code_generator/library.dart b/lib/src/code_generator/library.dart
index 8ae4a06..027c1f1 100644
--- a/lib/src/code_generator/library.dart
+++ b/lib/src/code_generator/library.dart
@@ -8,33 +8,46 @@
import 'package:meta/meta.dart';
import 'binding.dart';
+import 'utils.dart';
import 'writer.dart';
-var _logger = Logger('code_generator');
+var _logger = Logger('code_generator:library.dart');
/// Container for all Bindings.
class Library {
- /// Variable identifier used for dynamicLibrary. Defaults to `_dylib`,
- final String dylibIdentifier;
-
- /// Init function for providing dynamic library. Defaults to `init`,
- ///
- /// Can be renamed in case of name conflicts with something else.
- final String initFunctionIdentifier;
-
- /// Header of file.
- final String header;
-
/// List of bindings in this library.
final List<Binding> bindings;
+ Writer _writer;
+ Writer get writer => _writer;
+
Library({
@required this.bindings,
- this.dylibIdentifier = '_dylib',
- this.initFunctionIdentifier = 'init',
- this.header,
- }) : assert(dylibIdentifier != null),
- assert(initFunctionIdentifier != null);
+ String header,
+ String initFunctionIdentifier = 'init',
+ }) {
+ // Handle any declaration-declaration name conflict.
+ final declConflictHandler = UniqueNamer({});
+ for (final b in bindings) {
+ // Print warning if name was conflicting and has been changed.
+ if (declConflictHandler.isUsed(b.name)) {
+ final oldName = b.name;
+ b.name = declConflictHandler.makeUnique(b.name);
+
+ _logger.warning(
+ "Resolved name conflict: Declaration '$oldName' and has been renamed to '${b.name}'.");
+ } else {
+ declConflictHandler.markUsed(b.name);
+ }
+ }
+
+ final declarationNames = bindings.map((e) => e.name).toSet();
+ _writer = Writer(
+ usedUpNames: declarationNames,
+ initFunctionIdentifier: initFunctionIdentifier,
+ header: header,
+ );
+ }
/// Sort all bindings in alphabetical order.
void sort() {
@@ -53,7 +66,6 @@
/// Generates bindings and stores it in given [Writer].
void _generate(Writer w) {
- w.header = header;
for (final b in bindings) {
w.addBindingString(b.toBindingString(w));
}
@@ -70,10 +82,7 @@
/// Generates the bindings.
String generate() {
- final w = Writer(
- dylibIdentifier: dylibIdentifier,
- initFunctionIdentifier: initFunctionIdentifier,
- );
+ final w = writer;
_generate(w);
return w.generate();
}
diff --git a/lib/src/code_generator/struc.dart b/lib/src/code_generator/struc.dart
index 5e2db56..949c239 100644
--- a/lib/src/code_generator/struc.dart
+++ b/lib/src/code_generator/struc.dart
@@ -7,6 +7,7 @@
import 'binding.dart';
import 'binding_string.dart';
import 'type.dart';
+import 'utils.dart';
import 'writer.dart';
/// A binding for C Struct.
@@ -34,7 +35,7 @@
/// }
/// ```
class Struc extends Binding {
- final List<Member> members;
+ List<Member> members;
Struc({
@required String name,
@@ -55,8 +56,9 @@
@override
BindingString toBindingString(Writer w) {
+ members = members ?? [];
final s = StringBuffer();
-
+ final enclosingClassName = name;
if (dartDoc != null) {
s.write('/// ');
s.writeAll(dartDoc.split('\n'), '\n/// ');
@@ -65,18 +67,37 @@
final helpers = <ArrayHelper>[];
- // Write class declaration.
- s.write('class $name extends ${w.ffiLibraryPrefix}.Struct{\n');
+ // Write typedef's required by members and resolve name conflicts.
for (final m in members) {
+ final base = m.type.getBaseType();
+ if (base.broadType == BroadType.NativeFunction) {
+ base.nativeFunc.name =
+ w.uniqueNamer.makeUnique(base.nativeFunc.name);
+ s.write(base.nativeFunc.toTypedefString(w));
+ }
+ }
+
+ final expandedArrayItemPrefix = getUniqueExpandedArrayItemPrefix();
+
+ /// Adding [enclosingClassName] because dart doesn't allow class member
+ /// to have the same name as the class.
+ final localUniqueNamer = UniqueNamer({enclosingClassName});
+
+ // Write class declaration.
+ s.write(
+ 'class $enclosingClassName extends ${w.ffiLibraryPrefix}.Struct{\n');
+ for (final m in members) {
+ final memberName = localUniqueNamer.makeUnique(m.name);
if (m.type.broadType == BroadType.ConstantArray) {
// TODO(5): Remove array helpers when inline array support arives.
final arrayHelper = ArrayHelper(
- helperClassGroupName: 'ArrayHelper_${name}_${m.name}',
+ helperClassGroupName:
+ '${w.arrayHelperClassPrefix}_${enclosingClassName}_${memberName}',
elementType: m.type.getBaseArrayType(),
dimensions: _getArrayDimensionLengths(m.type),
- name: m.name,
- structName: name,
- elementNamePrefix: '_${m.name}_item_',
+ name: memberName,
+ structName: enclosingClassName,
+ elementNamePrefix: '${expandedArrayItemPrefix}${memberName}_item_',
);
s.write(arrayHelper.declarationString(w));
helpers.add(arrayHelper);
@@ -90,7 +111,7 @@
if (m.type.isPrimitive) {
s.write('$depth@${m.type.getCType(w)}()\n');
}
- s.write('$depth${m.type.getDartType(w)} ${m.name};\n\n');
+ s.write('$depth${m.type.getDartType(w)} ${memberName};\n\n');
}
}
s.write('}\n\n');
@@ -101,6 +122,22 @@
return BindingString(type: BindingStringType.struc, string: s.toString());
}
+
+ /// Gets a unique prefix in local namespace for expanded array items.
+ String getUniqueExpandedArrayItemPrefix() {
+ final base = '_unique';
+ String expandedArrayItemPrefix = base;
+ int suffixInt = 0;
+ for (int i = 0; i < members.length; i++) {
+ if (members[i].name.startsWith(expandedArrayItemPrefix)) {
+ // Not a unique prefix, start over with a new suffix.
+ i = -1;
+ suffixInt++;
+ expandedArrayItemPrefix = '${base}${suffixInt}';
+ }
+ }
+ return expandedArrayItemPrefix + '_';
+ }
}
class Member {
diff --git a/lib/src/code_generator/type.dart b/lib/src/code_generator/type.dart
index dccdec3..a07b776 100644
--- a/lib/src/code_generator/type.dart
+++ b/lib/src/code_generator/type.dart
@@ -4,6 +4,8 @@
import 'package:meta/meta.dart';
+import 'struc.dart';
+import 'typedefc.dart';
import 'writer.dart';
class _SubType {
@@ -62,11 +64,11 @@
SupportedNativeType.IntPtr: _SubType(c: 'IntPtr', dart: 'int'),
};
- /// For providing name of Struct.
- String structName;
+ /// Reference to the [Struc] binding this type refers to.
+ Struc struc;
- /// For providing name of nativeFunc.
- String nativeFuncName;
+ /// Reference to the [TypedefC] this type refers to.
+ TypedefC nativeFunc;
/// For providing [SupportedNativeType] only.
final SupportedNativeType nativeType;
@@ -86,9 +88,9 @@
Type._({
@required this.broadType,
this.child,
- this.structName,
+ this.struc,
this.nativeType,
- this.nativeFuncName,
+ this.nativeFunc,
this.length,
this.unimplementedReason,
});
@@ -96,12 +98,11 @@
factory Type.pointer(Type child) {
return Type._(broadType: BroadType.Pointer, child: child);
}
- factory Type.struct(String structName) {
- return Type._(broadType: BroadType.Struct, structName: structName);
+ factory Type.struct(Struc struc) {
+ return Type._(broadType: BroadType.Struct, struc: struc);
}
- factory Type.nativeFunc(String nativeFuncName) {
- return Type._(
- broadType: BroadType.NativeFunction, nativeFuncName: nativeFuncName);
+ factory Type.nativeFunc(TypedefC nativeFunc) {
+ return Type._(broadType: BroadType.NativeFunction, nativeFunc: nativeFunc);
}
factory Type.nativeType(SupportedNativeType nativeType) {
return Type._(broadType: BroadType.NativeType, nativeType: nativeType);
@@ -124,15 +125,15 @@
broadType: BroadType.Unimplemented, unimplementedReason: reason);
}
- /// Get base broad type for any type.
+ /// Get base type for any type.
///
- /// E.g int** has base Broadtype as NativeType,
- /// double[2][3] has base broadtype as double.
- BroadType getBaseBroadType() {
+ /// E.g int** has base [Type] with [Broadtype] as NativeType,
+ /// double[2][3] has base [Type] with [Broadtype] as double.
+ Type getBaseType() {
if (child != null) {
- return child.getBaseBroadType();
+ return child.getBaseType();
} else {
- return broadType;
+ return this;
}
}
@@ -157,9 +158,9 @@
case BroadType.Pointer:
return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
case BroadType.Struct:
- return structName;
+ return '${struc.name}';
case BroadType.NativeFunction:
- return '${w.ffiLibraryPrefix}.NativeFunction<${nativeFuncName}>';
+ return '${w.ffiLibraryPrefix}.NativeFunction<${nativeFunc.name}>';
case BroadType
.IncompleteArray: // Array parameters are treated as Pointers in C.
return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
@@ -178,9 +179,9 @@
case BroadType.Pointer:
return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
case BroadType.Struct:
- return structName;
+ return '${struc.name}';
case BroadType.NativeFunction:
- return '${w.ffiLibraryPrefix}.NativeFunction<${nativeFuncName}>';
+ return '${w.ffiLibraryPrefix}.NativeFunction<${nativeFunc.name}>';
case BroadType
.IncompleteArray: // Array parameters are treated as Pointers in C.
return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
diff --git a/lib/src/code_generator/typedef.dart b/lib/src/code_generator/typedefc.dart
similarity index 71%
rename from lib/src/code_generator/typedef.dart
rename to lib/src/code_generator/typedefc.dart
index ea9568f..28075aa 100644
--- a/lib/src/code_generator/typedef.dart
+++ b/lib/src/code_generator/typedefc.dart
@@ -4,8 +4,6 @@
import 'package:meta/meta.dart';
-import 'binding.dart';
-import 'binding_string.dart';
import 'func.dart' show Parameter;
import 'type.dart';
import 'writer.dart';
@@ -18,23 +16,25 @@
/// $parameter2...,
/// .
/// .
-/// );`
+/// );
/// ```
-/// Note: This doesn't bind with anything.
-class TypedefC extends Binding {
+/// Used for generating typedefs for `Pointer<NativeFunction>`.
+///
+/// Name conflict resolution must be done before using.
+class TypedefC {
+ String name;
+ String dartDoc;
final Type returnType;
final List<Parameter> parameters;
TypedefC({
- @required String name,
- String dartDoc,
+ @required this.name,
+ this.dartDoc,
@required this.returnType,
List<Parameter> parameters,
- }) : parameters = parameters ?? [],
- super(name: name, dartDoc: dartDoc);
+ }) : parameters = parameters ?? [];
- @override
- BindingString toBindingString(Writer w) {
+ String toTypedefString(Writer w) {
final s = StringBuffer();
if (dartDoc != null) {
@@ -49,6 +49,6 @@
}
s.write(');\n\n');
- return BindingString(type: BindingStringType.typeDef, string: s.toString());
+ return s.toString();
}
}
diff --git a/lib/src/code_generator/utils.dart b/lib/src/code_generator/utils.dart
new file mode 100644
index 0000000..fbb1cce
--- /dev/null
+++ b/lib/src/code_generator/utils.dart
@@ -0,0 +1,37 @@
+class UniqueNamer {
+ final Set<String> _usedUpNames;
+ UniqueNamer(this._usedUpNames);
+
+ /// Returns a unique name by appending `_<int>` to it if necessary.
+ ///
+ /// Adds the resulting name to the used names by default.
+ String makeUnique(String name, [bool addToUsedUpNames = true]) {
+ String cr_name = name;
+ int i = 1;
+ while (_usedUpNames.contains(cr_name)) {
+ cr_name = '${name}_$i';
+ i++;
+ }
+ if (addToUsedUpNames) {
+ _usedUpNames.add(cr_name);
+ }
+ return cr_name;
+ }
+
+ /// Adds a name to used names.
+ ///
+ /// Note: [makeUnique] also adds the name by default.
+ void markUsed(String name) {
+ _usedUpNames.add(name);
+ }
+
+ /// Returns true if a name has been used before.
+ bool isUsed(String name) {
+ return _usedUpNames.contains(name);
+ }
+
+ /// Returns true if a name has not been used before.
+ bool isUnique(String name) {
+ return !_usedUpNames.contains(name);
+ }
+}
diff --git a/lib/src/code_generator/writer.dart b/lib/src/code_generator/writer.dart
index cc4496f..aa8129c 100644
--- a/lib/src/code_generator/writer.dart
+++ b/lib/src/code_generator/writer.dart
@@ -2,29 +2,62 @@
// 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/utils.dart';
+import 'package:meta/meta.dart';
+
import 'binding_string.dart';
/// To store generated String bindings.
class Writer {
- String header;
- String dylibIdentifier;
- String initFunctionIdentifier;
+ final String header;
+ String _initFunctionIdentifier;
- /// dart:ffi library import prefix.
- String ffiLibraryPrefix;
+ final UniqueNamer uniqueNamer;
+
+ String _ffiLibraryPrefix;
+ String get ffiLibraryPrefix =>
+ _ffiLibraryPrefix ??= uniqueNamer.makeUnique('ffi');
+
+ String _dylibIdentifier;
+ String get dylibIdentifier =>
+ _dylibIdentifier ??= uniqueNamer.makeUnique('_dylib');
+
+ String _arrayHelperClassPrefix;
+
+ /// Guaranteed to be a unique prefix.
+ String get arrayHelperClassPrefix => _arrayHelperClassPrefix;
final List<BindingString> _bindings = [];
+ /// [usedUpNames] should contain names of all the declarations which are
+ /// already used. This is used to avoid name collisions.
Writer({
- this.dylibIdentifier = '_dylib',
- this.initFunctionIdentifier = 'init',
- this.ffiLibraryPrefix = 'ffi',
- });
+ @required Set<String> usedUpNames,
+ String initFunctionIdentifier = 'init',
+ this.header,
+ }) : uniqueNamer = UniqueNamer(usedUpNames),
+ assert(initFunctionIdentifier != null) {
+ _initFunctionIdentifier =
+ uniqueNamer.makeUnique(initFunctionIdentifier);
+ /// Finding a unique prefix for Array Helper Classes and store into
+ /// [_arrayHelperClassPrefix].
+ final base = 'ArrayHelper';
+ _arrayHelperClassPrefix = base;
+ int suffixInt = 0;
+ for (int i = 0; i < usedUpNames.length; i++) {
+ if (usedUpNames.elementAt(i).startsWith(_arrayHelperClassPrefix)) {
+ // Not a unique prefix, start over with a new suffix.
+ i = -1;
+ suffixInt++;
+ _arrayHelperClassPrefix = '${base}${suffixInt}';
+ }
+ }
+ }
String generate() {
final s = StringBuffer();
- // Write header (if any)
+ // Write file header (if any).
if (header != null) {
s.write(header);
s.write('\n');
@@ -46,8 +79,8 @@
s.write('\n');
s.write('/// Initialises the Dynamic library.\n');
s.write(
- 'void $initFunctionIdentifier($ffiLibraryPrefix.DynamicLibrary dylib){\n');
- s.write(' ${dylibIdentifier} = dylib;\n');
+ 'void $_initFunctionIdentifier($ffiLibraryPrefix.DynamicLibrary dynamicLibrary){\n');
+ s.write(' ${dylibIdentifier} = dynamicLibrary;\n');
s.write('}\n');
// Write bindings.
diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart
index fbd2ae6..7abfb66 100644
--- a/lib/src/config_provider/config.dart
+++ b/lib/src/config_provider/config.dart
@@ -15,10 +15,10 @@
import 'package:yaml/yaml.dart';
import '../strings.dart' as strings;
-import 'filter.dart';
+import 'declaration.dart';
import 'spec_utils.dart';
-var _logger = Logger('config_provider/config');
+var _logger = Logger('config_provider:config.dart');
/// Provides configurations to other modules.
///
@@ -44,14 +44,14 @@
/// CommandLine Arguments to pass to clang_compiler.
List<String> compilerOpts;
- /// Filter for functions.
- Filter functionFilters;
+ /// Declaration config for Functions.
+ Declaration functionDecl;
- /// Filter for structs.
- Filter structFilters;
+ /// Declaration config for Structs.
+ Declaration structDecl;
- /// Filter for enumClass.
- Filter enumClassFilters;
+ /// Declaration config for Enums.
+ Declaration enumClassDecl;
/// If generated bindings should be sorted alphabetically.
bool sort;
@@ -67,23 +67,11 @@
/// If false(default), structs with inline array members will have all its members removed.
bool arrayWorkaround;
- /// Manually creating configurations.
- ///
- /// Use [Config.fromYaml] if extracting info from a yaml file.
- /// Ensure that log printing is setup before using this.
- Config.raw({
- this.output,
- @required this.libclang_dylib_path,
- @required this.headers,
- this.headerFilter,
- this.compilerOpts,
- this.functionFilters,
- this.structFilters,
- this.enumClassFilters,
- this.sort = false,
- this.useSupportedTypedefs = true,
- this.comment,
- });
+ /// Name of the init function used to initialise the dynamic library.
+ String initFunctionName;
+
+ /// Header of the generated bindings.
+ String preamble;
Config._();
@@ -137,7 +125,7 @@
if (map.containsKey(key)) {
spec.extractedResult(spec.extractor(map[key]));
} else {
- spec.extractedResult(spec.defaultValue);
+ spec.extractedResult(spec.defaultValue?.call());
}
}
}
@@ -152,14 +140,13 @@
isRequired: true,
validator: outputValidator,
extractor: outputExtractor,
- defaultValue: null,
extractedResult: (dynamic result) => output = result as String,
),
strings.libclang_dylib_folder: Specification<String>(
description:
'Path to folder containing libclang dynamic library, used to parse C headers',
isRequired: false,
- defaultValue: getDylibPath(Platform.script
+ defaultValue: () => getDylibPath(Platform.script
.resolve(path.join('..', 'tool', 'wrapped_libclang'))
.toFilePath()),
validator: libclangDylibValidator,
@@ -178,7 +165,7 @@
description: 'Include/Exclude inclusion headers',
validator: headerFilterValidator,
extractor: headerFilterExtractor,
- defaultValue: HeaderFilter(),
+ defaultValue: () => HeaderFilter(),
extractedResult: (dynamic result) {
return headerFilter = result as HeaderFilter;
},
@@ -188,40 +175,47 @@
isRequired: false,
validator: compilerOptsValidator,
extractor: compilerOptsExtractor,
- defaultValue: null,
extractedResult: (dynamic result) =>
compilerOpts = result as List<String>,
),
- strings.functions: Specification<Filter>(
+ strings.functions: Specification<Declaration>(
description: 'Filter for functions',
isRequired: false,
- validator: filterValidator,
- extractor: filterExtractor,
- defaultValue: null,
- extractedResult: (dynamic result) => functionFilters = result as Filter,
+ validator: declarationConfigValidator,
+ extractor: declarationConfigExtractor,
+ defaultValue: () => Declaration(declarationTypeName: 'Function'),
+ extractedResult: (dynamic result) {
+ functionDecl = result as Declaration;
+ functionDecl.declarationTypeName = 'Function';
+ },
),
- strings.structs: Specification<Filter>(
+ strings.structs: Specification<Declaration>(
description: 'Filter for Structs',
isRequired: false,
- validator: filterValidator,
- extractor: filterExtractor,
- defaultValue: null,
- extractedResult: (dynamic result) => structFilters = result as Filter,
+ validator: declarationConfigValidator,
+ extractor: declarationConfigExtractor,
+ defaultValue: () => Declaration(declarationTypeName: 'Struct'),
+ extractedResult: (dynamic result) {
+ structDecl = result as Declaration;
+ structDecl.declarationTypeName = 'Struct';
+ },
),
- strings.enums: Specification<Filter>(
+ strings.enums: Specification<Declaration>(
description: 'Filter for enums',
isRequired: false,
- validator: filterValidator,
- extractor: filterExtractor,
- defaultValue: null,
- extractedResult: (dynamic result) =>
- enumClassFilters = result as Filter,
+ validator: declarationConfigValidator,
+ extractor: declarationConfigExtractor,
+ defaultValue: () => Declaration(declarationTypeName: 'Enum'),
+ extractedResult: (dynamic result) {
+ enumClassDecl = result as Declaration;
+ enumClassDecl.declarationTypeName = 'Enum';
+ },
),
strings.sizemap: Specification<Map<int, SupportedNativeType>>(
description: 'map of types: byte size in int',
validator: sizemapValidator,
extractor: sizemapExtractor,
- defaultValue: <int, SupportedNativeType>{},
+ defaultValue: () => <int, SupportedNativeType>{},
extractedResult: (dynamic result) {
final map = result as Map<int, SupportedNativeType>;
for (final key in map.keys) {
@@ -236,7 +230,7 @@
isRequired: false,
validator: booleanValidator,
extractor: booleanExtractor,
- defaultValue: false,
+ defaultValue: () => false,
extractedResult: (dynamic result) => sort = result as bool,
),
strings.useSupportedTypedefs: Specification<bool>(
@@ -244,7 +238,7 @@
isRequired: false,
validator: booleanValidator,
extractor: booleanExtractor,
- defaultValue: true,
+ defaultValue: () => true,
extractedResult: (dynamic result) =>
useSupportedTypedefs = result as bool,
),
@@ -253,7 +247,7 @@
isRequired: false,
validator: commentValidator,
extractor: commentExtractor,
- defaultValue: strings.brief,
+ defaultValue: () => strings.brief,
extractedResult: (dynamic result) => comment = result as String,
),
strings.arrayWorkaround: Specification<bool>(
@@ -262,9 +256,25 @@
isRequired: false,
validator: booleanValidator,
extractor: booleanExtractor,
- defaultValue: false,
+ defaultValue: () => false,
extractedResult: (dynamic result) => arrayWorkaround = result as bool,
),
+ strings.initFunctionName: Specification<String>(
+ description: 'Name of the init function to use',
+ isRequired: false,
+ validator: nonEmptyStringValidator,
+ extractor: stringExtractor,
+ defaultValue: () => 'init',
+ extractedResult: (dynamic result) =>
+ initFunctionName = result as String,
+ ),
+ strings.preamble: Specification<String>(
+ description: 'Header String for the generated bindings',
+ isRequired: false,
+ validator: nonEmptyStringValidator,
+ extractor: stringExtractor,
+ extractedResult: (dynamic result) => preamble = result as String,
+ ),
};
}
}
@@ -276,7 +286,8 @@
final String description;
final bool Function(String name, dynamic value) validator;
final E Function(dynamic map) extractor;
- final E defaultValue;
+ final E Function() defaultValue;
+
final bool isRequired;
final void Function(dynamic result) extractedResult;
diff --git a/lib/src/config_provider/declaration.dart b/lib/src/config_provider/declaration.dart
new file mode 100644
index 0000000..4674bc5
--- /dev/null
+++ b/lib/src/config_provider/declaration.dart
@@ -0,0 +1,107 @@
+// 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 'package:logging/logging.dart';
+
+var _logger = Logger('config_provider:declaration.dart');
+
+/// A generic declaration config.
+class Declaration {
+ /// Display name of a declaration type.
+ ///
+ /// Used for logging and warning purposes.
+ String declarationTypeName;
+
+ // matchers
+ List<RegExp> _includeMatchers = [];
+ Set<String> _includeFull = {};
+ List<RegExp> _excludeMatchers = [];
+ Set<String> _excludeFull = {};
+ String _globalPrefix = '';
+ Map<String, String> _prefixReplacement = {};
+
+ Declaration({
+ this.declarationTypeName = 'declaration',
+ List<String> includeMatchers,
+ List<String> includeFull,
+ List<String> excludeMatchers,
+ List<String> excludeFull,
+ String globalPrefix,
+ Map<String, String> prefixReplacement,
+ }) {
+ if (includeMatchers != null) {
+ _includeMatchers =
+ includeMatchers.map((e) => RegExp(e, dotAll: true)).toList();
+ }
+ if (includeFull != null) {
+ _includeFull = includeFull.map((e) => e).toSet();
+ }
+ if (excludeMatchers != null) {
+ _excludeMatchers =
+ excludeMatchers.map((e) => RegExp(e, dotAll: true)).toList();
+ }
+ if (excludeFull != null) {
+ _excludeFull = excludeFull.map((e) => e).toSet();
+ }
+ if (globalPrefix != null) {
+ _globalPrefix = globalPrefix;
+ }
+ if (prefixReplacement != null) {
+ _prefixReplacement = prefixReplacement;
+ }
+ }
+
+ /// Applies prefix and replacement and returns the result.
+ ///
+ /// Also logs warnings if declaration starts with '_'.
+ String getPrefixedName(String name) {
+ // Apply prefix replacement.
+ for (final pattern in _prefixReplacement.keys) {
+ if (name.startsWith(pattern)) {
+ name = name.replaceFirst(pattern, _prefixReplacement[pattern]);
+ break;
+ }
+ }
+
+ // Apply global prefixes.
+ name = '${_globalPrefix}$name';
+
+ // Warn user if a declaration starts with '_'.
+ if (name.startsWith('_')) {
+ _logger.warning(
+ "Generated $declarationTypeName '$name' start's with '_' and therefore will be private.");
+ }
+ return name;
+ }
+
+ /// Checks if a name is allowed by a filter.
+ bool shouldInclude(String name) {
+ if (_excludeFull.contains(name)) {
+ return false;
+ }
+
+ for (final em in _excludeMatchers) {
+ if (em.firstMatch(name)?.end == name.length) {
+ return false;
+ }
+ }
+
+ if (_includeFull.contains(name)) {
+ return true;
+ }
+
+ for (final im in _includeMatchers) {
+ if (im.firstMatch(name)?.end == name.length) {
+ return true;
+ }
+ }
+
+ // If user has provided 'include' field in the filter, then default
+ // matching is false.
+ if (_includeMatchers.isNotEmpty || _includeFull.isNotEmpty) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+}
diff --git a/lib/src/config_provider/filter.dart b/lib/src/config_provider/filter.dart
deleted file mode 100644
index b35dc0b..0000000
--- a/lib/src/config_provider/filter.dart
+++ /dev/null
@@ -1,80 +0,0 @@
-// 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.
-
-/// A generic filter for filtering strings based on regexes and prefixes.
-///
-/// Excludes override includes.
-///
-/// User can provide fiters for functions, structs, enums and include/exclude
-/// them using regexp and full name matching.
-class Filter {
- // matchers
- List<RegExp> _includeMatchers = [];
- Set<String> _includeFull = {};
- List<RegExp> _excludeMatchers = [];
- Set<String> _excludeFull = {};
-
- Filter({
- List<String> includeMatchers,
- List<String> includeFull,
- List<String> excludeMatchers,
- List<String> excludeFull,
- }) {
- if (includeMatchers != null) {
- _includeMatchers =
- includeMatchers.map((e) => RegExp(e, dotAll: true)).toList();
- }
- if (includeFull != null) {
- _includeFull = includeFull.map((e) => e).toSet();
- }
- if (excludeMatchers != null) {
- _excludeMatchers =
- excludeMatchers.map((e) => RegExp(e, dotAll: true)).toList();
- }
- if (excludeFull != null) {
- _excludeFull = excludeFull.map((e) => e).toSet();
- }
- }
-
- /// Checks if a name is allowed by a filter.
- bool shouldInclude(String name) {
- if (_excludeFull.contains(name)) {
- return false;
- }
-
- for (final em in _excludeMatchers) {
- if (em.firstMatch(name)?.end == name.length) {
- return false;
- }
- }
-
- if (_includeFull.contains(name)) {
- return true;
- }
-
- for (final im in _includeMatchers) {
- if (im.firstMatch(name)?.end == name.length) {
- return true;
- }
- }
-
- // If user has provided 'include' field in the filter, then default
- // matching is false.
- if (_includeMatchers.isNotEmpty || _includeFull.isNotEmpty) {
- return false;
- } else {
- return true;
- }
- }
-
- @override
- String toString() {
- return ''' (includeFull, includeMatchers, excludeFull, excludeMatchers)
-$_includeFull
-$_includeMatchers
-$_excludeFull
-$_excludeMatchers
- ''';
- }
-}
diff --git a/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart
index 3544330..560cc59 100644
--- a/lib/src/config_provider/spec_utils.dart
+++ b/lib/src/config_provider/spec_utils.dart
@@ -12,9 +12,9 @@
import '../strings.dart' as strings;
import './config.dart';
-import 'filter.dart';
+import 'declaration.dart';
-var _logger = Logger('config_provider/utils');
+var _logger = Logger('config_provider:spec_utils.dart');
bool booleanExtractor(dynamic value) => value as bool;
@@ -166,13 +166,15 @@
if (value is String) {
return true;
} else {
- _logger.severe("Expected value of key '${strings.output}' to be a String.");
+ _logger.severe("Expected value of key '$name' to be a String.");
return false;
}
}
-Filter filterExtractor(dynamic yamlMap) {
+Declaration declarationConfigExtractor(dynamic yamlMap) {
List<String> includeMatchers, includeFull, excludeMatchers, excludeFull;
+ String prefix;
+ Map<String, String> prefixReplacement;
final include = yamlMap[strings.include] as YamlMap;
if (include != null) {
@@ -186,21 +188,29 @@
excludeFull = (exclude[strings.names] as YamlList)?.cast<String>();
}
- return Filter(
+ prefix = yamlMap[strings.prefix] as String;
+
+ prefixReplacement =
+ (yamlMap[strings.prefix_replacement] as YamlMap)?.cast<String, String>();
+
+ return Declaration(
includeMatchers: includeMatchers,
includeFull: includeFull,
excludeMatchers: excludeMatchers,
excludeFull: excludeFull,
+ globalPrefix: prefix,
+ prefixReplacement: prefixReplacement,
);
}
-bool filterValidator(String name, dynamic value) {
+bool declarationConfigValidator(String name, dynamic value) {
var _result = true;
if (value is YamlMap) {
for (final key in value.keys) {
if (key == strings.include || key == strings.exclude) {
if (value[key] is! YamlMap) {
_logger.severe("Expected '$name -> $key' to be a Map.");
+ _result = false;
}
for (final subkey in value[key].keys) {
if (subkey == strings.matches || subkey == strings.names) {
@@ -213,6 +223,24 @@
_logger.severe("Unknown key '$subkey' in '$name -> $key'.");
}
}
+ } else if (key == strings.prefix) {
+ if (value[key] is! String) {
+ _logger.severe("Expected '$name -> $key' to be a String.");
+ _result = false;
+ }
+ } else if (key == strings.prefix_replacement) {
+ if (value[key] is! YamlMap) {
+ _logger.severe("Expected '$name -> $key' to be a Map.");
+ _result = false;
+ } else {
+ for (final subkey in value[key].keys) {
+ if (value[key][subkey] is! String) {
+ _logger.severe(
+ "Expected '$name -> $key -> $subkey' to be a String.");
+ _result = false;
+ }
+ }
+ }
} else {
_logger.severe("Unknown key '$key' in '$name'.");
_result = false;
@@ -241,6 +269,17 @@
}
}
+String stringExtractor(dynamic value) => value as String;
+
+bool nonEmptyStringValidator(String name, dynamic value) {
+ if (value is String && value.isNotEmpty) {
+ return true;
+ } else {
+ _logger.severe("Expected value of key '$name' to be a non-empty String.");
+ return false;
+ }
+}
+
String commentExtractor(dynamic value) => value as String;
bool commentValidator(String name, dynamic value) {
diff --git a/lib/src/header_parser/clang_bindings/clang_bindings.dart b/lib/src/header_parser/clang_bindings/clang_bindings.dart
index 546c8dc..e71a162 100644
--- a/lib/src/header_parser/clang_bindings/clang_bindings.dart
+++ b/lib/src/header_parser/clang_bindings/clang_bindings.dart
@@ -7,8 +7,8 @@
ffi.DynamicLibrary _dylib;
/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib) {
- _dylib = dylib;
+void init(ffi.DynamicLibrary __dylib) {
+ _dylib = __dylib;
}
/// Describes how the traversal of the children of a particular cursor should
@@ -35,9 +35,9 @@
@ffi.Int32()
int xdata;
- ffi.Pointer<ffi.Void> _data_item_0;
- ffi.Pointer<ffi.Void> _data_item_1;
- ffi.Pointer<ffi.Void> _data_item_2;
+ ffi.Pointer<ffi.Void> _exp_workaround_data_item_0;
+ ffi.Pointer<ffi.Void> _exp_workaround_data_item_1;
+ ffi.Pointer<ffi.Void> _exp_workaround_data_item_2;
/// Helper for array `data`.
ArrayHelper_CXCursor_data_level0 get data =>
@@ -64,11 +64,11 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- return _struct._data_item_0;
+ return _struct._exp_workaround_data_item_0;
case 1:
- return _struct._data_item_1;
+ return _struct._exp_workaround_data_item_1;
case 2:
- return _struct._data_item_2;
+ return _struct._exp_workaround_data_item_2;
default:
throw Exception('Invalid Array Helper generated.');
}
@@ -78,13 +78,13 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- _struct._data_item_0 = value;
+ _struct._exp_workaround_data_item_0 = value;
break;
case 1:
- _struct._data_item_1 = value;
+ _struct._exp_workaround_data_item_1 = value;
break;
case 2:
- _struct._data_item_2 = value;
+ _struct._exp_workaround_data_item_2 = value;
break;
default:
throw Exception('Invalid Array Helper generated.');
@@ -769,8 +769,8 @@
/// Identifies a specific source location within a translation unit.
class CXSourceLocation extends ffi.Struct {
- ffi.Pointer<ffi.Void> _ptr_data_item_0;
- ffi.Pointer<ffi.Void> _ptr_data_item_1;
+ ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_0;
+ ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_1;
/// Helper for array `ptr_data`.
ArrayHelper_CXSourceLocation_ptr_data_level0 get ptr_data =>
@@ -799,9 +799,9 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- return _struct._ptr_data_item_0;
+ return _struct._exp_workaround_ptr_data_item_0;
case 1:
- return _struct._ptr_data_item_1;
+ return _struct._exp_workaround_ptr_data_item_1;
default:
throw Exception('Invalid Array Helper generated.');
}
@@ -811,10 +811,10 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- _struct._ptr_data_item_0 = value;
+ _struct._exp_workaround_ptr_data_item_0 = value;
break;
case 1:
- _struct._ptr_data_item_1 = value;
+ _struct._exp_workaround_ptr_data_item_1 = value;
break;
default:
throw Exception('Invalid Array Helper generated.');
@@ -824,8 +824,8 @@
/// Identifies a half-open character range in the source code.
class CXSourceRange extends ffi.Struct {
- ffi.Pointer<ffi.Void> _ptr_data_item_0;
- ffi.Pointer<ffi.Void> _ptr_data_item_1;
+ ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_0;
+ ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_1;
/// Helper for array `ptr_data`.
ArrayHelper_CXSourceRange_ptr_data_level0 get ptr_data =>
@@ -857,9 +857,9 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- return _struct._ptr_data_item_0;
+ return _struct._exp_workaround_ptr_data_item_0;
case 1:
- return _struct._ptr_data_item_1;
+ return _struct._exp_workaround_ptr_data_item_1;
default:
throw Exception('Invalid Array Helper generated.');
}
@@ -869,10 +869,10 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- _struct._ptr_data_item_0 = value;
+ _struct._exp_workaround_ptr_data_item_0 = value;
break;
case 1:
- _struct._ptr_data_item_1 = value;
+ _struct._exp_workaround_ptr_data_item_1 = value;
break;
default:
throw Exception('Invalid Array Helper generated.');
@@ -959,8 +959,8 @@
@ffi.Int32()
int kind;
- ffi.Pointer<ffi.Void> _data_item_0;
- ffi.Pointer<ffi.Void> _data_item_1;
+ ffi.Pointer<ffi.Void> _exp_workaround_data_item_0;
+ ffi.Pointer<ffi.Void> _exp_workaround_data_item_1;
/// Helper for array `data`.
ArrayHelper_CXType_data_level0 get data =>
@@ -987,9 +987,9 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- return _struct._data_item_0;
+ return _struct._exp_workaround_data_item_0;
case 1:
- return _struct._data_item_1;
+ return _struct._exp_workaround_data_item_1;
default:
throw Exception('Invalid Array Helper generated.');
}
@@ -999,10 +999,10 @@
_checkBounds(index);
switch (_absoluteIndex + index) {
case 0:
- _struct._data_item_0 = value;
+ _struct._exp_workaround_data_item_0 = value;
break;
case 1:
- _struct._data_item_1 = value;
+ _struct._exp_workaround_data_item_1 = value;
break;
default:
throw Exception('Invalid Array Helper generated.');
@@ -1150,12 +1150,6 @@
int Length;
}
-typedef ModifiedCXCursorVisitor = ffi.Int32 Function(
- ffi.Pointer<CXCursor>,
- ffi.Pointer<CXCursor>,
- ffi.Pointer<ffi.Void>,
-);
-
ffi.Pointer<CXCursor> clang_Cursor_getArgument_wrap(
ffi.Pointer<CXCursor> cursor,
int i,
@@ -2001,11 +1995,17 @@
int options,
);
+typedef ModifiedCXCursorVisitor_1 = ffi.Int32 Function(
+ ffi.Pointer<CXCursor>,
+ ffi.Pointer<CXCursor>,
+ ffi.Pointer<ffi.Void>,
+);
+
/// Visitor is a function pointer with parameters having pointers to cxcursor
/// instead of cxcursor by default.
int clang_visitChildren_wrap(
ffi.Pointer<CXCursor> parent,
- ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
+ ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
ffi.Pointer<ffi.Void> clientData,
) {
return _clang_visitChildren_wrap(
@@ -2021,12 +2021,12 @@
typedef _c_clang_visitChildren_wrap = ffi.Uint32 Function(
ffi.Pointer<CXCursor> parent,
- ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
+ ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
ffi.Pointer<ffi.Void> clientData,
);
typedef _dart_clang_visitChildren_wrap = int Function(
ffi.Pointer<CXCursor> parent,
- ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
+ ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
ffi.Pointer<ffi.Void> clientData,
);
diff --git a/lib/src/header_parser/includer.dart b/lib/src/header_parser/includer.dart
index 23698a5..f0ab13c 100644
--- a/lib/src/header_parser/includer.dart
+++ b/lib/src/header_parser/includer.dart
@@ -2,25 +2,23 @@
// 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:meta/meta.dart';
+import 'package:ffigen/src/code_generator.dart';
import 'package:path/path.dart' as p;
import 'data.dart';
/// Utility functions to check whether a binding should be parsed or not
-/// based on filters and if a binding is seen already.
+/// based on filters.
-// Stores binding names already scene.
-Set<String> _structs = {};
-Set<String> _functions = {};
-Set<String> _enumClass = {};
-Set<String> _typedefC = {};
+// Stores binding names already scene. Mp key is same as their original name.
+Map<String, Struc> _structs = {};
+Map<String, Func> _functions = {};
+Map<String, EnumClass> _enumClass = {};
bool shouldIncludeStruct(String name) {
- if (_structs.contains(name) || name == '') {
+ if (_structs.containsKey(name) || name == '') {
return false;
- } else if (config.structFilters == null ||
- config.structFilters.shouldInclude(name)) {
- _structs.add(name);
+ } else if (config.structDecl == null ||
+ config.structDecl.shouldInclude(name)) {
return true;
} else {
return false;
@@ -28,11 +26,10 @@
}
bool shouldIncludeFunc(String name) {
- if (_functions.contains(name) || name == '') {
+ if (_functions.containsKey(name) || name == '') {
return false;
- } else if (config.functionFilters == null ||
- config.functionFilters.shouldInclude(name)) {
- _functions.add(name);
+ } else if (config.functionDecl == null ||
+ config.functionDecl.shouldInclude(name)) {
return true;
} else {
return false;
@@ -40,11 +37,10 @@
}
bool shouldIncludeEnumClass(String name) {
- if (_enumClass.contains(name) || name == '') {
+ if (_enumClass.containsKey(name) || name == '') {
return false;
- } else if (config.enumClassFilters == null ||
- config.enumClassFilters.shouldInclude(name)) {
- _enumClass.add(name);
+ } else if (config.enumClassDecl == null ||
+ config.enumClassDecl.shouldInclude(name)) {
return true;
} else {
return false;
@@ -72,24 +68,38 @@
}
}
-bool isUnseenTypedefC(String name, {@required bool addToSeen}) {
- if (_typedefC.contains(name)) {
- return false;
- } else {
- if (addToSeen) {
- _typedefC.add(name);
- }
- return true;
- }
+bool isSeenStruc(String originalName) {
+ return _structs.containsKey(originalName);
}
-bool isUnseenStruct(String name, {@required bool addToSeen}) {
- if (_structs.contains(name)) {
- return false;
- } else {
- if (addToSeen) {
- _structs.add(name);
- }
- return true;
- }
+void addStrucToSeen(String originalName, Struc struc) {
+ _structs[originalName] = struc;
+}
+
+Struc getSeenStruc(String originalName) {
+ return _structs[originalName];
+}
+
+bool isSeenFunc(String originalName) {
+ return _functions.containsKey(originalName);
+}
+
+void addFuncToSeen(String originalName, Func func) {
+ _functions[originalName] = func;
+}
+
+Func getSeenFunc(String originalName) {
+ return _functions[originalName];
+}
+
+bool isSeenEnumClass(String originalName) {
+ return _enumClass.containsKey(originalName);
+}
+
+void addEnumClassToSeen(String originalName, EnumClass enumClass) {
+ _enumClass[originalName] = enumClass;
+}
+
+EnumClass getSeenEnumClass(String originalName) {
+ return _enumClass[originalName];
}
diff --git a/lib/src/header_parser/parser.dart b/lib/src/header_parser/parser.dart
index eac3c93..f50e2e5 100644
--- a/lib/src/header_parser/parser.dart
+++ b/lib/src/header_parser/parser.dart
@@ -20,7 +20,11 @@
final bindings = parseToBindings();
- final library = Library(bindings: bindings);
+ final library = Library(
+ bindings: bindings,
+ initFunctionIdentifier: data.config.initFunctionName,
+ header: data.config.preamble,
+ );
if (sort) {
library.sort();
@@ -32,7 +36,7 @@
// BELOW FUNCTIONS ARE MEANT FOR INTERNAL USE AND TESTING
// ===================================================================================
-var _logger = Logger('parser:parser');
+var _logger = Logger('header_parser:parser.dart');
/// initialises parser, clears any previous values.
void initParser(Config c) {
diff --git a/lib/src/header_parser/sub_parsers/enumdecl_parser.dart b/lib/src/header_parser/sub_parsers/enumdecl_parser.dart
index c3e5a54..25266e1 100644
--- a/lib/src/header_parser/sub_parsers/enumdecl_parser.dart
+++ b/lib/src/header_parser/sub_parsers/enumdecl_parser.dart
@@ -5,13 +5,14 @@
import 'dart:ffi';
import 'package:ffigen/src/code_generator.dart';
+import 'package:ffigen/src/header_parser/data.dart';
import 'package:logging/logging.dart';
import '../clang_bindings/clang_bindings.dart' as clang;
import '../includer.dart';
import '../utils.dart';
-var _logger = Logger('parser:enumdecl_parser');
+var _logger = Logger('header_parser:enumdecl_parser.dart');
/// Temporarily holds a enumClass before its returned by [parseEnumDeclaration].
EnumClass _enumClass;
@@ -28,12 +29,13 @@
final enumName = name ?? cursor.spelling();
if (enumName == '') {
_logger.finest('unnamed enum declaration');
- } else if (shouldIncludeEnumClass(enumName)) {
+ } else if (shouldIncludeEnumClass(enumName) && !isSeenEnumClass(enumName)) {
_logger.fine('++++ Adding Enum: ${cursor.completeStringRepr()}');
_enumClass = EnumClass(
dartDoc: getCursorDocComment(cursor),
- name: enumName,
+ name: config.enumClassDecl.getPrefixedName(enumName),
);
+ addEnumClassToSeen(enumName, _enumClass);
_addEnumConstant(cursor);
}
diff --git a/lib/src/header_parser/sub_parsers/functiondecl_parser.dart b/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
index 3afb7b7..98b93d0 100644
--- a/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
+++ b/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
@@ -5,13 +5,14 @@
import 'dart:ffi';
import 'package:ffigen/src/code_generator.dart';
+import 'package:ffigen/src/header_parser/data.dart';
import 'package:logging/logging.dart';
import '../clang_bindings/clang_bindings.dart' as clang;
import '../includer.dart';
import '../utils.dart';
-var _logger = Logger('parser:functiondecl_parser');
+var _logger = Logger('header_parser:functiondecl_parser.dart');
/// Temporarily holds a function before its returned by [parseFunctionDeclaration].
Func _func;
@@ -22,8 +23,8 @@
structByValueParameter = false;
unimplementedParameterType = false;
- final name = cursor.spelling();
- if (shouldIncludeFunc(name)) {
+ final funcName = cursor.spelling();
+ if (shouldIncludeFunc(funcName) && !isSeenFunc(funcName)) {
_logger.fine('++++ Adding Function: ${cursor.completeStringRepr()}');
final rt = _getFunctionReturnType(cursor);
@@ -34,25 +35,27 @@
_logger.fine(
'---- Removed Function, reason: struct pass/return by value: ${cursor.completeStringRepr()}');
_logger.warning(
- "Skipped Function '$name', struct pass/return by value not supported.");
+ "Skipped Function '$funcName', struct pass/return by value not supported.");
return null; // Returning null so that [addToBindings] function excludes this.
}
- if (rt.getBaseBroadType() == BroadType.Unimplemented ||
+ if (rt.getBaseType().broadType == BroadType.Unimplemented ||
unimplementedParameterType) {
_logger.fine(
'---- Removed Function, reason: unsupported return type or parameter type: ${cursor.completeStringRepr()}');
_logger.warning(
- "Skipped Function '$name', function has unsupported return type or parameter type.");
+ "Skipped Function '$funcName', function has unsupported return type or parameter type.");
return null; // Returning null so that [addToBindings] function excludes this.
}
_func = Func(
dartDoc: getCursorDocComment(cursor),
- name: name,
+ name: config.functionDecl.getPrefixedName(funcName),
+ lookupSymbolName: funcName,
returnType: rt,
parameters: parameters,
);
+ addFuncToSeen(funcName, _func);
}
return _func;
@@ -77,7 +80,7 @@
//TODO(3): Remove this when support for Structs by value arrives.
if (pt.broadType == BroadType.Struct) {
structByValueParameter = true;
- } else if (pt.getBaseBroadType() == BroadType.Unimplemented) {
+ } else if (pt.getBaseType().broadType == BroadType.Unimplemented) {
unimplementedParameterType = true;
}
diff --git a/lib/src/header_parser/sub_parsers/structdecl_parser.dart b/lib/src/header_parser/sub_parsers/structdecl_parser.dart
index d7c9dc4..a71f69e 100644
--- a/lib/src/header_parser/sub_parsers/structdecl_parser.dart
+++ b/lib/src/header_parser/sub_parsers/structdecl_parser.dart
@@ -12,7 +12,7 @@
import '../includer.dart';
import '../utils.dart';
-var _logger = Logger('parser:structdecl_parser');
+var _logger = Logger('header_parser:structdecl_parser.dart');
/// Temporarily holds a struc before its returned by [parseStructDeclaration].
Struc _struc;
@@ -24,11 +24,9 @@
/// Optionally provide name (useful in case struct is inside a typedef).
String name,
- /// Option to override shouldInclude methods. (Useful in case of extracting
- /// structs when they are passed/returned by an included function.)
- ///
- /// Check if binding is not already included before setting this to true.
- bool doInclude = false,
+ /// Option to ignore struct filter (Useful in case of extracting structs
+ /// when they are passed/returned by an included function.)
+ bool ignoreFilter = false,
}) {
_struc = null;
final structName = name ?? cursor.spelling();
@@ -36,16 +34,19 @@
if (structName == '') {
_logger.finest('unnamed structure or typedef structure declaration');
return null;
- } else if (doInclude || shouldIncludeStruct(structName)) {
+ } else if ((ignoreFilter || shouldIncludeStruct(structName)) &&
+ (!isSeenStruc(structName))) {
_logger.fine(
'++++ Adding Structure: structName: ${structName}, ${cursor.completeStringRepr()}');
- final members = _getMembers(cursor, structName);
_struc = Struc(
+ name: config.structDecl.getPrefixedName(structName),
dartDoc: getCursorDocComment(cursor),
- name: structName,
- members: members,
);
+ // Adding to seen here to stop recursion if a struct has itself as a
+ // member, members are updated later.
+ addStrucToSeen(structName, _struc);
+ _struc.members = _getMembers(cursor, structName);
}
return _struc;
@@ -72,19 +73,19 @@
'---- Removed Struct members, reason: struct has array members ${cursor.completeStringRepr()}');
_logger.warning(
'Removed All Struct Members from: $structName, Array members not supported');
- return null;
+ return [];
} else if (nestedStructMember) {
_logger.fine(
'---- Removed Struct members, reason: struct has struct members ${cursor.completeStringRepr()}');
_logger.warning(
"Removed All Struct Members from '$structName', Nested Structures not supported.");
- return null;
+ return [];
} else if (unimplementedMemberType) {
_logger.fine(
'---- Removed Struct members, reason: member with unimplementedtype ${cursor.completeStringRepr()}');
_logger.warning(
"Removed All Struct Members from '$structName', struct member has an unsupported type.");
- return null;
+ return [];
}
return _members;
@@ -119,7 +120,7 @@
}
}
- if (mt.getBaseBroadType() == BroadType.Unimplemented) {
+ if (mt.getBaseType().broadType == BroadType.Unimplemented) {
unimplementedMemberType = true;
}
diff --git a/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart b/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart
index c68b5e3..30ec2ab 100644
--- a/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart
+++ b/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart
@@ -12,7 +12,7 @@
import '../sub_parsers/structdecl_parser.dart';
import '../utils.dart';
-var _logger = Logger('parser:typedefdecl_parser');
+var _logger = Logger('header_parser:typedefdecl_parser.dart');
/// Temporarily holds a binding before its returned by [parseTypedefDeclaration].
Binding _binding;
diff --git a/lib/src/header_parser/translation_unit_parser.dart b/lib/src/header_parser/translation_unit_parser.dart
index 8632b25..a1b794b 100644
--- a/lib/src/header_parser/translation_unit_parser.dart
+++ b/lib/src/header_parser/translation_unit_parser.dart
@@ -15,7 +15,7 @@
import 'sub_parsers/typedefdecl_parser.dart';
import 'utils.dart';
-var _logger = Logger('parser:root_parser');
+var _logger = Logger('header_parser:translation_unit_parser.dart');
List<Binding> _bindings;
diff --git a/lib/src/header_parser/type_extractor/extractor.dart b/lib/src/header_parser/type_extractor/extractor.dart
index 9584cea..65fd6f0 100644
--- a/lib/src/header_parser/type_extractor/extractor.dart
+++ b/lib/src/header_parser/type_extractor/extractor.dart
@@ -16,7 +16,7 @@
import '../type_extractor/cxtypekindmap.dart';
import '../utils.dart';
-var _logger = Logger('parser:extractor');
+var _logger = Logger('header_parser:extractor.dart');
const _padding = ' ';
/// Converts cxtype to a typestring code_generator can accept.
@@ -100,12 +100,20 @@
structName = cxtype.spelling();
}
- type = Type.struct(structName);
+ final fixedStructName = config.structDecl.getPrefixedName(structName);
// Also add a struct binding, if its unseen.
- if (isUnseenStruct(structName, addToSeen: true)) {
- addToBindings(
- parseStructDeclaration(cursor, name: structName, doInclude: true));
+ // TODO(23): Check if we should auto add struct.
+ if (isSeenStruc(structName)) {
+ type = Type.struct(getSeenStruc(structName));
+ } else {
+ final struc = parseStructDeclaration(cursor,
+ name: fixedStructName, ignoreFilter: true);
+ type = Type.struct(struc);
+ // Add to bindings.
+ addToBindings(struc);
+ // Add to seen.
+ addStrucToSeen(structName, struc);
}
cxtype.dispose();
@@ -127,25 +135,34 @@
// Set a name for typedefc incase it was null or empty.
if (name == null || name == '') {
- name = _getNextUniqueString('_typedefC_noname');
+ name = _getNextUniqueString('_typedefC');
+ } else {
+ name = _getNextUniqueString(name);
}
+ final _parameters = <Parameter>[];
+ final totalArgs = clang.clang_getNumArgTypes_wrap(cxtype);
+ for (var i = 0; i < totalArgs; i++) {
+ final t = clang.clang_getArgType_wrap(cxtype, i);
+ final pt = t.toCodeGenTypeAndDispose();
- if (isUnseenTypedefC(name, addToSeen: true)) {
- final typedefC = TypedefC(
- name: name,
- returnType:
- clang.clang_getResultType_wrap(cxtype).toCodeGenTypeAndDispose(),
- );
- final totalArgs = clang.clang_getNumArgTypes_wrap(cxtype);
- for (var i = 0; i < totalArgs; i++) {
- final t = clang.clang_getArgType_wrap(cxtype, i);
- typedefC.parameters.add(
- Parameter(name: '', type: t.toCodeGenTypeAndDispose()),
- );
+ if (pt.broadType == BroadType.Struct) {
+ return Type.unimplemented('Struct by value in function parameter.');
+ } else if (pt.broadType == BroadType.Unimplemented) {
+ return Type.unimplemented('Function parameter has an unsupported type.');
}
- addToBindings(typedefC);
+
+ _parameters.add(
+ Parameter(name: '', type: pt),
+ );
}
- return Type.nativeFunc(name);
+ final typedefC = TypedefC(
+ name: name,
+ parameters: _parameters,
+ returnType:
+ clang.clang_getResultType_wrap(cxtype).toCodeGenTypeAndDispose(),
+ );
+
+ return Type.nativeFunc(typedefC);
}
/// Generate a unique string for naming in [TypedefC].
diff --git a/lib/src/strings.dart b/lib/src/strings.dart
index a03aa97..27e1d50 100644
--- a/lib/src/strings.dart
+++ b/lib/src/strings.dart
@@ -19,6 +19,8 @@
// Sub-fields of Declarations.
const include = 'include';
const exclude = 'exclude';
+const prefix = 'prefix';
+const prefix_replacement = 'prefix-replacement';
// Sub-fields of include/exclude.
const matches = 'matches'; // regex
@@ -68,6 +70,10 @@
// Contains all possibe comment types.
const commentTypeSet = {brief, full, none};
+// Library input.
+const initFunctionName = 'init-function-name';
+const preamble = 'preamble';
+
// Dynamic library names.
const libclang_dylib_linux = 'libwrapped_clang.so';
const libclang_dylib_macos = 'libwrapped_clang.dylib';
diff --git a/test/code_generator_test.dart b/test/code_generator_test.dart
index 4312837..cddaab4 100644
--- a/test/code_generator_test.dart
+++ b/test/code_generator_test.dart
@@ -14,6 +14,7 @@
bindings: [
Func(
name: 'noParam',
+ lookupSymbolName: 'noParam',
dartDoc: 'Just a test function\nheres another line',
returnType: Type.nativeType(
SupportedNativeType.Int32,
@@ -21,6 +22,7 @@
),
Func(
name: 'withPrimitiveParam',
+ lookupSymbolName: 'withPrimitiveParam',
parameters: [
Parameter(
name: 'a',
@@ -41,6 +43,7 @@
),
Func(
name: 'withPointerParam',
+ lookupSymbolName: 'withPointerParam',
parameters: [
Parameter(
name: 'a',
@@ -86,8 +89,8 @@
ffi.DynamicLibrary _dylib;
/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
- _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary){
+ _dylib = dynamicLibrary;
}
/// Just a test function
/// heres another line
@@ -237,8 +240,8 @@
ffi.DynamicLibrary _dylib;
/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
- _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary){
+ _dylib = dynamicLibrary;
}
/// Just a test struct
/// heres another line
@@ -279,40 +282,42 @@
});
test('Function and Struct Binding (pointer to Struct)', () {
+ final struct_some = Struc(
+ name: 'SomeStruc',
+ members: [
+ Member(
+ name: 'a',
+ type: Type.nativeType(
+ SupportedNativeType.Int32,
+ ),
+ ),
+ Member(
+ name: 'b',
+ type: Type.nativeType(
+ SupportedNativeType.Double,
+ ),
+ ),
+ Member(
+ name: 'c',
+ type: Type.nativeType(
+ SupportedNativeType.Char,
+ ),
+ ),
+ ],
+ );
final library = Library(
bindings: [
- Struc(
- name: 'SomeStruc',
- members: [
- Member(
- name: 'a',
- type: Type.nativeType(
- SupportedNativeType.Int32,
- ),
- ),
- Member(
- name: 'b',
- type: Type.nativeType(
- SupportedNativeType.Double,
- ),
- ),
- Member(
- name: 'c',
- type: Type.nativeType(
- SupportedNativeType.Char,
- ),
- ),
- ],
- ),
+ struct_some,
Func(
name: 'someFunc',
+ lookupSymbolName: 'someFunc',
parameters: [
Parameter(
name: 'some',
type: Type.pointer(
Type.pointer(
Type.struct(
- 'SomeStruc',
+ struct_some,
),
),
),
@@ -320,7 +325,7 @@
],
returnType: Type.pointer(
Type.struct(
- 'SomeStruc',
+ struct_some,
),
),
),
@@ -343,8 +348,8 @@
ffi.DynamicLibrary _dylib;
/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
- _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary){
+ _dylib = dynamicLibrary;
}
class SomeStruc extends ffi.Struct{
@ffi.Int32()
@@ -388,30 +393,34 @@
});
test('global (primitives, pointers, pointer to struct)', () {
+ final struc_some = Struc(
+ name: 'Some',
+ );
final library = Library(
bindings: [
Global(
name: 'test1',
+ lookupSymbolName: 'test1',
type: Type.nativeType(
SupportedNativeType.Int32,
),
),
Global(
name: 'test2',
+ lookupSymbolName: 'test2',
type: Type.pointer(
Type.nativeType(
SupportedNativeType.Float,
),
),
),
- Struc(
- name: 'Some',
- ),
+ struc_some,
Global(
name: 'test5',
+ lookupSymbolName: 'test5',
type: Type.pointer(
Type.struct(
- 'Some',
+ struc_some,
),
),
),
@@ -434,8 +443,8 @@
ffi.DynamicLibrary _dylib;
/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
- _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary){
+ _dylib = dynamicLibrary;
}
final int test1 = _dylib.lookup<ffi.Int32>('test1').value;
@@ -493,8 +502,8 @@
ffi.DynamicLibrary _dylib;
/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
- _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary){
+ _dylib = dynamicLibrary;
}
const int test1 = 20;
@@ -511,83 +520,6 @@
}
});
- test('TypedefC (primitive, pointers, pointer to struct)', () {
- final library = Library(
- bindings: [
- TypedefC(
- dartDoc: 'just a test',
- name: 'test1',
- returnType: Type.nativeType(
- SupportedNativeType.Int32,
- ),
- ),
- Struc(name: 'SomeStruct'),
- TypedefC(
- name: 'test2',
- returnType: Type.pointer(
- Type.nativeType(
- SupportedNativeType.Int32,
- ),
- ),
- parameters: [
- Parameter(
- name: 'param1',
- type: Type.pointer(
- Type.struct('SomeStruct'),
- ),
- ),
- Parameter(
- name: 'param2',
- type: Type.nativeType(
- SupportedNativeType.Char,
- ),
- ),
- ],
- ),
- ],
- );
-
- final gen = library.generate();
-
- // Writing to file for debug purpose.
- final file =
- File('test/debug_generated/typedef-Binding-test-output.dart');
- try {
- expect(gen, '''/// AUTO GENERATED FILE, DO NOT EDIT.
-///
-/// Generated by `package:ffigen`.
-import 'dart:ffi' as ffi;
-
-/// Holds the Dynamic library.
-ffi.DynamicLibrary _dylib;
-
-/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
- _dylib = dylib;
-}
-/// just a test
-typedef test1 = ffi.Int32 Function(
-);
-
-class SomeStruct extends ffi.Struct{
-}
-
-typedef test2 = ffi.Pointer<ffi.Int32> Function(
- ffi.Pointer<SomeStruct> param1,
- ffi.Uint8 param2,
-);
-
-''');
- if (file.existsSync()) {
- file.delete();
- }
- } catch (e) {
- file.writeAsStringSync(gen);
- print('Failed test, Debug output: ${file.absolute?.path}');
- rethrow;
- }
- });
-
test('enum_class', () {
final library = Library(
bindings: [
@@ -621,8 +553,8 @@
ffi.DynamicLibrary _dylib;
/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
- _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary){
+ _dylib = dynamicLibrary;
}
/// test line 1
/// test line 2
@@ -642,5 +574,208 @@
rethrow;
}
});
+ test('Internal conflict resolution', () {
+ final library = Library(
+ initFunctionIdentifier: 'init_dylib',
+ bindings: [
+ Func(
+ name: 'test',
+ lookupSymbolName: 'test',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ ),
+ Func(
+ name: '_test',
+ lookupSymbolName: '_test',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ ),
+ Func(
+ name: '_c_test',
+ lookupSymbolName: '_c_test',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ ),
+ Func(
+ name: '_dart_test',
+ lookupSymbolName: '_dart_test',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ ),
+ Struc(
+ name: '_Test',
+ members: [
+ Member(
+ name: 'array',
+ type: Type.constantArray(
+ 2,
+ Type.nativeType(
+ SupportedNativeType.Int8,
+ ),
+ ),
+ ),
+ ],
+ ),
+ Struc(name: 'ArrayHelperPrefixCollisionTest'),
+ Func(
+ name: 'Test',
+ lookupSymbolName: 'Test',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ ),
+ EnumClass(name: '_c_Test'),
+ EnumClass(name: 'init_dylib'),
+ ],
+ );
+
+ final gen = library.generate();
+
+ // Writing to file for debug purpose.
+ final file = File(
+ 'test/debug_generated/internal-conflict-resolution.dart',
+ );
+ try {
+ expect(gen, r'''/// AUTO GENERATED FILE, DO NOT EDIT.
+///
+/// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+/// Holds the Dynamic library.
+ffi.DynamicLibrary _dylib;
+
+/// Initialises the Dynamic library.
+void init_dylib_1(ffi.DynamicLibrary dynamicLibrary){
+ _dylib = dynamicLibrary;
+}
+void test(
+) {
+ return _test_1(
+ );
+}
+
+final _dart_test_1 _test_1 = _dylib.lookupFunction<_c_test_1,_dart_test_1>('test');
+
+typedef _c_test_1 = ffi.Void Function(
+);
+
+typedef _dart_test_1 = void Function(
+);
+
+void _test(
+) {
+ return __test(
+ );
+}
+
+final _dart__test __test = _dylib.lookupFunction<_c__test,_dart__test>('_test');
+
+typedef _c__test = ffi.Void Function(
+);
+
+typedef _dart__test = void Function(
+);
+
+void _c_test(
+) {
+ return __c_test(
+ );
+}
+
+final _dart__c_test __c_test = _dylib.lookupFunction<_c__c_test,_dart__c_test>('_c_test');
+
+typedef _c__c_test = ffi.Void Function(
+);
+
+typedef _dart__c_test = void Function(
+);
+
+void _dart_test(
+) {
+ return __dart_test(
+ );
+}
+
+final _dart__dart_test __dart_test = _dylib.lookupFunction<_c__dart_test,_dart__dart_test>('_dart_test');
+
+typedef _c__dart_test = ffi.Void Function(
+);
+
+typedef _dart__dart_test = void Function(
+);
+
+class _Test extends ffi.Struct{
+ @ffi.Int8()
+ int _exp_workaround_array_item_0;
+ @ffi.Int8()
+ int _exp_workaround_array_item_1;
+/// Helper for array `array`.
+ArrayHelper1__Test_array_level0 get array => ArrayHelper1__Test_array_level0(this, [2], 0, 0);
+}
+
+/// Helper for array `array` in struct `_Test`.
+class ArrayHelper1__Test_array_level0{
+final _Test _struct;
+final List<int> dimensions;
+final int level;
+final int _absoluteIndex;
+int get length => dimensions[level];
+ArrayHelper1__Test_array_level0(this._struct, this.dimensions, this.level, this._absoluteIndex);
+ void _checkBounds(int index) {
+ if (index >= length || index < 0) {
+ throw RangeError('Dimension $level: index not in range 0..${length} exclusive.');
+ }
+ }
+ int operator[](int index){
+_checkBounds(index);
+switch(_absoluteIndex+index){
+case 0:
+ return _struct._exp_workaround_array_item_0;
+case 1:
+ return _struct._exp_workaround_array_item_1;
+default:
+ throw Exception('Invalid Array Helper generated.');}
+}
+void operator[]=(int index, int value){
+_checkBounds(index);
+switch(_absoluteIndex+index){
+case 0:
+ _struct._exp_workaround_array_item_0 = value;
+ break;
+case 1:
+ _struct._exp_workaround_array_item_1 = value;
+ break;
+default:
+ throw Exception('Invalid Array Helper generated.');
+}
+}
+}
+class ArrayHelperPrefixCollisionTest extends ffi.Struct{
+}
+
+void Test(
+) {
+ return _Test_1(
+ );
+}
+
+final _dart_Test _Test_1 = _dylib.lookupFunction<_c_Test_1,_dart_Test>('Test');
+
+typedef _c_Test_1 = ffi.Void Function(
+);
+
+typedef _dart_Test = void Function(
+);
+
+class _c_Test {
+}
+
+class init_dylib {
+}
+
+''');
+ if (file.existsSync()) {
+ file.delete();
+ }
+ } catch (e) {
+ file.writeAsStringSync(gen);
+ print('Failed test, Debug output: ${file.absolute?.path}');
+ rethrow;
+ }
+ });
});
}
diff --git a/test/collision_tests/decl_decl_collision_test.dart b/test/collision_tests/decl_decl_collision_test.dart
new file mode 100644
index 0000000..a96d763
--- /dev/null
+++ b/test/collision_tests/decl_decl_collision_test.dart
@@ -0,0 +1,29 @@
+// 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 'package:ffigen/src/code_generator.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('Declaration-Declaration Collision', () {
+ test('struct-func', () {
+ final l1 = Library(bindings: [
+ Func(
+ name: 'test',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ ),
+ Struc(name: 'test'),
+ ]);
+ final l2 = Library(bindings: [
+ Func(
+ name: 'test',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ ),
+ Struc(name: 'test_1'),
+ ]);
+
+ expect(l1.generate(), l2.generate());
+ });
+ });
+}
diff --git a/test/header_parser_tests/functions_test.dart b/test/header_parser_tests/functions_test.dart
index f9e261e..fa09f9c 100644
--- a/test/header_parser_tests/functions_test.dart
+++ b/test/header_parser_tests/functions_test.dart
@@ -2,47 +2,37 @@
// 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/code_generator/writer.dart';
import 'package:ffigen/src/header_parser.dart' as parser;
import 'package:ffigen/src/config_provider.dart';
import 'package:logging/logging.dart';
import 'package:test/test.dart';
+import 'package:yaml/yaml.dart' as yaml;
+import 'package:ffigen/src/strings.dart' as strings;
-final writer = Writer();
+Library actual, expected;
void main() {
group('header_parser', () {
- Library actual, expected;
-
setUpAll(() {
expected = expectedLibrary();
- var dylibPath = 'tool/wrapped_libclang/libwrapped_clang.so';
- if (Platform.isMacOS) {
- dylibPath = 'tool/wrapped_libclang/libwrapped_clang.dylib';
- } else if (Platform.isWindows) {
- dylibPath = 'tool/wrapped_libclang/wrapped_clang.dll';
- }
-
Logger.root.onRecord.listen((log) {
- print('${log.level.name.padRight(8)}: ${log.message}');
+ if (log.level > Level.INFO) {
+ print(
+ 'functions_test.dart: ${log.level.name.padRight(8)}: ${log.message}');
+ }
});
-
actual = parser.parse(
- Config.raw(
- libclang_dylib_path: dylibPath,
- headers: [
- 'test/header_parser_tests/functions.h',
- ],
- headerFilter: HeaderFilter(
- includedInclusionHeaders: {
- 'functions.h',
- },
- ),
- ),
+ Config.fromYaml(yaml.loadYaml('''
+${strings.output}: 'unused'
+${strings.libclang_dylib_folder}: 'tool/wrapped_libclang'
+${strings.headers}:
+ - 'test/header_parser_tests/functions.h'
+${strings.headerFilter}:
+ ${strings.include}:
+ - 'functions.h'
+ ''') as yaml.YamlMap),
);
});
test('Total bindings count', () {
@@ -69,7 +59,7 @@
String binding(Library lib, String name) {
return lib.bindings
.firstWhere((element) => element.name == name)
- .toBindingString(writer)
+ .toBindingString(lib.writer)
.string;
}
@@ -78,12 +68,14 @@
bindings: [
Func(
name: 'func1',
+ lookupSymbolName: 'func1',
returnType: Type.nativeType(
SupportedNativeType.Void,
),
),
Func(
name: 'func2',
+ lookupSymbolName: 'func2',
returnType: Type.nativeType(
SupportedNativeType.Int32,
),
@@ -98,6 +90,7 @@
),
Func(
name: 'func3',
+ lookupSymbolName: 'func3',
returnType: Type.nativeType(
SupportedNativeType.Double,
),
@@ -129,6 +122,7 @@
),
Func(
name: 'func4',
+ lookupSymbolName: 'func4',
returnType: Type.pointer(Type.nativeType(SupportedNativeType.Void)),
parameters: [
Parameter(
diff --git a/test/prefix_tests/prefix.h b/test/prefix_tests/prefix.h
new file mode 100644
index 0000000..1e8b72d
--- /dev/null
+++ b/test/prefix_tests/prefix.h
@@ -0,0 +1,26 @@
+// 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 Struct1
+{
+};
+struct Test_Struct2
+{
+};
+
+void func1(struct Struct1 *s);
+void test_func2(struct Test_Struct2 *s);
+
+enum Enum1
+{
+ a = 0,
+ b = 1,
+ c = 2
+};
+enum Test_Enum2
+{
+ e = 0,
+ f = 1,
+ g = 2
+};
diff --git a/test/prefix_tests/prefix_test.dart b/test/prefix_tests/prefix_test.dart
new file mode 100644
index 0000000..d0397e4
--- /dev/null
+++ b/test/prefix_tests/prefix_test.dart
@@ -0,0 +1,150 @@
+// 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 'package:ffigen/src/code_generator.dart';
+import 'package:ffigen/src/header_parser.dart' as parser;
+import 'package:ffigen/src/config_provider.dart';
+import 'package:logging/logging.dart';
+import 'package:test/test.dart';
+import 'package:yaml/yaml.dart' as yaml;
+import 'package:ffigen/src/strings.dart' as strings;
+
+Library actual, expected;
+final functionPrefix = 'fff';
+final structPrefix = 'sss';
+final enumPrefix = 'eee';
+
+final functionPrefixReplacedWith = 'rf';
+final structPrefixReplacedWith = 'rs';
+final enumPrefixReplacedWith = 're';
+
+void main() {
+ group('Global Prefix Test', () {
+ setUpAll(() {
+ Logger.root.onRecord.listen((log) {
+ if (log.level > Level.INFO) {
+ print(
+ 'prefix_test.dart: ${log.level.name.padRight(8)}: ${log.message}');
+ }
+ });
+ expected = expectedLibrary();
+ actual = parser.parse(Config.fromYaml(yaml.loadYaml('''
+${strings.output}: 'unused'
+${strings.libclang_dylib_folder}: 'tool/wrapped_libclang'
+${strings.headers}:
+ - 'test/prefix_tests/prefix.h'
+${strings.headerFilter}:
+ ${strings.include}:
+ - 'prefix.h'
+
+functions:
+ ${strings.prefix}: $functionPrefix
+ ${strings.prefix_replacement}:
+ 'test_': '$functionPrefixReplacedWith'
+
+structs:
+ ${strings.prefix}: $structPrefix
+ ${strings.prefix_replacement}:
+ 'Test_': '$structPrefixReplacedWith'
+
+enums:
+ ${strings.prefix}: $enumPrefix
+ ${strings.prefix_replacement}:
+ 'Test_': '$enumPrefixReplacedWith'
+
+ ''') as yaml.YamlMap));
+ });
+
+ test('Function prefix', () {
+ expect(binding(actual, '${functionPrefix}func1'),
+ binding(expected, '${functionPrefix}func1'));
+ });
+ test('Struct prefix', () {
+ expect(binding(actual, '${structPrefix}Struct1'),
+ binding(expected, '${structPrefix}Struct1'));
+ });
+ test('Enum prefix', () {
+ expect(binding(actual, '${enumPrefix}Enum1'),
+ binding(expected, '${enumPrefix}Enum1'));
+ });
+ test('Function prefix-replacement', () {
+ expect(
+ binding(
+ actual, '${functionPrefix}${functionPrefixReplacedWith}func2'),
+ binding(
+ expected, '${functionPrefix}${functionPrefixReplacedWith}func2'));
+ });
+ test('Struct prefix-replacement', () {
+ expect(
+ binding(actual, '${structPrefix}${structPrefixReplacedWith}Struct2'),
+ binding(
+ expected, '${structPrefix}${structPrefixReplacedWith}Struct2'));
+ });
+ test('Enum prefix-replacement', () {
+ expect(binding(actual, '${enumPrefix}${enumPrefixReplacedWith}Enum2'),
+ binding(expected, '${enumPrefix}${enumPrefixReplacedWith}Enum2'));
+ });
+ });
+}
+
+/// Extracts a binding's string with a given name from a library.
+String binding(Library lib, String name) {
+ return lib.bindings
+ .firstWhere((element) => element.name == name)
+ .toBindingString(lib.writer)
+ .string;
+}
+
+Library expectedLibrary() {
+ final struc1 = Struc(name: '${structPrefix}Struct1');
+ final struc2 =
+ Struc(name: '${structPrefix}${structPrefixReplacedWith}Struct2');
+ return Library(
+ bindings: [
+ Func(
+ name: '${functionPrefix}func1',
+ lookupSymbolName: 'func1',
+ returnType: Type.nativeType(
+ SupportedNativeType.Void,
+ ),
+ parameters: [
+ Parameter(
+ name: 's',
+ type: Type.pointer(Type.struct(struc1)),
+ ),
+ ],
+ ),
+ Func(
+ name: '${functionPrefix}${functionPrefixReplacedWith}func2',
+ lookupSymbolName: 'test_func2',
+ returnType: Type.nativeType(
+ SupportedNativeType.Void,
+ ),
+ parameters: [
+ Parameter(
+ name: 's',
+ type: Type.pointer(Type.struct(struc2)),
+ ),
+ ],
+ ),
+ struc1,
+ struc2,
+ EnumClass(
+ name: '${enumPrefix}Enum1',
+ enumConstants: [
+ EnumConstant(name: 'a', value: 0),
+ EnumConstant(name: 'b', value: 1),
+ EnumConstant(name: 'c', value: 2),
+ ],
+ ),
+ EnumClass(
+ name: '${enumPrefix}${enumPrefixReplacedWith}Enum2',
+ enumConstants: [
+ EnumConstant(name: 'e', value: 0),
+ EnumConstant(name: 'f', value: 1),
+ EnumConstant(name: 'g', value: 2),
+ ],
+ ),
+ ],
+ );
+}