Skip to content

Include namespaces in mangled symbols #281

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 2 commits into from
Nov 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
260 changes: 130 additions & 130 deletions libbindgen/src/ir/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

use clang;
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
use regex::Regex;
use std::cell::{Cell, RefCell};
use std::fmt::Write;
use super::annotations::Annotations;
use super::context::{BindgenContext, ItemId};
use super::function::Function;
Expand Down Expand Up @@ -490,7 +490,8 @@ impl Item {
}
}

fn is_module(&self) -> bool {
/// Is this item a module?
pub fn is_module(&self) -> bool {
match self.kind {
ItemKind::Module(..) => true,
_ => false,
Expand Down Expand Up @@ -525,6 +526,108 @@ impl Item {
self.as_type().map_or(false, |ty| ty.is_type_ref())
}

/// Get the target item id for name generation.
fn name_target(&self, ctx: &BindgenContext, for_name_checking: bool) -> ItemId {
let mut item = self;
loop {
match *item.kind() {
ItemKind::Type(ref ty) => {
match *ty.kind() {
// If we're a template specialization, our name is our
// parent's name.
TypeKind::Comp(ref ci) if ci.is_template_specialization() => {
item = ctx.resolve_item(ci.specialized_template().unwrap());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here we may be able to just do return ci.specialized_template(), this can't be recursive if I'm not wrong.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do this, but also add a debug_assert! that the specialized template's name target is itself.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion is failing in our tests, I'm going to leave the code as it was.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, which tests are failing?

},
// Same as above.
TypeKind::ResolvedTypeRef(inner) |
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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably should be able to just return inner in this case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, will try with a debug_assert!.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

assert_eq!(item.id(), item.name_target(ctx, for_name_checking));
return item.id();
}
_ => return item.id(),
}
},
_ => return item.id(),
}
}
}

/// Get this function item's name, or `None` if this item is not a function.
fn func_name(&self) -> Option<&str> {
match *self.kind() {
ItemKind::Function(ref func) => Some(func.name()),
_ => None,
}
}

/// Get the overload index for this method. If this is not a method, return
/// `None`.
fn method_overload_index(&self, ctx: &BindgenContext) -> Option<usize> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I understand why this can't be completely moved to codegen, we generate calls for it... Well looks fine :)

self.func_name().and_then(|func_name| {
let parent = ctx.resolve_item(self.parent_id());
if let ItemKind::Type(ref ty) = *parent.kind() {
if let TypeKind::Comp(ref ci) = *ty.kind() {
return ci.methods()
.iter()
.filter(|method| {
let item = ctx.resolve_item(method.signature());
let func = item.expect_function();
func.name() == func_name
})
.enumerate()
.find(|&(_, ref method)| method.signature() == self.id())
.map(|(idx, _)| idx);
}
}

None
})
}

/// 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) -> String {
match *self.kind() {
ItemKind::Var(ref var) => var.name().to_owned(),
ItemKind::Module(ref module) => {
module.name()
.map(ToOwned::to_owned)
.unwrap_or_else(|| format!("_bindgen_mod_{}", self.exposed_id(ctx)))
},
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 => Some(""),
TypeKind::TemplateAlias(..) => None,
_ => ty.name(),
};
name.map(ToOwned::to_owned)
.unwrap_or_else(|| format!("_bindgen_ty_{}", self.exposed_id(ctx)))
}
ItemKind::Function(ref fun) => {
let mut name = fun.name().to_owned();

if let Some(idx) = self.method_overload_index(ctx) {
if idx > 0 {
write!(&mut name, "{}", idx).unwrap();
}
}

name
},
}
}

/// Get the canonical name without taking into account the replaces
/// annotation.
///
Expand All @@ -538,102 +641,38 @@ impl Item {
/// type and the parent chain, since it should be consistent.
pub fn real_canonical_name(&self,
ctx: &BindgenContext,
count_namespaces: bool,
within_namespace: bool,
for_name_checking: bool)
-> String {
let base_name = match *self.kind() {
ItemKind::Type(ref ty) => {
match *ty.kind() {
// If we're a template specialization, our name is our
// parent's.
TypeKind::Comp(ref ci)
if ci.is_template_specialization() => {
return ci.specialized_template().unwrap()
.canonical_name(ctx);
},
// Same as above
TypeKind::ResolvedTypeRef(inner) |
TypeKind::TemplateRef(inner, _) => {
return inner.canonical_name(ctx);
}
// If we're a named type, we don't need to mangle it, and we
// should be able to assert we're not top level.
TypeKind::Named(ref name, _) => {
return name.to_owned();
}
// 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)
}
ItemKind::Function(ref fun) => {
let mut base = fun.name().to_owned();

// We might need to deduplicate if we're a method.
let parent = ctx.resolve_item(self.parent_id());
if let ItemKind::Type(ref ty) = *parent.kind() {
if let TypeKind::Comp(ref ci) = *ty.kind() {
let mut count = 0;
let mut found = false;
for method in ci.methods() {
if method.signature() == self.id() {
found = true;
break;
}
let fun = ctx.resolve_item(method.signature())
.expect_function();
if fun.name() == base {
count += 1;
}
}

assert!(found, "Method not found?");
if count != 0 {
base.push_str(&count.to_string());
}
}
}
Some(base)
}
ItemKind::Var(ref var) => Some(var.name().to_owned()),
ItemKind::Module(ref module) => {
module.name().map(ToOwned::to_owned)
}
};
let target = ctx.resolve_item(self.name_target(ctx, for_name_checking));
let base_name = target.base_name(ctx, for_name_checking);

let parent = ctx.resolve_item(self.parent_id());
let parent_is_namespace = parent.is_module();
// Named template type arguments are never namespaced, and never
// mangled.
if target.as_type().map_or(false, |ty| ty.is_named()) {
return base_name;
}

if self.is_toplevel(ctx) || (parent_is_namespace && count_namespaces) {
let base_name = self.make_exposed_name(None, base_name, ctx);
if within_namespace {
return ctx.rust_mangle(&base_name).into_owned();
}

// TODO: allow modification of the mangling functions, maybe even per
// item type?
let parent_name = parent.canonical_name(ctx);
self.make_exposed_name(Some(parent_name), base_name, ctx)
// Concatenate this item's ancestors' names together.
let mut names: Vec<_> = target.parent_id()
.ancestors(ctx)
.filter(|id| *id != ctx.root_module())
.map(|id| {
let item = ctx.resolve_item(id);
let target = ctx.resolve_item(item.name_target(ctx, false));
target.base_name(ctx, false)
})
.filter(|name| !name.is_empty())
.collect();
names.reverse();
names.push(base_name);
let name = names.join("_");

ctx.rust_mangle(&name).into_owned()
}

fn exposed_id(&self, ctx: &BindgenContext) -> String {
Expand All @@ -654,45 +693,6 @@ impl Item {
format!("id_{}", self.id().as_usize())
}

fn make_exposed_name(&self,
parent_name: Option<String>,
base_name: Option<String>,
ctx: &BindgenContext)
-> String {
lazy_static! {
static ref RE_ENDS_WITH_BINDGEN_TY: Regex =
Regex::new(r"_bindgen_ty(_\d+)+$").unwrap();

static ref RE_ENDS_WITH_BINDGEN_MOD: Regex =
Regex::new(r"_bindgen_mod(_\d+)+$").unwrap();
}

let (re, kind) = match *self.kind() {
ItemKind::Module(..) => (&*RE_ENDS_WITH_BINDGEN_MOD, "mod"),
_ => (&*RE_ENDS_WITH_BINDGEN_TY, "ty"),
};

let parent_name =
parent_name.and_then(|n| if n.is_empty() { None } else { Some(n) });
match (parent_name, base_name) {
(Some(parent), Some(base)) => format!("{}_{}", parent, base),
(Some(parent), None) => {
if re.is_match(parent.as_str()) {
format!("{}_{}", parent, self.exposed_id(ctx))
} else {
format!("{}__bindgen_{}_{}",
parent,
kind,
self.exposed_id(ctx))
}
}
(None, Some(base)) => base,
(None, None) => {
format!("_bindgen_{}_{}", kind, self.exposed_id(ctx))
}
}
}

/// Get a mutable reference to this item's `Module`, or `None` if this is
/// not a `Module` item.
pub fn as_module_mut(&mut self) -> Option<&mut Module> {
Expand Down
28 changes: 16 additions & 12 deletions libbindgen/tests/expectations/tests/class_with_inner_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,38 +129,42 @@ pub struct C {
#[repr(C)]
#[derive(Debug, Copy)]
pub struct C__bindgen_ty_1 {
pub mFunc: __BindgenUnionField<C__bindgen_ty_1_1>,
pub __bindgen_anon_1: __BindgenUnionField<C__bindgen_ty_1_2>,
pub mFunc: __BindgenUnionField<C__bindgen_ty_1__bindgen_ty_1>,
pub __bindgen_anon_1: __BindgenUnionField<C__bindgen_ty_1__bindgen_ty_2>,
pub bindgen_union_field: [u32; 4usize],
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct C__bindgen_ty_1_1 {
pub struct C__bindgen_ty_1__bindgen_ty_1 {
pub mX1: f32,
pub mY1: f32,
pub mX2: f32,
pub mY2: f32,
}
#[test]
fn bindgen_test_layout_C__bindgen_ty_1_1() {
assert_eq!(::std::mem::size_of::<C__bindgen_ty_1_1>() , 16usize);
assert_eq!(::std::mem::align_of::<C__bindgen_ty_1_1>() , 4usize);
fn bindgen_test_layout_C__bindgen_ty_1__bindgen_ty_1() {
assert_eq!(::std::mem::size_of::<C__bindgen_ty_1__bindgen_ty_1>() ,
16usize);
assert_eq!(::std::mem::align_of::<C__bindgen_ty_1__bindgen_ty_1>() ,
4usize);
}
impl Clone for C__bindgen_ty_1_1 {
impl Clone for C__bindgen_ty_1__bindgen_ty_1 {
fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct C__bindgen_ty_1_2 {
pub struct C__bindgen_ty_1__bindgen_ty_2 {
pub mStepSyntax: StepSyntax,
pub mSteps: ::std::os::raw::c_uint,
}
#[test]
fn bindgen_test_layout_C__bindgen_ty_1_2() {
assert_eq!(::std::mem::size_of::<C__bindgen_ty_1_2>() , 8usize);
assert_eq!(::std::mem::align_of::<C__bindgen_ty_1_2>() , 4usize);
fn bindgen_test_layout_C__bindgen_ty_1__bindgen_ty_2() {
assert_eq!(::std::mem::size_of::<C__bindgen_ty_1__bindgen_ty_2>() ,
8usize);
assert_eq!(::std::mem::align_of::<C__bindgen_ty_1__bindgen_ty_2>() ,
4usize);
}
impl Clone for C__bindgen_ty_1_2 {
impl Clone for C__bindgen_ty_1__bindgen_ty_2 {
fn clone(&self) -> Self { *self }
}
#[test]
Expand Down
4 changes: 2 additions & 2 deletions libbindgen/tests/expectations/tests/elaborated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
#![allow(non_snake_case)]


pub type whatever_t = ::std::os::raw::c_int;
pub type whatever_whatever_t = ::std::os::raw::c_int;
extern "C" {
#[link_name = "_Z9somethingPKi"]
pub fn something(wat: *const whatever_t);
pub fn something(wat: *const whatever_whatever_t);
}
2 changes: 1 addition & 1 deletion libbindgen/tests/expectations/tests/inherit-namespaced.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct RootedBase<T> {
pub struct js_RootedBase<T> {
pub _address: u8,
pub _phantom_0: ::std::marker::PhantomData<T>,
}
Expand Down
Loading