Updated parsing of typedef enclosed declarations (#83)
* added getCursorUSR_wrap method to wrapper, and bindings
* Updated code to use libclang's USR for identification
* Struct's typedef name will be used now (if it is only used in 1 typedef)
* parseXXX now returns seen binding instead of null
* added tests and removed obsolete code
* updated version, changelog, test_coverage.dart
* added PR ref to changelog
* minor changes
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ebc9c26..0c54f0a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 0.2.2
+- Fixed multiple generation/skipping of typedef enclosed declarations.
+- Typedef names are now given higher preference over inner names, See [#83](https://github.com/dart-lang/ffigen/pull/83).
+
# 0.2.1+1
- Added FAQ to readme.
diff --git a/lib/src/clang_library/wrapper.c b/lib/src/clang_library/wrapper.c
index c43c7f6..2482e36 100644
--- a/lib/src/clang_library/wrapper.c
+++ b/lib/src/clang_library/wrapper.c
@@ -358,4 +358,9 @@
return clang_Cursor_isAnonymousRecordDecl(*cursor);
}
+CXString *clang_getCursorUSR_wrap(CXCursor *cursor)
+{
+ return ptrToCXString(clang_getCursorUSR(*cursor));
+}
+
// END ===== WRAPPER FUNCTIONS =====================
diff --git a/lib/src/clang_library/wrapper.def b/lib/src/clang_library/wrapper.def
index c82231f..5cb8a5c 100644
--- a/lib/src/clang_library/wrapper.def
+++ b/lib/src/clang_library/wrapper.def
@@ -358,3 +358,4 @@
clang_Cursor_Evaluate_wrap
clang_Cursor_isAnonymous_wrap
clang_Cursor_isAnonymousRecordDecl_wrap
+clang_getCursorUSR_wrap
diff --git a/lib/src/code_generator/binding.dart b/lib/src/code_generator/binding.dart
index 5a10c06..b4267b8 100644
--- a/lib/src/code_generator/binding.dart
+++ b/lib/src/code_generator/binding.dart
@@ -12,13 +12,23 @@
///
/// Do not extend directly, use [LookUpBinding] or [NoLookUpBinding].
abstract class Binding {
+ /// Holds the Unified Symbol Resolution string obtained from libclang.
+ final String usr;
+
+ /// The name as it was in C.
final String originalName;
+ /// Binding name to generate, may get changed to resolve name conflicts.
String name;
final String dartDoc;
- Binding({@required this.originalName, @required this.name, this.dartDoc});
+ Binding({
+ @required this.usr,
+ @required this.originalName,
+ @required this.name,
+ this.dartDoc,
+ });
/// Return typedef dependencies.
List<Typedef> getTypedefDependencies(Writer w);
@@ -33,17 +43,29 @@
/// Base class for bindings which look up symbols in dynamic library.
abstract class LookUpBinding extends Binding {
LookUpBinding({
- @required String originalName,
+ String usr,
+ String originalName,
@required String name,
String dartDoc,
- }) : super(originalName: originalName, name: name, dartDoc: dartDoc);
+ }) : super(
+ usr: usr ?? name,
+ originalName: originalName ?? name,
+ name: name,
+ dartDoc: dartDoc,
+ );
}
/// Base class for bindings which don't look up symbols in dynamic library.
abstract class NoLookUpBinding extends Binding {
NoLookUpBinding({
- @required String originalName,
+ String usr,
+ String originalName,
@required String name,
String dartDoc,
- }) : super(originalName: originalName, name: name, dartDoc: dartDoc);
+ }) : super(
+ usr: usr ?? name,
+ originalName: originalName ?? name,
+ name: name,
+ dartDoc: dartDoc,
+ );
}
diff --git a/lib/src/code_generator/constant.dart b/lib/src/code_generator/constant.dart
index b5521ad..41572ab 100644
--- a/lib/src/code_generator/constant.dart
+++ b/lib/src/code_generator/constant.dart
@@ -31,12 +31,18 @@
final String rawValue;
Constant({
+ String usr,
String originalName,
@required String name,
String dartDoc,
@required this.rawType,
@required this.rawValue,
- }) : super(originalName: originalName ?? name, name: name, dartDoc: dartDoc);
+ }) : super(
+ usr: usr,
+ originalName: originalName,
+ name: name,
+ dartDoc: dartDoc,
+ );
@override
BindingString toBindingString(Writer w) {
diff --git a/lib/src/code_generator/enum_class.dart b/lib/src/code_generator/enum_class.dart
index 1a383ce..9404c4b 100644
--- a/lib/src/code_generator/enum_class.dart
+++ b/lib/src/code_generator/enum_class.dart
@@ -28,12 +28,18 @@
final List<EnumConstant> enumConstants;
EnumClass({
+ String usr,
String originalName,
@required String name,
String dartDoc,
List<EnumConstant> enumConstants,
}) : enumConstants = enumConstants ?? [],
- super(originalName: originalName ?? name, name: name, dartDoc: dartDoc);
+ super(
+ usr: usr,
+ originalName: originalName,
+ name: name,
+ dartDoc: dartDoc,
+ );
@override
BindingString toBindingString(Writer w) {
diff --git a/lib/src/code_generator/func.dart b/lib/src/code_generator/func.dart
index 551dae9..d29abcb 100644
--- a/lib/src/code_generator/func.dart
+++ b/lib/src/code_generator/func.dart
@@ -36,6 +36,7 @@
/// [originalName] is looked up in dynamic library, if not
/// provided, takes the value of [name].
Func({
+ String usr,
@required String name,
String originalName,
String dartDoc,
@@ -43,7 +44,11 @@
List<Parameter> parameters,
}) : parameters = parameters ?? [],
super(
- originalName: originalName ?? name, name: name, dartDoc: dartDoc) {
+ usr: usr,
+ originalName: originalName,
+ name: name,
+ dartDoc: dartDoc,
+ ) {
for (var i = 0; i < this.parameters.length; i++) {
if (this.parameters[i].name == null ||
this.parameters[i].name.trim() == '') {
diff --git a/lib/src/code_generator/global.dart b/lib/src/code_generator/global.dart
index d0e67cf..79478fa 100644
--- a/lib/src/code_generator/global.dart
+++ b/lib/src/code_generator/global.dart
@@ -25,11 +25,17 @@
final Type type;
Global({
+ String usr,
String originalName,
@required String name,
@required this.type,
String dartDoc,
- }) : super(originalName: originalName ?? name, name: name, dartDoc: dartDoc);
+ }) : super(
+ usr: usr,
+ originalName: originalName,
+ name: name,
+ dartDoc: dartDoc,
+ );
@override
BindingString toBindingString(Writer w) {
diff --git a/lib/src/code_generator/struc.dart b/lib/src/code_generator/struc.dart
index f241fd7..8cd6df3 100644
--- a/lib/src/code_generator/struc.dart
+++ b/lib/src/code_generator/struc.dart
@@ -39,12 +39,18 @@
List<Member> members;
Struc({
+ String usr,
String originalName,
@required String name,
String dartDoc,
List<Member> members,
}) : members = members ?? [],
- super(originalName: originalName ?? name, name: name, dartDoc: dartDoc);
+ super(
+ usr: usr,
+ originalName: originalName,
+ name: name,
+ dartDoc: dartDoc,
+ );
List<int> _getArrayDimensionLengths(Type type) {
final array = <int>[];
diff --git a/lib/src/header_parser/clang_bindings/clang_bindings.dart b/lib/src/header_parser/clang_bindings/clang_bindings.dart
index 55c1903..82222c7 100644
--- a/lib/src/header_parser/clang_bindings/clang_bindings.dart
+++ b/lib/src/header_parser/clang_bindings/clang_bindings.dart
@@ -489,7 +489,7 @@
/// instead of cxcursor by default.
int clang_visitChildren_wrap(
ffi.Pointer<CXCursor> parent,
- ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
+ ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
int uid,
) {
_clang_visitChildren_wrap ??= _dylib.lookupFunction<
@@ -778,6 +778,19 @@
_dart_clang_Cursor_isAnonymousRecordDecl_wrap
_clang_Cursor_isAnonymousRecordDecl_wrap;
+
+ ffi.Pointer<CXString> clang_getCursorUSR_wrap(
+ ffi.Pointer<CXCursor> cursor,
+ ) {
+ _clang_getCursorUSR_wrap ??= _dylib.lookupFunction<
+ _c_clang_getCursorUSR_wrap,
+ _dart_clang_getCursorUSR_wrap>('clang_getCursorUSR_wrap');
+ return _clang_getCursorUSR_wrap(
+ cursor,
+ );
+ }
+
+ _dart_clang_getCursorUSR_wrap _clang_getCursorUSR_wrap;
}
/// A character string.
@@ -2451,7 +2464,7 @@
int opts,
);
-typedef ModifiedCXCursorVisitor_1 = ffi.Int32 Function(
+typedef ModifiedCXCursorVisitor = ffi.Int32 Function(
ffi.Pointer<CXCursor>,
ffi.Pointer<CXCursor>,
ffi.Pointer<ffi.Void>,
@@ -2459,13 +2472,13 @@
typedef _c_clang_visitChildren_wrap = ffi.Uint32 Function(
ffi.Pointer<CXCursor> parent,
- ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
+ ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
ffi.Int64 uid,
);
typedef _dart_clang_visitChildren_wrap = int Function(
ffi.Pointer<CXCursor> parent,
- ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
+ ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
int uid,
);
@@ -2641,3 +2654,11 @@
typedef _dart_clang_Cursor_isAnonymousRecordDecl_wrap = int Function(
ffi.Pointer<CXCursor> cursor,
);
+
+typedef _c_clang_getCursorUSR_wrap = ffi.Pointer<CXString> Function(
+ ffi.Pointer<CXCursor> cursor,
+);
+
+typedef _dart_clang_getCursorUSR_wrap = ffi.Pointer<CXString> Function(
+ ffi.Pointer<CXCursor> cursor,
+);
diff --git a/lib/src/header_parser/data.dart b/lib/src/header_parser/data.dart
index 6c21338..c307a26 100644
--- a/lib/src/header_parser/data.dart
+++ b/lib/src/header_parser/data.dart
@@ -37,8 +37,8 @@
final uid = Isolate.current.controlPort.nativePort;
/// Saved macros, Key: prefixedName, Value originalName.
-Map<String, String> get savedMacros => _savedMacros;
-Map<String, String> _savedMacros;
+Map<String, Macro> get savedMacros => _savedMacros;
+Map<String, Macro> _savedMacros;
/// Saved unnamed EnumConstants.
List<Constant> get unnamedEnumConstants => _unnamedEnumConstants;
diff --git a/lib/src/header_parser/includer.dart b/lib/src/header_parser/includer.dart
index a4766e1..5c534a7 100644
--- a/lib/src/header_parser/includer.dart
+++ b/lib/src/header_parser/includer.dart
@@ -7,8 +7,8 @@
/// Utility functions to check whether a binding should be parsed or not
/// based on filters.
-bool shouldIncludeStruct(String name) {
- if (bindingsIndex.isSeenStruct(name) || name == '') {
+bool shouldIncludeStruct(String usr, String name) {
+ if (bindingsIndex.isSeenStruct(usr) || name == '') {
return false;
} else if (config.structDecl == null ||
config.structDecl.shouldInclude(name)) {
@@ -18,8 +18,8 @@
}
}
-bool shouldIncludeFunc(String name) {
- if (bindingsIndex.isSeenFunc(name) || name == '') {
+bool shouldIncludeFunc(String usr, String name) {
+ if (bindingsIndex.isSeenFunc(usr) || name == '') {
return false;
} else if (config.functionDecl == null ||
config.functionDecl.shouldInclude(name)) {
@@ -29,8 +29,8 @@
}
}
-bool shouldIncludeEnumClass(String name) {
- if (bindingsIndex.isSeenEnumClass(name) || name == '') {
+bool shouldIncludeEnumClass(String usr, String name) {
+ if (bindingsIndex.isSeenEnumClass(usr) || name == '') {
return false;
} else if (config.enumClassDecl == null ||
config.enumClassDecl.shouldInclude(name)) {
@@ -40,8 +40,8 @@
}
}
-bool shouldIncludeMacro(String name) {
- if (bindingsIndex.isSeenMacro(name) || name == '') {
+bool shouldIncludeMacro(String usr, String name) {
+ if (bindingsIndex.isSeenMacro(usr) || name == '') {
return false;
} else if (config.macroDecl == null || config.macroDecl.shouldInclude(name)) {
return true;
diff --git a/lib/src/header_parser/parser.dart b/lib/src/header_parser/parser.dart
index 1771574..c5698b0 100644
--- a/lib/src/header_parser/parser.dart
+++ b/lib/src/header_parser/parser.dart
@@ -82,8 +82,8 @@
cmdLen = config.compilerOpts.length;
}
- // Contains all bindings.
- final bindings = <Binding>[];
+ // Contains all bindings. A set ensures we never have duplicates.
+ final bindings = <Binding>{};
// Log all headers for user.
_logger.info('Input Headers: ${config.headers.entryPoints}');
@@ -130,5 +130,5 @@
clangCmdArgs.dispose(config.compilerOpts.length);
}
clang.clang_disposeIndex(index);
- return bindings;
+ return bindings.toList();
}
diff --git a/lib/src/header_parser/sub_parsers/enumdecl_parser.dart b/lib/src/header_parser/sub_parsers/enumdecl_parser.dart
index 3460e28..50248a6 100644
--- a/lib/src/header_parser/sub_parsers/enumdecl_parser.dart
+++ b/lib/src/header_parser/sub_parsers/enumdecl_parser.dart
@@ -28,10 +28,11 @@
EnumClass parseEnumDeclaration(
Pointer<clang_types.CXCursor> cursor, {
- /// Optionally provide name to use (useful in case struct is inside a typedef).
+ /// Optionally provide name to use (useful in case enum is inside a typedef).
String name,
}) {
_stack.push(_ParsedEnum());
+ final enumUsr = cursor.usr();
final enumName = name ?? cursor.spelling();
if (enumName == '') {
// Save this unnamed enum if it is anonymous (therefore not in a typedef).
@@ -42,17 +43,24 @@
} else {
_logger.fine('Unnamed enum inside a typedef.');
}
- } else if (shouldIncludeEnumClass(enumName) &&
- !bindingsIndex.isSeenEnumClass(enumName)) {
+ } else if (shouldIncludeEnumClass(enumUsr, enumName)) {
_logger.fine('++++ Adding Enum: ${cursor.completeStringRepr()}');
_stack.top.enumClass = EnumClass(
+ usr: enumUsr,
dartDoc: getCursorDocComment(cursor),
originalName: enumName,
name: config.enumClassDecl.renameUsingConfig(enumName),
);
- bindingsIndex.addEnumClassToSeen(enumName, _stack.top.enumClass);
+ bindingsIndex.addEnumClassToSeen(enumUsr, _stack.top.enumClass);
_addEnumConstant(cursor);
}
+ if (bindingsIndex.isSeenEnumClass(enumUsr)) {
+ _stack.top.enumClass = bindingsIndex.getSeenEnumClass(enumUsr);
+
+ // If enum is seen, update it's name.
+ _stack.top.enumClass.name =
+ config.enumClassDecl.renameUsingConfig(enumName);
+ }
return _stack.pop().enumClass;
}
diff --git a/lib/src/header_parser/sub_parsers/functiondecl_parser.dart b/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
index 9137c73..78d52b4 100644
--- a/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
+++ b/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
@@ -31,8 +31,9 @@
_stack.top.structByValueParameter = false;
_stack.top.unimplementedParameterType = false;
+ final funcUsr = cursor.usr();
final funcName = cursor.spelling();
- if (shouldIncludeFunc(funcName) && !bindingsIndex.isSeenFunc(funcName)) {
+ if (shouldIncludeFunc(funcUsr, funcName)) {
_logger.fine('++++ Adding Function: ${cursor.completeStringRepr()}');
final rt = _getFunctionReturnType(cursor);
@@ -65,12 +66,15 @@
cursor,
nesting.length + commentPrefix.length,
),
+ usr: funcUsr,
name: config.functionDecl.renameUsingConfig(funcName),
originalName: funcName,
returnType: rt,
parameters: parameters,
);
- bindingsIndex.addFuncToSeen(funcName, _stack.top.func);
+ bindingsIndex.addFuncToSeen(funcUsr, _stack.top.func);
+ } else if (bindingsIndex.isSeenFunc(funcUsr)) {
+ _stack.top.func = bindingsIndex.getSeenFunc(funcUsr);
}
return _stack.pop().func;
diff --git a/lib/src/header_parser/sub_parsers/macro_parser.dart b/lib/src/header_parser/sub_parsers/macro_parser.dart
index dd35b78..ad9df56 100644
--- a/lib/src/header_parser/sub_parsers/macro_parser.dart
+++ b/lib/src/header_parser/sub_parsers/macro_parser.dart
@@ -20,25 +20,25 @@
/// Adds a macro definition to be parsed later.
void saveMacroDefinition(Pointer<clang_types.CXCursor> cursor) {
+ final macroUsr = cursor.usr();
final originalMacroName = cursor.spelling();
- if (shouldIncludeMacro(originalMacroName) &&
- !bindingsIndex.isSeenMacro(originalMacroName) &&
- clang.clang_Cursor_isMacroBuiltin_wrap(cursor) == 0 &&
- clang.clang_Cursor_isMacroFunctionLike_wrap(cursor) == 0) {
+ if (clang.clang_Cursor_isMacroBuiltin_wrap(cursor) == 0 &&
+ clang.clang_Cursor_isMacroFunctionLike_wrap(cursor) == 0 &&
+ shouldIncludeMacro(macroUsr, originalMacroName)) {
// Parse macro only if it's not builtin or function-like.
_logger.fine(
"++++ Saved Macro '$originalMacroName' for later : ${cursor.completeStringRepr()}");
final prefixedName = config.macroDecl.renameUsingConfig(originalMacroName);
- bindingsIndex.addMacroToSeen(originalMacroName, prefixedName);
- _saveMacro(prefixedName, originalMacroName);
+ bindingsIndex.addMacroToSeen(macroUsr, prefixedName);
+ _saveMacro(prefixedName, macroUsr, originalMacroName);
}
}
/// Saves a macro to be parsed later.
///
/// Macros are parsed later in [parseSavedMacros()].
-void _saveMacro(String name, String originalName) {
- savedMacros[name] = originalName;
+void _saveMacro(String name, String usr, String originalName) {
+ savedMacros[name] = Macro(usr, originalName);
}
List<Constant> _bindings;
@@ -114,7 +114,8 @@
switch (k) {
case clang_types.CXEvalResultKind.CXEval_Int:
constant = Constant(
- originalName: savedMacros[macroName],
+ usr: savedMacros[macroName].usr,
+ originalName: savedMacros[macroName].originalName,
name: macroName,
rawType: 'int',
rawValue: clang.clang_EvalResult_getAsLongLong(e).toString(),
@@ -122,7 +123,8 @@
break;
case clang_types.CXEvalResultKind.CXEval_Float:
constant = Constant(
- originalName: savedMacros[macroName],
+ usr: savedMacros[macroName].usr,
+ originalName: savedMacros[macroName].originalName,
name: macroName,
rawType: 'double',
rawValue: clang.clang_EvalResult_getAsDouble(e).toString(),
@@ -135,7 +137,8 @@
// Escape ' character, because our strings are enclosed with '.
value = value.replaceAll("'", r"\'");
constant = Constant(
- originalName: savedMacros[macroName],
+ usr: savedMacros[macroName].usr,
+ originalName: savedMacros[macroName].originalName,
name: macroName,
rawType: 'String',
rawValue: "'${value}'",
@@ -204,7 +207,8 @@
for (final prefixedMacroName in savedMacros.keys) {
// Write macro.
final macroVarName = MacroVariableString.encode(prefixedMacroName);
- sb.writeln('auto ${macroVarName} = ${savedMacros[prefixedMacroName]};');
+ sb.writeln(
+ 'auto ${macroVarName} = ${savedMacros[prefixedMacroName].originalName};');
// Add to _macroVarNames.
_macroVarNames.add(macroVarName);
}
diff --git a/lib/src/header_parser/sub_parsers/structdecl_parser.dart b/lib/src/header_parser/sub_parsers/structdecl_parser.dart
index 3b62123..6ae4c80 100644
--- a/lib/src/header_parser/sub_parsers/structdecl_parser.dart
+++ b/lib/src/header_parser/sub_parsers/structdecl_parser.dart
@@ -38,25 +38,34 @@
bool ignoreFilter = false,
}) {
_stack.push(_ParsedStruc());
+
+ final structUsr = cursor.usr();
final structName = name ?? cursor.spelling();
if (structName.isEmpty) {
_logger.finest('unnamed structure or typedef structure declaration');
- } else if ((ignoreFilter || shouldIncludeStruct(structName)) &&
- (!bindingsIndex.isSeenStruct(structName))) {
+ } else if ((ignoreFilter || shouldIncludeStruct(structUsr, structName)) &&
+ (!bindingsIndex.isSeenStruct(structUsr))) {
_logger.fine(
'++++ Adding Structure: structName: ${structName}, ${cursor.completeStringRepr()}');
_stack.top.struc = Struc(
+ usr: structUsr,
originalName: structName,
name: config.structDecl.renameUsingConfig(structName),
dartDoc: getCursorDocComment(cursor),
);
// Adding to seen here to stop recursion if a struct has itself as a
// member, members are updated later.
- bindingsIndex.addStructToSeen(structName, _stack.top.struc);
+ bindingsIndex.addStructToSeen(structUsr, _stack.top.struc);
_setStructMembers(cursor);
}
+ if (bindingsIndex.isSeenStruct(structUsr)) {
+ _stack.top.struc = bindingsIndex.getSeenStruct(structUsr);
+
+ // If struct is seen, update it's name.
+ _stack.top.struc.name = config.structDecl.renameUsingConfig(structName);
+ }
return _stack.pop().struc;
}
diff --git a/lib/src/header_parser/sub_parsers/unnamed_enumdecl_parser.dart b/lib/src/header_parser/sub_parsers/unnamed_enumdecl_parser.dart
index b5039c4..713fae0 100644
--- a/lib/src/header_parser/sub_parsers/unnamed_enumdecl_parser.dart
+++ b/lib/src/header_parser/sub_parsers/unnamed_enumdecl_parser.dart
@@ -56,6 +56,7 @@
void _addUnNamedEnumConstant(Pointer<clang_types.CXCursor> cursor) {
unnamedEnumConstants.add(
Constant(
+ usr: cursor.usr(),
originalName: cursor.spelling(),
name: config.enumClassDecl.renameMemberUsingConfig(
'', // Un-named enum constants have an empty declaration name.
diff --git a/lib/src/header_parser/translation_unit_parser.dart b/lib/src/header_parser/translation_unit_parser.dart
index 4c1f36c..f576fae 100644
--- a/lib/src/header_parser/translation_unit_parser.dart
+++ b/lib/src/header_parser/translation_unit_parser.dart
@@ -19,12 +19,12 @@
var _logger = Logger('ffigen.header_parser.translation_unit_parser');
-List<Binding> _bindings;
+Set<Binding> _bindings;
/// Parses the translation unit and returns the generated bindings.
-List<Binding> parseTranslationUnit(
+Set<Binding> parseTranslationUnit(
Pointer<clang_types.CXCursor> translationUnitCursor) {
- _bindings = [];
+ _bindings = {};
final resultCode = clang.clang_visitChildren_wrap(
translationUnitCursor,
Pointer.fromFunction(
@@ -77,9 +77,10 @@
return clang_types.CXChildVisitResult.CXChildVisit_Continue;
}
-/// Adds to binding if not null.
+/// Adds to binding if unseen and not null.
void addToBindings(Binding b) {
if (b != null) {
+ // This is a set, and hence will not have duplicates.
_bindings.add(b);
}
}
diff --git a/lib/src/header_parser/type_extractor/extractor.dart b/lib/src/header_parser/type_extractor/extractor.dart
index d73e029..a198420 100644
--- a/lib/src/header_parser/type_extractor/extractor.dart
+++ b/lib/src/header_parser/type_extractor/extractor.dart
@@ -51,7 +51,7 @@
et.dispose();
return s;
case clang_types.CXTypeKind.CXType_Record:
- return _extractfromRecord(cxtype);
+ return _extractfromRecord(cxtype, parentName);
case clang_types.CXTypeKind.CXType_Enum:
return Type.nativeType(
enumNativeType,
@@ -87,7 +87,7 @@
}
}
-Type _extractfromRecord(Pointer<clang_types.CXType> cxtype) {
+Type _extractfromRecord(Pointer<clang_types.CXType> cxtype, String parentName) {
Type type;
final cursor = clang.clang_getTypeDeclaration_wrap(cxtype);
@@ -96,26 +96,21 @@
switch (clang.clang_getCursorKind_wrap(cursor)) {
case clang_types.CXCursorKind.CXCursor_StructDecl:
final cxtype = cursor.type();
- var structName = cursor.spelling();
- if (structName == '') {
- // Incase of anonymous structs defined inside a typedef.
- structName = cxtype.spelling();
- }
+ final structUsr = cursor.usr();
- final fixedStructName = config.structDecl.renameUsingConfig(structName);
+ // Name of typedef (parentName) is used if available.
+ final structName = parentName ?? cursor.spelling();
// Also add a struct binding, if its unseen.
// TODO(23): Check if we should auto add struct.
- if (bindingsIndex.isSeenStruct(structName)) {
- type = Type.struct(bindingsIndex.getSeenStruct(structName));
+ if (bindingsIndex.isSeenStruct(structUsr)) {
+ type = Type.struct(bindingsIndex.getSeenStruct(structUsr));
} else {
final struc = parseStructDeclaration(cursor,
- name: fixedStructName, ignoreFilter: true);
+ name: structName, ignoreFilter: true);
type = Type.struct(struc);
// Add to bindings.
addToBindings(struc);
- // Add to seen.
- bindingsIndex.addStructToSeen(structName, struc);
}
cxtype.dispose();
diff --git a/lib/src/header_parser/utils.dart b/lib/src/header_parser/utils.dart
index 54fcc8b..d578b00 100644
--- a/lib/src/header_parser/utils.dart
+++ b/lib/src/header_parser/utils.dart
@@ -57,6 +57,10 @@
}
extension CXCursorExt on Pointer<clang_types.CXCursor> {
+ String usr() {
+ return clang.clang_getCursorUSR_wrap(this).toStringAndDispose();
+ }
+
/// Returns the kind int from [clang_types.CXCursorKind].
int kind() {
return clang.clang_getCursorKind_wrap(this);
@@ -78,7 +82,7 @@
String completeStringRepr() {
final cxtype = type();
final s =
- '(Cursor) spelling: ${spelling()}, kind: ${kind()}, kindSpelling: ${kindSpelling()}, type: ${cxtype.kind()}, typeSpelling: ${cxtype.spelling()}';
+ '(Cursor) spelling: ${spelling()}, kind: ${kind()}, kindSpelling: ${kindSpelling()}, type: ${cxtype.kind()}, typeSpelling: ${cxtype.spelling()}, usr: ${usr()}';
cxtype.dispose();
return s;
}
@@ -323,9 +327,16 @@
}
}
+class Macro {
+ final String usr;
+ final String originalName;
+
+ Macro(this.usr, this.originalName);
+}
+
/// Tracks if a binding is 'seen' or not.
class BindingsIndex {
- // Stores binding names already seen. Map key is same as their original name.
+ // Tracks if bindings are already seen, Map key is USR obtained from libclang.
final Map<String, Struc> _structs = {};
final Map<String, Func> _functions = {};
final Map<String, EnumClass> _enumClass = {};
@@ -333,52 +344,52 @@
// Stores only named typedefC used in NativeFunc.
final Map<String, Typedef> _functionTypedefs = {};
- bool isSeenStruct(String originalName) {
- return _structs.containsKey(originalName);
+ bool isSeenStruct(String usr) {
+ return _structs.containsKey(usr);
}
- void addStructToSeen(String originalName, Struc struc) {
- _structs[originalName] = struc;
+ void addStructToSeen(String usr, Struc struc) {
+ _structs[usr] = struc;
}
- Struc getSeenStruct(String originalName) {
- return _structs[originalName];
+ Struc getSeenStruct(String usr) {
+ return _structs[usr];
}
- bool isSeenFunc(String originalName) {
- return _functions.containsKey(originalName);
+ bool isSeenFunc(String usr) {
+ return _functions.containsKey(usr);
}
- void addFuncToSeen(String originalName, Func func) {
- _functions[originalName] = func;
+ void addFuncToSeen(String usr, Func func) {
+ _functions[usr] = func;
}
- Func getSeenFunc(String originalName) {
- return _functions[originalName];
+ Func getSeenFunc(String usr) {
+ return _functions[usr];
}
- bool isSeenEnumClass(String originalName) {
- return _enumClass.containsKey(originalName);
+ bool isSeenEnumClass(String usr) {
+ return _enumClass.containsKey(usr);
}
- void addEnumClassToSeen(String originalName, EnumClass enumClass) {
- _enumClass[originalName] = enumClass;
+ void addEnumClassToSeen(String usr, EnumClass enumClass) {
+ _enumClass[usr] = enumClass;
}
- EnumClass getSeenEnumClass(String originalName) {
- return _enumClass[originalName];
+ EnumClass getSeenEnumClass(String usr) {
+ return _enumClass[usr];
}
- bool isSeenMacro(String originalName) {
- return _macros.containsKey(originalName);
+ bool isSeenMacro(String usr) {
+ return _macros.containsKey(usr);
}
- void addMacroToSeen(String originalName, String macro) {
- _macros[originalName] = macro;
+ void addMacroToSeen(String usr, String macro) {
+ _macros[usr] = macro;
}
- String getSeenMacro(String originalName) {
- return _macros[originalName];
+ String getSeenMacro(String usr) {
+ return _macros[usr];
}
bool isSeenFunctionTypedef(String originalName) {
diff --git a/lib/src/strings.dart b/lib/src/strings.dart
index e055347..726e2f5 100644
--- a/lib/src/strings.dart
+++ b/lib/src/strings.dart
@@ -7,7 +7,7 @@
as clang;
// This version must be updated whenever we update the libclang wrapper.
-const dylibVersion = 'v2';
+const dylibVersion = 'v3';
/// Name of the dynamic library file according to current platform.
String get dylibFileName {
diff --git a/pubspec.yaml b/pubspec.yaml
index 1820277..13ee6db 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@
# BSD-style license that can be found in the LICENSE file.
name: ffigen
-version: 0.2.1+1
+version: 0.2.2
homepage: https://github.com/dart-lang/ffigen
description: Experimental generator for FFI bindings, using LibClang to parse C/C++ header files.
diff --git a/test/header_parser_tests/typedef.h b/test/header_parser_tests/typedef.h
index f9aa357..3e9d996 100644
--- a/test/header_parser_tests/typedef.h
+++ b/test/header_parser_tests/typedef.h
@@ -11,3 +11,43 @@
};
extern NamedFunctionProto func1(NamedFunctionProto named, void (*unnamed)(int));
+
+typedef struct
+{
+
+} AnonymousStructInTypedef;
+// These typerefs do not affect the name of AnonymousStructInTypedef.
+typedef AnonymousStructInTypedef Typeref1;
+typedef AnonymousStructInTypedef Typeref2;
+
+// Name from global namespace is used.
+typedef struct _NamedStructInTypedef
+{
+
+} NamedStructInTypedef;
+
+// Both these names must be exlucded or this struct will be generated.
+typedef struct _ExcludedStruct
+{
+
+} ExcludedStruct;
+typedef ExcludedStruct NTyperef1;
+
+// Because `struct _ExcludedStruct` is excluded, the type name used
+// in this function (the first function) will be used.
+// Therefore, _ExcludedStruct will be generated as NTyperef1.
+void func2(NTyperef1 *);
+
+typedef enum
+{
+
+} AnonymousEnumInTypedef;
+// These typerefs do not affect the name of AnonymousEnumInTypedef.
+typedef AnonymousEnumInTypedef Typeref1;
+typedef AnonymousEnumInTypedef Typeref2;
+
+// Name from global namespace is used.
+typedef enum _NamedEnumInTypedef
+{
+
+} NamedEnumInTypedef;
diff --git a/test/header_parser_tests/typedef_test.dart b/test/header_parser_tests/typedef_test.dart
index 8480acd..7f7646c 100644
--- a/test/header_parser_tests/typedef_test.dart
+++ b/test/header_parser_tests/typedef_test.dart
@@ -27,6 +27,10 @@
${strings.headers}:
${strings.entryPoints}:
- 'test/header_parser_tests/typedef.h'
+${strings.structs}:
+ ${strings.exclude}:
+ - ExcludedStruct
+ - _ExcludedStruct
''') as yaml.YamlMap),
);
});
@@ -43,6 +47,8 @@
typedefType: TypedefType.C,
returnType: Type.nativeType(SupportedNativeType.Void),
);
+
+ final excludedNtyperef = Struc(name: 'NTyperef1');
return Library(
name: 'Bindings',
bindings: [
@@ -81,6 +87,18 @@
],
returnType: Type.pointer(Type.nativeFunc(namedTypedef)),
),
+ Struc(name: 'AnonymousStructInTypedef'),
+ Struc(name: 'NamedStructInTypedef'),
+ excludedNtyperef,
+ Func(
+ name: 'func2',
+ returnType: Type.nativeType(SupportedNativeType.Void),
+ parameters: [
+ Parameter(type: Type.pointer(Type.struct(excludedNtyperef)))
+ ],
+ ),
+ EnumClass(name: 'AnonymousEnumInTypedef'),
+ EnumClass(name: 'NamedEnumInTypedef'),
],
);
}
diff --git a/test/test_coverage.dart b/test/test_coverage.dart
index 812105f..a35f0f7 100644
--- a/test/test_coverage.dart
+++ b/test/test_coverage.dart
@@ -21,6 +21,8 @@
as header_parser_tests_macros_test;
import 'header_parser_tests/nested_parsing_test.dart'
as header_parser_tests_nested_parsing_test;
+import 'header_parser_tests/typedef_test.dart'
+ as header_parser_tests_typedef_test;
import 'header_parser_tests/unnamed_enums_test.dart'
as header_parser_tests_unnamed_enums_test;
import 'large_integration_tests/large_test.dart'
@@ -39,6 +41,7 @@
header_parser_tests_macros_test.main();
header_parser_tests_function_n_struct_test.main();
header_parser_tests_nested_parsing_test.main();
+ header_parser_tests_typedef_test.main();
header_parser_tests_unnamed_enums_test.main();
native_test_native_test.main();
rename_tests_rename_test.main();
diff --git a/tool/libclang_config.yaml b/tool/libclang_config.yaml
index 1f93991..c6baf25 100644
--- a/tool/libclang_config.yaml
+++ b/tool/libclang_config.yaml
@@ -99,3 +99,4 @@
- clang_Cursor_Evaluate_wrap
- clang_Cursor_isAnonymous_wrap
- clang_Cursor_isAnonymousRecordDecl_wrap
+ - clang_getCursorUSR_wrap