blob: 309ab3947706f060915ef52bda2dfaec906c0fb8 [file] [log] [blame]
// 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 'dart:ffi';
import 'package:ffigen/src/code_generator.dart';
import 'package:logging/logging.dart';
import '../clang_bindings/clang_bindings.dart' as clang_types;
import '../data.dart';
import '../includer.dart';
import '../utils.dart';
var _logger = Logger('header_parser:structdecl_parser.dart');
/// Temporarily holds a struc before its returned by [parseStructDeclaration].
Struc _struc;
/// Parses a struct declaration.
Struc parseStructDeclaration(
Pointer<clang_types.CXCursor> cursor, {
/// Optionally provide name (useful in case struct is inside a typedef).
String name,
/// 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();
if (structName == '') {
_logger.finest('unnamed structure or typedef structure declaration');
return null;
} else if ((ignoreFilter || shouldIncludeStruct(structName)) &&
(!isSeenStruc(structName))) {
_logger.fine(
'++++ Adding Structure: structName: ${structName}, ${cursor.completeStringRepr()}');
_struc = Struc(
name: config.structDecl.getPrefixedName(structName),
dartDoc: getCursorDocComment(cursor),
);
// 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;
}
List<Member> _members;
List<Member> _getMembers(Pointer<clang_types.CXCursor> cursor, String structName) {
_members = [];
arrayMember = false;
nestedStructMember = false;
unimplementedMemberType = false;
final resultCode = clang.clang_visitChildren_wrap(
cursor,
Pointer.fromFunction(
_structMembersVisitor, clang_types.CXChildVisitResult.CXChildVisit_Break),
nullptr);
visitChildrenResultChecker(resultCode);
// Returning null to exclude the struct members as it has a struct by value field.
if (arrayMember && !config.arrayWorkaround) {
_logger.fine(
'---- Removed Struct members, reason: struct has array members ${cursor.completeStringRepr()}');
_logger.warning(
'Removed All Struct Members from: $structName, Array members not supported');
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 [];
} 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 [];
}
return _members;
}
bool nestedStructMember = false;
bool unimplementedMemberType = false;
bool arrayMember = false;
/// Visitor for the struct cursor [CXCursorKind.CXCursor_StructDecl].
///
/// Child visitor invoked on struct cursor.
int _structMembersVisitor(Pointer<clang_types.CXCursor> cursor,
Pointer<clang_types.CXCursor> parent, Pointer<Void> clientData) {
try {
if (cursor.kind() == clang_types.CXCursorKind.CXCursor_FieldDecl) {
_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.
nestedStructMember = true;
} else if (mt.broadType == BroadType.ConstantArray) {
arrayMember = true;
if (mt.child.broadType == BroadType.Struct) {
// Setting this flag will exclude adding members for this struct's
// bindings.
nestedStructMember = true;
}
}
if (mt.getBaseType().broadType == BroadType.Unimplemented) {
unimplementedMemberType = true;
}
_members.add(
Member(
dartDoc: getCursorDocComment(
cursor,
nesting.length + commentPrefix.length,
),
name: cursor.spelling(),
type: mt,
),
);
}
cursor.dispose();
parent.dispose();
} catch (e, s) {
_logger.severe(e);
_logger.severe(s);
rethrow;
}
return clang_types.CXChildVisitResult.CXChildVisit_Continue;
}