Skip to content

Commit 2a93411

Browse files
committed
Include namespaces in mangled symbols
When we aren't using `--enable-cxx-namespaces`, we can end up with conflicting struct symbol names that we need to disambiguate. The solution is to mangle the namespaced C++ symbol "foo::bar::Baz" into the Rust "foo_bar_Baz" symbol.
1 parent 0e96de1 commit 2a93411

14 files changed

+253
-202
lines changed

libbindgen/src/ir/item.rs

Lines changed: 128 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
33
use clang;
44
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
5-
use regex::Regex;
65
use std::cell::{Cell, RefCell};
6+
use std::fmt::Write;
77
use super::annotations::Annotations;
88
use super::context::{BindgenContext, ItemId};
99
use super::function::Function;
@@ -526,6 +526,108 @@ impl Item {
526526
self.as_type().map_or(false, |ty| ty.is_type_ref())
527527
}
528528

529+
/// Get the target item id for name generation.
530+
fn name_target(&self, ctx: &BindgenContext, for_name_checking: bool) -> ItemId {
531+
let mut item = self;
532+
loop {
533+
match *item.kind() {
534+
ItemKind::Type(ref ty) => {
535+
match *ty.kind() {
536+
// If we're a template specialization, our name is our
537+
// parent's name.
538+
TypeKind::Comp(ref ci) if ci.is_template_specialization() => {
539+
item = ctx.resolve_item(ci.specialized_template().unwrap());
540+
},
541+
// Same as above.
542+
TypeKind::ResolvedTypeRef(inner) |
543+
TypeKind::TemplateRef(inner, _) => {
544+
item = ctx.resolve_item(inner);
545+
}
546+
// Template aliases use their inner alias type's name if we
547+
// are checking names for whitelisting/replacement/etc.
548+
TypeKind::TemplateAlias(inner, _) if for_name_checking => {
549+
item = ctx.resolve_item(inner);
550+
assert_eq!(item.id(), item.name_target(ctx, for_name_checking));
551+
return item.id();
552+
}
553+
_ => return item.id(),
554+
}
555+
},
556+
_ => return item.id(),
557+
}
558+
}
559+
}
560+
561+
/// Get this function item's name, or `None` if this item is not a function.
562+
fn func_name(&self) -> Option<&str> {
563+
match *self.kind() {
564+
ItemKind::Function(ref func) => Some(func.name()),
565+
_ => None,
566+
}
567+
}
568+
569+
/// Get the overload index for this method. If this is not a method, return
570+
/// `None`.
571+
fn method_overload_index(&self, ctx: &BindgenContext) -> Option<usize> {
572+
self.func_name().and_then(|func_name| {
573+
let parent = ctx.resolve_item(self.parent_id());
574+
if let ItemKind::Type(ref ty) = *parent.kind() {
575+
if let TypeKind::Comp(ref ci) = *ty.kind() {
576+
return ci.methods()
577+
.iter()
578+
.filter(|method| {
579+
let item = ctx.resolve_item(method.signature());
580+
let func = item.expect_function();
581+
func.name() == func_name
582+
})
583+
.enumerate()
584+
.find(|&(_, ref method)| method.signature() == self.id())
585+
.map(|(idx, _)| idx);
586+
}
587+
}
588+
589+
None
590+
})
591+
}
592+
593+
/// Get this item's base name (aka non-namespaced name).
594+
///
595+
/// The `for_name_checking` boolean parameter informs us whether we are
596+
/// asking for the name in order to do a whitelisting/replacement/etc check
597+
/// or if we are instead using it for code generation.
598+
fn base_name(&self, ctx: &BindgenContext, for_name_checking: bool) -> String {
599+
match *self.kind() {
600+
ItemKind::Var(ref var) => var.name().to_owned(),
601+
ItemKind::Module(ref module) => {
602+
module.name()
603+
.map(ToOwned::to_owned)
604+
.unwrap_or_else(|| format!("_bindgen_mod_{}", self.exposed_id(ctx)))
605+
},
606+
ItemKind::Type(ref ty) => {
607+
let name = match *ty.kind() {
608+
TypeKind::ResolvedTypeRef(..) =>
609+
panic!("should have resolved this in name_target()"),
610+
TypeKind::TemplateAlias(..) if !for_name_checking => Some(""),
611+
TypeKind::TemplateAlias(..) => None,
612+
_ => ty.name(),
613+
};
614+
name.map(ToOwned::to_owned)
615+
.unwrap_or_else(|| format!("_bindgen_ty_{}", self.exposed_id(ctx)))
616+
}
617+
ItemKind::Function(ref fun) => {
618+
let mut name = fun.name().to_owned();
619+
620+
if let Some(idx) = self.method_overload_index(ctx) {
621+
if idx > 0 {
622+
write!(&mut name, "{}", idx).unwrap();
623+
}
624+
}
625+
626+
name
627+
},
628+
}
629+
}
630+
529631
/// Get the canonical name without taking into account the replaces
530632
/// annotation.
531633
///
@@ -539,102 +641,38 @@ impl Item {
539641
/// type and the parent chain, since it should be consistent.
540642
pub fn real_canonical_name(&self,
541643
ctx: &BindgenContext,
542-
count_namespaces: bool,
644+
within_namespace: bool,
543645
for_name_checking: bool)
544646
-> String {
545-
let base_name = match *self.kind() {
546-
ItemKind::Type(ref ty) => {
547-
match *ty.kind() {
548-
// If we're a template specialization, our name is our
549-
// parent's.
550-
TypeKind::Comp(ref ci)
551-
if ci.is_template_specialization() => {
552-
return ci.specialized_template().unwrap()
553-
.canonical_name(ctx);
554-
},
555-
// Same as above
556-
TypeKind::ResolvedTypeRef(inner) |
557-
TypeKind::TemplateRef(inner, _) => {
558-
return inner.canonical_name(ctx);
559-
}
560-
// If we're a named type, we don't need to mangle it, and we
561-
// should be able to assert we're not top level.
562-
TypeKind::Named(ref name, _) => {
563-
return name.to_owned();
564-
}
565-
// We call codegen on the inner type, but we do not want
566-
// this alias's name to appear in the canonical name just
567-
// because it is in the inner type's parent chain, so we use
568-
// an empty base name.
569-
//
570-
// Note that this would be incorrect if this type could be
571-
// referenced from, let's say, a member variable, but in
572-
// that case the referenced type is the inner alias, so
573-
// we're good there. If we wouldn't, a more complex solution
574-
// would be needed.
575-
TypeKind::TemplateAlias(inner, _) => {
576-
if for_name_checking {
577-
return ctx.resolve_item(inner)
578-
.real_canonical_name(ctx,
579-
count_namespaces,
580-
false);
581-
}
582-
Some("")
583-
}
584-
// Else use the proper name, or fallback to a name with an
585-
// id.
586-
_ => {
587-
ty.name()
588-
}
589-
}.map(ToOwned::to_owned)
590-
}
591-
ItemKind::Function(ref fun) => {
592-
let mut base = fun.name().to_owned();
593-
594-
// We might need to deduplicate if we're a method.
595-
let parent = ctx.resolve_item(self.parent_id());
596-
if let ItemKind::Type(ref ty) = *parent.kind() {
597-
if let TypeKind::Comp(ref ci) = *ty.kind() {
598-
let mut count = 0;
599-
let mut found = false;
600-
for method in ci.methods() {
601-
if method.signature() == self.id() {
602-
found = true;
603-
break;
604-
}
605-
let fun = ctx.resolve_item(method.signature())
606-
.expect_function();
607-
if fun.name() == base {
608-
count += 1;
609-
}
610-
}
611-
612-
assert!(found, "Method not found?");
613-
if count != 0 {
614-
base.push_str(&count.to_string());
615-
}
616-
}
617-
}
618-
Some(base)
619-
}
620-
ItemKind::Var(ref var) => Some(var.name().to_owned()),
621-
ItemKind::Module(ref module) => {
622-
module.name().map(ToOwned::to_owned)
623-
}
624-
};
647+
let target = ctx.resolve_item(self.name_target(ctx, for_name_checking));
648+
let base_name = target.base_name(ctx, for_name_checking);
625649

626-
let parent = ctx.resolve_item(self.parent_id());
627-
let parent_is_namespace = parent.is_module();
650+
// Named template type arguments are never namespaced, and never
651+
// mangled.
652+
if target.as_type().map_or(false, |ty| ty.is_named()) {
653+
return base_name;
654+
}
628655

629-
if self.is_toplevel(ctx) || (parent_is_namespace && count_namespaces) {
630-
let base_name = self.make_exposed_name(None, base_name, ctx);
656+
if within_namespace {
631657
return ctx.rust_mangle(&base_name).into_owned();
632658
}
633659

634-
// TODO: allow modification of the mangling functions, maybe even per
635-
// item type?
636-
let parent_name = parent.canonical_name(ctx);
637-
self.make_exposed_name(Some(parent_name), base_name, ctx)
660+
// Concatenate this item's ancestors' names together.
661+
let mut names: Vec<_> = target.parent_id()
662+
.ancestors(ctx)
663+
.filter(|id| *id != ctx.root_module())
664+
.map(|id| {
665+
let item = ctx.resolve_item(id);
666+
let target = ctx.resolve_item(item.name_target(ctx, false));
667+
target.base_name(ctx, false)
668+
})
669+
.filter(|name| !name.is_empty())
670+
.collect();
671+
names.reverse();
672+
names.push(base_name);
673+
let name = names.join("_");
674+
675+
ctx.rust_mangle(&name).into_owned()
638676
}
639677

640678
fn exposed_id(&self, ctx: &BindgenContext) -> String {
@@ -655,45 +693,6 @@ impl Item {
655693
format!("id_{}", self.id().as_usize())
656694
}
657695

658-
fn make_exposed_name(&self,
659-
parent_name: Option<String>,
660-
base_name: Option<String>,
661-
ctx: &BindgenContext)
662-
-> String {
663-
lazy_static! {
664-
static ref RE_ENDS_WITH_BINDGEN_TY: Regex =
665-
Regex::new(r"_bindgen_ty(_\d+)+$").unwrap();
666-
667-
static ref RE_ENDS_WITH_BINDGEN_MOD: Regex =
668-
Regex::new(r"_bindgen_mod(_\d+)+$").unwrap();
669-
}
670-
671-
let (re, kind) = match *self.kind() {
672-
ItemKind::Module(..) => (&*RE_ENDS_WITH_BINDGEN_MOD, "mod"),
673-
_ => (&*RE_ENDS_WITH_BINDGEN_TY, "ty"),
674-
};
675-
676-
let parent_name =
677-
parent_name.and_then(|n| if n.is_empty() { None } else { Some(n) });
678-
match (parent_name, base_name) {
679-
(Some(parent), Some(base)) => format!("{}_{}", parent, base),
680-
(Some(parent), None) => {
681-
if re.is_match(parent.as_str()) {
682-
format!("{}_{}", parent, self.exposed_id(ctx))
683-
} else {
684-
format!("{}__bindgen_{}_{}",
685-
parent,
686-
kind,
687-
self.exposed_id(ctx))
688-
}
689-
}
690-
(None, Some(base)) => base,
691-
(None, None) => {
692-
format!("_bindgen_{}_{}", kind, self.exposed_id(ctx))
693-
}
694-
}
695-
}
696-
697696
/// Get a mutable reference to this item's `Module`, or `None` if this is
698697
/// not a `Module` item.
699698
pub fn as_module_mut(&mut self) -> Option<&mut Module> {

libbindgen/tests/expectations/tests/class_with_inner_struct.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -129,38 +129,42 @@ pub struct C {
129129
#[repr(C)]
130130
#[derive(Debug, Copy)]
131131
pub struct C__bindgen_ty_1 {
132-
pub mFunc: __BindgenUnionField<C__bindgen_ty_1_1>,
133-
pub __bindgen_anon_1: __BindgenUnionField<C__bindgen_ty_1_2>,
132+
pub mFunc: __BindgenUnionField<C__bindgen_ty_1__bindgen_ty_1>,
133+
pub __bindgen_anon_1: __BindgenUnionField<C__bindgen_ty_1__bindgen_ty_2>,
134134
pub bindgen_union_field: [u32; 4usize],
135135
}
136136
#[repr(C)]
137137
#[derive(Debug, Copy)]
138-
pub struct C__bindgen_ty_1_1 {
138+
pub struct C__bindgen_ty_1__bindgen_ty_1 {
139139
pub mX1: f32,
140140
pub mY1: f32,
141141
pub mX2: f32,
142142
pub mY2: f32,
143143
}
144144
#[test]
145-
fn bindgen_test_layout_C__bindgen_ty_1_1() {
146-
assert_eq!(::std::mem::size_of::<C__bindgen_ty_1_1>() , 16usize);
147-
assert_eq!(::std::mem::align_of::<C__bindgen_ty_1_1>() , 4usize);
145+
fn bindgen_test_layout_C__bindgen_ty_1__bindgen_ty_1() {
146+
assert_eq!(::std::mem::size_of::<C__bindgen_ty_1__bindgen_ty_1>() ,
147+
16usize);
148+
assert_eq!(::std::mem::align_of::<C__bindgen_ty_1__bindgen_ty_1>() ,
149+
4usize);
148150
}
149-
impl Clone for C__bindgen_ty_1_1 {
151+
impl Clone for C__bindgen_ty_1__bindgen_ty_1 {
150152
fn clone(&self) -> Self { *self }
151153
}
152154
#[repr(C)]
153155
#[derive(Debug, Copy)]
154-
pub struct C__bindgen_ty_1_2 {
156+
pub struct C__bindgen_ty_1__bindgen_ty_2 {
155157
pub mStepSyntax: StepSyntax,
156158
pub mSteps: ::std::os::raw::c_uint,
157159
}
158160
#[test]
159-
fn bindgen_test_layout_C__bindgen_ty_1_2() {
160-
assert_eq!(::std::mem::size_of::<C__bindgen_ty_1_2>() , 8usize);
161-
assert_eq!(::std::mem::align_of::<C__bindgen_ty_1_2>() , 4usize);
161+
fn bindgen_test_layout_C__bindgen_ty_1__bindgen_ty_2() {
162+
assert_eq!(::std::mem::size_of::<C__bindgen_ty_1__bindgen_ty_2>() ,
163+
8usize);
164+
assert_eq!(::std::mem::align_of::<C__bindgen_ty_1__bindgen_ty_2>() ,
165+
4usize);
162166
}
163-
impl Clone for C__bindgen_ty_1_2 {
167+
impl Clone for C__bindgen_ty_1__bindgen_ty_2 {
164168
fn clone(&self) -> Self { *self }
165169
}
166170
#[test]

libbindgen/tests/expectations/tests/elaborated.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
#![allow(non_snake_case)]
55

66

7-
pub type whatever_t = ::std::os::raw::c_int;
7+
pub type whatever_whatever_t = ::std::os::raw::c_int;
88
extern "C" {
99
#[link_name = "_Z9somethingPKi"]
10-
pub fn something(wat: *const whatever_t);
10+
pub fn something(wat: *const whatever_whatever_t);
1111
}

libbindgen/tests/expectations/tests/inherit-namespaced.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
#[repr(C)]
88
#[derive(Debug, Copy, Clone)]
9-
pub struct RootedBase<T> {
9+
pub struct js_RootedBase<T> {
1010
pub _address: u8,
1111
pub _phantom_0: ::std::marker::PhantomData<T>,
1212
}

0 commit comments

Comments
 (0)