//! 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::int::IntKind; 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; /// 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 struct Type { /// The name of the type, or None if it was an unnamed struct or union. name: Option, /// The layout of the type, if known. layout: Option, /// 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 const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32; impl Type { /// Get the underlying `CompInfo` for this type, or `None` if this is some /// other kind of type. pub fn as_comp(&self) -> Option<&CompInfo> { match self.kind { TypeKind::Comp(ref ci) => Some(ci), _ => None, } } /// Get the underlying `CompInfo` for this type as a mutable reference, or /// `None` if this is some other kind of type. pub 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 fn new( name: Option, layout: Option, kind: TypeKind, is_const: bool, ) -> Self { Type { name, layout, kind, is_const, } } /// Which kind of type is this? pub fn kind(&self) -> &TypeKind { &self.kind } /// Get a mutable reference to this type's kind. pub fn kind_mut(&mut self) -> &mut TypeKind { &mut self.kind } /// Get this type's name. pub fn name(&self) -> Option<&str> { self.name.as_deref() } /// Whether this is a block pointer type. pub fn is_block_pointer(&self) -> bool { matches!(self.kind, TypeKind::BlockPointer(..)) } /// Is this an integer type, including `bool` or `char`? pub fn is_int(&self) -> bool { matches!(self.kind, TypeKind::Int(_)) } /// Is this a compound type? pub fn is_comp(&self) -> bool { matches!(self.kind, TypeKind::Comp(..)) } /// Is this a union? pub fn is_union(&self) -> bool { match self.kind { TypeKind::Comp(ref comp) => comp.is_union(), _ => false, } } /// Is this type of kind `TypeKind::TypeParam`? pub fn is_type_param(&self) -> bool { matches!(self.kind, TypeKind::TypeParam) } /// Is this a template instantiation type? pub fn is_template_instantiation(&self) -> bool { matches!(self.kind, TypeKind::TemplateInstantiation(..)) } /// Is this a template alias type? pub fn is_template_alias(&self) -> bool { matches!(self.kind, TypeKind::TemplateAlias(..)) } /// Is this a function type? pub fn is_function(&self) -> bool { matches!(self.kind, TypeKind::Function(..)) } /// Is this an enum type? pub fn is_enum(&self) -> bool { matches!(self.kind, TypeKind::Enum(..)) } /// Is this either a builtin or named type? pub 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 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 fn is_float(&self) -> bool { matches!(self.kind, TypeKind::Float(..)) } /// Is this a boolean type? pub fn is_bool(&self) -> bool { matches!(self.kind, TypeKind::Int(IntKind::Bool)) } /// Is this an integer type? pub 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 fn as_integer(&self) -> Option { match self.kind { TypeKind::Int(int_kind) => Some(int_kind), _ => None, } } /// Is this a `const` qualified type? pub fn is_const(&self) -> bool { self.is_const } /// Is this a reference to another type? pub fn is_type_ref(&self) -> bool { matches!( self.kind, TypeKind::ResolvedTypeRef(_) | TypeKind::UnresolvedTypeRef(_, _, _) ) } /// Is this an unresolved reference? pub fn is_unresolved_ref(&self) -> bool { matches!(self.kind, TypeKind::UnresolvedTypeRef(_, _, _)) } /// Is this a incomplete array type? pub fn is_incomplete_array(&self, ctx: &BindgenContext) -> Option { 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 fn layout(&self, ctx: &BindgenContext) -> Option { self.layout.or_else(|| { match self.kind { TypeKind::Comp(ref ci) => ci.layout(ctx), TypeKind::Array(inner, length) if length == 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 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 { 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 fn sanitized_name<'a>( &'a self, ctx: &BindgenContext, ) -> Option> { 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 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 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 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 { self.kind.as_template_param(ctx, item) } } impl AsTemplateParam for TypeKind { type Extra = Item; fn as_template_param( &self, ctx: &BindgenContext, item: &Item, ) -> Option { 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( &self, ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { if let Some(ref layout) = self.layout { writeln!( out, "size{} align{}", layout.size, layout.align )?; if layout.packed { writeln!(out, "packedtrue")?; } } if self.is_const { writeln!(out, "consttrue")?; } self.kind.dot_attributes(ctx, out) } } impl DotAttributes for TypeKind { fn dot_attributes( &self, ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write, { writeln!( out, "type kind{}", 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 { self.kind.self_template_params(ctx) } } impl TemplateParameters for TypeKind { fn self_template_params(&self, ctx: &BindgenContext) -> Vec { 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 enum FloatKind { /// 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 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), /// 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, ), /// 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 fn from_clang_ty( potential_id: ItemId, ty: &clang::Type, location: Cursor, parent_id: Option, ctx: &mut BindgenContext, ) -> Result, 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 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(&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 => {} } } }