Skip to content
This repository was archived by the owner on Jan 28, 2024. It is now read-only.

Support nested structs #126

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/test-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ env:

jobs:
# Check code formatting and static analysis on a single OS (linux)
# against Dart stable.
# against Dart master.
analyze:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
sdk: [stable]
sdk: [master]
steps:
- uses: actions/checkout@v2
- uses: dart-lang/[email protected]
Expand All @@ -44,7 +44,7 @@ jobs:
- uses: actions/checkout@v2
- uses: dart-lang/[email protected]
with:
channel: stable
channel: master
- name: Install dependencies
run: dart pub get
- name: Install libclang-10-dev
Expand Down
207 changes: 195 additions & 12 deletions example/libclang-example/generated_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2851,7 +2851,32 @@ class ArrayHelper_CXCursor_data_level0 {

/// 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 {}
class CXPlatformAvailability extends ffi.Struct {
/// A string that describes the platform for which this structure
/// provides availability information.
///
/// Possible values are "ios" or "macos".
CXString Platform;

/// The version number in which this entity was introduced.
CXVersion Introduced;

/// The version number in which this entity was deprecated (but is
/// still available).
CXVersion Deprecated;

/// The version number in which this entity was obsoleted, and therefore
/// is no longer available.
CXVersion Obsoleted;

/// Whether the entity is unconditionally unavailable on this platform.
@ffi.Int32()
int Unavailable;

/// An optional message to provide to a user of this API, e.g., to
/// suggest replacement APIs.
CXString Message;
}

class CXCursorSetImpl extends ffi.Struct {}

Expand Down Expand Up @@ -3202,20 +3227,127 @@ class ArrayHelper_CXIdxLoc_ptr_data_level0 {
}

/// Data for ppIncludedFile callback.
class CXIdxIncludedFileInfo extends ffi.Struct {}
class CXIdxIncludedFileInfo extends ffi.Struct {
/// Location of '#' in the \#include/\#import directive.
CXIdxLoc hashLoc;

/// Filename as written in the \#include/\#import directive.
ffi.Pointer<ffi.Int8> filename;

/// The actual file that the \#include/\#import directive resolved to.
ffi.Pointer<ffi.Void> file;

@ffi.Int32()
int isImport;

@ffi.Int32()
int isAngled;

/// Non-zero if the directive was automatically turned into a module
/// import.
@ffi.Int32()
int isModuleImport;
}

/// Data for IndexerCallbacks#importedASTFile.
class CXIdxImportedASTFileInfo extends ffi.Struct {}
class CXIdxImportedASTFileInfo extends ffi.Struct {
/// Top level AST file containing the imported PCH, module or submodule.
ffi.Pointer<ffi.Void> file;

/// The imported module or NULL if the AST file is a PCH.
ffi.Pointer<ffi.Void> module;

/// Location where the file is imported. Applicable only for modules.
CXIdxLoc loc;

/// Non-zero if an inclusion directive was automatically turned into
/// a module import. Applicable only for modules.
@ffi.Int32()
int isImplicit;
}

class CXIdxAttrInfo extends ffi.Struct {
@ffi.Int32()
int kind;

CXCursor cursor;

CXIdxLoc loc;
}

class CXIdxEntityInfo extends ffi.Struct {
@ffi.Int32()
int kind;

@ffi.Int32()
int templateKind;

@ffi.Int32()
int lang;

class CXIdxAttrInfo extends ffi.Struct {}
ffi.Pointer<ffi.Int8> name;

class CXIdxEntityInfo extends ffi.Struct {}
ffi.Pointer<ffi.Int8> USR;

class CXIdxContainerInfo extends ffi.Struct {}
CXCursor cursor;

ffi.Pointer<ffi.Pointer<CXIdxAttrInfo>> attributes;

@ffi.Uint32()
int numAttributes;
}

class CXIdxContainerInfo extends ffi.Struct {
CXCursor cursor;
}

class CXIdxIBOutletCollectionAttrInfo extends ffi.Struct {
ffi.Pointer<CXIdxAttrInfo> attrInfo;

ffi.Pointer<CXIdxEntityInfo> objcClass;

CXCursor classCursor;

CXIdxLoc classLoc;
}

class CXIdxIBOutletCollectionAttrInfo extends ffi.Struct {}
class CXIdxDeclInfo extends ffi.Struct {
ffi.Pointer<CXIdxEntityInfo> entityInfo;

class CXIdxDeclInfo extends ffi.Struct {}
CXCursor cursor;

CXIdxLoc loc;

ffi.Pointer<CXIdxContainerInfo> semanticContainer;

/// Generally same as #semanticContainer but can be different in
/// cases like out-of-line C++ member functions.
ffi.Pointer<CXIdxContainerInfo> lexicalContainer;

@ffi.Int32()
int isRedeclaration;

@ffi.Int32()
int isDefinition;

@ffi.Int32()
int isContainer;

ffi.Pointer<CXIdxContainerInfo> declAsContainer;

/// Whether the declaration exists in code or was created implicitly
/// by the compiler, e.g. implicit Objective-C methods for properties.
@ffi.Int32()
int isImplicit;

ffi.Pointer<ffi.Pointer<CXIdxAttrInfo>> attributes;

@ffi.Uint32()
int numAttributes;

@ffi.Uint32()
int flags;
}

class CXIdxObjCContainerDeclInfo extends ffi.Struct {
ffi.Pointer<CXIdxDeclInfo> declInfo;
Expand All @@ -3224,9 +3356,21 @@ class CXIdxObjCContainerDeclInfo extends ffi.Struct {
int kind;
}

class CXIdxBaseClassInfo extends ffi.Struct {}
class CXIdxBaseClassInfo extends ffi.Struct {
ffi.Pointer<CXIdxEntityInfo> base;

class CXIdxObjCProtocolRefInfo extends ffi.Struct {}
CXCursor cursor;

CXIdxLoc loc;
}

class CXIdxObjCProtocolRefInfo extends ffi.Struct {
ffi.Pointer<CXIdxEntityInfo> protocol;

CXCursor cursor;

CXIdxLoc loc;
}

class CXIdxObjCProtocolRefListInfo extends ffi.Struct {
ffi.Pointer<ffi.Pointer<CXIdxObjCProtocolRefInfo>> protocols;
Expand All @@ -3243,7 +3387,17 @@ class CXIdxObjCInterfaceDeclInfo extends ffi.Struct {
ffi.Pointer<CXIdxObjCProtocolRefListInfo> protocols;
}

class CXIdxObjCCategoryDeclInfo extends ffi.Struct {}
class CXIdxObjCCategoryDeclInfo extends ffi.Struct {
ffi.Pointer<CXIdxObjCContainerDeclInfo> containerInfo;

ffi.Pointer<CXIdxEntityInfo> objcClass;

CXCursor classCursor;

CXIdxLoc classLoc;

ffi.Pointer<CXIdxObjCProtocolRefListInfo> protocols;
}

class CXIdxObjCPropertyDeclInfo extends ffi.Struct {
ffi.Pointer<CXIdxDeclInfo> declInfo;
Expand All @@ -3263,7 +3417,36 @@ class CXIdxCXXClassDeclInfo extends ffi.Struct {
}

/// Data for IndexerCallbacks#indexEntityReference.
class CXIdxEntityRefInfo extends ffi.Struct {}
class CXIdxEntityRefInfo extends ffi.Struct {
@ffi.Int32()
int kind;

/// Reference cursor.
CXCursor cursor;

CXIdxLoc loc;

/// The entity that gets referenced.
ffi.Pointer<CXIdxEntityInfo> referencedEntity;

/// Immediate "parent" of the reference. For example:
///
/// \code
/// Foo *var;
/// \endcode
///
/// The parent of reference of type 'Foo' is the variable 'var'.
/// For references inside statement bodies of functions/methods,
/// the parentEntity will be the function/method.
ffi.Pointer<CXIdxEntityInfo> parentEntity;

/// Lexical container context of the reference.
ffi.Pointer<CXIdxContainerInfo> container;

/// Sets of symbol roles of the reference.
@ffi.Int32()
int role;
}

/// A group of callbacks used by #clang_indexSourceFile and
/// #clang_indexTranslationUnit.
Expand Down
22 changes: 1 addition & 21 deletions lib/src/header_parser/sub_parsers/structdecl_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ final _logger = Logger('ffigen.header_parser.structdecl_parser');
/// Holds temporary information regarding [struc] while parsing.
class _ParsedStruc {
Struc struc;
bool nestedStructMember = false;
bool unimplementedMemberType = false;
bool flexibleArrayMember = false;
bool arrayMember = false;
Expand Down Expand Up @@ -73,7 +72,6 @@ Struc parseStructDeclaration(

void _setStructMembers(Pointer<clang_types.CXCursor> cursor) {
_stack.top.arrayMember = false;
_stack.top.nestedStructMember = false;
_stack.top.unimplementedMemberType = false;

final resultCode = clang.clang_visitChildren_wrap(
Expand All @@ -92,12 +90,6 @@ void _setStructMembers(Pointer<clang_types.CXCursor> cursor) {
_logger.warning(
'Removed All Struct Members from: ${_stack.top.struc.name}(${_stack.top.struc.originalName}), Array members not supported');
return _stack.top.struc.members.clear();
} else if (_stack.top.nestedStructMember) {
_logger.fine(
'---- Removed Struct members, reason: struct has struct members ${cursor.completeStringRepr()}');
_logger.warning(
'Removed All Struct Members from ${_stack.top.struc.name}(${_stack.top.struc.originalName}), Nested Structures not supported.');
return _stack.top.struc.members.clear();
} else if (_stack.top.unimplementedMemberType) {
_logger.fine(
'---- Removed Struct members, reason: member with unimplementedtype ${cursor.completeStringRepr()}');
Expand Down Expand Up @@ -135,19 +127,7 @@ int _structMembersVisitor(Pointer<clang_types.CXCursor> cursor,
_logger.finer('===== member: ${cursor.completeStringRepr()}');

final mt = cursor.type().toCodeGenTypeAndDispose();
//TODO(4): Remove these when support for Structs by value arrives.
if (mt.broadType == BroadType.Struct) {
// Setting this flag will exclude adding members for this struct's
// bindings.
_stack.top.nestedStructMember = true;
} else if (mt.broadType == BroadType.ConstantArray) {
_stack.top.arrayMember = true;
if (mt.child.broadType == BroadType.Struct) {
// Setting this flag will exclude adding members for this struct's
// bindings.
_stack.top.nestedStructMember = true;
}
} else if (mt.broadType == BroadType.IncompleteArray) {
if (mt.broadType == BroadType.IncompleteArray) {
// TODO(68): Structs with flexible Array Members are not supported.
_stack.top.flexibleArrayMember = true;
} else if (clang.clang_getFieldDeclBitWidth_wrap(cursor) != -1) {
Expand Down
19 changes: 16 additions & 3 deletions test/header_parser_tests/function_n_struct_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:test/test.dart';
import 'package:yaml/yaml.dart' as yaml;
import 'package:ffigen/src/strings.dart' as strings;

import '../native_test/native_test_bindings.dart';
import '../test_utils.dart';

Library actual, expected;
Expand Down Expand Up @@ -41,7 +42,8 @@ ${strings.headers}:
expected.getBindingAsString('func2'));
});
test('Struct2 nested struct member', () {
expect((actual.getBinding('Struct2') as Struc).members.isEmpty, true);
expect(actual.getBindingAsString('Struct2'),
expected.getBindingAsString('Struct2'));
});
test('Struct3 flexible array member', () {
expect((actual.getBinding('Struct3') as Struc).members.isEmpty, true);
Expand All @@ -53,7 +55,13 @@ ${strings.headers}:
}

Library expectedLibrary() {
final struc2 = Struc(name: 'Struct2', members: []);
final struc1 = Struc(name: 'Struct1', members: []);
final struc2 = Struc(name: 'Struct2', members: [
Member(
name: 'a',
type: Type.struct(struc1),
),
]);
final struc3 = Struc(name: 'Struct3', members: []);
return Library(
name: 'Bindings',
Expand Down Expand Up @@ -84,7 +92,12 @@ Library expectedLibrary() {
SupportedNativeType.Void,
),
),
Struc(name: 'Struct4'),
Struc(name: 'Struct4', members: [
Member(
name: 'a',
type: Type.struct(struc1),
),
]),
],
);
}
Loading