| //! Everything related to types in our intermediate representation. |
| |
| use super::comp::CompInfo; |
| use super::context::{BindgenContext, ItemId, TypeId}; |
| use super::dot::DotAttributes; |
| use super::enum_ty::Enum; |
| use super::function::FunctionSig; |
| use super::item::{IsOpaque, Item}; |
| use super::layout::{Layout, Opaque}; |
| use super::objc::ObjCInterface; |
| use super::template::{ |
| AsTemplateParam, TemplateInstantiation, TemplateParameters, |
| }; |
| use super::traversal::{EdgeKind, Trace, Tracer}; |
| use crate::clang::{self, Cursor}; |
| use crate::parse::{ParseError, ParseResult}; |
| use std::borrow::Cow; |
| use std::io; |
| |
| pub use super::int::IntKind; |
| |
| /// 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) struct Type { |
| /// 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; |
| |
| impl Type { |
| /// 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(&mut self) -> Option<&mut CompInfo> { |
| match self.kind { |
| TypeKind::Comp(ref mut 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(&mut self) -> &mut TypeKind { |
| &mut self.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 { |
| match self.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> { |
| match self.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> { |
| match self.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(|| { |
| match self.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 { |
| match self.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) |
| } |
| |
| /// Get this type's santizied name. |
| pub(crate) fn sanitized_name<'a>( |
| &'a self, |
| ctx: &BindgenContext, |
| ) -> Option<Cow<'a, str>> { |
| let name_info = match *self.kind() { |
| TypeKind::Pointer(inner) => Some((inner, Cow::Borrowed("ptr"))), |
| TypeKind::Reference(inner) => Some((inner, Cow::Borrowed("ref"))), |
| TypeKind::Array(inner, length) => { |
| Some((inner, format!("array{}", length).into())) |
| } |
| _ => None, |
| }; |
| if let Some((inner, prefix)) = name_info { |
| ctx.resolve_item(inner) |
| .expect_type() |
| .sanitized_name(ctx) |
| .map(|name| format!("{}_{}", prefix, name).into()) |
| } else { |
| self.name().map(Self::sanitize_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> { |
| match self.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), |
| |
| TypeKind::ResolvedTypeRef(inner) | |
| TypeKind::Alias(inner) | |
| TypeKind::TemplateAlias(inner, _) => { |
| ctx.resolve_type(inner).safe_canonical_type(ctx) |
| } |
| TypeKind::TemplateInstantiation(ref inst) => ctx |
| .resolve_type(inst.template_definition()) |
| .safe_canonical_type(ctx), |
| |
| TypeKind::UnresolvedTypeRef(..) => None, |
| } |
| } |
| |
| /// 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(..) |
| ) |
| } |
| } |
| |
| impl IsOpaque for Type { |
| type Extra = Item; |
| |
| fn is_opaque(&self, ctx: &BindgenContext, item: &Item) -> bool { |
| match self.kind { |
| TypeKind::Opaque => true, |
| TypeKind::TemplateInstantiation(ref inst) => { |
| inst.is_opaque(ctx, item) |
| } |
| TypeKind::Comp(ref comp) => comp.is_opaque(ctx, &self.layout), |
| TypeKind::ResolvedTypeRef(to) => to.is_opaque(ctx, &()), |
| _ => false, |
| } |
| } |
| } |
| |
| impl AsTemplateParam for Type { |
| type Extra = Item; |
| |
| fn as_template_param( |
| &self, |
| ctx: &BindgenContext, |
| item: &Item, |
| ) -> Option<TypeId> { |
| self.kind.as_template_param(ctx, item) |
| } |
| } |
| |
| impl AsTemplateParam for TypeKind { |
| type Extra = Item; |
| |
| fn as_template_param( |
| &self, |
| ctx: &BindgenContext, |
| item: &Item, |
| ) -> Option<TypeId> { |
| match *self { |
| TypeKind::TypeParam => Some(item.id().expect_type_id(ctx)), |
| TypeKind::ResolvedTypeRef(id) => id.as_template_param(ctx, &()), |
| _ => None, |
| } |
| } |
| } |
| |
| impl DotAttributes for Type { |
| fn dot_attributes<W>( |
| &self, |
| ctx: &BindgenContext, |
| out: &mut W, |
| ) -> io::Result<()> |
| where |
| W: io::Write, |
| { |
| if let Some(ref layout) = self.layout { |
| writeln!( |
| out, |
| "<tr><td>size</td><td>{}</td></tr> |
| <tr><td>align</td><td>{}</td></tr>", |
| layout.size, layout.align |
| )?; |
| if layout.packed { |
| writeln!(out, "<tr><td>packed</td><td>true</td></tr>")?; |
| } |
| } |
| |
| if self.is_const { |
| writeln!(out, "<tr><td>const</td><td>true</td></tr>")?; |
| } |
| |
| self.kind.dot_attributes(ctx, out) |
| } |
| } |
| |
| impl DotAttributes for TypeKind { |
| fn dot_attributes<W>( |
| &self, |
| ctx: &BindgenContext, |
| out: &mut W, |
| ) -> io::Result<()> |
| where |
| W: io::Write, |
| { |
| writeln!( |
| out, |
| "<tr><td>type kind</td><td>{}</td></tr>", |
| self.kind_name() |
| )?; |
| |
| if let TypeKind::Comp(ref comp) = *self { |
| comp.dot_attributes(ctx, out)?; |
| } |
| |
| Ok(()) |
| } |
| } |
| |
| impl TypeKind { |
| fn kind_name(&self) -> &'static str { |
| match *self { |
| TypeKind::Void => "Void", |
| TypeKind::NullPtr => "NullPtr", |
| TypeKind::Comp(..) => "Comp", |
| TypeKind::Opaque => "Opaque", |
| TypeKind::Int(..) => "Int", |
| TypeKind::Float(..) => "Float", |
| TypeKind::Complex(..) => "Complex", |
| TypeKind::Alias(..) => "Alias", |
| TypeKind::TemplateAlias(..) => "TemplateAlias", |
| TypeKind::Array(..) => "Array", |
| TypeKind::Vector(..) => "Vector", |
| TypeKind::Function(..) => "Function", |
| TypeKind::Enum(..) => "Enum", |
| TypeKind::Pointer(..) => "Pointer", |
| TypeKind::BlockPointer(..) => "BlockPointer", |
| TypeKind::Reference(..) => "Reference", |
| TypeKind::TemplateInstantiation(..) => "TemplateInstantiation", |
| TypeKind::UnresolvedTypeRef(..) => "UnresolvedTypeRef", |
| TypeKind::ResolvedTypeRef(..) => "ResolvedTypeRef", |
| TypeKind::TypeParam => "TypeParam", |
| TypeKind::ObjCInterface(..) => "ObjCInterface", |
| TypeKind::ObjCId => "ObjCId", |
| TypeKind::ObjCSel => "ObjCSel", |
| } |
| } |
| } |
| |
| #[test] |
| fn is_invalid_type_param_valid() { |
| let ty = Type::new(Some("foo".into()), None, TypeKind::TypeParam, false); |
| assert!(!ty.is_invalid_type_param()) |
| } |
| |
| #[test] |
| fn is_invalid_type_param_valid_underscore_and_numbers() { |
| let ty = Type::new( |
| Some("_foo123456789_".into()), |
| None, |
| TypeKind::TypeParam, |
| false, |
| ); |
| assert!(!ty.is_invalid_type_param()) |
| } |
| |
| #[test] |
| fn is_invalid_type_param_valid_unnamed_kind() { |
| let ty = Type::new(Some("foo".into()), None, TypeKind::Void, false); |
| assert!(!ty.is_invalid_type_param()) |
| } |
| |
| #[test] |
| fn is_invalid_type_param_invalid_start() { |
| let ty = Type::new(Some("1foo".into()), None, TypeKind::TypeParam, false); |
| assert!(ty.is_invalid_type_param()) |
| } |
| |
| #[test] |
| fn is_invalid_type_param_invalid_remaing() { |
| let ty = Type::new(Some("foo-".into()), None, TypeKind::TypeParam, false); |
| assert!(ty.is_invalid_type_param()) |
| } |
| |
| #[test] |
| #[should_panic] |
| fn is_invalid_type_param_unnamed() { |
| let ty = Type::new(None, None, TypeKind::TypeParam, false); |
| assert!(ty.is_invalid_type_param()) |
| } |
| |
| #[test] |
| fn is_invalid_type_param_empty_name() { |
| let ty = Type::new(Some("".into()), None, TypeKind::TypeParam, false); |
| assert!(ty.is_invalid_type_param()) |
| } |
| |
| impl TemplateParameters for Type { |
| fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> { |
| self.kind.self_template_params(ctx) |
| } |
| } |
| |
| impl TemplateParameters for TypeKind { |
| fn self_template_params(&self, ctx: &BindgenContext) -> Vec<TypeId> { |
| match *self { |
| TypeKind::ResolvedTypeRef(id) => { |
| ctx.resolve_type(id).self_template_params(ctx) |
| } |
| TypeKind::Comp(ref comp) => comp.self_template_params(ctx), |
| TypeKind::TemplateAlias(_, ref args) => args.clone(), |
| |
| TypeKind::Opaque | |
| TypeKind::TemplateInstantiation(..) | |
| TypeKind::Void | |
| TypeKind::NullPtr | |
| TypeKind::Int(_) | |
| TypeKind::Float(_) | |
| TypeKind::Complex(_) | |
| TypeKind::Array(..) | |
| TypeKind::Vector(..) | |
| TypeKind::Function(_) | |
| TypeKind::Enum(_) | |
| TypeKind::Pointer(_) | |
| TypeKind::BlockPointer(_) | |
| TypeKind::Reference(_) | |
| TypeKind::UnresolvedTypeRef(..) | |
| TypeKind::TypeParam | |
| TypeKind::Alias(_) | |
| TypeKind::ObjCId | |
| TypeKind::ObjCSel | |
| TypeKind::ObjCInterface(_) => vec![], |
| } |
| } |
| } |
| |
| /// 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, |
| } |
| |
| impl Type { |
| /// 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), |
| ); |
| if let 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(); |
| let mut name = if is_anonymous { |
| None |
| } else { |
| Some(cursor.spelling()).filter(|n| !n.is_empty()) |
| }; |
| |
| debug!( |
| "from_clang_ty: {:?}, ty: {:?}, loc: {:?}", |
| potential_id, ty, location |
| ); |
| debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types()); |
| |
| let canonical_ty = ty.canonical_type(); |
| |
| // Parse objc protocols as if they were interfaces |
| let mut 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); |
| return Self::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(..) |
| } else if 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. |
| let mut inner = Err(ParseError::Continue); |
| let mut args = vec![]; |
| |
| location.visit(|cur| { |
| match cur.kind() { |
| CXCursor_TypeAliasDecl => { |
| let current = cur.cur_type(); |
| |
| debug_assert_eq!( |
| current.kind(), |
| CXType_Typedef |
| ); |
| |
| name = Some(location.spelling()); |
| |
| let inner_ty = cur |
| .typedef_type() |
| .expect("Not valid Type?"); |
| inner = Ok(Item::from_ty_or_ref( |
| inner_ty, |
| cur, |
| Some(potential_id), |
| ctx, |
| )); |
| } |
| CXCursor_TemplateTypeParameter => { |
| let param = Item::type_param( |
| None, cur, ctx, |
| ) |
| .expect( |
| "Item::type_param shouldn't \ |
| ever fail if we are looking \ |
| at a TemplateTypeParameter", |
| ); |
| args.push(param); |
| } |
| _ => {} |
| } |
| CXChildVisit_Continue |
| }); |
| |
| let inner_type = match inner { |
| Ok(inner) => inner, |
| Err(..) => { |
| warn!( |
| "Failed to parse template alias \ |
| {:?}", |
| location |
| ); |
| return Err(ParseError::Continue); |
| } |
| }; |
| |
| TypeKind::TemplateAlias(inner_type, args) |
| } |
| CXCursor_TemplateRef => { |
| let referenced = location.referenced().unwrap(); |
| let referenced_ty = referenced.cur_type(); |
| |
| debug!( |
| "TemplateRef: location = {:?}; referenced = \ |
| {:?}; referenced_ty = {:?}", |
| location, |
| referenced, |
| referenced_ty |
| ); |
| |
| return Self::from_clang_ty( |
| potential_id, |
| &referenced_ty, |
| referenced, |
| parent_id, |
| ctx, |
| ); |
| } |
| CXCursor_TypeRef => { |
| let referenced = location.referenced().unwrap(); |
| let referenced_ty = referenced.cur_type(); |
| let declaration = referenced_ty.declaration(); |
| |
| debug!( |
| "TypeRef: location = {:?}; referenced = \ |
| {:?}; referenced_ty = {:?}", |
| location, referenced, referenced_ty |
| ); |
| |
| let id = Item::from_ty_or_ref_with_id( |
| potential_id, |
| referenced_ty, |
| declaration, |
| parent_id, |
| ctx, |
| ); |
| return Ok(ParseResult::AlreadyResolved( |
| id.into(), |
| )); |
| } |
| CXCursor_NamespaceRef => { |
| return Err(ParseError::Continue); |
| } |
| _ => { |
| if ty.kind() == CXType_Unexposed { |
| warn!( |
| "Unexposed type {:?}, recursing inside, \ |
| loc: {:?}", |
| ty, |
| location |
| ); |
| return Err(ParseError::Recurse); |
| } |
| |
| warn!("invalid type {:?}", ty); |
| return Err(ParseError::Continue); |
| } |
| } |
| } |
| } |
| CXType_Auto => { |
| if canonical_ty == *ty { |
| debug!("Couldn't find deduced type: {:?}", ty); |
| return Err(ParseError::Continue); |
| } |
| |
| return Self::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 => { |
| let mut 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. |
| if let Some(ref mut 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); |
| } |
| } |
| |
| TypeKind::Comp(complex) |
| } |
| CXType_Vector => { |
| let inner = Item::from_ty( |
| ty.elem_type().as_ref().unwrap(), |
| location, |
| None, |
| ctx, |
| )?; |
| TypeKind::Vector(inner, ty.num_elements().unwrap()) |
| } |
| CXType_ConstantArray => { |
| let inner = Item::from_ty( |
| ty.elem_type().as_ref().unwrap(), |
| location, |
| None, |
| ctx, |
| ) |
| .expect("Not able to resolve array element?"); |
| TypeKind::Array(inner, ty.num_elements().unwrap()) |
| } |
| CXType_Elaborated => { |
| return Self::from_clang_ty( |
| potential_id, |
| &ty.named(), |
| location, |
| parent_id, |
| ctx, |
| ); |
| } |
| CXType_ObjCId => TypeKind::ObjCId, |
| CXType_ObjCSel => TypeKind::ObjCSel, |
| CXType_ObjCClass | CXType_ObjCInterface => { |
| let interface = ObjCInterface::from_ty(&location, ctx) |
| .expect("Not a valid objc interface?"); |
| if !is_anonymous { |
| name = Some(interface.rust_name()); |
| } |
| TypeKind::ObjCInterface(interface) |
| } |
| CXType_Dependent => { |
| return Err(ParseError::Continue); |
| } |
| _ => { |
| warn!( |
| "unsupported type: kind = {:?}; ty = {:?}; at {:?}", |
| ty.kind(), |
| ty, |
| location |
| ); |
| return Err(ParseError::Continue); |
| } |
| } |
| }; |
| |
| name = name.filter(|n| !n.is_empty()); |
| |
| let is_const = ty.is_const() || |
| (ty.kind() == CXType_ConstantArray && |
| ty.elem_type() |
| .map_or(false, |element| element.is_const())); |
| |
| let ty = Type::new(name, layout, kind, is_const); |
| // TODO: maybe declaration.canonical()? |
| Ok(ParseResult::New(ty, Some(cursor.canonical()))) |
| } |
| } |
| |
| impl Trace for Type { |
| type Extra = Item; |
| |
| fn trace<T>(&self, context: &BindgenContext, tracer: &mut T, item: &Item) |
| where |
| T: Tracer, |
| { |
| if self |
| .name() |
| .map_or(false, |name| context.is_stdint_type(name)) |
| { |
| // These types are special-cased in codegen and don't need to be traversed. |
| return; |
| } |
| match *self.kind() { |
| TypeKind::Pointer(inner) | |
| TypeKind::Reference(inner) | |
| TypeKind::Array(inner, _) | |
| TypeKind::Vector(inner, _) | |
| TypeKind::BlockPointer(inner) | |
| TypeKind::Alias(inner) | |
| TypeKind::ResolvedTypeRef(inner) => { |
| tracer.visit_kind(inner.into(), EdgeKind::TypeReference); |
| } |
| TypeKind::TemplateAlias(inner, ref template_params) => { |
| tracer.visit_kind(inner.into(), EdgeKind::TypeReference); |
| for param in template_params { |
| tracer.visit_kind( |
| param.into(), |
| EdgeKind::TemplateParameterDefinition, |
| ); |
| } |
| } |
| TypeKind::TemplateInstantiation(ref inst) => { |
| inst.trace(context, tracer, &()); |
| } |
| TypeKind::Comp(ref ci) => ci.trace(context, tracer, item), |
| TypeKind::Function(ref sig) => sig.trace(context, tracer, &()), |
| TypeKind::Enum(ref en) => { |
| if let Some(repr) = en.repr() { |
| tracer.visit(repr.into()); |
| } |
| } |
| TypeKind::UnresolvedTypeRef(_, _, Some(id)) => { |
| tracer.visit(id); |
| } |
| |
| TypeKind::ObjCInterface(ref interface) => { |
| interface.trace(context, tracer, &()); |
| } |
| |
| // None of these variants have edges to other items and types. |
| TypeKind::Opaque | |
| TypeKind::UnresolvedTypeRef(_, _, None) | |
| TypeKind::TypeParam | |
| TypeKind::Void | |
| TypeKind::NullPtr | |
| TypeKind::Int(_) | |
| TypeKind::Float(_) | |
| TypeKind::Complex(_) | |
| TypeKind::ObjCId | |
| TypeKind::ObjCSel => {} |
| } |
| } |
| } |