Skip to content

Handle templated aliases. #85

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1050,7 +1050,9 @@ pub fn kind_to_str(x: Enum_CXCursorKind) -> &'static str {
//CXCursor_FirstPreprocessing => "FirstPreprocessing",
//CXCursor_LastPreprocessing => "LastPreprocessing",
CXCursor_PackedAttr => "PackedAttr",

CXCursor_ModuleImportDecl => "ModuleImportDecl",
CXCursor_TypeAliasTemplateDecl => "TypeAliasTemplateDecl",
CXCursor_StaticAssert => "StaticAssert",
_ => "?",
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/clangll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,11 @@ pub const CXCursor_InclusionDirective: c_uint = 503;
pub const CXCursor_FirstPreprocessing: c_uint = 500;
pub const CXCursor_LastPreprocessing: c_uint = 503;
pub const CXCursor_ModuleImportDecl: c_uint = 600;
pub const CXCursor_TypeAliasTemplateDecl: c_uint = 601;
pub const CXCursor_StaticAssert: c_uint = 602;
pub const CXCursor_FirstExtraDecl: c_uint = 600;
pub const CXCursor_LastExtraDecl: c_uint = 600;
pub const CXCursor_LastExtraDecl: c_uint = 602;
pub const CXCursor_OverloadCandidate: c_uint = 700;
#[repr(C)]
#[derive(Copy, Clone)]
pub struct CXCursor {
Expand Down
8 changes: 8 additions & 0 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,12 @@ impl CodeGenerator for Type {
return;
}
TypeKind::Comp(ref ci) => ci.codegen(ctx, result, item),
TypeKind::TemplateAlias(inner, _) => {
// NB: The inner Alias will pick the correct
// applicable_template_args.
let inner_item = ctx.resolve_item(inner);
inner_item.expect_type().codegen(ctx, result, inner_item);
}
TypeKind::Alias(ref spelling, inner) => {
let inner_item = ctx.resolve_item(inner);
let name = item.canonical_name(ctx);
Expand Down Expand Up @@ -1361,6 +1367,7 @@ impl ToRustTy for Type {
let path = item.canonical_path(ctx);
aster::AstBuilder::new().ty().path().ids(path).build()
}
TypeKind::TemplateAlias(inner, ref template_args) |
TypeKind::TemplateRef(inner, ref template_args) => {
// PS: Sorry for the duplication here.
let mut inner_ty = inner.to_rust_ty(ctx).unwrap();
Expand Down Expand Up @@ -1618,6 +1625,7 @@ impl TypeCollector for Type {
TypeKind::Pointer(inner) |
TypeKind::Reference(inner) |
TypeKind::Array(inner, _) |
TypeKind::TemplateAlias(inner, _) |
TypeKind::Alias(_, inner) |
TypeKind::Named(_, Some(inner)) |
TypeKind::ResolvedTypeRef(inner)
Expand Down
79 changes: 66 additions & 13 deletions src/ir/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,20 @@ impl Item {
self.kind().expect_function()
}

// This check is needed because even though the type might not contain the
// applicable template args itself, they might apply transitively via, for
// example, the parent.
//
// It's kind of unfortunate (in the sense that it's a sort of complex
// process, but I think it gets all the cases).
fn signature_contains_named_type(&self, ctx: &BindgenContext, ty: &Type) -> bool {
debug_assert!(ty.is_named());
self.expect_type().signature_contains_named_type(ctx, ty) ||
self.applicable_template_args(ctx).iter().any(|template| {
ctx.resolve_type(*template).signature_contains_named_type(ctx, ty)
})
}

pub fn applicable_template_args(&self, ctx: &BindgenContext) -> Vec<ItemId> {
let ty = match *self.kind() {
ItemKind::Type(ref ty) => ty,
Expand Down Expand Up @@ -197,7 +211,8 @@ impl Item {
TypeKind::Alias(_, inner) => {
let parent_args = ctx.resolve_item(self.parent_id())
.applicable_template_args(ctx);
let inner = ctx.resolve_type(inner);
let inner = ctx.resolve_item(inner);

// Avoid unused type parameters, sigh.
parent_args.iter().cloned().filter(|arg| {
let arg = ctx.resolve_type(*arg);
Expand All @@ -206,6 +221,7 @@ impl Item {
}
// XXX Is this completely correct? Partial template specialization
// is hard anyways, sigh...
TypeKind::TemplateAlias(_, ref args) |
TypeKind::TemplateRef(_, ref args) => {
args.clone()
}
Expand Down Expand Up @@ -247,19 +263,22 @@ impl Item {
debug_assert!(ctx.in_codegen_phase(),
"You're not supposed to call this yet");
self.annotations.hide() ||
ctx.hidden_by_name(&self.real_canonical_name(ctx, false), self.id)
ctx.hidden_by_name(&self.real_canonical_name(ctx, false, true), self.id)
}

pub fn is_opaque(&self, ctx: &BindgenContext) -> bool {
debug_assert!(ctx.in_codegen_phase(),
"You're not supposed to call this yet");
self.annotations.opaque() ||
ctx.opaque_by_name(&self.real_canonical_name(ctx, false))
ctx.opaque_by_name(&self.real_canonical_name(ctx, false, true))
}

/// Get the canonical name without taking into account the replaces
/// annotation.
fn real_canonical_name(&self, ctx: &BindgenContext, count_namespaces: bool) -> String {
fn real_canonical_name(&self,
ctx: &BindgenContext,
count_namespaces: bool,
for_name_checking: bool) -> String {
let base_name = match *self.kind() {
ItemKind::Type(ref ty) => {
match *ty.kind() {
Expand All @@ -277,11 +296,29 @@ impl Item {
TypeKind::Named(ref name, _) => {
return name.to_owned();
}
_ => {}
}

ty.name().map(ToOwned::to_owned)
.unwrap_or_else(|| format!("_bindgen_ty{}", self.id()))
// We call codegen on the inner type, but we do not want
// this alias's name to appear in the canonical name just
// because it is in the inner type's parent chain, so we use
// an empty base name.
//
// Note that this would be incorrect if this type could be
// referenced from, let's say, a member variable, but in
// that case the referenced type is the inner alias, so
// we're good there. If we wouldn't, a more complex solution
// would be needed.
TypeKind::TemplateAlias(inner, _) => {
if for_name_checking {
return ctx.resolve_item(inner).real_canonical_name(ctx, count_namespaces, false);
}
Some("")
}
// Else use the proper name, or fallback to a name with an
// id.
_ => {
ty.name()
}
}.map(ToOwned::to_owned)
.unwrap_or_else(|| format!("_bindgen_ty{}", self.id()))
}
ItemKind::Function(ref fun) => {
let mut base = fun.name().to_owned();
Expand Down Expand Up @@ -329,7 +366,12 @@ impl Item {

// TODO: allow modification of the mangling functions, maybe even per
// item type?
format!("{}_{}", parent.canonical_name(ctx), base_name)
let parent = parent.canonical_name(ctx);
if parent.is_empty() {
base_name.to_owned()
} else {
format!("{}_{}", parent, base_name)
}
}

pub fn as_module_mut(&mut self) -> Option<&mut Module> {
Expand Down Expand Up @@ -444,7 +486,7 @@ impl ClangItemParser for Item {
if cursor.kind() == clangll::CXCursor_UnexposedDecl {
Err(ParseError::Recurse)
} else {
error!("Unhandled cursor kind: {}", ::clang::kind_to_str(cursor.kind()));
error!("Unhandled cursor kind: {} ({})", ::clang::kind_to_str(cursor.kind()), cursor.kind());
Err(ParseError::Continue)
}
}
Expand Down Expand Up @@ -661,7 +703,7 @@ impl ItemCanonicalName for Item {
if let Some(other_canon_type) = self.annotations.use_instead_of() {
return other_canon_type.to_owned();
}
self.real_canonical_name(ctx, ctx.options().enable_cxx_namespaces)
self.real_canonical_name(ctx, ctx.options().enable_cxx_namespaces, false)
}
}

Expand Down Expand Up @@ -698,7 +740,18 @@ impl ItemCanonicalPath for Item {
}

let mut parent_path = self.parent_id().canonical_path(&ctx);
parent_path.push(self.real_canonical_name(ctx, true));
if parent_path.last().map_or(false, |parent_name| parent_name.is_empty()) {
// This only happens (or should only happen) when we're an alias,
// and our parent is a templated alias, in which case the last
// component of the path will be empty.
let is_alias = match *self.expect_type().kind() {
TypeKind::Alias(..) => true,
_ => false,
};
debug_assert!(is_alias, "How can this ever happen?");
parent_path.pop().unwrap();
}
parent_path.push(self.real_canonical_name(ctx, true, false));

parent_path
}
Expand Down
68 changes: 65 additions & 3 deletions src/ir/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,14 @@ impl Type {
type_resolver.resolve_type(t).can_derive_debug(type_resolver)
}
TypeKind::ResolvedTypeRef(t) |
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(_, t) => {
type_resolver.resolve_type(t).can_derive_debug(type_resolver)
}
TypeKind::Comp(ref info) => {
info.can_derive_debug(type_resolver, self.layout(type_resolver))
}
_ => true,
_ => true,
}
}

Expand All @@ -177,6 +178,7 @@ impl Type {
pub fn can_derive_copy_in_array(&self, type_resolver: &BindgenContext, item: &Item) -> bool {
match self.kind {
TypeKind::ResolvedTypeRef(t) |
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(_, t) |
TypeKind::Array(t, _) => {
type_resolver.resolve_item(t)
Expand All @@ -194,6 +196,7 @@ impl Type {
type_resolver.resolve_item(t).can_derive_copy_in_array(type_resolver)
}
TypeKind::ResolvedTypeRef(t) |
TypeKind::TemplateAlias(t, _) |
TypeKind::TemplateRef(t, _) |
TypeKind::Alias(_, t) => {
type_resolver.resolve_item(t).can_derive_copy(type_resolver)
Expand All @@ -209,6 +212,7 @@ impl Type {
// FIXME: Can we do something about template parameters? Huh...
match self.kind {
TypeKind::TemplateRef(t, _) |
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(_, t) |
TypeKind::ResolvedTypeRef(t) |
TypeKind::Array(t, _) => {
Expand All @@ -225,6 +229,7 @@ impl Type {
pub fn has_destructor(&self, type_resolver: &BindgenContext) -> bool {
self.is_opaque(type_resolver) || match self.kind {
TypeKind::TemplateRef(t, _) |
TypeKind::TemplateAlias(t, _) |
TypeKind::Alias(_, t) |
TypeKind::ResolvedTypeRef(t) |
TypeKind::Array(t, _) => {
Expand Down Expand Up @@ -263,7 +268,8 @@ impl Type {
type_resolver.resolve_type(sig.return_type())
.signature_contains_named_type(type_resolver, ty)
},
TypeKind::TemplateRef(_inner, ref template_args) => {
TypeKind::TemplateAlias(_, ref template_args) |
TypeKind::TemplateRef(_, ref template_args) => {
template_args.iter().any(|arg| {
type_resolver.resolve_type(*arg)
.signature_contains_named_type(type_resolver, ty)
Expand Down Expand Up @@ -292,6 +298,7 @@ impl Type {

TypeKind::ResolvedTypeRef(inner) |
TypeKind::Alias(_, inner) |
TypeKind::TemplateAlias(inner, _) |
TypeKind::TemplateRef(inner, _)
=> type_resolver.resolve_type(inner).canonical_type(type_resolver),

Expand Down Expand Up @@ -327,6 +334,9 @@ pub enum TypeKind {
Float(FloatKind),
/// A type alias, with a name, that points to another type.
Alias(String, ItemId),
/// A templated alias, pointing to an inner Alias type, with template
/// parameters.
TemplateAlias(ItemId, Vec<ItemId>),
/// An array of a type and a lenght.
Array(ItemId, usize),
/// A function type, with a given signature.
Expand Down Expand Up @@ -371,6 +381,7 @@ impl Type {
}
TypeKind::ResolvedTypeRef(inner) |
TypeKind::Alias(_, inner) |
TypeKind::TemplateAlias(inner, _) |
TypeKind::TemplateRef(inner, _)
=> type_resolver.resolve_type(inner).is_unsized(type_resolver),
TypeKind::Named(..) |
Expand Down Expand Up @@ -444,6 +455,57 @@ impl Type {
.expect("C'mon");
TypeKind::Comp(complex)
}
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 => {
debug_assert!(cur.cur_type().kind() == CXType_Typedef);
inner = Item::from_ty(&cur.cur_type(),
Some(*cur),
Some(potential_id),
ctx);
}
CXCursor_TemplateTypeParameter => {
// See the comment in src/ir/comp.rs
// about the same situation.
if cur.spelling().is_empty() {
return CXChildVisit_Continue;
}

let default_type =
Item::from_ty(&cur.cur_type(),
Some(*cur),
Some(potential_id),
ctx).ok();
let param =
Item::named_type(cur.spelling(),
default_type,
potential_id, ctx);
args.push(param);
}
_ => {}
}
CXChildVisit_Continue
});

if inner.is_err() {
error!("Failed to parse templated type alias {:?}", location);
return Err(ParseError::Continue);
}

if args.is_empty() {
error!("Failed to get any template parameter, maybe a specialization? {:?}", location);
return Err(ParseError::Continue);
}

TypeKind::TemplateAlias(inner.unwrap(), args)
}
CXCursor_TemplateRef => {
let referenced = location.referenced();
return Self::from_clang_ty(potential_id,
Expand Down Expand Up @@ -521,7 +583,7 @@ impl Type {
let signature = try!(FunctionSig::from_ty(ty, &location.unwrap_or(cursor), ctx));
TypeKind::Function(signature)
}
CXType_Typedef => {
CXType_Typedef => {
let inner = cursor.typedef_type();
let inner =
Item::from_ty_or_ref(inner, location, parent_id, ctx);
Expand Down
12 changes: 12 additions & 0 deletions tests/expectations/template_alias.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* automatically generated by rust-bindgen */


#![allow(non_snake_case)]


pub type Wrapped<T> = T;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Rooted<T> {
pub ptr: Wrapped<T>,
}
7 changes: 7 additions & 0 deletions tests/expectations/template_alias_basic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* automatically generated by rust-bindgen */


#![allow(non_snake_case)]


pub type Wrapped<T> = T;
21 changes: 21 additions & 0 deletions tests/expectations/template_alias_namespace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* automatically generated by rust-bindgen */


#![allow(non_snake_case)]


pub mod root {
use root;
pub mod JS {
use root;
pub mod detail {
use root;
pub type Wrapped<T> = T;
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Rooted<T> {
pub ptr: root::JS::detail::Wrapped<T>,
}
}
}
Loading