use super::context::{BindgenContext, ItemId};
use super::derive::{CanDeriveCopy, CanDeriveDebug};
use super::item::{Item, ItemAncestors};
use super::layout::Layout;
use super::traversal::{EdgeKind, Trace, Tracer};
use clang;
use parse::ClangItemParser;
pub trait TemplateParameters {
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()
})
}
}
pub trait AsNamed {
type Extra;
fn as_named(&self,
ctx: &BindgenContext,
extra: &Self::Extra)
-> Option<ItemId>;
fn is_named(&self, ctx: &BindgenContext, extra: &Self::Extra) -> bool {
self.as_named(ctx, extra).is_some()
}
}
#[derive(Clone, Debug)]
pub struct TemplateInstantiation {
definition: ItemId,
args: Vec<ItemId>,
}
impl TemplateInstantiation {
pub fn new<I>(template_definition: ItemId,
template_args: I)
-> TemplateInstantiation
where I: IntoIterator<Item = ItemId>,
{
TemplateInstantiation {
definition: template_definition,
args: template_args.into_iter().collect(),
}
}
pub fn template_definition(&self) -> ItemId {
self.definition
}
pub fn template_arguments(&self) -> &[ItemId] {
&self.args[..]
}
pub fn from_ty(ty: &clang::Type,
ctx: &mut BindgenContext)
-> Option<TemplateInstantiation> {
use clang_sys::*;
let template_args = ty.template_args()
.map_or(vec![], |args| {
match ty.canonical_type().template_args() {
Some(canonical_args) => {
let arg_count = args.len();
args.chain(canonical_args.skip(arg_count))
.filter(|t| t.kind() != CXType_Invalid)
.map(|t| {
Item::from_ty_or_ref(t, t.declaration(), None, ctx)
}).collect()
}
None => {
args.filter(|t| t.kind() != CXType_Invalid)
.map(|t| {
Item::from_ty_or_ref(t, t.declaration(), None, ctx)
}).collect()
}
}
});
let declaration = ty.declaration();
let definition = if declaration.kind() == CXCursor_TypeAliasTemplateDecl {
Some(declaration)
} else {
declaration
.specialized()
.or_else(|| {
let mut template_ref = None;
ty.declaration().visit(|child| {
if child.kind() == CXCursor_TemplateRef {
template_ref = Some(child);
return CXVisit_Break;
}
CXChildVisit_Recurse
});
template_ref.and_then(|cur| cur.referenced())
})
};
let definition = match definition {
Some(def) => def,
None => {
if !ty.declaration().is_builtin() {
warn!("Could not find template definition for template \
instantiation");
}
return None
}
};
let template_definition =
Item::from_ty_or_ref(definition.cur_type(), definition, None, ctx);
Some(TemplateInstantiation::new(template_definition, template_args))
}
pub fn has_vtable(&self, ctx: &BindgenContext) -> bool {
ctx.resolve_type(self.definition).has_vtable(ctx)
}
pub fn has_destructor(&self, ctx: &BindgenContext) -> bool {
ctx.resolve_type(self.definition).has_destructor(ctx) ||
self.args.iter().any(|arg| ctx.resolve_type(*arg).has_destructor(ctx))
}
}
impl<'a> CanDeriveCopy<'a> for TemplateInstantiation {
type Extra = ();
fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool {
self.definition.can_derive_copy(ctx, ()) &&
self.args.iter().all(|arg| arg.can_derive_copy(ctx, ()))
}
fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool {
self.definition.can_derive_copy_in_array(ctx, ()) &&
self.args.iter().all(|arg| arg.can_derive_copy_in_array(ctx, ()))
}
}
impl CanDeriveDebug for TemplateInstantiation {
type Extra = Option<Layout>;
fn can_derive_debug(&self,
ctx: &BindgenContext,
layout: Option<Layout>)
-> bool {
self.args.iter().all(|arg| arg.can_derive_debug(ctx, ())) &&
ctx.resolve_type(self.definition)
.as_comp()
.and_then(|c| {
if c.has_non_type_template_params() {
let opaque = layout.unwrap_or(Layout::zero()).opaque();
Some(opaque.can_derive_debug(ctx, ()))
} else {
None
}
})
.unwrap_or_else(|| self.definition.can_derive_debug(ctx, ()))
}
}
impl Trace for TemplateInstantiation {
type Extra = ();
fn trace<T>(&self, _ctx: &BindgenContext, tracer: &mut T, _: &())
where T: Tracer,
{
tracer.visit_kind(self.definition, EdgeKind::TemplateDeclaration);
for &item in self.template_arguments() {
tracer.visit_kind(item, EdgeKind::TemplateArgument);
}
}
}