Skip to content

Commit 9fe355a

Browse files
committed
Support nested structs
Fixes #4
1 parent 7ee3ec7 commit 9fe355a

File tree

4 files changed

+396
-48
lines changed

4 files changed

+396
-48
lines changed

example/libclang-example/generated_bindings.dart

Lines changed: 195 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2851,7 +2851,32 @@ class ArrayHelper_CXCursor_data_level0 {
28512851

28522852
/// Describes the availability of a given entity on a particular platform, e.g.,
28532853
/// a particular class might only be available on Mac OS 10.7 or newer.
2854-
class CXPlatformAvailability extends ffi.Struct {}
2854+
class CXPlatformAvailability extends ffi.Struct {
2855+
/// A string that describes the platform for which this structure
2856+
/// provides availability information.
2857+
///
2858+
/// Possible values are "ios" or "macos".
2859+
CXString Platform;
2860+
2861+
/// The version number in which this entity was introduced.
2862+
CXVersion Introduced;
2863+
2864+
/// The version number in which this entity was deprecated (but is
2865+
/// still available).
2866+
CXVersion Deprecated;
2867+
2868+
/// The version number in which this entity was obsoleted, and therefore
2869+
/// is no longer available.
2870+
CXVersion Obsoleted;
2871+
2872+
/// Whether the entity is unconditionally unavailable on this platform.
2873+
@ffi.Int32()
2874+
int Unavailable;
2875+
2876+
/// An optional message to provide to a user of this API, e.g., to
2877+
/// suggest replacement APIs.
2878+
CXString Message;
2879+
}
28552880

28562881
class CXCursorSetImpl extends ffi.Struct {}
28572882

@@ -3202,20 +3227,127 @@ class ArrayHelper_CXIdxLoc_ptr_data_level0 {
32023227
}
32033228

32043229
/// Data for ppIncludedFile callback.
3205-
class CXIdxIncludedFileInfo extends ffi.Struct {}
3230+
class CXIdxIncludedFileInfo extends ffi.Struct {
3231+
/// Location of '#' in the \#include/\#import directive.
3232+
CXIdxLoc hashLoc;
3233+
3234+
/// Filename as written in the \#include/\#import directive.
3235+
ffi.Pointer<ffi.Int8> filename;
3236+
3237+
/// The actual file that the \#include/\#import directive resolved to.
3238+
ffi.Pointer<ffi.Void> file;
3239+
3240+
@ffi.Int32()
3241+
int isImport;
3242+
3243+
@ffi.Int32()
3244+
int isAngled;
3245+
3246+
/// Non-zero if the directive was automatically turned into a module
3247+
/// import.
3248+
@ffi.Int32()
3249+
int isModuleImport;
3250+
}
32063251

32073252
/// Data for IndexerCallbacks#importedASTFile.
3208-
class CXIdxImportedASTFileInfo extends ffi.Struct {}
3253+
class CXIdxImportedASTFileInfo extends ffi.Struct {
3254+
/// Top level AST file containing the imported PCH, module or submodule.
3255+
ffi.Pointer<ffi.Void> file;
3256+
3257+
/// The imported module or NULL if the AST file is a PCH.
3258+
ffi.Pointer<ffi.Void> module;
3259+
3260+
/// Location where the file is imported. Applicable only for modules.
3261+
CXIdxLoc loc;
3262+
3263+
/// Non-zero if an inclusion directive was automatically turned into
3264+
/// a module import. Applicable only for modules.
3265+
@ffi.Int32()
3266+
int isImplicit;
3267+
}
3268+
3269+
class CXIdxAttrInfo extends ffi.Struct {
3270+
@ffi.Int32()
3271+
int kind;
3272+
3273+
CXCursor cursor;
3274+
3275+
CXIdxLoc loc;
3276+
}
3277+
3278+
class CXIdxEntityInfo extends ffi.Struct {
3279+
@ffi.Int32()
3280+
int kind;
3281+
3282+
@ffi.Int32()
3283+
int templateKind;
3284+
3285+
@ffi.Int32()
3286+
int lang;
32093287

3210-
class CXIdxAttrInfo extends ffi.Struct {}
3288+
ffi.Pointer<ffi.Int8> name;
32113289

3212-
class CXIdxEntityInfo extends ffi.Struct {}
3290+
ffi.Pointer<ffi.Int8> USR;
32133291

3214-
class CXIdxContainerInfo extends ffi.Struct {}
3292+
CXCursor cursor;
3293+
3294+
ffi.Pointer<ffi.Pointer<CXIdxAttrInfo>> attributes;
3295+
3296+
@ffi.Uint32()
3297+
int numAttributes;
3298+
}
3299+
3300+
class CXIdxContainerInfo extends ffi.Struct {
3301+
CXCursor cursor;
3302+
}
3303+
3304+
class CXIdxIBOutletCollectionAttrInfo extends ffi.Struct {
3305+
ffi.Pointer<CXIdxAttrInfo> attrInfo;
3306+
3307+
ffi.Pointer<CXIdxEntityInfo> objcClass;
3308+
3309+
CXCursor classCursor;
3310+
3311+
CXIdxLoc classLoc;
3312+
}
32153313

3216-
class CXIdxIBOutletCollectionAttrInfo extends ffi.Struct {}
3314+
class CXIdxDeclInfo extends ffi.Struct {
3315+
ffi.Pointer<CXIdxEntityInfo> entityInfo;
32173316

3218-
class CXIdxDeclInfo extends ffi.Struct {}
3317+
CXCursor cursor;
3318+
3319+
CXIdxLoc loc;
3320+
3321+
ffi.Pointer<CXIdxContainerInfo> semanticContainer;
3322+
3323+
/// Generally same as #semanticContainer but can be different in
3324+
/// cases like out-of-line C++ member functions.
3325+
ffi.Pointer<CXIdxContainerInfo> lexicalContainer;
3326+
3327+
@ffi.Int32()
3328+
int isRedeclaration;
3329+
3330+
@ffi.Int32()
3331+
int isDefinition;
3332+
3333+
@ffi.Int32()
3334+
int isContainer;
3335+
3336+
ffi.Pointer<CXIdxContainerInfo> declAsContainer;
3337+
3338+
/// Whether the declaration exists in code or was created implicitly
3339+
/// by the compiler, e.g. implicit Objective-C methods for properties.
3340+
@ffi.Int32()
3341+
int isImplicit;
3342+
3343+
ffi.Pointer<ffi.Pointer<CXIdxAttrInfo>> attributes;
3344+
3345+
@ffi.Uint32()
3346+
int numAttributes;
3347+
3348+
@ffi.Uint32()
3349+
int flags;
3350+
}
32193351

32203352
class CXIdxObjCContainerDeclInfo extends ffi.Struct {
32213353
ffi.Pointer<CXIdxDeclInfo> declInfo;
@@ -3224,9 +3356,21 @@ class CXIdxObjCContainerDeclInfo extends ffi.Struct {
32243356
int kind;
32253357
}
32263358

3227-
class CXIdxBaseClassInfo extends ffi.Struct {}
3359+
class CXIdxBaseClassInfo extends ffi.Struct {
3360+
ffi.Pointer<CXIdxEntityInfo> base;
32283361

3229-
class CXIdxObjCProtocolRefInfo extends ffi.Struct {}
3362+
CXCursor cursor;
3363+
3364+
CXIdxLoc loc;
3365+
}
3366+
3367+
class CXIdxObjCProtocolRefInfo extends ffi.Struct {
3368+
ffi.Pointer<CXIdxEntityInfo> protocol;
3369+
3370+
CXCursor cursor;
3371+
3372+
CXIdxLoc loc;
3373+
}
32303374

32313375
class CXIdxObjCProtocolRefListInfo extends ffi.Struct {
32323376
ffi.Pointer<ffi.Pointer<CXIdxObjCProtocolRefInfo>> protocols;
@@ -3243,7 +3387,17 @@ class CXIdxObjCInterfaceDeclInfo extends ffi.Struct {
32433387
ffi.Pointer<CXIdxObjCProtocolRefListInfo> protocols;
32443388
}
32453389

3246-
class CXIdxObjCCategoryDeclInfo extends ffi.Struct {}
3390+
class CXIdxObjCCategoryDeclInfo extends ffi.Struct {
3391+
ffi.Pointer<CXIdxObjCContainerDeclInfo> containerInfo;
3392+
3393+
ffi.Pointer<CXIdxEntityInfo> objcClass;
3394+
3395+
CXCursor classCursor;
3396+
3397+
CXIdxLoc classLoc;
3398+
3399+
ffi.Pointer<CXIdxObjCProtocolRefListInfo> protocols;
3400+
}
32473401

32483402
class CXIdxObjCPropertyDeclInfo extends ffi.Struct {
32493403
ffi.Pointer<CXIdxDeclInfo> declInfo;
@@ -3263,7 +3417,36 @@ class CXIdxCXXClassDeclInfo extends ffi.Struct {
32633417
}
32643418

32653419
/// Data for IndexerCallbacks#indexEntityReference.
3266-
class CXIdxEntityRefInfo extends ffi.Struct {}
3420+
class CXIdxEntityRefInfo extends ffi.Struct {
3421+
@ffi.Int32()
3422+
int kind;
3423+
3424+
/// Reference cursor.
3425+
CXCursor cursor;
3426+
3427+
CXIdxLoc loc;
3428+
3429+
/// The entity that gets referenced.
3430+
ffi.Pointer<CXIdxEntityInfo> referencedEntity;
3431+
3432+
/// Immediate "parent" of the reference. For example:
3433+
///
3434+
/// \code
3435+
/// Foo *var;
3436+
/// \endcode
3437+
///
3438+
/// The parent of reference of type 'Foo' is the variable 'var'.
3439+
/// For references inside statement bodies of functions/methods,
3440+
/// the parentEntity will be the function/method.
3441+
ffi.Pointer<CXIdxEntityInfo> parentEntity;
3442+
3443+
/// Lexical container context of the reference.
3444+
ffi.Pointer<CXIdxContainerInfo> container;
3445+
3446+
/// Sets of symbol roles of the reference.
3447+
@ffi.Int32()
3448+
int role;
3449+
}
32673450

32683451
/// A group of callbacks used by #clang_indexSourceFile and
32693452
/// #clang_indexTranslationUnit.

lib/src/header_parser/sub_parsers/structdecl_parser.dart

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ final _logger = Logger('ffigen.header_parser.structdecl_parser');
1717
/// Holds temporary information regarding [struc] while parsing.
1818
class _ParsedStruc {
1919
Struc struc;
20-
bool nestedStructMember = false;
2120
bool unimplementedMemberType = false;
2221
bool flexibleArrayMember = false;
2322
bool arrayMember = false;
@@ -73,7 +72,6 @@ Struc parseStructDeclaration(
7372

7473
void _setStructMembers(Pointer<clang_types.CXCursor> cursor) {
7574
_stack.top.arrayMember = false;
76-
_stack.top.nestedStructMember = false;
7775
_stack.top.unimplementedMemberType = false;
7876

7977
final resultCode = clang.clang_visitChildren_wrap(
@@ -92,12 +90,6 @@ void _setStructMembers(Pointer<clang_types.CXCursor> cursor) {
9290
_logger.warning(
9391
'Removed All Struct Members from: ${_stack.top.struc.name}(${_stack.top.struc.originalName}), Array members not supported');
9492
return _stack.top.struc.members.clear();
95-
} else if (_stack.top.nestedStructMember) {
96-
_logger.fine(
97-
'---- Removed Struct members, reason: struct has struct members ${cursor.completeStringRepr()}');
98-
_logger.warning(
99-
'Removed All Struct Members from ${_stack.top.struc.name}(${_stack.top.struc.originalName}), Nested Structures not supported.');
100-
return _stack.top.struc.members.clear();
10193
} else if (_stack.top.unimplementedMemberType) {
10294
_logger.fine(
10395
'---- Removed Struct members, reason: member with unimplementedtype ${cursor.completeStringRepr()}');
@@ -135,19 +127,7 @@ int _structMembersVisitor(Pointer<clang_types.CXCursor> cursor,
135127
_logger.finer('===== member: ${cursor.completeStringRepr()}');
136128

137129
final mt = cursor.type().toCodeGenTypeAndDispose();
138-
//TODO(4): Remove these when support for Structs by value arrives.
139-
if (mt.broadType == BroadType.Struct) {
140-
// Setting this flag will exclude adding members for this struct's
141-
// bindings.
142-
_stack.top.nestedStructMember = true;
143-
} else if (mt.broadType == BroadType.ConstantArray) {
144-
_stack.top.arrayMember = true;
145-
if (mt.child.broadType == BroadType.Struct) {
146-
// Setting this flag will exclude adding members for this struct's
147-
// bindings.
148-
_stack.top.nestedStructMember = true;
149-
}
150-
} else if (mt.broadType == BroadType.IncompleteArray) {
130+
if (mt.broadType == BroadType.IncompleteArray) {
151131
// TODO(68): Structs with flexible Array Members are not supported.
152132
_stack.top.flexibleArrayMember = true;
153133
} else if (clang.clang_getFieldDeclBitWidth_wrap(cursor) != -1) {

test/header_parser_tests/function_n_struct_test.dart

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:test/test.dart';
1010
import 'package:yaml/yaml.dart' as yaml;
1111
import 'package:ffigen/src/strings.dart' as strings;
1212

13+
import '../native_test/native_test_bindings.dart';
1314
import '../test_utils.dart';
1415

1516
Library actual, expected;
@@ -41,7 +42,8 @@ ${strings.headers}:
4142
expected.getBindingAsString('func2'));
4243
});
4344
test('Struct2 nested struct member', () {
44-
expect((actual.getBinding('Struct2') as Struc).members.isEmpty, true);
45+
expect(actual.getBindingAsString('Struct2'),
46+
expected.getBindingAsString('Struct2'));
4547
});
4648
test('Struct3 flexible array member', () {
4749
expect((actual.getBinding('Struct3') as Struc).members.isEmpty, true);
@@ -53,7 +55,13 @@ ${strings.headers}:
5355
}
5456

5557
Library expectedLibrary() {
56-
final struc2 = Struc(name: 'Struct2', members: []);
58+
final struc1 = Struc(name: 'Struct1', members: []);
59+
final struc2 = Struc(name: 'Struct2', members: [
60+
Member(
61+
name: 'a',
62+
type: Type.struct(struc1),
63+
),
64+
]);
5765
final struc3 = Struc(name: 'Struct3', members: []);
5866
return Library(
5967
name: 'Bindings',
@@ -84,7 +92,12 @@ Library expectedLibrary() {
8492
SupportedNativeType.Void,
8593
),
8694
),
87-
Struc(name: 'Struct4'),
95+
Struc(name: 'Struct4', members: [
96+
Member(
97+
name: 'a',
98+
type: Type.struct(struc1),
99+
),
100+
]),
88101
],
89102
);
90103
}

0 commit comments

Comments
 (0)