diff --git a/src/bin/bindgen.rs b/src/bin/bindgen.rs index 2e31983e1f..759baa0517 100644 --- a/src/bin/bindgen.rs +++ b/src/bin/bindgen.rs @@ -18,11 +18,11 @@ struct StdLogger; impl Logger for StdLogger { fn error(&self, msg: &str) { - error!("{}", msg); + println!("{}", msg); } fn warn(&self, msg: &str) { - warn!("{}", msg); + println!("{}", msg); } } @@ -99,6 +99,10 @@ fn parse_args(args: &[String]) -> ParseResult { options.builtins = true; ix += 1; } + "-ignore-functions" => { + options.ignore_functions = true; + ix += 1; + } "-allow-unknown-types" => { options.fail_on_unknown_type = false; ix += 1; @@ -110,6 +114,10 @@ fn parse_args(args: &[String]) -> ParseResult { options.override_enum_ty = args[ix + 1].clone(); ix += 2; } + "-enable-cxx-namespaces" => { + options.enable_cxx_namespaces = true; + ix += 1; + } _ => { options.clang_args.push(args[ix].clone()); ix += 1; @@ -138,6 +146,8 @@ Options: matching any rule are bound to. -builtins Output bindings for builtin definitions (for example __builtin_va_list) + -ignore-functions Don't generate bindings for functions and methods. + This is useful when you only care about struct layouts. -allow-unknown-types Don't fail if we encounter types we do not support, instead treat them as void -emit-clang-ast Output the ast (for debugging purposes) diff --git a/src/clang.rs b/src/clang.rs index 5d49f41c34..7aad4f7e65 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -37,6 +37,12 @@ impl Cursor { mangling } + pub fn semantic_parent(&self) -> Cursor { + unsafe { + Cursor { x: clang_getCursorSemanticParent(self.x) } + } + } + pub fn kind(&self) -> Enum_CXCursorKind { unsafe { clang_getCursorKind(self.x) @@ -246,7 +252,7 @@ pub struct Type { impl Type { // common pub fn kind(&self) -> Enum_CXTypeKind { - return self.x.kind; + self.x.kind } pub fn declaration(&self) -> Cursor { @@ -334,7 +340,7 @@ impl Type { for i in 0..num { args.push(Type { x: clang_getArgType(self.x, i as c_uint) }); } - return args; + args } } diff --git a/src/clangll.rs b/src/clangll.rs index 1cef3d14f6..e32e99fd34 100644 --- a/src/clangll.rs +++ b/src/clangll.rs @@ -5,7 +5,6 @@ #![allow(unused_attributes)] #![allow(non_snake_case)] #![allow(non_upper_case_globals)] -#![allow(raw_pointer_derive)] pub type ptrdiff_t = ::libc::c_long; pub type size_t = ::libc::c_ulong; diff --git a/src/gen.rs b/src/gen.rs index ae56e3af97..c5ebbb651c 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -2,8 +2,6 @@ use std::cell::RefCell; use std::vec::Vec; use std::rc::Rc; use std::collections::HashMap; -use std::collections::hash_map::Entry; - use syntax::abi; use syntax::ast; use syntax::codemap::{Span, Spanned, respan, ExpnInfo, NameAndSpan, MacroBang}; @@ -24,12 +22,38 @@ use types::*; struct GenCtx<'r> { ext_cx: base::ExtCtxt<'r>, - unnamed_ty: usize, - span: Span + span: Span, + module_map: ModuleMap, + enable_cxx_namespaces: bool, + current_module_id: ModuleId, +} + +impl<'r> GenCtx<'r> { + fn full_path_for_module(&self, id: ModuleId) -> Vec { + if !self.enable_cxx_namespaces { + return vec![]; + } + + let mut ret = vec![]; + + let mut current_id = Some(id); + while let Some(current) = current_id { + let module = &self.module_map.get(¤t).unwrap(); + ret.push(module.name.clone()); + current_id = module.parent_id; + } + + if self.current_module_id == ROOT_MODULE_ID { + ret.pop(); // The root module doens'n need a root:: in the pattern + } + + ret.reverse(); + ret + } } fn first((val, _): (A, B)) -> A { - return val; + val } fn ref_eq<'a, 'b, T>(thing: &'a T, other: &'b T) -> bool { @@ -47,78 +71,48 @@ fn empty_generics() -> ast::Generics { } } -fn rust_id(ctx: &mut GenCtx, name: String) -> (String, bool) { - let token = parse::token::Ident(ctx.ext_cx.ident_of(&name), parse::token::Plain); - if token.is_any_keyword() || "bool" == &name { +fn rust_id(ctx: &mut GenCtx, name: &str) -> (String, bool) { + let token = parse::token::Ident(ctx.ext_cx.ident_of(name), parse::token::Plain); + if token.is_any_keyword() || "bool" == name { let mut s = "_".to_string(); - s.push_str(&name); + s.push_str(name); (s, true) } else { - (name, false) + (name.to_owned(), false) } } -fn rust_type_id(ctx: &mut GenCtx, name: String) -> String { - if "bool" == name || - "uint" == name || - "u8" == name || - "u16" == name || - "u32" == name || - "f32" == name || - "f64" == name || - "i8" == name || - "i16" == name || - "i32" == name || - "i64" == name || - "Self" == name || - "str" == name { - let mut s = "_".to_string(); - s.push_str(&name); - s - } else { - match name.as_str() { - "int8_t" => "i8".to_string(), - "uint8_t" => "u8".to_string(), - "int16_t" => "i16".to_string(), - "uint16_t" => "u16".to_string(), - "int32_t" => "i32".to_string(), - "uint32_t" => "u32".to_string(), - "int64_t" => "i64".to_string(), - "uint64_t" => "u64".to_string(), - _ => { - let (n, _) = rust_id(ctx, name); - n - } +fn rust_type_id(ctx: &mut GenCtx, name: &str) -> String { + match name { + "bool" | "uint" | "u8" | "u16" | + "u32" | "f32" | "f64" | "i8" | + "i16" | "i32" | "i64" | "Self" | + "str" => { + let mut s = "_".to_string(); + s.push_str(name); + s } + _ => first(rust_id(ctx, name)) } } -fn unnamed_name(ctx: &mut GenCtx, name: String, filename: String) -> String { - return if name.is_empty() { - ctx.unnamed_ty += 1; - format!("{}_unnamed_{}", filename, ctx.unnamed_ty) - } else { - name - }; -} - -fn comp_name(kind: CompKind, name: &String) -> String { +fn comp_name(kind: CompKind, name: &str) -> String { match kind { CompKind::Struct => struct_name(name), CompKind::Union => union_name(name), } } -fn struct_name(name: &String) -> String { - format!("{}", name) +fn struct_name(name: &str) -> String { + name.to_owned() } -fn union_name(name: &String) -> String { - format!("{}", name) +fn union_name(name: &str) -> String { + name.to_owned() } -fn enum_name(name: &String) -> String { - format!("{}", name) +fn enum_name(name: &str) -> String { + name.to_owned() } fn gen_unmangle_method(ctx: &mut GenCtx, @@ -158,7 +152,7 @@ fn gen_unmangle_method(ctx: &mut GenCtx, unnamed += 1; format!("arg{}", unnamed) } else { - rust_id(ctx, n.clone()).0 + first(rust_id(ctx, &n)) }; let expr = ast::Expr { id: ast::DUMMY_NODE_ID, @@ -228,7 +222,7 @@ fn gen_unmangle_method(ctx: &mut GenCtx, count += 1; counts.insert(v.name.clone(), count); - let mut attrs = mk_doc_attr(ctx, v.comment.clone()); + let mut attrs = mk_doc_attr(ctx, &v.comment); attrs.push(respan(ctx.span, ast::Attribute_ { id: mk_attr_id(), style: ast::AttrStyle::Outer, @@ -248,12 +242,15 @@ fn gen_unmangle_method(ctx: &mut GenCtx, P(item) } -pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> Vec> { +pub fn gen_mods(links: &[(String, LinkType)], + map: ModuleMap, + enable_namespaces: bool, + span: Span) -> Vec> { // Create a dummy ExtCtxt. We only need this for string interning and that uses TLS. let mut features = Features::new(); features.allow_quote = true; let cfg = ExpansionConfig { - crate_name: "xxx".to_string(), + crate_name: "xxx".to_owned(), features: Some(&features), recursion_limit: 64, trace_mac: false, @@ -262,9 +259,12 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> let mut feature_gated_cfgs = vec![]; let mut ctx = GenCtx { ext_cx: base::ExtCtxt::new(sess, Vec::new(), cfg, &mut feature_gated_cfgs), - unnamed_ty: 0, - span: span + span: span, + module_map: map, + enable_cxx_namespaces: enable_namespaces, + current_module_id: ROOT_MODULE_ID, }; + ctx.ext_cx.bt_push(ExpnInfo { call_site: ctx.span, callee: NameAndSpan { @@ -273,6 +273,115 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> span: None } }); + + if let Some(root_mod) = gen_mod(&mut ctx, ROOT_MODULE_ID, links, span) { + if !ctx.enable_cxx_namespaces { + match root_mod.node { + // XXX This clone might be really expensive, but doing: + // ast::ItemMod(ref mut root) => { + // return ::std::mem::replace(&mut root.items, vec![]); + // } + // fails with "error: cannot borrow immutable anonymous field as mutable". + // So... + ast::ItemMod(ref root) => { + return root.items.clone() + } + _ => unreachable!(), + } + } + + let root_export = P(ast::Item { + ident: ctx.ext_cx.ident_of(""), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemUse(P( + Spanned { + node: ast::ViewPathGlob(ast::Path { + span: span.clone(), + global: false, + segments: vec![ast::PathSegment { + identifier: root_mod.ident, + parameters: ast::PathParameters::none(), + }] + }), + span: span.clone(), + })), + vis: ast::Public, + span: span.clone(), + }); + + vec![root_export, root_mod] + } else { + vec![] + } +} + +fn gen_mod(mut ctx: &mut GenCtx, + module_id: ModuleId, + links: &[(String, LinkType)], + span: Span) -> Option> { + + // XXX avoid this clone + let module = ctx.module_map.get(&module_id).unwrap().clone(); + + // Import just the root to minimise name conflicts + let mut globals = if module_id != ROOT_MODULE_ID { + // XXX Pass this previously instead of looking it up always? + let root = ctx.ext_cx.ident_of(&ctx.module_map.get(&ROOT_MODULE_ID).unwrap().name); + vec![P(ast::Item { + ident: ctx.ext_cx.ident_of(""), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemUse(P( + Spanned { + node: ast::ViewPathSimple(root.clone(), + ast::Path { + span: span.clone(), + global: false, + segments: vec![ast::PathSegment { + identifier: root, + parameters: ast::PathParameters::none(), + }] + }), + span: span.clone(), + })), + vis: ast::Public, + span: span.clone(), + })] + } else { + vec![] + }; + + ctx.current_module_id = module_id; + + globals.extend(gen_globals(&mut ctx, links, &module.globals).into_iter()); + + globals.extend(module.children_ids.iter().filter_map(|id| { + gen_mod(ctx, *id, links, span.clone()) + })); + + if !globals.is_empty() { + Some(P(ast::Item { + ident: ctx.ext_cx.ident_of(&module.name), + attrs: vec![], + id: ast::DUMMY_NODE_ID, + node: ast::ItemMod(ast::Mod { + inner: span, + items: globals, + }), + vis: ast::Public, + span: span.clone(), + })) + } else { + None + } +} + + + +fn gen_globals(mut ctx: &mut GenCtx, + links: &[(String, LinkType)], + globs: &[Global]) -> Vec> { let uniq_globs = tag_dup_decl(globs); let mut fs = vec!(); @@ -309,51 +418,35 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> match g { GType(ti) => { let t = ti.borrow().clone(); - defs.extend(ctypedef_to_rs(&mut ctx, t.name.clone(), t.comment.clone(), &t.ty).into_iter()) + defs.extend(ctypedef_to_rs(&mut ctx, t).into_iter()) }, GCompDecl(ci) => { - { - let mut c = ci.borrow_mut(); - c.name = unnamed_name(&mut ctx, c.name.clone(), c.filename.clone()); - } let c = ci.borrow().clone(); defs.push(opaque_to_rs(&mut ctx, comp_name(c.kind, &c.name))); }, GComp(ci) => { - { - let mut c = ci.borrow_mut(); - c.name = unnamed_name(&mut ctx, c.name.clone(), c.filename.clone()); - } let c = ci.borrow().clone(); defs.extend(comp_to_rs(&mut ctx, comp_name(c.kind, &c.name), c).into_iter()) }, GEnumDecl(ei) => { - { - let mut e = ei.borrow_mut(); - e.name = unnamed_name(&mut ctx, e.name.clone(), e.filename.clone()); - } let e = ei.borrow().clone(); defs.push(opaque_to_rs(&mut ctx, enum_name(&e.name))); }, GEnum(ei) => { - { - let mut e = ei.borrow_mut(); - e.name = unnamed_name(&mut ctx, e.name.clone(), e.filename.clone()); - } let e = ei.borrow().clone(); defs.extend(cenum_to_rs(&mut ctx, enum_name(&e.name), e.comment, e.items, e.layout).into_iter()) }, GVar(vi) => { let v = vi.borrow(); - let ty = cty_to_rs(&mut ctx, &v.ty, v.is_const); + let ty = cty_to_rs(&mut ctx, &v.ty, v.is_const, true); defs.push(const_to_rs(&mut ctx, v.name.clone(), v.val.unwrap(), ty)); }, _ => { } } } - let vars = vs.into_iter().map(|v| { + let vars: Vec<_> = vs.into_iter().map(|v| { match v { GVar(vi) => { let v = vi.borrow(); @@ -397,19 +490,12 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> let mut map: HashMap> = HashMap::new(); for (abi, func) in func_list { - match map.entry(abi) { - Entry::Occupied(mut occ) => { - occ.get_mut().push(func); - } - Entry::Vacant(vac) => { - vac.insert(vec!(func)); - } - } + map.entry(abi).or_insert(vec![]).push(func); } map }; - if !Vec::is_empty(&vars) { + if !vars.is_empty() { defs.push(mk_extern(&mut ctx, links, vars, abi::C)); } @@ -425,37 +511,33 @@ pub fn gen_mod(links: &[(String, LinkType)], globs: Vec, span: Span) -> fn mk_extern(ctx: &mut GenCtx, links: &[(String, LinkType)], foreign_items: Vec>, abi: abi::Abi) -> P { - let attrs = if links.is_empty() { - Vec::new() - } else { - links.iter().map(|&(ref l, ref k)| { - let k = match k { - &LinkType::Default => None, - &LinkType::Static => Some("static"), - &LinkType::Framework => Some("framework") - }; - let link_name = P(respan(ctx.span, ast::MetaNameValue( - InternedString::new("name"), - respan(ctx.span, ast::LitStr(intern(l).as_str(), ast::CookedStr)) - ))); - let link_args = match k { - None => vec!(link_name), - Some(ref k) => vec!(link_name, P(respan(ctx.span, ast::MetaNameValue( - InternedString::new("kind"), - respan(ctx.span, ast::LitStr(intern(k).as_str(), ast::CookedStr)) - )))) - }; - respan(ctx.span, ast::Attribute_ { - id: mk_attr_id(), - style: ast::AttrStyle::Outer, - value: P(respan(ctx.span, ast::MetaList( - InternedString::new("link"), - link_args) - )), - is_sugared_doc: false - }) - }).collect() - }; + let attrs: Vec<_> = links.iter().map(|&(ref l, ref k)| { + let k = match k { + &LinkType::Default => None, + &LinkType::Static => Some("static"), + &LinkType::Framework => Some("framework") + }; + let link_name = P(respan(ctx.span, ast::MetaNameValue( + InternedString::new("name"), + respan(ctx.span, ast::LitStr(intern(l).as_str(), ast::CookedStr)) + ))); + let link_args = match k { + None => vec!(link_name), + Some(ref k) => vec!(link_name, P(respan(ctx.span, ast::MetaNameValue( + InternedString::new("kind"), + respan(ctx.span, ast::LitStr(intern(k).as_str(), ast::CookedStr)) + )))) + }; + respan(ctx.span, ast::Attribute_ { + id: mk_attr_id(), + style: ast::AttrStyle::Outer, + value: P(respan(ctx.span, ast::MetaList( + InternedString::new("link"), + link_args) + )), + is_sugared_doc: false + }) + }).collect(); let mut items = Vec::new(); items.extend(foreign_items.into_iter()); @@ -464,14 +546,14 @@ fn mk_extern(ctx: &mut GenCtx, links: &[(String, LinkType)], items: items }); - return P(ast::Item { - ident: ctx.ext_cx.ident_of(""), - attrs: attrs, - id: ast::DUMMY_NODE_ID, - node: ext, - vis: ast::Inherited, - span: ctx.span - }); + P(ast::Item { + ident: ctx.ext_cx.ident_of(""), + attrs: attrs, + id: ast::DUMMY_NODE_ID, + node: ext, + vis: ast::Inherited, + span: ctx.span + }) } fn mk_impl(ctx: &mut GenCtx, ty: P, @@ -522,12 +604,12 @@ fn remove_redundant_decl(gs: Vec) -> Vec { } ).collect(); - return gs.into_iter().filter(|g| + gs.into_iter().filter(|g| !typedefs.iter().any(|t| check_decl(g, t)) - ).collect(); + ).collect() } -fn tag_dup_decl(gs: Vec) -> Vec { +fn tag_dup_decl(gs: &[Global]) -> Vec { fn check(name1: &str, name2: &str) -> bool { !name1.is_empty() && name1 == name2 } @@ -592,7 +674,7 @@ fn tag_dup_decl(gs: Vec) -> Vec { } if gs.is_empty() { - return gs; + return vec![]; } let len = gs.len(); @@ -642,13 +724,13 @@ fn tag_dup_decl(gs: Vec) -> Vec { return res; } -fn ctypedef_to_rs(ctx: &mut GenCtx, name: String, comment: String, ty: &Type) -> Vec> { - fn mk_item(ctx: &mut GenCtx, name: String, comment: String, ty: &Type) -> P { +fn ctypedef_to_rs(ctx: &mut GenCtx, ty: TypeInfo) -> Vec> { + fn mk_item(ctx: &mut GenCtx, name: &str, comment: &str, ty: &Type) -> P { let rust_name = rust_type_id(ctx, name); let rust_ty = if cty_is_translatable(ty) { - cty_to_rs(ctx, ty, true) + cty_to_rs(ctx, ty, true, true) } else { - cty_to_rs(ctx, &TVoid, true) + cty_to_rs(ctx, &TVoid, true, true) }; let base = ast::ItemTy( P(ast::Ty { @@ -659,38 +741,26 @@ fn ctypedef_to_rs(ctx: &mut GenCtx, name: String, comment: String, ty: &Type) -> empty_generics() ); - return P(ast::Item { - ident: ctx.ext_cx.ident_of(&rust_name), - attrs: mk_doc_attr(ctx, comment), - id: ast::DUMMY_NODE_ID, - node: base, - vis: ast::Public, - span: ctx.span - }); + P(ast::Item { + ident: ctx.ext_cx.ident_of(&rust_name), + attrs: mk_doc_attr(ctx, comment), + id: ast::DUMMY_NODE_ID, + node: base, + vis: ast::Public, + span: ctx.span + }) } - return match *ty { + match ty.ty { TComp(ref ci) => { - let is_empty = ci.borrow().name.is_empty(); - if is_empty { - ci.borrow_mut().name = name.clone(); - let c = ci.borrow().clone(); - comp_to_rs(ctx, name, c) - } else { - vec!(mk_item(ctx, name, comment, ty)) - } + assert!(!ci.borrow().name.is_empty()); + vec!(mk_item(ctx, &ty.name, &ty.comment, &ty.ty)) }, TEnum(ref ei) => { - let is_empty = ei.borrow().name.is_empty(); - if is_empty { - ei.borrow_mut().name = name.clone(); - let e = ei.borrow().clone(); - cenum_to_rs(ctx, name, e.comment, e.items, e.layout) - } else { - vec!(mk_item(ctx, name, comment, ty)) - } + assert!(!ei.borrow().name.is_empty()); + vec!(mk_item(ctx, &ty.name, &ty.comment, &ty.ty)) }, - _ => vec!(mk_item(ctx, name, comment, ty)) + _ => vec!(mk_item(ctx, &ty.name, &ty.comment, &ty.ty)), } } @@ -705,7 +775,7 @@ fn comp_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec> { let layout = ci.layout; let members = &ci.members; - let args = &ci.args; + let template_args = &ci.args; let methodlist = &ci.methods; let mut fields = vec!(); let mut methods = vec!(); @@ -717,12 +787,12 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec true, _ => false }) { + template_args.iter().any(|f| f == &TVoid) { return vec!(); } - let id = rust_type_id(ctx, name.clone()); - let id_ty = P(mk_ty(ctx, false, vec!(id.clone()))); + let id = rust_type_id(ctx, &name); + let id_ty = P(mk_ty(ctx, false, &[id.clone()])); if ci.has_vtable { let mut vffields = vec!(); @@ -750,7 +820,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec Vec Vec), + ty: quote_ty!(&ctx.ext_cx, ::std::marker::PhantomData<$inner_type>), attrs: vec!(), })); } @@ -864,7 +934,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec rust_type_id(ctx, f.name.clone()) + None => rust_type_id(ctx, &f.name) }; let mut offset: u32 = 0; @@ -891,7 +961,10 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec Vec Vec { ctx.ext_cx.ident_of(&ti.borrow().name) @@ -970,7 +1043,7 @@ fn cstruct_to_rs(ctx: &mut GenCtx, name: String, ci: CompInfo) -> Vec P { empty_generics() ); - let id = rust_type_id(ctx, name); + let id = rust_type_id(ctx, &name); return P(ast::Item { ident: ctx.ext_cx.ident_of(&id), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, @@ -1056,18 +1129,19 @@ fn opaque_to_rs(ctx: &mut GenCtx, name: String) -> P { fn cunion_to_rs(ctx: &mut GenCtx, name: String, layout: Layout, members: Vec) -> Vec> { fn mk_item(ctx: &mut GenCtx, name: String, item: ast::Item_, vis: ast::Visibility, attrs: Vec) -> P { - return P(ast::Item { + P(ast::Item { ident: ctx.ext_cx.ident_of(&name), attrs: attrs, id: ast::DUMMY_NODE_ID, node: item, vis: vis, span: ctx.span - }); + }) } - let ci = Rc::new(RefCell::new(CompInfo::new(name.clone(), name.clone(), "".to_owned(), CompKind::Union, members.clone(), layout))); - let union = TNamed(Rc::new(RefCell::new(TypeInfo::new(name.clone(), TComp(ci), layout)))); + // XXX what module id is correct? + let ci = Rc::new(RefCell::new(CompInfo::new(name.clone(), ROOT_MODULE_ID, name.clone(), "".to_owned(), CompKind::Union, members.clone(), layout))); + let union = TNamed(Rc::new(RefCell::new(TypeInfo::new(name.clone(), ROOT_MODULE_ID, TComp(ci), layout)))); // Nested composites may need to emit declarations and implementations as // they are encountered. The declarations end up in 'extra' and are emitted @@ -1081,7 +1155,7 @@ fn cunion_to_rs(ctx: &mut GenCtx, name: String, layout: Layout, members: Vec P "i32", }; - let mut attrs = mk_doc_attr(ctx, comment); + let mut attrs = mk_doc_attr(ctx, &comment); attrs.push(respan(ctx.span, ast::Attribute_ { id: mk_attr_id(), style: ast::AttrStyle::Outer, @@ -1194,8 +1276,8 @@ fn gen_comp_methods(ctx: &mut GenCtx, data_field: &str, data_offset: usize, // TODO: Implement bitfield accessors if f.bitfields.is_some() { return None; } - let (f_name, _) = rust_id(ctx, f.name.clone()); - let ret_ty = P(cty_to_rs(ctx, &TPtr(Box::new(f.ty.clone()), false, false, Layout::zero()), true)); + let f_name = first(rust_id(ctx, &f.name)); + let ret_ty = P(cty_to_rs(ctx, &TPtr(Box::new(f.ty.clone()), false, false, Layout::zero()), true, true)); // When the offset is zero, generate slightly prettier code. let method = { @@ -1263,14 +1345,14 @@ fn type_for_bitfield_width(ctx: &mut GenCtx, width: u32) -> ast::Ty { } else { "bool" }; - mk_ty(ctx, false, vec!(input_type.to_string())) + mk_ty(ctx, false, &[input_type.to_owned()]) } fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &String, field_name: &String, field_type: &Type, offset: usize, width: u32) -> ast::ImplItem { let input_type = type_for_bitfield_width(ctx, width); - let field_type = cty_to_rs(ctx, &field_type, false); + let field_type = cty_to_rs(ctx, &field_type, false, true); let setter_name = ctx.ext_cx.ident_of(&format!("set_{}", field_name)); let bindgen_ident = ctx.ext_cx.ident_of(&*bindgen_name); @@ -1289,17 +1371,25 @@ fn gen_bitfield_method(ctx: &mut GenCtx, bindgen_name: &String, } fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String, - field_type: &Type, bitfields: &Vec<(String, u32)>) -> ast::ImplItem { - let field_type = cty_to_rs(ctx, field_type, false); + field_type: &Type, bitfields: &[(String, u32)]) -> ast::ImplItem { + let field_type = cty_to_rs(ctx, field_type, false, true); let mut args = vec!(); + let mut unnamed: usize = 0; for &(ref name, width) in bitfields.iter() { + let ident = if name.is_empty() { + unnamed += 1; + let dummy = format!("unnamed_bitfield{}", unnamed); + ctx.ext_cx.ident_of(&dummy) + } else { + ctx.ext_cx.ident_of(name) + }; args.push(ast::Arg { ty: P(type_for_bitfield_width(ctx, width)), pat: P(ast::Pat { id: ast::DUMMY_NODE_ID, node: ast::PatIdent( ast::BindingMode::ByValue(ast::MutImmutable), - respan(ctx.span, ctx.ext_cx.ident_of(name)), + respan(ctx.span, ident), None ), span: ctx.span @@ -1318,8 +1408,15 @@ fn gen_fullbitfield_method(ctx: &mut GenCtx, bindgen_name: &String, let mut offset = 0; let mut exprs = quote_expr!(&ctx.ext_cx, 0); + let mut unnamed: usize = 0; for &(ref name, width) in bitfields.iter() { - let name_ident = ctx.ext_cx.ident_of(&name); + let name_ident = if name.is_empty() { + unnamed += 1; + let dummy = format!("unnamed_bitfield{}", unnamed); + ctx.ext_cx.ident_of(&dummy) + } else { + ctx.ext_cx.ident_of(name) + }; exprs = quote_expr!(&ctx.ext_cx, $exprs | (($name_ident as $field_type) << $offset) ); @@ -1365,7 +1462,7 @@ fn mk_blob_field(ctx: &GenCtx, name: &str, layout: Layout) -> Spanned ast::Attribute { }) } -fn mk_doc_attr(ctx: &mut GenCtx, doc: String) -> Vec { +fn mk_doc_attr(ctx: &mut GenCtx, doc: &str) -> Vec { if doc.is_empty() { return vec!(); } let attr_val = P(respan(ctx.span, ast::MetaNameValue( InternedString::new("doc"), - respan(ctx.span, ast::LitStr(intern(&doc).as_str(), ast::CookedStr)) + respan(ctx.span, ast::LitStr(intern(doc).as_str(), ast::CookedStr)) ))); vec!(respan(ctx.span, ast::Attribute_ { @@ -1451,7 +1548,7 @@ fn cvar_to_rs(ctx: &mut GenCtx, name: String, mangled: String, ty: &Type, is_const: bool) -> P { - let (rust_name, was_mangled) = rust_id(ctx, name.clone()); + let (rust_name, was_mangled) = rust_id(ctx, &name); let mut attrs = Vec::new(); if !mangled.is_empty() { @@ -1460,7 +1557,7 @@ fn cvar_to_rs(ctx: &mut GenCtx, name: String, attrs.push(mk_link_name_attr(ctx, name)); } - let val_ty = P(cty_to_rs(ctx, ty, true)); + let val_ty = P(cty_to_rs(ctx, ty, true, true)); return P(ast::ForeignItem { ident: ctx.ext_cx.ident_of(&rust_name), @@ -1481,8 +1578,8 @@ fn cfuncty_to_rs(ctx: &mut GenCtx, TVoid => ast::DefaultReturn(ctx.span), // Disable references in returns for now TPtr(ref t, is_const, _, ref layout) => - ast::Return(P(cty_to_rs(ctx, &TPtr(t.clone(), is_const, false, layout.clone()), true))), - _ => ast::Return(P(cty_to_rs(ctx, rty, true))) + ast::Return(P(cty_to_rs(ctx, &TPtr(t.clone(), is_const, false, layout.clone()), true, true))), + _ => ast::Return(P(cty_to_rs(ctx, rty, true, true))) }; let mut unnamed: usize = 0; @@ -1493,7 +1590,7 @@ fn cfuncty_to_rs(ctx: &mut GenCtx, unnamed += 1; format!("arg{}", unnamed) } else { - first(rust_id(ctx, n.clone())) + first(rust_id(ctx, &n)) }; // From the C90 standard (http://c0x.coding-guidelines.com/6.7.5.3.html) @@ -1502,8 +1599,8 @@ fn cfuncty_to_rs(ctx: &mut GenCtx, // (if any) are those specified within the [ and ] of the array type // derivation. let arg_ty = P(match t { - &TArray(ref typ, _, ref l) => cty_to_rs(ctx, &TPtr(typ.clone(), false, false, l.clone()), true), - _ => cty_to_rs(ctx, t, true), + &TArray(ref typ, _, ref l) => cty_to_rs(ctx, &TPtr(typ.clone(), false, false, l.clone()), true, true), + _ => cty_to_rs(ctx, t, true, true), }); ast::Arg { @@ -1543,9 +1640,9 @@ fn cfunc_to_rs(ctx: &mut GenCtx, empty_generics() ); - let (rust_name, was_mangled) = rust_id(ctx, name.clone()); + let (rust_name, was_mangled) = rust_id(ctx, &name); - let mut attrs = mk_doc_attr(ctx, comment); + let mut attrs = mk_doc_attr(ctx, &comment); if !mangled.is_empty() { attrs.push(mk_link_name_attr(ctx, mangled)); } else if was_mangled { @@ -1562,9 +1659,9 @@ fn cfunc_to_rs(ctx: &mut GenCtx, }); } -fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { - return match ty { - &TVoid => mk_ty(ctx, true, vec!("libc".to_string(), "c_void".to_string())), +fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool, use_full_path: bool) -> ast::Ty { + match ty { + &TVoid => mk_ty(ctx, true, &["libc".to_owned(), "c_void".to_owned()]), &TInt(i, ref layout) => match i { IBool => { let ty_name = match layout.size { @@ -1574,25 +1671,25 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { 8 => "u64", _ => "u8", }; - mk_ty(ctx, false, vec!(ty_name.to_string())) + mk_ty(ctx, false, &[ty_name.to_owned()]) }, - ISChar => mk_ty(ctx, true, vec!("libc".to_string(), "c_char".to_string())), + ISChar => mk_ty(ctx, true, &["libc".to_owned(), "c_char".to_owned()]), IInt | IShort | - ILongLong => mk_ty(ctx, false, vec!(format!("i{}", layout.size * 8))), + ILongLong => mk_ty(ctx, false, &[format!("i{}", layout.size * 8)]), IUChar | IUInt | IUShort | - IULongLong => mk_ty(ctx, false, vec!(format!("u{}", layout.size * 8))), - ILong => mk_ty(ctx, true, vec!("libc".to_string(), "c_long".to_string())), - IULong => mk_ty(ctx, true, vec!("libc".to_string(), "c_ulong".to_string())), + IULongLong => mk_ty(ctx, false, &[format!("u{}", layout.size * 8)]), + ILong => mk_ty(ctx, true, &["libc".to_owned(), "c_long".to_owned()]), + IULong => mk_ty(ctx, true, &["libc".to_owned(), "c_ulong".to_owned()]), }, &TFloat(f, _) => match f { - FFloat => mk_ty(ctx, false, vec!("f32".to_string())), - FDouble => mk_ty(ctx, false, vec!("f64".to_string())) + FFloat => mk_ty(ctx, false, &["f32".to_owned()]), + FDouble => mk_ty(ctx, false, &["f64".to_owned()]) }, &TPtr(ref t, is_const, _is_ref, _) => { - let id = cty_to_rs(ctx, &**t, allow_bool); + let id = cty_to_rs(ctx, &**t, allow_bool, use_full_path); /* if is_ref { mk_refty(ctx, &id, is_const) @@ -1602,7 +1699,7 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { // } }, &TArray(ref t, s, _) => { - let ty = cty_to_rs(ctx, &**t, allow_bool); + let ty = cty_to_rs(ctx, &**t, allow_bool, use_full_path); mk_arrty(ctx, &ty, s) }, &TFuncPtr(ref sig) => { @@ -1614,23 +1711,46 @@ fn cty_to_rs(ctx: &mut GenCtx, ty: &Type, allow_bool: bool) -> ast::Ty { mk_fn_proto_ty(ctx, &decl, sig.abi) }, &TNamed(ref ti) => { - let id = rust_type_id(ctx, ti.borrow().name.clone()); - mk_ty(ctx, false, vec!(id)) + let id = rust_type_id(ctx, &ti.borrow().name); + + if use_full_path { + let mut path = ctx.full_path_for_module(ti.borrow().module_id); + path.push(id); + mk_ty(ctx, false, &path) + } else { + mk_ty(ctx, false, &[id]) + } }, &TComp(ref ci) => { - let mut c = ci.borrow_mut(); - c.name = unnamed_name(ctx, c.name.clone(), c.filename.clone()); + let c = ci.borrow(); + let id = comp_name(c.kind, &c.name); + let args = c.args.iter().map(|gt| { - P(cty_to_rs(ctx, gt, allow_bool)) + P(cty_to_rs(ctx, gt, allow_bool, false)) }).collect(); - mk_ty_args(ctx, false, vec!(comp_name(c.kind, &c.name)), args) + + if use_full_path { + let mut path = ctx.full_path_for_module(c.module_id); + path.push(id); + mk_ty_args(ctx, false, &path, args) + } else { + mk_ty_args(ctx, false, &[id], args) + } + }, &TEnum(ref ei) => { - let mut e = ei.borrow_mut(); - e.name = unnamed_name(ctx, e.name.clone(), e.filename.clone()); - mk_ty(ctx, false, vec!(enum_name(&e.name))) + let e = ei.borrow(); + let id = enum_name(&e.name); + + if use_full_path { + let mut path = ctx.full_path_for_module(e.module_id); + path.push(id); + mk_ty(ctx, false, &path) + } else { + mk_ty(ctx, false, &[id]) + } } - }; + } } fn cty_is_translatable(ty: &Type) -> bool { @@ -1662,11 +1782,7 @@ fn cty_has_destructor(ty: &Type) -> bool { }) { return true; } - if let Some(ref ty) = c.ref_template { - true - } else { - false - } + c.ref_template.is_some() }, &TNamed(ref ti) => { cty_has_destructor(&ti.borrow().ty) @@ -1675,22 +1791,23 @@ fn cty_has_destructor(ty: &Type) -> bool { } } -fn mk_ty(ctx: &GenCtx, global: bool, segments: Vec) -> ast::Ty { +fn mk_ty(ctx: &GenCtx, global: bool, segments: &[String]) -> ast::Ty { mk_ty_args(ctx, global, segments, vec!()) } -fn mk_ty_args(ctx: &GenCtx, global: bool, segments: Vec, args: Vec>) -> ast::Ty { +fn mk_ty_args(ctx: &GenCtx, global: bool, segments: &[String], args: Vec>) -> ast::Ty { + let segment_count = segments.len(); let ty = ast::TyPath( None, ast::Path { span: ctx.span, global: global, - segments: segments.iter().map(|s| { + segments: segments.iter().enumerate().map(|(i, s)| { ast::PathSegment { identifier: ctx.ext_cx.ident_of(s), parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { lifetimes: vec!(), - types: OwnedSlice::from_vec(args.clone()), + types: OwnedSlice::from_vec(if i == segment_count - 1 { args.clone() } else { vec![] }), bindings: OwnedSlice::empty(), }), } @@ -1698,11 +1815,11 @@ fn mk_ty_args(ctx: &GenCtx, global: bool, segments: Vec, args: Vec ast::Ty { @@ -1711,13 +1828,14 @@ fn mk_ptrty(ctx: &mut GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty { mutbl: if is_const { ast::MutImmutable } else { ast::MutMutable } }); - return ast::Ty { + ast::Ty { id: ast::DUMMY_NODE_ID, node: ty, span: ctx.span - }; + } } +#[allow(dead_code)] fn mk_refty(ctx: &mut GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty { let ty = ast::TyRptr( None, @@ -1727,11 +1845,11 @@ fn mk_refty(ctx: &mut GenCtx, base: &ast::Ty, is_const: bool) -> ast::Ty { } ); - return ast::Ty { + ast::Ty { id: ast::DUMMY_NODE_ID, node: ty, span: ctx.span - }; + } } fn mk_arrty(ctx: &GenCtx, base: &ast::Ty, n: usize) -> ast::Ty { @@ -1747,11 +1865,11 @@ fn mk_arrty(ctx: &GenCtx, base: &ast::Ty, n: usize) -> ast::Ty { }) ); - return ast::Ty { + ast::Ty { id: ast::DUMMY_NODE_ID, node: ty, span: ctx.span - }; + } } fn mk_fn_proto_ty(ctx: &mut GenCtx, decl: &ast::FnDecl, abi: abi::Abi) -> ast::Ty { @@ -1810,7 +1928,7 @@ fn mk_fnty(ctx: &mut GenCtx, decl: &ast::FnDecl, abi: abi::Abi) -> ast::Ty { } ]; - return ast::Ty { + ast::Ty { id: ast::DUMMY_NODE_ID, node: ast::TyPath( None, @@ -1821,5 +1939,5 @@ fn mk_fnty(ctx: &mut GenCtx, decl: &ast::FnDecl, abi: abi::Abi) -> ast::Ty { }, ), span: ctx.span - }; + } } diff --git a/src/lib.rs b/src/lib.rs index cd73860bf0..390c008338 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![crate_name = "bindgen"] #![crate_type = "dylib"] -#![feature(convert, quote)] +#![feature(quote)] extern crate syntex_syntax as syntax; extern crate libc; @@ -20,7 +20,7 @@ use syntax::print::pprust; use syntax::print::pp::eof; use syntax::ptr::P; -use types::Global; +use types::ModuleMap; mod types; mod clangll; @@ -104,7 +104,9 @@ pub struct BindgenOptions { pub builtins: bool, pub links: Vec<(String, LinkType)>, pub emit_ast: bool, + pub ignore_functions: bool, pub fail_on_unknown_type: bool, + pub enable_cxx_namespaces: bool, pub override_enum_ty: String, pub clang_args: Vec, } @@ -116,7 +118,9 @@ impl Default for BindgenOptions { builtins: false, links: Vec::new(), emit_ast: false, + ignore_functions: false, fail_on_unknown_type: true, + enable_cxx_namespaces: false, override_enum_ty: "".to_string(), clang_args: Vec::new() } @@ -144,21 +148,18 @@ impl Bindings { /// Deprecated - use a `Builder` instead pub fn generate(options: &BindgenOptions, logger: Option<&Logger>, span: Option) -> Result { let l = DummyLogger; - let logger = match logger { - Some(l) => l, - None => &l as &Logger - }; + let logger = logger.unwrap_or(&l as &Logger); - let span = match span { - Some(s) => s, - None => DUMMY_SP - }; + let span = span.unwrap_or(DUMMY_SP); - let globals = try!(parse_headers(options, logger)); + let module_map = try!(parse_headers(options, logger)); let module = ast::Mod { inner: span, - items: gen::gen_mod(&options.links[..], globals, span) + items: gen::gen_mods(&options.links[..], + module_map, + options.enable_cxx_namespaces, + span) }; Ok(Bindings { @@ -202,7 +203,7 @@ impl Logger for DummyLogger { fn warn(&self, _msg: &str) { } } -fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result, ()> { +fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result { fn str_to_ikind(s: &str) -> Option { match s { "uchar" => Some(types::IUChar), @@ -224,7 +225,9 @@ fn parse_headers(options: &BindgenOptions, logger: &Logger) -> Result, pub builtins: bool, pub match_pat: Vec, pub emit_ast: bool, pub fail_on_unknown_type: bool, + pub ignore_functions: bool, + pub enable_cxx_namespaces: bool, pub override_enum_ty: Option, pub clang_args: Vec, } @@ -29,10 +32,26 @@ pub struct ClangParserOptions { struct ClangParserCtx<'a> { options: ClangParserOptions, name: HashMap, - globals: Vec, builtin_defs: Vec, + module_map: ModuleMap, + current_module_id: ModuleId, logger: &'a (Logger+'a), - err_count: i32 + err_count: i32, + anonymous_modules_found: usize, +} + +impl<'a> ClangParserCtx<'a> { + fn module(&self, id: &ModuleId) -> &Module { + self.module_map.get(id).expect("Module not found!") + } + + fn current_module(&self) -> &Module { + self.module(&self.current_module_id) + } + + fn current_module_mut(&mut self) -> &mut Module { + self.module_map.get_mut(&self.current_module_id).expect("Module not found!") + } } fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool { @@ -47,15 +66,7 @@ fn match_pattern(ctx: &mut ClangParserCtx, cursor: &Cursor) -> bool { } let name = file.name(); - let mut found = false; - ctx.options.match_pat.iter().all(|pat| { - if (&name).contains(pat) { - found = true; - } - true - }); - - return found; + ctx.options.match_pat.iter().any(|pat| name.contains(pat)) } fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { @@ -75,11 +86,11 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { }; let glob_decl = match cursor.kind() { CXCursor_StructDecl => { - let ci = Rc::new(RefCell::new(CompInfo::new(spelling, filename, comment, CompKind::Struct, vec!(), layout))); + let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Struct, vec!(), layout))); GCompDecl(ci) } CXCursor_UnionDecl => { - let ci = Rc::new(RefCell::new(CompInfo::new(spelling, filename, comment, CompKind::Union, vec!(), layout))); + let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Union, vec!(), layout))); GCompDecl(ci) } CXCursor_EnumDecl => { @@ -99,11 +110,11 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { _ => IInt, } }; - let ei = Rc::new(RefCell::new(EnumInfo::new(spelling, filename, kind, vec!(), layout))); + let ei = Rc::new(RefCell::new(EnumInfo::new(spelling, ctx.current_module_id, filename, kind, vec!(), layout))); GEnumDecl(ei) } CXCursor_ClassTemplate => { - let ci = Rc::new(RefCell::new(CompInfo::new(spelling, filename, comment, CompKind::Struct, vec!(), layout))); + let ci = Rc::new(RefCell::new(CompInfo::new(spelling, ctx.current_module_id, filename, comment, CompKind::Struct, vec!(), layout))); GCompDecl(ci) } CXCursor_ClassDecl => { @@ -118,12 +129,31 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { list } }; - let ci = Rc::new(RefCell::new(CompInfo::new(spelling, filename, comment, CompKind::Struct, vec!(), layout))); + + let module_id = if args.is_empty() { + ctx.current_module_id + } else { + // it's an instantiation of another template, + // find the canonical declaration to find the module it belongs to. + let parent = cursor.specialized(); + ctx.name.get(&parent).and_then(|global| { + if let GCompDecl(ref ci) = *global { + Some(ci.borrow().module_id) + } else { + None + } + }).unwrap_or_else(|| { + ctx.logger.warn("Template class wasn't declared when parsing specialisation!"); + ctx.current_module_id + }) + }; + + let ci = Rc::new(RefCell::new(CompInfo::new(spelling, module_id, filename, comment, CompKind::Struct, vec!(), layout))); ci.borrow_mut().args = args; GCompDecl(ci) } CXCursor_TypedefDecl => { - let ti = Rc::new(RefCell::new(TypeInfo::new(spelling, TVoid, layout))); + let ti = Rc::new(RefCell::new(TypeInfo::new(spelling, ctx.current_module_id, TVoid, layout))); GType(ti) } CXCursor_VarDecl => { @@ -160,7 +190,7 @@ fn decl_name(ctx: &mut ClangParserCtx, cursor: &Cursor) -> Global { fn opaque_decl(ctx: &mut ClangParserCtx, decl: &Cursor) { let name = decl_name(ctx, decl); - ctx.globals.push(name); + ctx.current_module_mut().globals.push(name); } fn fwd_decl()>(ctx: &mut ClangParserCtx, cursor: &Cursor, f: F) { @@ -298,7 +328,7 @@ fn conv_decl_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il: } CXCursor_NoDeclFound | CXCursor_TypeAliasDecl => { let layout = Layout::new(ty.size(), ty.align()); - TNamed(Rc::new(RefCell::new(TypeInfo::new(ty.spelling().replace("const ", ""), TVoid, layout)))) + TNamed(Rc::new(RefCell::new(TypeInfo::new(ty.spelling().replace("const ", ""), ctx.current_module_id, TVoid, layout)))) } _ => { let fail = ctx.options.fail_on_unknown_type; @@ -314,8 +344,6 @@ fn conv_decl_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il: } fn conv_ty(ctx: &mut ClangParserCtx, ty: &cx::Type, cursor: &Cursor) -> il::Type { - debug!("conv_ty: ty=`{}` sp=`{}` loc=`{}`", type_to_str(ty.kind()), cursor.spelling(), cursor.location()); - let layout = Layout::new(ty.size(), ty.align()); return match ty.kind() { CXType_Void | CXType_Invalid => TVoid, @@ -544,7 +572,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, CXCursor_TemplateTypeParameter => { let ty = conv_ty(ctx, &cursor.cur_type(), cursor); let layout = Layout::new(ty.size(), ty.align()); - ci.args.push(TNamed(Rc::new(RefCell::new(TypeInfo::new(cursor.spelling(), TVoid, layout))))); + ci.args.push(TNamed(Rc::new(RefCell::new(TypeInfo::new(cursor.spelling(), ctx.current_module_id, TVoid, layout))))); } CXCursor_EnumDecl => { let anno = Annotations::new(cursor); @@ -590,6 +618,10 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, ci.base_members += 1; } CXCursor_CXXMethod => { + if ctx.options.ignore_functions { + return CXChildVisit_Continue; + } + let linkage = cursor.linkage(); if linkage != CXLinkage_External { return CXChildVisit_Continue; @@ -648,7 +680,7 @@ fn visit_composite(cursor: &Cursor, parent: &Cursor, sig.args.insert(0, ("this".to_string(),TPtr(Box::new(TVoid), cursor.cur_type().is_const(), false, Layout::zero()))); } else { sig.args.insert(0, ("this".to_string(), - TPtr(Box::new(TNamed(Rc::new(RefCell::new(TypeInfo::new(ci.name.clone(), TVoid, Layout::zero()))))), cursor.cur_type().is_const(), false, Layout::zero()))); + TPtr(Box::new(TNamed(Rc::new(RefCell::new(TypeInfo::new(ci.name.clone(), ctx.current_module_id, TVoid, Layout::zero()))))), cursor.cur_type().is_const(), false, Layout::zero()))); } } @@ -730,7 +762,7 @@ fn visit_literal(cursor: &Cursor, unit: &TranslationUnit) -> Option { } fn visit_top<'r>(cursor: &Cursor, - ctx: &mut ClangParserCtx, + mut ctx: &mut ClangParserCtx, unit: &TranslationUnit) -> Enum_CXVisitorResult { if !match_pattern(ctx, cursor) { return CXChildVisit_Continue; @@ -755,7 +787,7 @@ fn visit_top<'r>(cursor: &Cursor, if anno.hide { ci.borrow_mut().hide = true; } - ctx_.globals.push(GComp(ci)); + ctx_.current_module_mut().globals.push(GComp(ci)); }); return CXChildVisit_Continue; } @@ -768,7 +800,7 @@ fn visit_top<'r>(cursor: &Cursor, let mut ei_ = ei.borrow_mut(); visit_enum(c, &mut ei_.items) }); - ctx_.globals.push(GEnum(ei)); + ctx_.current_module_mut().globals.push(GEnum(ei)); }); return CXChildVisit_Continue; } @@ -794,7 +826,7 @@ fn visit_top<'r>(cursor: &Cursor, let mut vi = vi.borrow_mut(); vi.ty = TFuncPtr(mk_fn_sig(ctx, &cursor.cur_type(), cursor)); - ctx.globals.push(func); + ctx.current_module_mut().globals.push(func); return CXChildVisit_Continue; } @@ -818,7 +850,7 @@ fn visit_top<'r>(cursor: &Cursor, vi.val = visit_literal(c, unit); CXChildVisit_Continue }); - ctx.globals.push(var); + ctx.current_module_mut().globals.push(var); return CXChildVisit_Continue; } @@ -838,7 +870,7 @@ fn visit_top<'r>(cursor: &Cursor, let mut ti = ti.borrow_mut(); ti.ty = ty.clone(); ti.comment = cursor.raw_comment(); - ctx.globals.push(typedef); + ctx.current_module_mut().globals.push(typedef); opaque_ty(ctx, &under_ty); @@ -848,7 +880,51 @@ fn visit_top<'r>(cursor: &Cursor, return CXChildVisit_Continue; } CXCursor_Namespace => { - return CXChildVisit_Recurse; + if !ctx.options.enable_cxx_namespaces { + return CXChildVisit_Recurse; + } + + let namespace_name = match unit.tokens(cursor) { + None => None, + Some(tokens) => { + if tokens.len() <= 1 { + None + } else { + match &*tokens[1].spelling { + "{" => None, + s => Some(s.to_owned()), + } + } + } + }.unwrap_or_else(|| { + ctx.anonymous_modules_found += 1; + format!("__anonymous{}", ctx.anonymous_modules_found) + }); + + // Find an existing namespace children of the current one + let mod_id = ctx.current_module() + .children_ids.iter() + .find(|id| ctx.module_map.get(id).unwrap().name == namespace_name) + .map(|id| *id); + + let mod_id = match mod_id { + Some(id) => id, + None => { + let parent_id = ctx.current_module_id; + let id = ModuleId::next(); + ctx.module_map.get_mut(&parent_id).unwrap().children_ids.push(id); + ctx.module_map.insert(id, Module::new(namespace_name, Some(parent_id))); + id + } + }; + + let previous_id = ctx.current_module_id; + + ctx.current_module_id = mod_id; + cursor.visit(|cur, _: &Cursor| visit_top(cur, &mut ctx, &unit)); + ctx.current_module_id = previous_id; + + return CXChildVisit_Continue; } CXCursor_MacroDefinition => { let val = parse_int_literal_tokens(cursor, unit, 1); @@ -866,7 +942,7 @@ fn visit_top<'r>(cursor: &Cursor, }; vi.is_const = true; vi.val = val; - ctx.globals.push(var); + ctx.current_module_mut().globals.push(var); return CXChildVisit_Continue; } @@ -875,25 +951,28 @@ fn visit_top<'r>(cursor: &Cursor, } fn log_err_warn(ctx: &mut ClangParserCtx, msg: &str, is_err: bool) { - match is_err { - true => { - ctx.err_count += 1; - ctx.logger.error(msg) - }, - false => ctx.logger.warn(msg) + if is_err { + ctx.err_count += 1; + ctx.logger.error(msg); + } else { + ctx.logger.warn(msg); } } -pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result, ()> { +pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result { let mut ctx = ClangParserCtx { options: options, name: HashMap::new(), builtin_defs: vec!(), - globals: vec!(), + module_map: ModuleMap::new(), + current_module_id: ROOT_MODULE_ID, logger: logger, - err_count: 0 + err_count: 0, + anonymous_modules_found: 0, }; + ctx.module_map.insert(ROOT_MODULE_ID, Module::new("root".to_owned(), None)); + let ix = cx::Index::create(false, true); if ix.is_null() { ctx.logger.error("Clang failed to create index"); @@ -937,5 +1016,5 @@ pub fn parse(options: ClangParserOptions, logger: &Logger) -> Result return Err(()) } - Ok(ctx.globals) + Ok(ctx.module_map) } diff --git a/src/types.rs b/src/types.rs index 64adeeb32c..1b047e538d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,6 +1,8 @@ use std::cell::RefCell; use std::fmt; use std::rc::Rc; +use std::collections::HashMap; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use syntax::abi; @@ -9,6 +11,45 @@ pub use self::Type::*; pub use self::IKind::*; pub use self::FKind::*; +static NEXT_MODULE_ID: AtomicUsize = ATOMIC_USIZE_INIT; + +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] +pub struct ModuleId(usize); +pub static ROOT_MODULE_ID: ModuleId = ModuleId(0); + +impl ModuleId { + pub fn next() -> ModuleId { + ModuleId(NEXT_MODULE_ID.fetch_add(1, Ordering::SeqCst) + 1) + } +} + +pub type ModuleMap = HashMap; + +#[derive(Clone)] +pub struct Module { + pub name: String, + pub globals: Vec, + pub parent_id: Option, + // Just for convenience + pub children_ids: Vec, +} + +impl Module { + pub fn new(name: String, parent_id: Option) -> Self { + Module { + name: name, + globals: vec![], + parent_id: parent_id, + children_ids: vec![], + } + } + + #[allow(dead_code)] + pub fn add_global(&mut self, g: Global) { + self.globals.push(g) + } +} + #[derive(Clone)] pub enum Global { GType(Rc>), @@ -180,6 +221,7 @@ pub enum CompKind { pub struct CompInfo { pub kind: CompKind, pub name: String, + pub module_id: ModuleId, pub filename: String, pub comment: String, pub members: Vec, @@ -194,11 +236,23 @@ pub struct CompInfo { pub layout: Layout, } +static mut UNNAMED_COUNTER: u32 = 0; + +fn unnamed_name(name: String, filename: &String) -> String { + return if name.is_empty() { + let n = unsafe { UNNAMED_COUNTER += 1; UNNAMED_COUNTER }; + format!("{}_unnamed_{}", filename, n) + } else { + name + }; +} + impl CompInfo { - pub fn new(name: String, filename: String, comment: String, kind: CompKind, members: Vec, layout: Layout) -> CompInfo { + pub fn new(name: String, module_id: ModuleId, filename: String, comment: String, kind: CompKind, members: Vec, layout: Layout) -> CompInfo { CompInfo { kind: kind, - name: name, + module_id: module_id, + name: unnamed_name(name, &filename), filename: filename, comment: comment, members: members, @@ -243,6 +297,7 @@ impl FieldInfo { #[derive(Clone, PartialEq)] pub struct EnumInfo { pub name: String, + pub module_id: ModuleId, pub comment: String, pub filename: String, pub items: Vec, @@ -251,9 +306,10 @@ pub struct EnumInfo { } impl EnumInfo { - pub fn new(name: String, filename: String, kind: IKind, items: Vec, layout: Layout) -> EnumInfo { + pub fn new(name: String, module_id: ModuleId, filename: String, kind: IKind, items: Vec, layout: Layout) -> EnumInfo { EnumInfo { - name: name, + name: unnamed_name(name, &filename), + module_id: module_id, comment: String::new(), filename: filename, items: items, @@ -289,15 +345,17 @@ impl EnumItem { #[derive(Clone, PartialEq)] pub struct TypeInfo { pub name: String, + pub module_id: ModuleId, pub comment: String, pub ty: Type, pub layout: Layout, } impl TypeInfo { - pub fn new(name: String, ty: Type, layout: Layout) -> TypeInfo { + pub fn new(name: String, module_id: ModuleId, ty: Type, layout: Layout) -> TypeInfo { TypeInfo { name: name, + module_id: module_id, comment: String::new(), ty: ty, layout: layout, diff --git a/tests/headers/namespace.h b/tests/headers/namespace.h new file mode 100644 index 0000000000..055e725837 --- /dev/null +++ b/tests/headers/namespace.h @@ -0,0 +1,45 @@ + + +void top_level(); + +namespace whatever { + typedef int whatever_int_t; + + void in_whatever(); +} + +namespace { + namespace empty {} + + void foo(); + struct A { + whatever::whatever_int_t b; + public: + int lets_hope_this_works(); + }; +} + +template +class C: public A { + T m_c; +}; + + +template<> +class C; + + +namespace w { + typedef unsigned int whatever_int_t; + + template + class D { + C m_c; + }; + + whatever_int_t heh(); // this should return w::whatever_int_t, and not whatever::whatever_int_t + + C foo(); + + C barr(); // <- This is the problematic one +} diff --git a/tests/support.rs b/tests/support.rs index a83bbc0230..f2a5abb14a 100644 --- a/tests/support.rs +++ b/tests/support.rs @@ -38,7 +38,7 @@ pub fn assert_bind_eq(filename: &str, reference_items_str: &str) let mut parser = parse::new_parser_from_source_str(ext_cx.parse_sess(), ext_cx.cfg(), "".to_string(), reference_items_str.to_string()); let mut reference_items = Vec::new(); - while let Some(item) = parser.parse_item() { + while let Ok(Some(item)) = parser.parse_item() { reference_items.push(item); } @@ -47,7 +47,7 @@ pub fn assert_bind_eq(filename: &str, reference_items_str: &str) // rendered versions, which is not beautiful, but should work. let reference_rendered = render_items(&reference_items); let generated_rendered = render_items(&generated_items); - + if reference_rendered != generated_rendered { println!("Generated bindings for {} do not match the reference bindings.", filename); println!("");