diff options
Diffstat (limited to 'libbindgen')
-rw-r--r-- | libbindgen/src/codegen/mod.rs | 13 | ||||
-rw-r--r-- | libbindgen/src/ir/annotations.rs | 15 | ||||
-rw-r--r-- | libbindgen/src/ir/context.rs | 100 | ||||
-rw-r--r-- | libbindgen/src/ir/item.rs | 104 | ||||
-rw-r--r-- | libbindgen/src/ir/ty.rs | 95 | ||||
-rw-r--r-- | libbindgen/tests/expectations/tests/reparented_replacement.rs | 29 | ||||
-rw-r--r-- | libbindgen/tests/expectations/tests/replace_template_alias.rs | 8 | ||||
-rw-r--r-- | libbindgen/tests/expectations/tests/type_alias_template_specialized.rs | 2 | ||||
-rw-r--r-- | libbindgen/tests/headers/reparented_replacement.hpp | 16 | ||||
-rw-r--r-- | libbindgen/tests/headers/replace_template_alias.hpp | 2 | ||||
-rw-r--r-- | libbindgen/tests/headers/whitelist-namespaces-basic.hpp | 2 |
11 files changed, 253 insertions, 133 deletions
diff --git a/libbindgen/src/codegen/mod.rs b/libbindgen/src/codegen/mod.rs index d2e2b96c..95a6f611 100644 --- a/libbindgen/src/codegen/mod.rs +++ b/libbindgen/src/codegen/mod.rs @@ -467,12 +467,9 @@ impl CodeGenerator for Type { TypeKind::Comp(ref ci) => { ci.codegen(ctx, result, whitelisted_items, item) } - // NB: The inner Alias will be generated and pick the correct + // NB: The code below will pick the correct // applicable_template_args. - TypeKind::TemplateAlias(inner, _) => { - ctx.resolve_item(inner) - .codegen(ctx, result, whitelisted_items, &()) - }, + TypeKind::TemplateAlias(ref spelling, inner, _) | TypeKind::Alias(ref spelling, inner) => { let inner_item = ctx.resolve_item(inner); let name = item.canonical_name(ctx); @@ -1777,10 +1774,9 @@ impl ToRustTy for Type { aster::ty::TyBuilder::new().array(len).build(inner) } TypeKind::Enum(..) => { - let path = item.canonical_path(ctx); + let path = item.namespace_aware_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(); @@ -1803,6 +1799,7 @@ impl ToRustTy for Type { P(inner_ty) } TypeKind::ResolvedTypeRef(inner) => inner.to_rust_ty(ctx), + TypeKind::TemplateAlias(ref spelling, inner, _) | TypeKind::Alias(ref spelling, inner) => { if item.is_opaque(ctx) { // Pray if there's no available layout. @@ -2141,7 +2138,7 @@ mod utils { ctx: &BindgenContext, only_named: bool) -> P<ast::Ty> { - let path = item.canonical_path(ctx); + let path = item.namespace_aware_canonical_path(ctx); let builder = aster::AstBuilder::new().ty().path(); let template_args = if only_named { diff --git a/libbindgen/src/ir/annotations.rs b/libbindgen/src/ir/annotations.rs index 58308d6d..948dbc96 100644 --- a/libbindgen/src/ir/annotations.rs +++ b/libbindgen/src/ir/annotations.rs @@ -27,9 +27,9 @@ pub struct Annotations { /// Whether this item should be hidden from the output. Only applies to /// types. hide: bool, - /// Whether this type should be replaced by another. The name must be the - /// canonical name that that type would get. - use_instead_of: Option<String>, + /// Whether this type should be replaced by another. The name is a + /// namespace-aware path. + use_instead_of: Option<Vec<String>>, /// Manually disable deriving copy/clone on this type. Only applies to /// struct or union types. disallow_copy: bool, @@ -106,7 +106,7 @@ impl Annotations { /// ``` /// /// That is, code for `Foo` is used to generate `Bar`. - pub fn use_instead_of(&self) -> Option<&str> { + pub fn use_instead_of(&self) -> Option<&[String]> { self.use_instead_of.as_ref().map(|s| &**s) } @@ -138,7 +138,12 @@ impl Annotations { "opaque" => self.opaque = true, "hide" => self.hide = true, "nocopy" => self.disallow_copy = true, - "replaces" => self.use_instead_of = Some(attr.value), + "replaces" => { + self.use_instead_of = + Some(attr.value.split("::") + .map(Into::into) + .collect()) + }, "private" => { self.private_fields = Some(attr.value != "false") } diff --git a/libbindgen/src/ir/context.rs b/libbindgen/src/ir/context.rs index f832a5d2..1d658e7d 100644 --- a/libbindgen/src/ir/context.rs +++ b/libbindgen/src/ir/context.rs @@ -10,7 +10,7 @@ use std::collections::{HashMap, hash_map}; use std::collections::btree_map::{self, BTreeMap}; use std::fmt; use super::int::IntKind; -use super::item::Item; +use super::item::{Item, ItemCanonicalPath}; use super::item_kind::ItemKind; use super::module::Module; use super::ty::{FloatKind, Type, TypeKind}; @@ -100,7 +100,7 @@ pub struct BindgenContext<'ctx> { parsed_macros: HashMap<Vec<u8>, cexpr::expr::EvalResult>, /// The active replacements collected from replaces="xxx" annotations. - replacements: HashMap<String, ItemId>, + replacements: HashMap<Vec<String>, ItemId>, collected_typerefs: bool, @@ -172,7 +172,8 @@ impl<'ctx> BindgenContext<'ctx> { declaration: Option<Cursor>, location: Option<Cursor>) { use clangll::{CXCursor_ClassTemplate, - CXCursor_ClassTemplatePartialSpecialization}; + CXCursor_ClassTemplatePartialSpecialization, + CXCursor_TypeAliasTemplateDecl}; debug!("BindgenContext::add_item({:?}, declaration: {:?}, loc: {:?}", item, declaration, @@ -207,7 +208,8 @@ impl<'ctx> BindgenContext<'ctx> { if let Some(location) = location { if location.kind() == CXCursor_ClassTemplate || location.kind() == - CXCursor_ClassTemplatePartialSpecialization { + CXCursor_ClassTemplatePartialSpecialization || + location.kind() == CXCursor_TypeAliasTemplateDecl { declaration = location; } } @@ -353,6 +355,10 @@ impl<'ctx> BindgenContext<'ctx> { let mut replacements = vec![]; for (id, item) in self.items.iter() { + if item.annotations().use_instead_of().is_some() { + continue; + } + // Calls to `canonical_name` are expensive, so eagerly filter out // items that cannot be replaced. let ty = match item.kind().as_type() { @@ -362,23 +368,13 @@ impl<'ctx> BindgenContext<'ctx> { match *ty.kind() { TypeKind::Comp(ref ci) if !ci.is_template_specialization() => {} - TypeKind::TemplateAlias(_, _) | - TypeKind::Alias(_, _) => {} + TypeKind::TemplateAlias(..) | + TypeKind::Alias(..) => {} _ => continue, } - let in_namespace = self.options().enable_cxx_namespaces; - - let name = if in_namespace { - item.name(self) - .within_namespaces() - .get() - } else { - item.name(self) - .for_name_checking() - .get() - }; - let replacement = self.replacements.get(&name); + let path = item.canonical_path(self); + let replacement = self.replacements.get(&path[1..]); if let Some(replacement) = replacement { if replacement != id { @@ -394,9 +390,33 @@ impl<'ctx> BindgenContext<'ctx> { for (id, replacement) in replacements { debug!("Replacing {:?} with {:?}", id, replacement); - let mut item = self.items.get_mut(&id).unwrap(); - *item.kind_mut().as_type_mut().unwrap().kind_mut() = - TypeKind::ResolvedTypeRef(replacement); + let new_parent = { + let mut item = self.items.get_mut(&id).unwrap(); + *item.kind_mut().as_type_mut().unwrap().kind_mut() = + TypeKind::ResolvedTypeRef(replacement); + item.parent_id() + }; + + + // Reparent the item. + let old_parent = self.resolve_item(replacement).parent_id(); + + if new_parent == old_parent { + continue; + } + + if let Some(mut module) = self.items.get_mut(&old_parent).unwrap().as_module_mut() { + // Deparent the replacement. + let position = module.children().iter().position(|id| *id == replacement).unwrap(); + module.children_mut().remove(position); + } + + if let Some(mut module) = self.items.get_mut(&new_parent).unwrap().as_module_mut() { + module.children_mut().push(replacement); + } + + self.items.get_mut(&replacement).unwrap().set_parent_for_replacement(new_parent); + self.items.get_mut(&id).unwrap().set_parent_for_replacement(old_parent); } } @@ -637,7 +657,8 @@ impl<'ctx> BindgenContext<'ctx> { if let Some(location) = location { if location.kind() == CXCursor_ClassTemplate || location.kind() == - CXCursor_ClassTemplatePartialSpecialization { + CXCursor_ClassTemplatePartialSpecialization || + location.kind() == CXCursor_TypeAliasTemplateDecl { declaration = location; } } @@ -827,17 +848,17 @@ impl<'ctx> BindgenContext<'ctx> { /// /// Replacement types are declared using the `replaces="xxx"` annotation, /// and implies that the original type is hidden. - pub fn replace(&mut self, name: &str, potential_ty: ItemId) { + pub fn replace(&mut self, name: &[String], potential_ty: ItemId) { match self.replacements.entry(name.into()) { hash_map::Entry::Vacant(entry) => { - debug!("Defining replacement for {} as {:?}", + debug!("Defining replacement for {:?} as {:?}", name, potential_ty); entry.insert(potential_ty); } hash_map::Entry::Occupied(occupied) => { - warn!("Replacement for {} already defined as {:?}; \ - ignoring duplicate replacement definition as {:?}}}", + warn!("Replacement for {:?} already defined as {:?}; \ + ignoring duplicate replacement definition as {:?}", name, occupied.get(), potential_ty); @@ -847,27 +868,27 @@ impl<'ctx> BindgenContext<'ctx> { /// Is the item with the given `name` hidden? Or is the item with the given /// `name` and `id` replaced by another type, and effectively hidden? - pub fn hidden_by_name(&self, name: &str, id: ItemId) -> bool { + pub fn hidden_by_name(&self, path: &[String], id: ItemId) -> bool { debug_assert!(self.in_codegen_phase(), "You're not supposed to call this yet"); - self.options.hidden_types.contains(name) || - self.is_replaced_type(name, id) + self.options.hidden_types.contains(&path[1..].join("::")) || + self.is_replaced_type(path, id) } /// Has the item with the given `name` and `id` been replaced by another /// type? - pub fn is_replaced_type(&self, name: &str, id: ItemId) -> bool { - match self.replacements.get(name) { + pub fn is_replaced_type(&self, path: &[String], id: ItemId) -> bool { + match self.replacements.get(path) { Some(replaced_by) if *replaced_by != id => true, _ => false, } } /// Is the type with the given `name` marked as opaque? - pub fn opaque_by_name(&self, name: &str) -> bool { + pub fn opaque_by_name(&self, path: &[String]) -> bool { debug_assert!(self.in_codegen_phase(), "You're not supposed to call this yet"); - self.options.opaque_types.contains(name) + self.options.opaque_types.contains(&path[1..].join("::")) } /// Get the options used to configure this bindgen context. @@ -953,7 +974,8 @@ impl<'ctx> BindgenContext<'ctx> { return true; } - let name = item.name(self).for_name_checking().get(); + let name = item.canonical_path(self)[1..].join("::"); + debug!("whitelisted_items: testing {:?}", name); match *item.kind() { ItemKind::Module(..) => true, ItemKind::Function(_) => { @@ -967,7 +989,10 @@ impl<'ctx> BindgenContext<'ctx> { return true; } - if self.resolve_item(item.parent_id()).is_module() { + let parent = self.resolve_item(item.parent_id()); + if parent.is_module() { + let mut prefix_path = parent.canonical_path(self); + // Unnamed top-level enums are special and we // whitelist them via the `whitelisted_vars` filter, // since they're effectively top-level constants, @@ -976,9 +1001,12 @@ impl<'ctx> BindgenContext<'ctx> { if let TypeKind::Enum(ref enum_) = *ty.kind() { if ty.name().is_none() && enum_.variants().iter().any(|variant| { + prefix_path.push(variant.name().into()); + let name = prefix_path[1..].join("::"); + prefix_path.pop().unwrap(); self.options() .whitelisted_vars - .matches(&variant.name()) + .matches(&name) }) { return true; } diff --git a/libbindgen/src/ir/item.rs b/libbindgen/src/ir/item.rs index f12e4b54..79aca5af 100644 --- a/libbindgen/src/ir/item.rs +++ b/libbindgen/src/ir/item.rs @@ -42,6 +42,12 @@ pub trait ItemCanonicalName { /// For bar, the canonical path is `vec!["foo", "BAR"]`, while the canonical /// name is just `"BAR"`. pub trait ItemCanonicalPath { + /// Get the namespace-aware canonical path for this item. This means that if + /// namespaces are disabled, you'll + fn namespace_aware_canonical_path(&self, + ctx: &BindgenContext) + -> Vec<String>; + /// Get the canonical path for this item. fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String>; } @@ -127,6 +133,14 @@ impl ItemCanonicalName for ItemId { } impl ItemCanonicalPath for ItemId { + fn namespace_aware_canonical_path(&self, + ctx: &BindgenContext) + -> Vec<String> { + debug_assert!(ctx.in_codegen_phase(), + "You're not supposed to call this yet"); + ctx.resolve_item(*self).namespace_aware_canonical_path(ctx) + } + fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> { debug_assert!(ctx.in_codegen_phase(), "You're not supposed to call this yet"); @@ -276,6 +290,13 @@ impl Item { self.parent_id } + /// Set this item's parent id. + /// + /// This is only used so replacements get generated in the proper module. + pub fn set_parent_for_replacement(&mut self, id: ItemId) { + self.parent_id = id; + } + /// Get this `Item`'s comment, if it has any. pub fn comment(&self) -> Option<&str> { self.comment.as_ref().map(|c| &**c) @@ -509,7 +530,7 @@ impl Item { } // XXX Is this completely correct? Partial template specialization // is hard anyways, sigh... - TypeKind::TemplateAlias(_, ref args) | + TypeKind::TemplateAlias(_, _, ref args) | TypeKind::TemplateRef(_, ref args) => args.clone(), // In a template specialization we've got all we want. TypeKind::Comp(ref ci) if ci.is_template_specialization() => { @@ -552,7 +573,7 @@ impl Item { debug_assert!(ctx.in_codegen_phase(), "You're not supposed to call this yet"); self.annotations.hide() || - ctx.hidden_by_name(&self.name(ctx).for_name_checking().get(), self.id) + ctx.hidden_by_name(&self.canonical_path(ctx), self.id) } /// Is this item opaque? @@ -560,7 +581,7 @@ impl Item { debug_assert!(ctx.in_codegen_phase(), "You're not supposed to call this yet"); self.annotations.opaque() || - ctx.opaque_by_name(&self.name(ctx).for_name_checking().get()) + ctx.opaque_by_name(&self.canonical_path(ctx)) } /// Is this a reference to another type? @@ -585,8 +606,7 @@ impl Item { /// Get the target item id for name generation. fn name_target(&self, - ctx: &BindgenContext, - for_name_checking: bool) + ctx: &BindgenContext) -> ItemId { let mut targets_seen = DebugOnlyItemSet::new(); let mut item = self; @@ -595,6 +615,10 @@ impl Item { debug_assert!(!targets_seen.contains(&item.id())); targets_seen.insert(item.id()); + if self.annotations().use_instead_of().is_some() { + return self.id(); + } + match *item.kind() { ItemKind::Type(ref ty) => { match *ty.kind() { @@ -611,13 +635,6 @@ impl Item { TypeKind::TemplateRef(inner, _) => { item = ctx.resolve_item(inner); } - // Template aliases use their inner alias type's name if - // we are checking names for - // whitelisting/replacement/etc. - TypeKind::TemplateAlias(inner, _) - if for_name_checking => { - item = ctx.resolve_item(inner); - } _ => return item.id(), } } @@ -657,14 +674,13 @@ impl Item { } /// Get this item's base name (aka non-namespaced name). - /// - /// The `for_name_checking` boolean parameter informs us whether we are - /// asking for the name in order to do a whitelisting/replacement/etc check - /// or if we are instead using it for code generation. fn base_name(&self, - ctx: &BindgenContext, - for_name_checking: bool) + ctx: &BindgenContext) -> String { + if let Some(path) = self.annotations().use_instead_of() { + return path.last().unwrap().clone(); + } + match *self.kind() { ItemKind::Var(ref var) => var.name().to_owned(), ItemKind::Module(ref module) => { @@ -677,9 +693,6 @@ impl Item { ItemKind::Type(ref ty) => { let name = match *ty.kind() { TypeKind::ResolvedTypeRef(..) => panic!("should have resolved this in name_target()"), - TypeKind::TemplateAlias(..) => { - if for_name_checking { None } else { Some("") } - } _ => ty.name(), }; name.map(ToOwned::to_owned) @@ -717,16 +730,17 @@ impl Item { opt: &NameOptions) -> String { let target = - ctx.resolve_item(self.name_target(ctx, opt.for_name_checking)); + ctx.resolve_item(self.name_target(ctx)); // Short-circuit if the target has an override, and just use that. - if !opt.for_name_checking { - if let Some(other) = target.annotations.use_instead_of() { - return other.to_owned(); + if let Some(path) = target.annotations.use_instead_of() { + if ctx.options().enable_cxx_namespaces { + return path.last().unwrap().clone(); } + return path.join("_").to_owned(); } - let base_name = target.base_name(ctx, opt.for_name_checking); + let base_name = target.base_name(ctx); // Named template type arguments are never namespaced, and never // mangled. @@ -744,8 +758,8 @@ impl Item { }) .map(|id| { let item = ctx.resolve_item(id); - let target = ctx.resolve_item(item.name_target(ctx, false)); - target.base_name(ctx, false) + let target = ctx.resolve_item(item.name_target(ctx)); + target.base_name(ctx) }) .filter(|name| !name.is_empty()) .collect(); @@ -1217,17 +1231,34 @@ impl ItemCanonicalName for Item { } impl ItemCanonicalPath for Item { + fn namespace_aware_canonical_path(&self, + ctx: &BindgenContext) + -> Vec<String> { + if ctx.options().enable_cxx_namespaces { + return self.canonical_path(ctx); + } + return vec![self.canonical_path(ctx)[1..].join("_")]; + } + fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> { - if !ctx.options().enable_cxx_namespaces { - return vec![self.canonical_name(ctx)]; + if let Some(path) = self.annotations().use_instead_of() { + let mut ret = + vec![ctx.resolve_item(ctx.root_module()).name(ctx).get()]; + ret.extend_from_slice(path); + return ret; } - let target = ctx.resolve_item(self.name_target(ctx, false)); + let target = ctx.resolve_item(self.name_target(ctx)); let mut path: Vec<_> = target.ancestors(ctx) .chain(iter::once(ctx.root_module())) .map(|id| ctx.resolve_item(id)) .filter(|item| item.is_module() || item.id() == target.id()) - .map(|item| item.name(ctx).within_namespaces().get()) + .map(|item| { + ctx.resolve_item(item.name_target(ctx)) + .name(ctx) + .within_namespaces() + .get() + }) .collect(); path.reverse(); path @@ -1242,7 +1273,6 @@ pub struct NameOptions<'item, 'ctx> { item: &'item Item, ctx: &'item BindgenContext<'ctx>, - for_name_checking: bool, within_namespaces: bool, } @@ -1252,18 +1282,10 @@ impl<'item, 'ctx> NameOptions<'item, 'ctx> { NameOptions { item: item, ctx: ctx, - for_name_checking: false, within_namespaces: false, } } - /// Construct a name that is suitable for replacements/whitelisting/opaque- - /// ness look ups. - pub fn for_name_checking(&mut self) -> &mut Self { - self.for_name_checking = true; - self - } - /// Construct the name without the item's containing C++ namespaces mangled /// into it. In other words, the item's name within the item's namespace. pub fn within_namespaces(&mut self) -> &mut Self { diff --git a/libbindgen/src/ir/ty.rs b/libbindgen/src/ir/ty.rs index 33e20861..8b0116df 100644 --- a/libbindgen/src/ir/ty.rs +++ b/libbindgen/src/ir/ty.rs @@ -64,6 +64,22 @@ impl Type { &self.kind } + /// Overrides the kind of the item. This is mostly a template alias + /// implementation detail, and debug assertions guard it like so. + pub fn set_kind(&mut self, kind: TypeKind) { + if cfg!(debug_assertions) { + match (&self.kind, &kind) { + (&TypeKind::Alias(ref alias_name, alias_inner), + &TypeKind::TemplateAlias(ref name, inner, _)) => { + assert_eq!(alias_name, name); + assert_eq!(alias_inner, inner); + } + _ => panic!("Unexpected kind in `set_kind`!"), + }; + } + self.kind = kind; + } + /// Get a mutable reference to this type's kind. pub fn kind_mut(&mut self) -> &mut TypeKind { &mut self.kind @@ -90,6 +106,14 @@ impl Type { } } + /// Is this a template alias type? + pub fn is_template_alias(&self) -> bool { + match self.kind { + TypeKind::TemplateAlias(..) => true, + _ => false, + } + } + /// Is this a function type? pub fn is_function(&self) -> bool { match self.kind { @@ -195,7 +219,7 @@ impl Type { ctx.resolve_type(t).can_derive_debug(ctx) } TypeKind::ResolvedTypeRef(t) | - TypeKind::TemplateAlias(t, _) | + TypeKind::TemplateAlias(_, t, _) | TypeKind::Alias(_, t) => ctx.resolve_type(t).can_derive_debug(ctx), TypeKind::Comp(ref info) => { info.can_derive_debug(ctx, self.layout(ctx)) @@ -232,7 +256,7 @@ impl Type { -> bool { match self.kind { TypeKind::ResolvedTypeRef(t) | - TypeKind::TemplateAlias(t, _) | + TypeKind::TemplateAlias(_, t, _) | TypeKind::Alias(_, t) | TypeKind::Array(t, _) => { ctx.resolve_item(t) @@ -252,7 +276,7 @@ impl Type { ctx.resolve_item(t).can_derive_copy_in_array(ctx) } TypeKind::ResolvedTypeRef(t) | - TypeKind::TemplateAlias(t, _) | + TypeKind::TemplateAlias(_, t, _) | TypeKind::TemplateRef(t, _) | TypeKind::Alias(_, t) => ctx.resolve_item(t).can_derive_copy(ctx), TypeKind::Comp(ref info) => info.can_derive_copy(ctx, item), @@ -265,7 +289,7 @@ impl Type { // FIXME: Can we do something about template parameters? Huh... match self.kind { TypeKind::TemplateRef(t, _) | - TypeKind::TemplateAlias(t, _) | + TypeKind::TemplateAlias(_, t, _) | TypeKind::Alias(_, t) | TypeKind::ResolvedTypeRef(t) => ctx.resolve_type(t).has_vtable(ctx), TypeKind::Comp(ref info) => info.has_vtable(ctx), @@ -278,7 +302,7 @@ impl Type { pub fn has_destructor(&self, ctx: &BindgenContext) -> bool { match self.kind { TypeKind::TemplateRef(t, _) | - TypeKind::TemplateAlias(t, _) | + TypeKind::TemplateAlias(_, t, _) | TypeKind::Alias(_, t) | TypeKind::ResolvedTypeRef(t) => { ctx.resolve_type(t).has_destructor(ctx) @@ -293,10 +317,9 @@ impl Type { ctx: &BindgenContext, ty: &Type) -> bool { - debug_assert!(ty.is_named()); let name = match *ty.kind() { TypeKind::Named(ref name, _) => name, - _ => unreachable!(), + ref other @ _ => unreachable!("Not a named type: {:?}", other), }; match self.kind { @@ -316,7 +339,7 @@ impl Type { ctx.resolve_type(sig.return_type()) .signature_contains_named_type(ctx, ty) } - TypeKind::TemplateAlias(_, ref template_args) | + TypeKind::TemplateAlias(_, _, ref template_args) | TypeKind::TemplateRef(_, ref template_args) => { template_args.iter().any(|arg| { ctx.resolve_type(*arg) @@ -361,7 +384,7 @@ impl Type { TypeKind::ResolvedTypeRef(inner) | TypeKind::Alias(_, inner) | - TypeKind::TemplateAlias(inner, _) | + TypeKind::TemplateAlias(_, inner, _) | TypeKind::TemplateRef(inner, _) => { ctx.resolve_type(inner).safe_canonical_type(ctx) } @@ -409,9 +432,9 @@ pub enum TypeKind { /// 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>), + /// A templated alias, pointing to an inner type, just as `Alias`, but with + /// template parameters. + TemplateAlias(String, ItemId, Vec<ItemId>), /// An array of a type and a lenght. Array(ItemId, usize), @@ -476,7 +499,7 @@ impl Type { } TypeKind::ResolvedTypeRef(inner) | TypeKind::Alias(_, inner) | - TypeKind::TemplateAlias(inner, _) | + TypeKind::TemplateAlias(_, inner, _) | TypeKind::TemplateRef(inner, _) => { ctx.resolve_type(inner).is_unsized(ctx) } @@ -630,13 +653,19 @@ impl Type { location.visit(|cur| { match cur.kind() { CXCursor_TypeAliasDecl => { - debug_assert!(cur.cur_type().kind() == + let current = cur.cur_type(); + + debug_assert!(current.kind() == CXType_Typedef); - inner = - Item::from_ty(&cur.cur_type(), - Some(cur), - Some(potential_id), - ctx); + + name = current.spelling(); + + let inner_ty = cur.typedef_type(); + inner = Item::from_ty( + &inner_ty, + Some(cur), + Some(potential_id), + ctx); } CXCursor_TemplateTypeParameter => { // See the comment in src/ir/comp.rs @@ -663,24 +692,16 @@ impl Type { CXChildVisit_Continue }); - if inner.is_err() { - error!("Failed to parse templated alias {:?}", - location); - return Err(ParseError::Continue); - } + let inner_type = match inner { + Ok(inner) => inner, + Err(..) => { + error!("Failed to parse template alias {:?}", + location); + return Err(ParseError::Continue); + } + }; - // NB: `args` may be empty here (if for example the - // template parameters are constants). - // - // We can't reject it here then because inner points - // to `potential_id` now, so either we remove - // `inner` and return an error, or carry on. - // - // In this case, we just carry on, since it seems - // easier if than removing every possible reference - // to `item` from `ctx`, and it doesn't give any - // problems that we didn't have anyway. - TypeKind::TemplateAlias(inner.unwrap(), args) + TypeKind::TemplateAlias(name.clone(), inner_type, args) } CXCursor_TemplateRef => { let referenced = location.referenced().unwrap(); @@ -870,13 +891,13 @@ 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) => { types.insert(inner); } + TypeKind::TemplateAlias(_, inner, ref template_args) | TypeKind::TemplateRef(inner, ref template_args) => { types.insert(inner); for &item in template_args { diff --git a/libbindgen/tests/expectations/tests/reparented_replacement.rs b/libbindgen/tests/expectations/tests/reparented_replacement.rs new file mode 100644 index 00000000..74ee229c --- /dev/null +++ b/libbindgen/tests/expectations/tests/reparented_replacement.rs @@ -0,0 +1,29 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(non_snake_case)] + + +pub mod root { + #[allow(unused_imports)] + use self::super::root; + pub mod foo { + #[allow(unused_imports)] + use self::super::super::root; + /// <div rustbindgen replaces="foo::Bar"></div> + #[repr(C)] + #[derive(Debug, Copy)] + pub struct Bar { + pub bazz: ::std::os::raw::c_int, + } + #[test] + fn bindgen_test_layout_Bar() { + assert_eq!(::std::mem::size_of::<Bar>() , 4usize); + assert_eq!(::std::mem::align_of::<Bar>() , 4usize); + } + impl Clone for Bar { + fn clone(&self) -> Self { *self } + } + } + pub type ReferencesBar = root::foo::Bar; +} diff --git a/libbindgen/tests/expectations/tests/replace_template_alias.rs b/libbindgen/tests/expectations/tests/replace_template_alias.rs index b9a0d0c9..f922ac77 100644 --- a/libbindgen/tests/expectations/tests/replace_template_alias.rs +++ b/libbindgen/tests/expectations/tests/replace_template_alias.rs @@ -4,12 +4,12 @@ #![allow(non_snake_case)] +/// But the replacement type does use T! +/// +/// <div rustbindgen replaces="JS::detail::MaybeWrapped" /> +pub type JS_detail_MaybeWrapped<T> = T; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct JS_Rooted<T> { pub ptr: JS_detail_MaybeWrapped<T>, } -/// But the replacement type does use T! -/// -/// <div rustbindgen replaces="JS_detail_MaybeWrapped" /> -pub type JS_detail_MaybeWrapped<T> = T; diff --git a/libbindgen/tests/expectations/tests/type_alias_template_specialized.rs b/libbindgen/tests/expectations/tests/type_alias_template_specialized.rs index 989f2015..11813bc6 100644 --- a/libbindgen/tests/expectations/tests/type_alias_template_specialized.rs +++ b/libbindgen/tests/expectations/tests/type_alias_template_specialized.rs @@ -17,3 +17,5 @@ fn bindgen_test_layout_Rooted() { impl Clone for Rooted { fn clone(&self) -> Self { *self } } +/// <div rustbindgen replaces="MaybeWrapped"></div> +pub type MaybeWrapped<a> = a; diff --git a/libbindgen/tests/headers/reparented_replacement.hpp b/libbindgen/tests/headers/reparented_replacement.hpp new file mode 100644 index 00000000..4ac2bf03 --- /dev/null +++ b/libbindgen/tests/headers/reparented_replacement.hpp @@ -0,0 +1,16 @@ +// bindgen-flags: --enable-cxx-namespaces + +namespace foo { + struct Bar { + int baz; + }; +} + +namespace bar { + /// <div rustbindgen replaces="foo::Bar"></div> + struct Bar_Replacement { + int bazz; + }; +}; + +typedef foo::Bar ReferencesBar; diff --git a/libbindgen/tests/headers/replace_template_alias.hpp b/libbindgen/tests/headers/replace_template_alias.hpp index b0648994..c325b5a3 100644 --- a/libbindgen/tests/headers/replace_template_alias.hpp +++ b/libbindgen/tests/headers/replace_template_alias.hpp @@ -18,6 +18,6 @@ class Rooted { /// But the replacement type does use T! /// -/// <div rustbindgen replaces="JS_detail_MaybeWrapped" /> +/// <div rustbindgen replaces="JS::detail::MaybeWrapped" /> template <typename T> using replaces_MaybeWrapped = T; diff --git a/libbindgen/tests/headers/whitelist-namespaces-basic.hpp b/libbindgen/tests/headers/whitelist-namespaces-basic.hpp index abe9dc11..2eaa8740 100644 --- a/libbindgen/tests/headers/whitelist-namespaces-basic.hpp +++ b/libbindgen/tests/headers/whitelist-namespaces-basic.hpp @@ -1,4 +1,4 @@ -// bindgen-flags: --enable-cxx-namespaces --whitelist-type outer_inner_Helper +// bindgen-flags: --enable-cxx-namespaces --whitelist-type outer::inner::Helper namespace outer { namespace inner { |