/// The base representation of a type in bindgen. /// /// A type has an optional name, which if present cannot be empty, a `layout` /// (size, alignment and packedness) if known, a `Kind`, which determines which /// kind of type it is, and whether the type is const. #[derive(Debug)] pub(crate) structType { /// The name of the type, or None if it was an unnamed struct or union.
name: Option<String>, /// The layout of the type, if known.
layout: Option<Layout>, /// The inner kind of the type
kind: TypeKind, /// Whether this type is const-qualified.
is_const: bool,
}
/// The maximum number of items in an array for which Rust implements common /// traits, and so if we have a type containing an array with more than this /// many items, we won't be able to derive common traits on that type. /// pub(crate) const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32;
implType { /// Get the underlying `CompInfo` for this type as a mutable reference, or /// `None` if this is some other kind of type. pub(crate) fn as_comp_mut(&mutself) -> Option<&mut CompInfo> { matchself.kind {
TypeKind::Comp(refmut ci) => Some(ci),
_ => None,
}
}
/// Construct a new `Type`. pub(crate) fn new(
name: Option<String>,
layout: Option<Layout>,
kind: TypeKind,
is_const: bool,
) -> Self { Type {
name,
layout,
kind,
is_const,
}
}
/// Which kind of type is this? pub(crate) fn kind(&self) -> &TypeKind {
&self.kind
}
/// Get a mutable reference to this type's kind. pub(crate) fn kind_mut(&mutself) -> &mut TypeKind {
&mutself.kind
}
/// Get this type's name. pub(crate) fn name(&self) -> Option<&str> { self.name.as_deref()
}
/// Whether this is a block pointer type. pub(crate) fn is_block_pointer(&self) -> bool {
matches!(self.kind, TypeKind::BlockPointer(..))
}
/// Is this an integer type, including `bool` or `char`? pub(crate) fn is_int(&self) -> bool {
matches!(self.kind, TypeKind::Int(_))
}
/// Is this a compound type? pub(crate) fn is_comp(&self) -> bool {
matches!(self.kind, TypeKind::Comp(..))
}
/// Is this a union? pub(crate) fn is_union(&self) -> bool { matchself.kind {
TypeKind::Comp(ref comp) => comp.is_union(),
_ => false,
}
}
/// Is this type of kind `TypeKind::TypeParam`? pub(crate) fn is_type_param(&self) -> bool {
matches!(self.kind, TypeKind::TypeParam)
}
/// Is this a template instantiation type? pub(crate) fn is_template_instantiation(&self) -> bool {
matches!(self.kind, TypeKind::TemplateInstantiation(..))
}
/// Is this a function type? pub(crate) fn is_function(&self) -> bool {
matches!(self.kind, TypeKind::Function(..))
}
/// Is this an enum type? pub(crate) fn is_enum(&self) -> bool {
matches!(self.kind, TypeKind::Enum(..))
}
/// Is this void? pub(crate) fn is_void(&self) -> bool {
matches!(self.kind, TypeKind::Void)
} /// Is this either a builtin or named type? pub(crate) fn is_builtin_or_type_param(&self) -> bool {
matches!( self.kind,
TypeKind::Void |
TypeKind::NullPtr |
TypeKind::Function(..) |
TypeKind::Array(..) |
TypeKind::Reference(..) |
TypeKind::Pointer(..) |
TypeKind::Int(..) |
TypeKind::Float(..) |
TypeKind::TypeParam
)
}
/// Creates a new named type, with name `name`. pub(crate) fn named(name: String) -> Self { let name = if name.is_empty() { None } else { Some(name) }; Self::new(name, None, TypeKind::TypeParam, false)
}
/// Is this a floating point type? pub(crate) fn is_float(&self) -> bool {
matches!(self.kind, TypeKind::Float(..))
}
/// Is this a boolean type? pub(crate) fn is_bool(&self) -> bool {
matches!(self.kind, TypeKind::Int(IntKind::Bool))
}
/// Is this an integer type? pub(crate) fn is_integer(&self) -> bool {
matches!(self.kind, TypeKind::Int(..))
}
/// Cast this type to an integer kind, or `None` if it is not an integer /// type. pub(crate) fn as_integer(&self) -> Option<IntKind> { matchself.kind {
TypeKind::Int(int_kind) => Some(int_kind),
_ => None,
}
}
/// Is this a `const` qualified type? pub(crate) fn is_const(&self) -> bool { self.is_const
}
/// Is this an unresolved reference? pub(crate) fn is_unresolved_ref(&self) -> bool {
matches!(self.kind, TypeKind::UnresolvedTypeRef(_, _, _))
}
/// Is this a incomplete array type? pub(crate) fn is_incomplete_array(
&self,
ctx: &BindgenContext,
) -> Option<ItemId> { matchself.kind {
TypeKind::Array(item, len) => { if len == 0 {
Some(item.into())
} else {
None
}
}
TypeKind::ResolvedTypeRef(inner) => {
ctx.resolve_type(inner).is_incomplete_array(ctx)
}
_ => None,
}
}
/// What is the layout of this type? pub(crate) fn layout(&self, ctx: &BindgenContext) -> Option<Layout> { self.layout.or_else(|| { matchself.kind {
TypeKind::Comp(ref ci) => ci.layout(ctx),
TypeKind::Array(inner, 0) => Some(Layout::new( 0,
ctx.resolve_type(inner).layout(ctx)?.align,
)), // FIXME(emilio): This is a hack for anonymous union templates. // Use the actual pointer size!
TypeKind::Pointer(..) => Some(Layout::new(
ctx.target_pointer_size(),
ctx.target_pointer_size(),
)),
TypeKind::ResolvedTypeRef(inner) => {
ctx.resolve_type(inner).layout(ctx)
}
_ => None,
}
})
}
/// Whether this named type is an invalid C++ identifier. This is done to /// avoid generating invalid code with some cases we can't handle, see: /// /// tests/headers/381-decltype-alias.hpp pub(crate) fn is_invalid_type_param(&self) -> bool { matchself.kind {
TypeKind::TypeParam => { let name = self.name().expect("Unnamed named type?");
!clang::is_valid_identifier(name)
}
_ => false,
}
}
/// Takes `name`, and returns a suitable identifier representation for it. fn sanitize_name(name: &str) -> Cow<str> { if clang::is_valid_identifier(name) { return Cow::Borrowed(name);
}
let name = name.replace(|c| c == ' ' || c == ':' || c == '.', "_");
Cow::Owned(name)
}
/// See safe_canonical_type. pub(crate) fn canonical_type<'tr>(
&'tr self,
ctx: &'tr BindgenContext,
) -> &'tr Type { self.safe_canonical_type(ctx)
.expect("Should have been resolved after parsing!")
}
/// Returns the canonical type of this type, that is, the "inner type". /// /// For example, for a `typedef`, the canonical type would be the /// `typedef`ed type, for a template instantiation, would be the template /// its specializing, and so on. Return None if the type is unresolved. pub(crate) fn safe_canonical_type<'tr>(
&'tr self,
ctx: &'tr BindgenContext,
) -> Option<&'tr Type> { matchself.kind {
TypeKind::TypeParam |
TypeKind::Array(..) |
TypeKind::Vector(..) |
TypeKind::Comp(..) |
TypeKind::Opaque |
TypeKind::Int(..) |
TypeKind::Float(..) |
TypeKind::Complex(..) |
TypeKind::Function(..) |
TypeKind::Enum(..) |
TypeKind::Reference(..) |
TypeKind::Void |
TypeKind::NullPtr |
TypeKind::Pointer(..) |
TypeKind::BlockPointer(..) |
TypeKind::ObjCId |
TypeKind::ObjCSel |
TypeKind::ObjCInterface(..) => Some(self),
/// There are some types we don't want to stop at when finding an opaque /// item, so we can arrive to the proper item that needs to be generated. pub(crate) fn should_be_traced_unconditionally(&self) -> bool {
matches!( self.kind,
TypeKind::Comp(..) |
TypeKind::Function(..) |
TypeKind::Pointer(..) |
TypeKind::Array(..) |
TypeKind::Reference(..) |
TypeKind::TemplateInstantiation(..) |
TypeKind::ResolvedTypeRef(..)
)
}
}
/// The kind of float this type represents. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub(crate) enum FloatKind { /// A half (`_Float16` or `__fp16`)
Float16, /// A `float`.
Float, /// A `double`.
Double, /// A `long double`.
LongDouble, /// A `__float128`.
Float128,
}
/// The different kinds of types that we can parse. #[derive(Debug)] pub(crate) enum TypeKind { /// The void type.
Void,
/// The `nullptr_t` type.
NullPtr,
/// A compound type, that is, a class, struct, or union.
Comp(CompInfo),
/// An opaque type that we just don't understand. All usage of this shoulf /// result in an opaque blob of bytes generated from the containing type's /// layout.
Opaque,
/// An integer type, of a given kind. `bool` and `char` are also considered /// integers.
Int(IntKind),
/// A floating point type.
Float(FloatKind),
/// A complex floating point type.
Complex(FloatKind),
/// A type alias, with a name, that points to another type.
Alias(TypeId),
/// A templated alias, pointing to an inner type, just as `Alias`, but with /// template parameters.
TemplateAlias(TypeId, Vec<TypeId>),
/// A packed vector type: element type, number of elements
Vector(TypeId, usize),
/// An array of a type and a length.
Array(TypeId, usize),
/// A function type, with a given signature.
Function(FunctionSig),
/// An `enum` type. Enum(Enum),
/// A pointer to a type. The bool field represents whether it's const or /// not.
Pointer(TypeId),
/// A pointer to an Apple block.
BlockPointer(TypeId),
/// A reference to a type, as in: int& foo().
Reference(TypeId),
/// An instantiation of an abstract template definition with a set of /// concrete template arguments.
TemplateInstantiation(TemplateInstantiation),
/// A reference to a yet-to-resolve type. This stores the clang cursor /// itself, and postpones its resolution. /// /// These are gone in a phase after parsing where these are mapped to /// already known types, and are converted to ResolvedTypeRef. /// /// see tests/headers/typeref.hpp to see somewhere where this is a problem.
UnresolvedTypeRef(
clang::Type,
clang::Cursor, /* parent_id */
Option<ItemId>,
),
/// An indirection to another type. /// /// These are generated after we resolve a forward declaration, or when we /// replace one type with another.
ResolvedTypeRef(TypeId),
/// A named type, that is, a template parameter.
TypeParam,
/// Objective C interface. Always referenced through a pointer
ObjCInterface(ObjCInterface),
/// Objective C 'id' type, points to any object
ObjCId,
/// Objective C selector type
ObjCSel,
}
implType { /// This is another of the nasty methods. This one is the one that takes /// care of the core logic of converting a clang type to a `Type`. /// /// It's sort of nasty and full of special-casing, but hopefully the /// comments in every special case justify why they're there. pub(crate) fn from_clang_ty(
potential_id: ItemId,
ty: &clang::Type,
location: Cursor,
parent_id: Option<ItemId>,
ctx: &mut BindgenContext,
) -> Result<ParseResult<Self>, ParseError> { use clang_sys::*;
{ let already_resolved = ctx.builtin_or_resolved_ty(
potential_id,
parent_id,
ty,
Some(location),
); iflet Some(ty) = already_resolved {
debug!("{:?} already resolved: {:?}", ty, location); return Ok(ParseResult::AlreadyResolved(ty.into()));
}
}
let layout = ty.fallible_layout(ctx).ok(); let cursor = ty.declaration(); let is_anonymous = cursor.is_anonymous(); letmut name = if is_anonymous {
None
} else {
Some(cursor.spelling()).filter(|n| !n.is_empty())
};
// Parse objc protocols as if they were interfaces letmut ty_kind = ty.kind(); match location.kind() {
CXCursor_ObjCProtocolDecl | CXCursor_ObjCCategoryDecl => {
ty_kind = CXType_ObjCInterface
}
_ => {}
}
// Objective C template type parameter // FIXME: This is probably wrong, we are attempting to find the // objc template params, which seem to manifest as a typedef. // We are rewriting them as ID to suppress multiple conflicting // typedefs at root level if ty_kind == CXType_Typedef { let is_template_type_param =
ty.declaration().kind() == CXCursor_TemplateTypeParameter; let is_canonical_objcpointer =
canonical_ty.kind() == CXType_ObjCObjectPointer;
// We have found a template type for objc interface if is_canonical_objcpointer && is_template_type_param { // Objective-C generics are just ids with fancy name. // To keep it simple, just name them ids
name = Some("id".to_owned());
}
}
if location.kind() == CXCursor_ClassTemplatePartialSpecialization { // Sorry! (Not sorry)
warn!( "Found a partial template specialization; bindgen does not \
support partial template specialization! Constructing \
opaque type instead."
); return Ok(ParseResult::New(
Opaque::from_clang_ty(&canonical_ty, ctx),
None,
));
}
let kind = if location.kind() == CXCursor_TemplateRef ||
(ty.template_args().is_some() && ty_kind != CXType_Typedef)
{ // This is a template instantiation. match TemplateInstantiation::from_ty(ty, ctx) {
Some(inst) => TypeKind::TemplateInstantiation(inst),
None => TypeKind::Opaque,
}
} else { match ty_kind {
CXType_Unexposed if *ty != canonical_ty &&
canonical_ty.kind() != CXType_Invalid &&
ty.ret_type().is_none() && // Sometime clang desugars some types more than // what we need, specially with function // pointers. // // We should also try the solution of inverting // those checks instead of doing this, that is, // something like: // // CXType_Unexposed if ty.ret_type().is_some() // => { ... } // // etc.
!canonical_ty.spelling().contains("type-parameter") =>
{
debug!("Looking for canonical type: {:?}", canonical_ty); returnSelf::from_clang_ty(
potential_id,
&canonical_ty,
location,
parent_id,
ctx,
);
}
CXType_Unexposed | CXType_Invalid => { // For some reason Clang doesn't give us any hint in some // situations where we should generate a function pointer (see // tests/headers/func_ptr_in_struct.h), so we do a guess here // trying to see if it has a valid return type. if ty.ret_type().is_some() { let signature =
FunctionSig::from_ty(ty, &location, ctx)?;
TypeKind::Function(signature) // Same here, with template specialisations we can safely // assume this is a Comp(..)
} elseif ty.is_fully_instantiated_template() {
debug!( "Template specialization: {:?}, {:?} {:?}",
ty, location, canonical_ty
); let complex = CompInfo::from_ty(
potential_id,
ty,
Some(location),
ctx,
)
.expect("C'mon");
TypeKind::Comp(complex)
} else { match location.kind() {
CXCursor_CXXBaseSpecifier |
CXCursor_ClassTemplate => { if location.kind() == CXCursor_CXXBaseSpecifier
{ // In the case we're parsing a base specifier // inside an unexposed or invalid type, it means // that we're parsing one of two things: // // * A template parameter. // * A complex class that isn't exposed. // // This means, unfortunately, that there's no // good way to differentiate between them. // // Probably we could try to look at the // declaration and complicate more this logic, // but we'll keep it simple... if it's a valid // C++ identifier, we'll consider it as a // template parameter. // // This is because: // // * We expect every other base that is a // proper identifier (that is, a simple // struct/union declaration), to be exposed, // so this path can't be reached in that // case. // // * Quite conveniently, complex base // specifiers preserve their full names (that // is: Foo<T> instead of Foo). We can take // advantage of this. // // If we find some edge case where this doesn't // work (which I guess is unlikely, see the // different test cases[1][2][3][4]), we'd need // to find more creative ways of differentiating // these two cases. // // [1]: inherit_named.hpp // [2]: forward-inherit-struct-with-fields.hpp // [3]: forward-inherit-struct.hpp // [4]: inherit-namespaced.hpp if location.spelling().chars().all(|c| {
c.is_alphanumeric() || c == '_'
}) { return Err(ParseError::Recurse);
}
} else {
name = Some(location.spelling());
}
let complex = CompInfo::from_ty(
potential_id,
ty,
Some(location),
ctx,
); match complex {
Ok(complex) => TypeKind::Comp(complex),
Err(_) => {
warn!( "Could not create complex type \
from class template or base \
specifier, using opaque blob"
); let opaque =
Opaque::from_clang_ty(ty, ctx); return Ok(ParseResult::New(
opaque, None,
));
}
}
}
CXCursor_TypeAliasTemplateDecl => {
debug!("TypeAliasTemplateDecl");
// We need to manually unwind this one. letmut inner = Err(ParseError::Continue); letmut args = vec![];
location.visit(|cur| { match cur.kind() {
CXCursor_TypeAliasDecl => { let current = cur.cur_type();
returnSelf::from_clang_ty(
potential_id,
&canonical_ty,
location,
parent_id,
ctx,
);
} // NOTE: We don't resolve pointers eagerly because the pointee type // might not have been parsed, and if it contains templates or // something else we might get confused, see the comment inside // TypeRef. // // We might need to, though, if the context is already in the // process of resolving them.
CXType_ObjCObjectPointer |
CXType_MemberPointer |
CXType_Pointer => { letmut pointee = ty.pointee_type().unwrap(); if *ty != canonical_ty { let canonical_pointee =
canonical_ty.pointee_type().unwrap(); // clang sometimes loses pointee constness here, see // #2244. if canonical_pointee.is_const() != pointee.is_const() {
pointee = canonical_pointee;
}
} let inner =
Item::from_ty_or_ref(pointee, location, None, ctx);
TypeKind::Pointer(inner)
}
CXType_BlockPointer => { let pointee = ty.pointee_type().expect("Not valid Type?"); let inner =
Item::from_ty_or_ref(pointee, location, None, ctx);
TypeKind::BlockPointer(inner)
} // XXX: RValueReference is most likely wrong, but I don't think we // can even add bindings for that, so huh.
CXType_RValueReference | CXType_LValueReference => { let inner = Item::from_ty_or_ref(
ty.pointee_type().unwrap(),
location,
None,
ctx,
);
TypeKind::Reference(inner)
} // XXX DependentSizedArray is wrong
CXType_VariableArray | CXType_DependentSizedArray => { let inner = Item::from_ty(
ty.elem_type().as_ref().unwrap(),
location,
None,
ctx,
)
.expect("Not able to resolve array element?");
TypeKind::Pointer(inner)
}
CXType_IncompleteArray => { let inner = Item::from_ty(
ty.elem_type().as_ref().unwrap(),
location,
None,
ctx,
)
.expect("Not able to resolve array element?");
TypeKind::Array(inner, 0)
}
CXType_FunctionNoProto | CXType_FunctionProto => { let signature = FunctionSig::from_ty(ty, &location, ctx)?;
TypeKind::Function(signature)
}
CXType_Typedef => { let inner = cursor.typedef_type().expect("Not valid Type?"); let inner_id =
Item::from_ty_or_ref(inner, location, None, ctx); if inner_id == potential_id {
warn!( "Generating oqaque type instead of self-referential \
typedef"); // This can happen if we bail out of recursive situations // within the clang parsing.
TypeKind::Opaque
} else { // Check if this type definition is an alias to a pointer of a `struct` / // `union` / `enum` with the same name and add the `_ptr` suffix to it to // avoid name collisions. iflet Some(refmut name) = name { if inner.kind() == CXType_Pointer &&
!ctx.options().c_naming
{ let pointee = inner.pointee_type().unwrap(); if pointee.kind() == CXType_Elaborated &&
pointee.declaration().spelling() == *name
{
*name += "_ptr";
}
}
}
TypeKind::Alias(inner_id)
}
}
CXType_Enum => { let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?");
if !is_anonymous { let pretty_name = ty.spelling(); if clang::is_valid_identifier(&pretty_name) {
name = Some(pretty_name);
}
}
TypeKind::Enum(enum_)
}
CXType_Record => { let complex = CompInfo::from_ty(
potential_id,
ty,
Some(location),
ctx,
)
.expect("Not a complex type?");
if !is_anonymous { // The pretty-printed name may contain typedefed name, // but may also be "struct (anonymous at .h:1)" let pretty_name = ty.spelling(); if clang::is_valid_identifier(&pretty_name) {
name = Some(pretty_name);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.