use super::comp::CompInfo;
use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault};
use super::dot::DotAttributes;
use super::enum_ty::Enum;
use super::function::FunctionSig;
use super::int::IntKind;
use super::item::{Item, ItemAncestors};
use super::layout::{Layout, Opaque};
use super::objc::ObjCInterface;
use super::template::{AsNamed, TemplateInstantiation};
use super::traversal::{EdgeKind, Trace, Tracer};
use clang::{self, Cursor};
use parse::{ClangItemParser, ParseError, ParseResult};
use std::cell::Cell;
use std::io;
use std::mem;
pub trait TemplateDeclaration {
fn self_template_params(&self,
ctx: &BindgenContext)
-> Option<Vec<ItemId>>;
fn num_self_template_params(&self, ctx: &BindgenContext) -> Option<usize> {
self.self_template_params(ctx).map(|params| params.len())
}
fn all_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
where Self: ItemAncestors,
{
let each_self_params: Vec<Vec<_>> = self.ancestors(ctx)
.filter_map(|id| id.self_template_params(ctx))
.collect();
if each_self_params.is_empty() {
None
} else {
Some(each_self_params.into_iter()
.rev()
.flat_map(|params| params)
.collect())
}
}
fn used_template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>>
where Self: AsRef<ItemId>,
{
assert!(ctx.in_codegen_phase(),
"template parameter usage is not computed until codegen");
let id = *self.as_ref();
ctx.resolve_item(id)
.all_template_params(ctx)
.map(|all_params| {
all_params.into_iter()
.filter(|p| ctx.uses_template_parameter(id, *p))
.collect()
})
}
}
#[derive(Debug)]
pub struct Type {
name: Option<String>,
layout: Option<Layout>,
kind: TypeKind,
is_const: bool,
detect_has_vtable_cycle: Cell<bool>,
}
pub const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32;
impl Type {
pub fn as_comp(&self) -> Option<&CompInfo> {
match self.kind {
TypeKind::Comp(ref ci) => Some(ci),
_ => None,
}
}
pub fn new(name: Option<String>,
layout: Option<Layout>,
kind: TypeKind,
is_const: bool)
-> Self {
Type {
name: name,
layout: layout,
kind: kind,
is_const: is_const,
detect_has_vtable_cycle: Cell::new(false),
}
}
pub fn kind(&self) -> &TypeKind {
&self.kind
}
pub fn kind_mut(&mut self) -> &mut TypeKind {
&mut self.kind
}
pub fn name(&self) -> Option<&str> {
self.name.as_ref().map(|name| &**name)
}
pub fn is_comp(&self) -> bool {
match self.kind {
TypeKind::Comp(..) => true,
_ => false,
}
}
pub fn is_opaque(&self) -> bool {
match self.kind {
TypeKind::Opaque => true,
_ => false,
}
}
pub fn is_named(&self) -> bool {
match self.kind {
TypeKind::Named => true,
_ => false,
}
}
pub fn is_template_alias(&self) -> bool {
match self.kind {
TypeKind::TemplateAlias(..) => true,
_ => false,
}
}
pub fn is_function(&self) -> bool {
match self.kind {
TypeKind::Function(..) => true,
_ => false,
}
}
pub fn is_enum(&self) -> bool {
match self.kind {
TypeKind::Enum(..) => true,
_ => false,
}
}
pub fn is_builtin_or_named(&self) -> bool {
match self.kind {
TypeKind::Void |
TypeKind::NullPtr |
TypeKind::Function(..) |
TypeKind::Array(..) |
TypeKind::Reference(..) |
TypeKind::Pointer(..) |
TypeKind::BlockPointer |
TypeKind::Int(..) |
TypeKind::Float(..) |
TypeKind::Named => true,
_ => false,
}
}
pub fn named(name: String) -> Self {
let name = if name.is_empty() {
None
} else {
Some(name)
};
Self::new(name, None, TypeKind::Named, false)
}
pub fn is_float(&self) -> bool {
match self.kind {
TypeKind::Float(..) => true,
_ => false,
}
}
pub fn is_bool(&self) -> bool {
match self.kind {
TypeKind::Int(IntKind::Bool) => true,
_ => false,
}
}
pub fn is_integer(&self) -> bool {
match self.kind {
TypeKind::Int(..) => true,
_ => false,
}
}
pub fn is_const(&self) -> bool {
self.is_const
}
pub fn is_type_ref(&self) -> bool {
match self.kind {
TypeKind::ResolvedTypeRef(_) |
TypeKind::UnresolvedTypeRef(_, _, _) => true,
_ => false,
}
}
pub fn is_incomplete_array(&self, ctx: &BindgenContext) -> Option<ItemId> {
match self.kind {
TypeKind::Array(item, len) => {
if len == 0 { Some(item) } else { None }
}
TypeKind::ResolvedTypeRef(inner) => {
ctx.resolve_type(inner).is_incomplete_array(ctx)
}
_ => None,
}
}
pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> {
use std::mem;
self.layout.or_else(|| {
match self.kind {
TypeKind::Comp(ref ci) => ci.layout(ctx),
TypeKind::Pointer(..) |
TypeKind::BlockPointer => {
Some(Layout::new(mem::size_of::<*mut ()>(),
mem::align_of::<*mut ()>()))
}
TypeKind::ResolvedTypeRef(inner) => {
ctx.resolve_type(inner).layout(ctx)
}
_ => None,
}
})
}
pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
if self.detect_has_vtable_cycle.get() {
return false;
}
self.detect_has_vtable_cycle.set(true);
let result = match self.kind {
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(t) |
TypeKind::ResolvedTypeRef(t) => ctx.resolve_type(t).has_vtable(ctx),
TypeKind::Comp(ref info) => info.has_vtable(ctx),
TypeKind::TemplateInstantiation(ref inst) => inst.has_vtable(ctx),
_ => false,
};
self.detect_has_vtable_cycle.set(false);
result
}
pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
match self.kind {
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(t) |
TypeKind::ResolvedTypeRef(t) => {
ctx.resolve_type(t).has_destructor(ctx)
}
TypeKind::TemplateInstantiation(ref inst) => {
inst.has_destructor(ctx)
}
TypeKind::Comp(ref info) => info.has_destructor(ctx),
_ => false,
}
}
pub fn is_invalid_named_type(&self) -> bool {
match self.kind {
TypeKind::Named => {
let name = self.name().expect("Unnamed named type?");
!Self::is_valid_identifier(&name)
}
_ => false,
}
}
pub fn is_valid_identifier(name: &str) -> bool {
clang::is_valid_identifier(name)
}
pub fn canonical_type<'tr>(&'tr self,
ctx: &'tr BindgenContext)
-> &'tr Type {
self.safe_canonical_type(ctx)
.expect("Should have been resolved after parsing!")
}
pub fn safe_canonical_type<'tr>(&'tr self,
ctx: &'tr BindgenContext)
-> Option<&'tr Type> {
match self.kind {
TypeKind::Named |
TypeKind::Array(..) |
TypeKind::Comp(..) |
TypeKind::Opaque |
TypeKind::Int(..) |
TypeKind::Float(..) |
TypeKind::Complex(..) |
TypeKind::Function(..) |
TypeKind::Enum(..) |
TypeKind::Reference(..) |
TypeKind::Void |
TypeKind::NullPtr |
TypeKind::BlockPointer |
TypeKind::Pointer(..) |
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,
}
}
pub fn should_be_traced_unconditionally(&self) -> bool {
match self.kind {
TypeKind::Function(..) |
TypeKind::Pointer(..) |
TypeKind::Array(..) |
TypeKind::Reference(..) |
TypeKind::TemplateInstantiation(..) |
TypeKind::ResolvedTypeRef(..) => true,
_ => false,
}
}
}
impl AsNamed for Type {
type Extra = Item;
fn as_named(&self, ctx: &BindgenContext, item: &Item) -> Option<ItemId> {
self.kind.as_named(ctx, item)
}
}
impl AsNamed for TypeKind {
type Extra = Item;
fn as_named(&self, ctx: &BindgenContext, item: &Item) -> Option<ItemId> {
match *self {
TypeKind::Named => Some(item.id()),
TypeKind::ResolvedTypeRef(id) => id.as_named(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 {
try!(writeln!(out,
"<tr><td>size</td><td>{}</td></tr>
<tr><td>align</td><td>{}</td></tr>",
layout.size,
layout.align));
if layout.packed {
try!(writeln!(out, "<tr><td>packed</td><td>true</td></tr>"));
}
}
if self.is_const {
try!(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,
{
write!(out,
"<tr><td>TypeKind</td><td>{}</td></tr>",
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::Function(..) => "Function",
TypeKind::Enum(..) => "Enum",
TypeKind::Pointer(..) => "Pointer",
TypeKind::BlockPointer => "BlockPointer",
TypeKind::Reference(..) => "Reference",
TypeKind::TemplateInstantiation(..) => "TemplateInstantiation",
TypeKind::ResolvedTypeRef(..) => "ResolvedTypeRef",
TypeKind::Named => "Named",
TypeKind::ObjCId => "ObjCId",
TypeKind::ObjCSel => "ObjCSel",
TypeKind::ObjCInterface(..) => "ObjCInterface",
TypeKind::UnresolvedTypeRef(..) => unreachable!("there shouldn't be any more of these anymore"),
})
}
}
#[test]
fn is_invalid_named_type_valid() {
let ty = Type::new(Some("foo".into()), None, TypeKind::Named, false);
assert!(!ty.is_invalid_named_type())
}
#[test]
fn is_invalid_named_type_valid_underscore_and_numbers() {
let ty =
Type::new(Some("_foo123456789_".into()), None, TypeKind::Named, false);
assert!(!ty.is_invalid_named_type())
}
#[test]
fn is_invalid_named_type_valid_unnamed_kind() {
let ty = Type::new(Some("foo".into()), None, TypeKind::Void, false);
assert!(!ty.is_invalid_named_type())
}
#[test]
fn is_invalid_named_type_invalid_start() {
let ty = Type::new(Some("1foo".into()), None, TypeKind::Named, false);
assert!(ty.is_invalid_named_type())
}
#[test]
fn is_invalid_named_type_invalid_remaing() {
let ty = Type::new(Some("foo-".into()), None, TypeKind::Named, false);
assert!(ty.is_invalid_named_type())
}
#[test]
#[should_panic]
fn is_invalid_named_type_unnamed() {
let ty = Type::new(None, None, TypeKind::Named, false);
assert!(ty.is_invalid_named_type())
}
#[test]
fn is_invalid_named_type_empty_name() {
let ty = Type::new(Some("".into()), None, TypeKind::Named, false);
assert!(ty.is_invalid_named_type())
}
impl TemplateDeclaration for Type {
fn self_template_params(&self,
ctx: &BindgenContext)
-> Option<Vec<ItemId>> {
self.kind.self_template_params(ctx)
}
}
impl TemplateDeclaration for TypeKind {
fn self_template_params(&self,
ctx: &BindgenContext)
-> Option<Vec<ItemId>> {
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) => Some(args.clone()),
TypeKind::Opaque |
TypeKind::TemplateInstantiation(..) |
TypeKind::Void |
TypeKind::NullPtr |
TypeKind::Int(_) |
TypeKind::Float(_) |
TypeKind::Complex(_) |
TypeKind::Array(..) |
TypeKind::Function(_) |
TypeKind::Enum(_) |
TypeKind::Pointer(_) |
TypeKind::BlockPointer |
TypeKind::Reference(_) |
TypeKind::UnresolvedTypeRef(..) |
TypeKind::Named |
TypeKind::Alias(_) |
TypeKind::ObjCId |
TypeKind::ObjCSel |
TypeKind::ObjCInterface(_) => None,
}
}
}
impl CanDeriveDebug for Type {
type Extra = ();
fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool {
match self.kind {
TypeKind::Array(t, len) => {
len <= RUST_DERIVE_IN_ARRAY_LIMIT && t.can_derive_debug(ctx, ())
}
TypeKind::ResolvedTypeRef(t) |
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(t) => t.can_derive_debug(ctx, ()),
TypeKind::Comp(ref info) => {
info.can_derive_debug(ctx, self.layout(ctx))
}
TypeKind::Pointer(inner) => {
let inner = ctx.resolve_type(inner);
if let TypeKind::Function(ref sig) =
*inner.canonical_type(ctx).kind() {
return sig.can_derive_debug(ctx, ());
}
return true;
}
TypeKind::TemplateInstantiation(ref inst) => {
inst.can_derive_debug(ctx, self.layout(ctx))
}
_ => true,
}
}
}
impl CanDeriveDefault for Type {
type Extra = ();
fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool {
match self.kind {
TypeKind::Array(t, len) => {
len <= RUST_DERIVE_IN_ARRAY_LIMIT &&
t.can_derive_default(ctx, ())
}
TypeKind::ResolvedTypeRef(t) |
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(t) => t.can_derive_default(ctx, ()),
TypeKind::Comp(ref info) => {
info.can_derive_default(ctx, self.layout(ctx))
}
TypeKind::Opaque => {
self.layout
.map_or(true, |l| l.opaque().can_derive_default(ctx, ()))
}
TypeKind::Void |
TypeKind::Named |
TypeKind::TemplateInstantiation(..) |
TypeKind::Reference(..) |
TypeKind::NullPtr |
TypeKind::Pointer(..) |
TypeKind::BlockPointer |
TypeKind::ObjCId |
TypeKind::ObjCSel |
TypeKind::ObjCInterface(..) |
TypeKind::Enum(..) => false,
TypeKind::Function(..) |
TypeKind::Int(..) |
TypeKind::Float(..) |
TypeKind::Complex(..) => true,
TypeKind::UnresolvedTypeRef(..) => unreachable!(),
}
}
}
impl<'a> CanDeriveCopy<'a> for Type {
type Extra = &'a Item;
fn can_derive_copy(&self, ctx: &BindgenContext, item: &Item) -> bool {
match self.kind {
TypeKind::Array(t, len) => {
len <= RUST_DERIVE_IN_ARRAY_LIMIT &&
t.can_derive_copy_in_array(ctx, ())
}
TypeKind::ResolvedTypeRef(t) |
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(t) => t.can_derive_copy(ctx, ()),
TypeKind::TemplateInstantiation(ref inst) => {
inst.can_derive_copy(ctx, ())
}
TypeKind::Comp(ref info) => {
info.can_derive_copy(ctx, (item, self.layout(ctx)))
}
TypeKind::Opaque => {
self.layout
.map_or(true, |l| l.opaque().can_derive_copy(ctx, ()))
}
_ => true,
}
}
fn can_derive_copy_in_array(&self,
ctx: &BindgenContext,
item: &Item)
-> bool {
match self.kind {
TypeKind::ResolvedTypeRef(t) |
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(t) |
TypeKind::Array(t, _) => t.can_derive_copy_in_array(ctx, ()),
TypeKind::Named => false,
_ => self.can_derive_copy(ctx, item),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum FloatKind {
Float,
Double,
LongDouble,
Float128,
}
impl FloatKind {
pub fn known_size(&self) -> usize {
match *self {
FloatKind::Float => mem::size_of::<f32>(),
FloatKind::Double | FloatKind::LongDouble => mem::size_of::<f64>(),
FloatKind::Float128 => mem::size_of::<f64>() * 2,
}
}
}
#[derive(Debug)]
pub enum TypeKind {
Void,
NullPtr,
Comp(CompInfo),
Opaque,
Int(IntKind),
Float(FloatKind),
Complex(FloatKind),
Alias(ItemId),
TemplateAlias(ItemId, Vec<ItemId>),
Array(ItemId, usize),
Function(FunctionSig),
Enum(Enum),
Pointer(ItemId),
BlockPointer,
Reference(ItemId),
TemplateInstantiation(TemplateInstantiation),
UnresolvedTypeRef(clang::Type,
clang::Cursor,
Option<ItemId>),
ResolvedTypeRef(ItemId),
Named,
ObjCInterface(ObjCInterface),
ObjCId,
ObjCSel,
}
impl Type {
pub fn is_unsized(&self, ctx: &BindgenContext) -> bool {
debug_assert!(ctx.in_codegen_phase(), "Not yet");
match self.kind {
TypeKind::Void => true,
TypeKind::Comp(ref ci) => ci.is_unsized(ctx),
TypeKind::Opaque => self.layout.map_or(true, |l| l.size == 0),
TypeKind::Array(inner, size) => {
size == 0 || ctx.resolve_type(inner).is_unsized(ctx)
}
TypeKind::ResolvedTypeRef(inner) |
TypeKind::Alias(inner) |
TypeKind::TemplateAlias(inner, _) => {
ctx.resolve_type(inner).is_unsized(ctx)
}
TypeKind::TemplateInstantiation(ref inst) => {
ctx.resolve_type(inst.template_definition()).is_unsized(ctx)
}
TypeKind::Named |
TypeKind::Int(..) |
TypeKind::Float(..) |
TypeKind::Complex(..) |
TypeKind::Function(..) |
TypeKind::Enum(..) |
TypeKind::Reference(..) |
TypeKind::NullPtr |
TypeKind::BlockPointer |
TypeKind::ObjCId |
TypeKind::ObjCSel |
TypeKind::Pointer(..) => false,
TypeKind::ObjCInterface(..) => true,
TypeKind::UnresolvedTypeRef(..) => {
unreachable!("Should have been resolved after parsing!");
}
}
}
pub 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));
}
}
let layout = ty.fallible_layout().ok();
let cursor = ty.declaration();
let mut name = cursor.spelling();
debug!("from_clang_ty: {:?}, ty: {:?}, loc: {:?}",
potential_id,
ty,
location);
debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types());
let canonical_ty = ty.canonical_type();
let mut ty_kind = ty.kind();
match location.kind() {
CXCursor_ObjCProtocolDecl |
CXCursor_ObjCCategoryDecl => ty_kind = CXType_ObjCInterface,
_ => {}
}
if location.kind() == CXCursor_ClassTemplatePartialSpecialization {
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),
None));
}
let kind = if location.kind() == CXCursor_TemplateRef ||
(ty.template_args().is_some() &&
ty_kind != CXType_Typedef) {
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() &&
!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 => {
if ty.ret_type().is_some() {
let signature =
try!(FunctionSig::from_ty(ty, &location, ctx));
TypeKind::Function(signature)
} 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 {
if location.spelling()
.chars()
.all(|c| {
c.is_alphanumeric() || c == '_'
}) {
return Err(ParseError::Recurse);
}
} else {
name = 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);
return Ok(ParseResult::New(opaque, None));
}
}
}
CXCursor_TypeAliasTemplateDecl => {
debug!("TypeAliasTemplateDecl");
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!(current.kind() ==
CXType_Typedef);
name = current.spelling();
let inner_ty = cur.typedef_type()
.expect("Not valid Type?");
inner =
Item::from_ty(&inner_ty,
cur,
Some(potential_id),
ctx);
}
CXCursor_TemplateTypeParameter => {
let param =
Item::named_type(None,
cur,
ctx)
.expect("Item::named_type 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(..) => {
error!("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 item =
Item::from_ty_or_ref_with_id(potential_id,
referenced_ty,
declaration,
parent_id,
ctx);
return Ok(ParseResult::AlreadyResolved(item));
}
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);
}
CXType_ObjCObjectPointer |
CXType_MemberPointer |
CXType_Pointer => {
let mut pointee = ty.pointee_type().unwrap();
let canonical_pointee = canonical_ty.pointee_type()
.unwrap();
if pointee.call_conv() != canonical_pointee.call_conv() {
pointee = canonical_pointee;
}
let inner =
Item::from_ty_or_ref(pointee, location, None, ctx);
TypeKind::Pointer(inner)
}
CXType_BlockPointer => TypeKind::BlockPointer,
CXType_RValueReference |
CXType_LValueReference => {
let inner = Item::from_ty_or_ref(ty.pointee_type()
.unwrap(),
location,
None,
ctx);
TypeKind::Reference(inner)
}
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 =
try!(FunctionSig::from_ty(ty, &location, ctx));
TypeKind::Function(signature)
}
CXType_Typedef => {
let inner = cursor.typedef_type().expect("Not valid Type?");
let inner =
Item::from_ty_or_ref(inner, location, None, ctx);
TypeKind::Alias(inner)
}
CXType_Enum => {
let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?");
if name.is_empty() {
let pretty_name = ty.spelling();
if Self::is_valid_identifier(&pretty_name) {
name = pretty_name;
}
}
TypeKind::Enum(enum_)
}
CXType_Record => {
let complex = CompInfo::from_ty(potential_id,
ty,
Some(location),
ctx)
.expect("Not a complex type?");
if name.is_empty() {
let pretty_name = ty.spelling();
if Self::is_valid_identifier(&pretty_name) {
name = pretty_name;
}
}
TypeKind::Comp(complex)
}
CXType_Vector |
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?");
name = interface.rust_name();
TypeKind::ObjCInterface(interface)
}
_ => {
error!("unsupported type: kind = {:?}; ty = {:?}; at {:?}",
ty.kind(),
ty,
location);
return Err(ParseError::Continue);
}
}
};
let name = if name.is_empty() { None } else { Some(name) };
let is_const = ty.is_const();
let ty = Type::new(name, layout, kind, is_const);
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,
{
match *self.kind() {
TypeKind::Pointer(inner) |
TypeKind::Reference(inner) |
TypeKind::Array(inner, _) |
TypeKind::Alias(inner) |
TypeKind::ResolvedTypeRef(inner) => {
tracer.visit_kind(inner, EdgeKind::TypeReference);
}
TypeKind::TemplateAlias(inner, ref template_params) => {
tracer.visit_kind(inner, EdgeKind::TypeReference);
for &item in template_params {
tracer.visit_kind(item,
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);
}
}
TypeKind::UnresolvedTypeRef(_, _, Some(id)) => {
tracer.visit(id);
}
TypeKind::ObjCInterface(ref interface) => {
interface.trace(context, tracer, &());
}
TypeKind::Opaque |
TypeKind::UnresolvedTypeRef(_, _, None) |
TypeKind::Named |
TypeKind::Void |
TypeKind::NullPtr |
TypeKind::Int(_) |
TypeKind::Float(_) |
TypeKind::Complex(_) |
TypeKind::ObjCId |
TypeKind::ObjCSel |
TypeKind::BlockPointer => {}
}
}
}