| //! Common context that is passed around during parsing and codegen. |
| |
| use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; |
| use super::int::IntKind; |
| use super::item::{Item, ItemCanonicalPath, ItemSet}; |
| use super::item_kind::ItemKind; |
| use super::module::{Module, ModuleKind}; |
| use super::traversal::{self, Edge, ItemTraversal}; |
| use super::ty::{FloatKind, TemplateDeclaration, Type, TypeKind}; |
| use BindgenOptions; |
| use cexpr; |
| use chooser::TypeChooser; |
| use clang::{self, Cursor}; |
| use clang_sys; |
| use parse::ClangItemParser; |
| use std::borrow::Cow; |
| use std::cell::Cell; |
| use std::collections::{HashMap, hash_map}; |
| use std::collections::btree_map::{self, BTreeMap}; |
| use std::fmt; |
| use std::iter::IntoIterator; |
| use syntax::ast::Ident; |
| use syntax::codemap::{DUMMY_SP, Span}; |
| use syntax::ext::base::ExtCtxt; |
| |
| /// A single identifier for an item. |
| /// |
| /// TODO: Build stronger abstractions on top of this, like TypeId(ItemId)? |
| #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| pub struct ItemId(usize); |
| |
| impl ItemId { |
| /// Get a numeric representation of this id. |
| pub fn as_usize(&self) -> usize { |
| self.0 |
| } |
| } |
| |
| impl CanDeriveDebug for ItemId { |
| type Extra = (); |
| |
| fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool { |
| ctx.resolve_item(*self).can_derive_debug(ctx, ()) |
| } |
| } |
| |
| impl CanDeriveDefault for ItemId { |
| type Extra = (); |
| |
| fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool { |
| ctx.resolve_item(*self).can_derive_default(ctx, ()) |
| } |
| } |
| |
| impl<'a> CanDeriveCopy<'a> for ItemId { |
| type Extra = (); |
| |
| fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool { |
| ctx.resolve_item(*self).can_derive_copy(ctx, ()) |
| } |
| |
| fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool { |
| ctx.resolve_item(*self).can_derive_copy_in_array(ctx, ()) |
| } |
| } |
| |
| /// A key used to index a resolved type, so we only process it once. |
| /// |
| /// This is almost always a USR string (an unique identifier generated by |
| /// clang), but it can also be the canonical declaration if the type is unnamed, |
| /// in which case clang may generate the same USR for multiple nested unnamed |
| /// types. |
| #[derive(Eq, PartialEq, Hash, Debug)] |
| enum TypeKey { |
| USR(String), |
| Declaration(Cursor), |
| } |
| |
| // This is just convenience to avoid creating a manual debug impl for the |
| // context. |
| struct GenContext<'ctx>(ExtCtxt<'ctx>); |
| |
| impl<'ctx> fmt::Debug for GenContext<'ctx> { |
| fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
| write!(fmt, "GenContext {{ ... }}") |
| } |
| } |
| |
| /// A context used during parsing and generation of structs. |
| #[derive(Debug)] |
| pub struct BindgenContext<'ctx> { |
| /// The map of all the items parsed so far. |
| /// |
| /// It's a BTreeMap because we want the keys to be sorted to have consistent |
| /// output. |
| items: BTreeMap<ItemId, Item>, |
| |
| /// The next item id to use during this bindings regeneration. |
| next_item_id: ItemId, |
| |
| /// Clang USR to type map. This is needed to be able to associate types with |
| /// item ids during parsing. |
| types: HashMap<TypeKey, ItemId>, |
| |
| /// A cursor to module map. Similar reason than above. |
| modules: HashMap<Cursor, ItemId>, |
| |
| /// The root module, this is guaranteed to be an item of kind Module. |
| root_module: ItemId, |
| |
| /// Current module being traversed. |
| current_module: ItemId, |
| |
| /// A stack with the current type declarations and types we're parsing. This |
| /// is needed to avoid infinite recursion when parsing a type like: |
| /// |
| /// struct c { struct c* next; }; |
| /// |
| /// This means effectively, that a type has a potential ID before knowing if |
| /// it's a correct type. But that's not important in practice. |
| /// |
| /// We could also use the `types` HashMap, but my intention with it is that |
| /// only valid types and declarations end up there, and this could |
| /// potentially break that assumption. |
| currently_parsed_types: Vec<PartialType>, |
| |
| /// A HashSet with all the already parsed macro names. This is done to avoid |
| /// hard errors while parsing duplicated macros, as well to allow macro |
| /// expression parsing. |
| parsed_macros: HashMap<Vec<u8>, cexpr::expr::EvalResult>, |
| |
| /// The active replacements collected from replaces="xxx" annotations. |
| replacements: HashMap<Vec<String>, ItemId>, |
| |
| collected_typerefs: bool, |
| |
| /// Dummy structures for code generation. |
| gen_ctx: Option<&'ctx GenContext<'ctx>>, |
| span: Span, |
| |
| /// The clang index for parsing. |
| index: clang::Index, |
| |
| /// The translation unit for parsing. |
| translation_unit: clang::TranslationUnit, |
| |
| /// The options given by the user via cli or other medium. |
| options: BindgenOptions, |
| |
| /// Whether a bindgen complex was generated |
| generated_bindegen_complex: Cell<bool>, |
| } |
| |
| /// A traversal of whitelisted items. |
| pub type WhitelistedItems<'ctx, 'gen> = ItemTraversal<'ctx, |
| 'gen, |
| ItemSet, |
| Vec<ItemId>, |
| fn(Edge) -> bool>; |
| |
| impl<'ctx> BindgenContext<'ctx> { |
| /// Construct the context for the given `options`. |
| pub fn new(options: BindgenOptions) -> Self { |
| use clang_sys; |
| |
| let index = clang::Index::new(false, true); |
| |
| let parse_options = |
| clang_sys::CXTranslationUnit_DetailedPreprocessingRecord; |
| let translation_unit = |
| clang::TranslationUnit::parse(&index, |
| "", |
| &options.clang_args, |
| &[], |
| parse_options) |
| .expect("TranslationUnit::parse"); |
| |
| let root_module = Self::build_root_module(ItemId(0)); |
| let mut me = BindgenContext { |
| items: Default::default(), |
| types: Default::default(), |
| modules: Default::default(), |
| next_item_id: ItemId(1), |
| root_module: root_module.id(), |
| current_module: root_module.id(), |
| currently_parsed_types: vec![], |
| parsed_macros: Default::default(), |
| replacements: Default::default(), |
| collected_typerefs: false, |
| gen_ctx: None, |
| span: DUMMY_SP, |
| index: index, |
| translation_unit: translation_unit, |
| options: options, |
| generated_bindegen_complex: Cell::new(false), |
| }; |
| |
| me.add_item(root_module, None, None); |
| |
| me |
| } |
| |
| /// Get the stack of partially parsed types that we are in the middle of |
| /// parsing. |
| pub fn currently_parsed_types(&self) -> &[PartialType] { |
| &self.currently_parsed_types[..] |
| } |
| |
| /// Begin parsing the given partial type, and push it onto the |
| /// `currently_parsed_types` stack so that we won't infinite recurse if we |
| /// run into a reference to it while parsing it. |
| pub fn begin_parsing(&mut self, partial_ty: PartialType) { |
| self.currently_parsed_types.push(partial_ty); |
| } |
| |
| /// Finish parsing the current partial type, pop it off the |
| /// `currently_parsed_types` stack, and return it. |
| pub fn finish_parsing(&mut self) -> PartialType { |
| self.currently_parsed_types.pop() |
| .expect("should have been parsing a type, if we finished parsing a type") |
| } |
| |
| /// Get the user-provided type chooser by reference, if any. |
| pub fn type_chooser(&self) -> Option<&TypeChooser> { |
| self.options().type_chooser.as_ref().map(|t| &**t) |
| } |
| |
| /// Define a new item. |
| /// |
| /// This inserts it into the internal items set, and its type into the |
| /// internal types set. |
| pub fn add_item(&mut self, |
| item: Item, |
| declaration: Option<Cursor>, |
| location: Option<Cursor>) { |
| debug!("BindgenContext::add_item({:?}, declaration: {:?}, loc: {:?}", |
| item, |
| declaration, |
| location); |
| debug_assert!(declaration.is_some() || !item.kind().is_type() || |
| item.kind().expect_type().is_builtin_or_named(), |
| "Adding a type without declaration?"); |
| |
| let id = item.id(); |
| let is_type = item.kind().is_type(); |
| let is_unnamed = is_type && item.expect_type().name().is_none(); |
| |
| // Be sure to track all the generated children under namespace, even |
| // those generated after resolving typerefs, etc. |
| if item.id() != item.parent_id() { |
| if let Some(mut parent) = self.items.get_mut(&item.parent_id()) { |
| if let Some(mut module) = parent.as_module_mut() { |
| module.children_mut().push(item.id()); |
| } |
| } |
| } |
| |
| let old_item = self.items.insert(id, item); |
| assert!(old_item.is_none(), "Inserted type twice?"); |
| |
| // Unnamed items can have an USR, but they can't be referenced from |
| // other sites explicitly and the USR can match if the unnamed items are |
| // nested, so don't bother tracking them. |
| if is_type && declaration.is_some() { |
| let mut declaration = declaration.unwrap(); |
| if !declaration.is_valid() { |
| if let Some(location) = location { |
| if location.is_template_like() { |
| declaration = location; |
| } |
| } |
| } |
| declaration = declaration.canonical(); |
| if !declaration.is_valid() { |
| // This could happen, for example, with types like `int*` or |
| // similar. |
| // |
| // Fortunately, we don't care about those types being |
| // duplicated, so we can just ignore them. |
| debug!("Invalid declaration {:?} found for type {:?}", |
| declaration, |
| self.items.get(&id).unwrap().kind().expect_type()); |
| return; |
| } |
| |
| let key = if is_unnamed { |
| TypeKey::Declaration(declaration) |
| } else if let Some(usr) = declaration.usr() { |
| TypeKey::USR(usr) |
| } else { |
| warn!("Valid declaration with no USR: {:?}, {:?}", |
| declaration, |
| location); |
| TypeKey::Declaration(declaration) |
| }; |
| |
| let old = self.types.insert(key, id); |
| debug_assert_eq!(old, None); |
| } |
| } |
| |
| // TODO: Move all this syntax crap to other part of the code. |
| |
| /// Given that we are in the codegen phase, get the syntex context. |
| pub fn ext_cx(&self) -> &ExtCtxt<'ctx> { |
| &self.gen_ctx.expect("Not in gen phase").0 |
| } |
| |
| /// Given that we are in the codegen phase, get the current syntex span. |
| pub fn span(&self) -> Span { |
| self.span |
| } |
| |
| /// Mangles a name so it doesn't conflict with any keyword. |
| pub fn rust_mangle<'a>(&self, name: &'a str) -> Cow<'a, str> { |
| use syntax::parse::token; |
| let ident = self.rust_ident_raw(name); |
| let token = token::Ident(ident); |
| if token.is_any_keyword() || name.contains("@") || |
| name.contains("?") || name.contains("$") || |
| "bool" == name { |
| let mut s = name.to_owned(); |
| s = s.replace("@", "_"); |
| s = s.replace("?", "_"); |
| s = s.replace("$", "_"); |
| s.push_str("_"); |
| return Cow::Owned(s); |
| } |
| Cow::Borrowed(name) |
| } |
| |
| /// Returns a mangled name as a rust identifier. |
| pub fn rust_ident(&self, name: &str) -> Ident { |
| self.rust_ident_raw(&self.rust_mangle(name)) |
| } |
| |
| /// Returns a mangled name as a rust identifier. |
| pub fn rust_ident_raw(&self, name: &str) -> Ident { |
| self.ext_cx().ident_of(name) |
| } |
| |
| /// Iterate over all items that have been defined. |
| pub fn items<'a>(&'a self) -> btree_map::Iter<'a, ItemId, Item> { |
| self.items.iter() |
| } |
| |
| /// Have we collected all unresolved type references yet? |
| pub fn collected_typerefs(&self) -> bool { |
| self.collected_typerefs |
| } |
| |
| /// Gather all the unresolved type references. |
| fn collect_typerefs |
| (&mut self) |
| -> Vec<(ItemId, clang::Type, Option<clang::Cursor>, Option<ItemId>)> { |
| debug_assert!(!self.collected_typerefs); |
| self.collected_typerefs = true; |
| let mut typerefs = vec![]; |
| for (id, ref mut item) in &mut self.items { |
| let kind = item.kind(); |
| let ty = match kind.as_type() { |
| Some(ty) => ty, |
| None => continue, |
| }; |
| |
| match *ty.kind() { |
| TypeKind::UnresolvedTypeRef(ref ty, loc, parent_id) => { |
| typerefs.push((*id, ty.clone(), loc, parent_id)); |
| } |
| _ => {} |
| }; |
| } |
| typerefs |
| } |
| |
| /// Collect all of our unresolved type references and resolve them. |
| fn resolve_typerefs(&mut self) { |
| let typerefs = self.collect_typerefs(); |
| |
| for (id, ty, loc, parent_id) in typerefs { |
| let _resolved = { |
| let resolved = Item::from_ty(&ty, loc, parent_id, self) |
| .expect("What happened?"); |
| let mut item = self.items.get_mut(&id).unwrap(); |
| |
| *item.kind_mut().as_type_mut().unwrap().kind_mut() = |
| TypeKind::ResolvedTypeRef(resolved); |
| resolved |
| }; |
| |
| // Something in the STL is trolling me. I don't need this assertion |
| // right now, but worth investigating properly once this lands. |
| // |
| // debug_assert!(self.items.get(&resolved).is_some(), "How?"); |
| } |
| } |
| |
| /// Iterate over all items and replace any item that has been named in a |
| /// `replaces="SomeType"` annotation with the replacement type. |
| fn process_replacements(&mut self) { |
| if self.replacements.is_empty() { |
| debug!("No replacements to process"); |
| return; |
| } |
| |
| // FIXME: This is linear, but the replaces="xxx" annotation was already |
| // there, and for better or worse it's useful, sigh... |
| // |
| // We leverage the ResolvedTypeRef thing, though, which is cool :P. |
| |
| 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() { |
| Some(ty) => ty, |
| None => continue, |
| }; |
| |
| match *ty.kind() { |
| TypeKind::Comp(ref ci) if !ci.is_template_specialization() => {} |
| TypeKind::TemplateAlias(..) | |
| TypeKind::Alias(..) => {} |
| _ => continue, |
| } |
| |
| let path = item.canonical_path(self); |
| let replacement = self.replacements.get(&path[1..]); |
| |
| if let Some(replacement) = replacement { |
| if replacement != id { |
| // We set this just after parsing the annotation. It's |
| // very unlikely, but this can happen. |
| if self.items.get(replacement).is_some() { |
| replacements.push((*id, *replacement)); |
| } |
| } |
| } |
| } |
| |
| for (id, replacement) in replacements { |
| debug!("Replacing {:?} with {:?}", id, 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); |
| } |
| } |
| |
| /// Enter the code generation phase, invoke the given callback `cb`, and |
| /// leave the code generation phase. |
| pub fn gen<F, Out>(&mut self, cb: F) -> Out |
| where F: FnOnce(&Self) -> Out, |
| { |
| use aster::symbol::ToSymbol; |
| use syntax::ext::expand::ExpansionConfig; |
| use syntax::codemap::{ExpnInfo, MacroBang, NameAndSpan}; |
| use syntax::ext::base; |
| use syntax::parse; |
| use std::mem; |
| |
| let cfg = ExpansionConfig::default("xxx".to_owned()); |
| let sess = parse::ParseSess::new(); |
| let mut loader = base::DummyResolver; |
| let mut ctx = GenContext(base::ExtCtxt::new(&sess, cfg, &mut loader)); |
| |
| ctx.0.bt_push(ExpnInfo { |
| call_site: self.span, |
| callee: NameAndSpan { |
| format: MacroBang("".to_symbol()), |
| allow_internal_unstable: false, |
| span: None, |
| }, |
| }); |
| |
| // FIXME: This is evil, we should move code generation to use a wrapper |
| // of BindgenContext instead, I guess. Even though we know it's fine |
| // because we remove it before the end of this function. |
| self.gen_ctx = Some(unsafe { mem::transmute(&ctx) }); |
| |
| self.assert_no_dangling_references(); |
| |
| if !self.collected_typerefs() { |
| self.resolve_typerefs(); |
| self.process_replacements(); |
| } |
| |
| let ret = cb(self); |
| self.gen_ctx = None; |
| ret |
| } |
| |
| /// This function trying to find any dangling references inside of `items` |
| fn assert_no_dangling_references(&self) { |
| if cfg!(feature = "assert_no_dangling_items") { |
| for _ in self.assert_no_dangling_item_traversal() { |
| // The iterator's next method does the asserting for us. |
| } |
| } |
| } |
| |
| fn assert_no_dangling_item_traversal<'me> |
| (&'me self) |
| -> traversal::AssertNoDanglingItemsTraversal<'me, 'ctx> { |
| assert!(self.in_codegen_phase()); |
| assert!(self.current_module == self.root_module); |
| |
| let roots = self.items().map(|(&id, _)| id); |
| traversal::AssertNoDanglingItemsTraversal::new(self, |
| roots, |
| traversal::all_edges) |
| } |
| |
| // This deserves a comment. Builtin types don't get a valid declaration, so |
| // we can't add it to the cursor->type map. |
| // |
| // That being said, they're not generated anyway, and are few, so the |
| // duplication and special-casing is fine. |
| // |
| // If at some point we care about the memory here, probably a map TypeKind |
| // -> builtin type ItemId would be the best to improve that. |
| fn add_builtin_item(&mut self, item: Item) { |
| debug!("add_builtin_item: item = {:?}", item); |
| debug_assert!(item.kind().is_type()); |
| let id = item.id(); |
| let old_item = self.items.insert(id, item); |
| assert!(old_item.is_none(), "Inserted type twice?"); |
| } |
| |
| fn build_root_module(id: ItemId) -> Item { |
| let module = Module::new(Some("root".into()), ModuleKind::Normal); |
| Item::new(id, None, None, id, ItemKind::Module(module)) |
| } |
| |
| /// Get the root module. |
| pub fn root_module(&self) -> ItemId { |
| self.root_module |
| } |
| |
| /// Resolve the given `ItemId` as a type. |
| /// |
| /// Panics if there is no item for the given `ItemId` or if the resolved |
| /// item is not a `Type`. |
| pub fn resolve_type(&self, type_id: ItemId) -> &Type { |
| self.items.get(&type_id).unwrap().kind().expect_type() |
| } |
| |
| /// Resolve the given `ItemId` as a type, or `None` if there is no item with |
| /// the given id. |
| /// |
| /// Panics if the id resolves to an item that is not a type. |
| pub fn safe_resolve_type(&self, type_id: ItemId) -> Option<&Type> { |
| self.items.get(&type_id).map(|t| t.kind().expect_type()) |
| } |
| |
| /// Resolve the given `ItemId` into an `Item`, or `None` if no such item |
| /// exists. |
| pub fn resolve_item_fallible(&self, item_id: ItemId) -> Option<&Item> { |
| self.items.get(&item_id) |
| } |
| |
| /// Resolve the given `ItemId` into an `Item`. |
| /// |
| /// Panics if the given id does not resolve to any item. |
| pub fn resolve_item(&self, item_id: ItemId) -> &Item { |
| match self.items.get(&item_id) { |
| Some(item) => item, |
| None => panic!("Not an item: {:?}", item_id), |
| } |
| } |
| |
| /// Get the current module. |
| pub fn current_module(&self) -> ItemId { |
| self.current_module |
| } |
| |
| /// Given a cursor pointing to the location of a template instantiation, |
| /// return a tuple of the form `(declaration_cursor, declaration_id, |
| /// num_expected_template_args)`. |
| /// |
| /// Note that `declaration_id` is not guaranteed to be in the context's item |
| /// set! It is possible that it is a partial type that we are still in the |
| /// middle of parsign. |
| fn get_declaration_info_for_template_instantiation |
| (&self, |
| instantiation: &Cursor) |
| -> Option<(Cursor, ItemId, usize)> { |
| instantiation.cur_type() |
| .canonical_declaration(Some(instantiation)) |
| .and_then(|canon_decl| { |
| self.get_resolved_type(&canon_decl) |
| .and_then(|template_decl_id| { |
| template_decl_id.num_template_params(self) |
| .map(|num_params| { |
| (*canon_decl.cursor(), |
| template_decl_id, |
| num_params) |
| }) |
| }) |
| }) |
| .or_else(|| { |
| // If we haven't already parsed the declaration of |
| // the template being instantiated, then it *must* |
| // be on the stack of types we are currently |
| // parsing. If it wasn't then clang would have |
| // already errored out before we started |
| // constructing our IR because you can't instantiate |
| // a template until it is fully defined. |
| instantiation.referenced() |
| .and_then(|referenced| { |
| self.currently_parsed_types() |
| .iter() |
| .find(|partial_ty| *partial_ty.decl() == referenced) |
| .cloned() |
| }) |
| .and_then(|template_decl| { |
| template_decl.num_template_params(self) |
| .map(|num_template_params| { |
| (*template_decl.decl(), |
| template_decl.id(), |
| num_template_params) |
| }) |
| }) |
| }) |
| } |
| |
| /// Parse a template instantiation, eg `Foo<int>`. |
| /// |
| /// This is surprisingly difficult to do with libclang, due to the fact that |
| /// it doesn't provide explicit template argument information, except for |
| /// function template declarations(!?!??!). |
| /// |
| /// The only way to do this is manually inspecting the AST and looking for |
| /// TypeRefs and TemplateRefs inside. This, unfortunately, doesn't work for |
| /// more complex cases, see the comment on the assertion below. |
| /// |
| /// To add insult to injury, the AST itself has structure that doesn't make |
| /// sense. Sometimes `Foo<Bar<int>>` has an AST with nesting like you might |
| /// expect: `(Foo (Bar (int)))`. Other times, the AST we get is completely |
| /// flat: `(Foo Bar int)`. |
| /// |
| /// To see an example of what this method handles: |
| /// |
| /// ```c++ |
| /// template<typename T> |
| /// class Incomplete { |
| /// T p; |
| /// }; |
| /// |
| /// template<typename U> |
| /// class Foo { |
| /// Incomplete<U> bar; |
| /// }; |
| /// ``` |
| fn instantiate_template(&mut self, |
| with_id: ItemId, |
| template: ItemId, |
| parent_id: ItemId, |
| ty: &clang::Type, |
| location: clang::Cursor) |
| -> Option<ItemId> { |
| use clang_sys; |
| |
| let num_expected_args = match self.resolve_type(template) |
| .num_template_params(self) { |
| Some(n) => n, |
| None => { |
| warn!("Tried to instantiate a template for which we could not \ |
| determine any template parameters"); |
| return None; |
| } |
| }; |
| |
| let mut args = vec![]; |
| let mut found_const_arg = false; |
| let mut children = location.collect_children(); |
| |
| if children.iter().all(|c| !c.has_children()) { |
| // This is insanity... If clang isn't giving us a properly nested |
| // AST for which template arguments belong to which template we are |
| // instantiating, we'll need to construct it ourselves. However, |
| // there is an extra `NamespaceRef, NamespaceRef, ..., TemplateRef` |
| // representing a reference to the outermost template declaration |
| // that we need to filter out of the children. We need to do this |
| // filtering because we already know which template declaration is |
| // being specialized via the `location`'s type, and if we do not |
| // filter it out, we'll add an extra layer of template instantiation |
| // on accident. |
| let idx = children.iter() |
| .position(|c| c.kind() == clang_sys::CXCursor_TemplateRef); |
| if let Some(idx) = idx { |
| if children.iter() |
| .take(idx) |
| .all(|c| c.kind() == clang_sys::CXCursor_NamespaceRef) { |
| children = children.into_iter().skip(idx + 1).collect(); |
| } |
| } |
| } |
| |
| for child in children.iter().rev() { |
| match child.kind() { |
| clang_sys::CXCursor_TypeRef | |
| clang_sys::CXCursor_TypedefDecl | |
| clang_sys::CXCursor_TypeAliasDecl => { |
| // The `with_id` id will potentially end up unused if we give up |
| // on this type (for example, because it has const value |
| // template args), so if we pass `with_id` as the parent, it is |
| // potentially a dangling reference. Instead, use the canonical |
| // template declaration as the parent. It is already parsed and |
| // has a known-resolvable `ItemId`. |
| let ty = Item::from_ty_or_ref(child.cur_type(), |
| Some(*child), |
| Some(template), |
| self); |
| args.push(ty); |
| } |
| clang_sys::CXCursor_TemplateRef => { |
| let (template_decl_cursor, template_decl_id, num_expected_template_args) = |
| match self.get_declaration_info_for_template_instantiation(child) { |
| Some(info) => info, |
| None => return None, |
| }; |
| |
| if num_expected_template_args == 0 || |
| child.has_at_least_num_children(num_expected_template_args) { |
| // Do a happy little parse. See comment in the TypeRef |
| // match arm about parent IDs. |
| let ty = Item::from_ty_or_ref(child.cur_type(), |
| Some(*child), |
| Some(template), |
| self); |
| args.push(ty); |
| } else { |
| // This is the case mentioned in the doc comment where |
| // clang gives us a flattened AST and we have to |
| // reconstruct which template arguments go to which |
| // instantiation :( |
| let args_len = args.len(); |
| if args_len < num_expected_template_args { |
| warn!("Found a template instantiation without \ |
| enough template arguments"); |
| return None; |
| } |
| |
| let mut sub_args: Vec<_> = |
| args.drain(args_len - num_expected_template_args..) |
| .collect(); |
| sub_args.reverse(); |
| |
| let sub_name = Some(template_decl_cursor.spelling()); |
| let sub_kind = |
| TypeKind::TemplateInstantiation(template_decl_id, |
| sub_args); |
| let sub_ty = Type::new(sub_name, |
| template_decl_cursor.cur_type() |
| .fallible_layout() |
| .ok(), |
| sub_kind, |
| false); |
| let sub_id = self.next_item_id(); |
| let sub_item = Item::new(sub_id, |
| None, |
| None, |
| template_decl_id, |
| ItemKind::Type(sub_ty)); |
| |
| // Bypass all the validations in add_item explicitly. |
| debug!("instantiate_template: inserting nested \ |
| instantiation item: {:?}", |
| sub_item); |
| debug_assert!(sub_id == sub_item.id()); |
| self.items.insert(sub_id, sub_item); |
| args.push(sub_id); |
| } |
| } |
| _ => { |
| warn!("Found template arg cursor we can't handle: {:?}", |
| child); |
| found_const_arg = true; |
| } |
| } |
| } |
| |
| if found_const_arg { |
| // This is a dependently typed template instantiation. That is, an |
| // instantiation of a template with one or more const values as |
| // template arguments, rather than only types as template |
| // arguments. For example, `Foo<true, 5>` versus `Bar<bool, int>`. |
| // We can't handle these instantiations, so just punt in this |
| // situation... |
| warn!("Found template instantiated with a const value; \ |
| bindgen can't handle this kind of template instantiation!"); |
| return None; |
| } |
| |
| if args.len() != num_expected_args { |
| warn!("Found a template with an unexpected number of template \ |
| arguments"); |
| return None; |
| } |
| |
| args.reverse(); |
| let type_kind = TypeKind::TemplateInstantiation(template, args); |
| let name = ty.spelling(); |
| let name = if name.is_empty() { None } else { Some(name) }; |
| let ty = Type::new(name, |
| ty.fallible_layout().ok(), |
| type_kind, |
| ty.is_const()); |
| let item = |
| Item::new(with_id, None, None, parent_id, ItemKind::Type(ty)); |
| |
| // Bypass all the validations in add_item explicitly. |
| debug!("instantiate_template: inserting item: {:?}", item); |
| debug_assert!(with_id == item.id()); |
| self.items.insert(with_id, item); |
| Some(with_id) |
| } |
| |
| /// If we have already resolved the type for the given type declaration, |
| /// return its `ItemId`. Otherwise, return `None`. |
| fn get_resolved_type(&self, |
| decl: &clang::CanonicalTypeDeclaration) |
| -> Option<ItemId> { |
| self.types |
| .get(&TypeKey::Declaration(*decl.cursor())) |
| .or_else(|| { |
| decl.cursor() |
| .usr() |
| .and_then(|usr| self.types.get(&TypeKey::USR(usr))) |
| }) |
| .cloned() |
| } |
| |
| /// Looks up for an already resolved type, either because it's builtin, or |
| /// because we already have it in the map. |
| pub fn builtin_or_resolved_ty(&mut self, |
| with_id: ItemId, |
| parent_id: Option<ItemId>, |
| ty: &clang::Type, |
| location: Option<clang::Cursor>) |
| -> Option<ItemId> { |
| use clang_sys::{CXCursor_TypeAliasTemplateDecl, CXCursor_TypeRef}; |
| debug!("builtin_or_resolved_ty: {:?}, {:?}, {:?}", |
| ty, |
| location, |
| parent_id); |
| |
| if let Some(decl) = ty.canonical_declaration(location.as_ref()) { |
| if let Some(id) = self.get_resolved_type(&decl) { |
| debug!("Already resolved ty {:?}, {:?}, {:?} {:?}", |
| id, |
| decl, |
| ty, |
| location); |
| // If the declaration already exists, then either: |
| // |
| // * the declaration is a template declaration of some sort, |
| // and we are looking at an instantiation or specialization |
| // of it, or |
| // * we have already parsed and resolved this type, and |
| // there's nothing left to do. |
| // |
| // Note that we only do the former if the `parent_id` exists, |
| // and we have a location for building the new arguments. The |
| // template argument names don't matter in the global context. |
| if decl.cursor().is_template_like() && |
| *ty != decl.cursor().cur_type() && |
| location.is_some() && |
| parent_id.is_some() { |
| let location = location.unwrap(); |
| let parent_id = parent_id.unwrap(); |
| |
| // For specialized type aliases, there's no way to get the |
| // template parameters as of this writing (for a struct |
| // specialization we wouldn't be in this branch anyway). |
| // |
| // Explicitly return `None` if there aren't any |
| // unspecialized parameters (contains any `TypeRef`) so we |
| // resolve the canonical type if there is one and it's |
| // exposed. |
| // |
| // This is _tricky_, I know :( |
| if decl.cursor().kind() == CXCursor_TypeAliasTemplateDecl && |
| !location.contains_cursor(CXCursor_TypeRef) && |
| ty.canonical_type().is_valid_and_exposed() { |
| return None; |
| } |
| |
| return self.instantiate_template(with_id, |
| id, |
| parent_id, |
| ty, |
| location) |
| .or_else(|| Some(id)); |
| } |
| |
| return Some(self.build_ty_wrapper(with_id, id, parent_id, ty)); |
| } |
| } |
| |
| debug!("Not resolved, maybe builtin?"); |
| self.build_builtin_ty(ty) |
| } |
| |
| // This is unfortunately a lot of bloat, but is needed to properly track |
| // constness et. al. |
| // |
| // We should probably make the constness tracking separate, so it doesn't |
| // bloat that much, but hey, we already bloat the heck out of builtin types. |
| fn build_ty_wrapper(&mut self, |
| with_id: ItemId, |
| wrapped_id: ItemId, |
| parent_id: Option<ItemId>, |
| ty: &clang::Type) |
| -> ItemId { |
| let spelling = ty.spelling(); |
| let is_const = ty.is_const(); |
| let layout = ty.fallible_layout().ok(); |
| let type_kind = TypeKind::ResolvedTypeRef(wrapped_id); |
| let ty = Type::new(Some(spelling), layout, type_kind, is_const); |
| let item = Item::new(with_id, |
| None, |
| None, |
| parent_id.unwrap_or(self.current_module), |
| ItemKind::Type(ty)); |
| self.add_builtin_item(item); |
| with_id |
| } |
| |
| /// Returns the next item id to be used for an item. |
| pub fn next_item_id(&mut self) -> ItemId { |
| let ret = self.next_item_id; |
| self.next_item_id = ItemId(self.next_item_id.0 + 1); |
| ret |
| } |
| |
| fn build_builtin_ty(&mut self, ty: &clang::Type) -> Option<ItemId> { |
| use clang_sys::*; |
| let type_kind = match ty.kind() { |
| CXType_NullPtr => TypeKind::NullPtr, |
| CXType_Void => TypeKind::Void, |
| CXType_Bool => TypeKind::Int(IntKind::Bool), |
| CXType_Int => TypeKind::Int(IntKind::Int), |
| CXType_UInt => TypeKind::Int(IntKind::UInt), |
| CXType_SChar | CXType_Char_S => TypeKind::Int(IntKind::Char), |
| CXType_UChar | CXType_Char_U => TypeKind::Int(IntKind::UChar), |
| CXType_Short => TypeKind::Int(IntKind::Short), |
| CXType_UShort => TypeKind::Int(IntKind::UShort), |
| CXType_WChar | CXType_Char16 => TypeKind::Int(IntKind::U16), |
| CXType_Char32 => TypeKind::Int(IntKind::U32), |
| CXType_Long => TypeKind::Int(IntKind::Long), |
| CXType_ULong => TypeKind::Int(IntKind::ULong), |
| CXType_LongLong => TypeKind::Int(IntKind::LongLong), |
| CXType_ULongLong => TypeKind::Int(IntKind::ULongLong), |
| CXType_Int128 => TypeKind::Int(IntKind::I128), |
| CXType_UInt128 => TypeKind::Int(IntKind::U128), |
| CXType_Float => TypeKind::Float(FloatKind::Float), |
| CXType_Double => TypeKind::Float(FloatKind::Double), |
| CXType_LongDouble => TypeKind::Float(FloatKind::LongDouble), |
| CXType_Float128 => TypeKind::Float(FloatKind::Float128), |
| CXType_Complex => { |
| let float_type = ty.elem_type() |
| .expect("Not able to resolve complex type?"); |
| let float_kind = match float_type.kind() { |
| CXType_Float => FloatKind::Float, |
| CXType_Double => FloatKind::Double, |
| CXType_LongDouble => FloatKind::LongDouble, |
| _ => panic!("Non floating-type complex?"), |
| }; |
| TypeKind::Complex(float_kind) |
| } |
| _ => return None, |
| }; |
| |
| let spelling = ty.spelling(); |
| let is_const = ty.is_const(); |
| let layout = ty.fallible_layout().ok(); |
| let ty = Type::new(Some(spelling), layout, type_kind, is_const); |
| let id = self.next_item_id(); |
| let item = |
| Item::new(id, None, None, self.root_module, ItemKind::Type(ty)); |
| self.add_builtin_item(item); |
| Some(id) |
| } |
| |
| /// Get the current Clang translation unit that is being processed. |
| pub fn translation_unit(&self) -> &clang::TranslationUnit { |
| &self.translation_unit |
| } |
| |
| /// Have we parsed the macro named `macro_name` already? |
| pub fn parsed_macro(&self, macro_name: &[u8]) -> bool { |
| self.parsed_macros.contains_key(macro_name) |
| } |
| |
| /// Get the currently parsed macros. |
| pub fn parsed_macros(&self) -> &HashMap<Vec<u8>, cexpr::expr::EvalResult> { |
| debug_assert!(!self.in_codegen_phase()); |
| &self.parsed_macros |
| } |
| |
| /// Mark the macro named `macro_name` as parsed. |
| pub fn note_parsed_macro(&mut self, |
| id: Vec<u8>, |
| value: cexpr::expr::EvalResult) { |
| self.parsed_macros.insert(id, value); |
| } |
| |
| /// Are we in the codegen phase? |
| pub fn in_codegen_phase(&self) -> bool { |
| self.gen_ctx.is_some() |
| } |
| |
| /// Mark the type with the given `name` as replaced by the type with id |
| /// `potential_ty`. |
| /// |
| /// Replacement types are declared using the `replaces="xxx"` annotation, |
| /// and implies that the original type is hidden. |
| 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 {:?}", |
| name, |
| potential_ty); |
| entry.insert(potential_ty); |
| } |
| hash_map::Entry::Occupied(occupied) => { |
| warn!("Replacement for {:?} already defined as {:?}; \ |
| ignoring duplicate replacement definition as {:?}", |
| name, |
| occupied.get(), |
| potential_ty); |
| } |
| } |
| } |
| |
| /// 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, path: &[String], id: ItemId) -> bool { |
| debug_assert!(self.in_codegen_phase(), |
| "You're not supposed to call this yet"); |
| self.options.hidden_types.matches(&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, 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, path: &[String]) -> bool { |
| debug_assert!(self.in_codegen_phase(), |
| "You're not supposed to call this yet"); |
| self.options.opaque_types.matches(&path[1..].join("::")) |
| } |
| |
| /// Get the options used to configure this bindgen context. |
| pub fn options(&self) -> &BindgenOptions { |
| &self.options |
| } |
| |
| /// Tokenizes a namespace cursor in order to get the name and kind of the |
| /// namespace, |
| fn tokenize_namespace(&self, |
| cursor: &clang::Cursor) |
| -> (Option<String>, ModuleKind) { |
| assert_eq!(cursor.kind(), |
| ::clang_sys::CXCursor_Namespace, |
| "Be a nice person"); |
| let tokens = match self.translation_unit.tokens(&cursor) { |
| Some(tokens) => tokens, |
| None => return (None, ModuleKind::Normal), |
| }; |
| |
| let mut iter = tokens.iter(); |
| let mut kind = ModuleKind::Normal; |
| let mut found_namespace_keyword = false; |
| let mut module_name = None; |
| while let Some(token) = iter.next() { |
| match &*token.spelling { |
| "inline" => { |
| assert!(!found_namespace_keyword); |
| assert!(kind != ModuleKind::Inline); |
| kind = ModuleKind::Inline; |
| } |
| "namespace" => { |
| found_namespace_keyword = true; |
| } |
| "{" => { |
| assert!(found_namespace_keyword); |
| break; |
| } |
| name if found_namespace_keyword => { |
| module_name = Some(name.to_owned()); |
| break; |
| } |
| _ => { |
| panic!("Unknown token while processing namespace: {:?}", |
| token); |
| } |
| } |
| } |
| |
| (module_name, kind) |
| } |
| |
| /// Given a CXCursor_Namespace cursor, return the item id of the |
| /// corresponding module, or create one on the fly. |
| pub fn module(&mut self, cursor: clang::Cursor) -> ItemId { |
| use clang_sys::*; |
| assert_eq!(cursor.kind(), CXCursor_Namespace, "Be a nice person"); |
| let cursor = cursor.canonical(); |
| if let Some(id) = self.modules.get(&cursor) { |
| return *id; |
| } |
| |
| let (module_name, kind) = self.tokenize_namespace(&cursor); |
| |
| let module_id = self.next_item_id(); |
| let module = Module::new(module_name, kind); |
| let module = Item::new(module_id, |
| None, |
| None, |
| self.current_module, |
| ItemKind::Module(module)); |
| |
| self.modules.insert(cursor, module.id()); |
| |
| self.add_item(module, None, None); |
| |
| module_id |
| } |
| |
| /// Start traversing the module with the given `module_id`, invoke the |
| /// callback `cb`, and then return to traversing the original module. |
| pub fn with_module<F>(&mut self, module_id: ItemId, cb: F) |
| where F: FnOnce(&mut Self), |
| { |
| debug_assert!(self.resolve_item(module_id).kind().is_module(), "Wat"); |
| |
| let previous_id = self.current_module; |
| self.current_module = module_id; |
| |
| cb(self); |
| |
| self.current_module = previous_id; |
| } |
| |
| /// Iterate over all (explicitly or transitively) whitelisted items. |
| /// |
| /// If no items are explicitly whitelisted, then all items are considered |
| /// whitelisted. |
| pub fn whitelisted_items<'me>(&'me self) -> WhitelistedItems<'me, 'ctx> { |
| assert!(self.in_codegen_phase()); |
| assert!(self.current_module == self.root_module); |
| |
| let roots = self.items() |
| .filter(|&(_, item)| { |
| // If nothing is explicitly whitelisted, then everything is fair |
| // game. |
| if self.options().whitelisted_types.is_empty() && |
| self.options().whitelisted_functions.is_empty() && |
| self.options().whitelisted_vars.is_empty() { |
| return true; |
| } |
| |
| // If this is a type that explicitly replaces another, we assume |
| // you know what you're doing. |
| if item.annotations().use_instead_of().is_some() { |
| return true; |
| } |
| |
| let name = item.canonical_path(self)[1..].join("::"); |
| debug!("whitelisted_items: testing {:?}", name); |
| match *item.kind() { |
| ItemKind::Module(..) => true, |
| ItemKind::Function(_) => { |
| self.options().whitelisted_functions.matches(&name) |
| } |
| ItemKind::Var(_) => { |
| self.options().whitelisted_vars.matches(&name) |
| } |
| ItemKind::Type(ref ty) => { |
| if self.options().whitelisted_types.matches(&name) { |
| return true; |
| } |
| |
| 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, |
| // and there's no way for them to be referenced |
| // consistently. |
| 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(&name) |
| }) { |
| return true; |
| } |
| } |
| } |
| |
| false |
| } |
| } |
| }) |
| .map(|(&id, _)| id); |
| |
| // The reversal preserves the expected ordering of traversal, resulting |
| // in more stable-ish bindgen-generated names for anonymous types (like |
| // unions). |
| let mut roots: Vec<_> = roots.collect(); |
| roots.reverse(); |
| |
| let predicate = if self.options().whitelist_recursively { |
| traversal::all_edges |
| } else { |
| traversal::no_edges |
| }; |
| |
| WhitelistedItems::new(self, roots, predicate) |
| } |
| |
| /// Convenient method for getting the prefix to use for most traits in |
| /// codegen depending on the `use_core` option. |
| pub fn trait_prefix(&self) -> Ident { |
| if self.options().use_core { |
| self.rust_ident_raw("core") |
| } else { |
| self.rust_ident_raw("std") |
| } |
| } |
| |
| /// Call if a binden complex is generated |
| pub fn generated_bindegen_complex(&self) { |
| self.generated_bindegen_complex.set(true) |
| } |
| |
| /// Whether we need to generate the binden complex type |
| pub fn need_bindegen_complex_type(&self) -> bool { |
| self.generated_bindegen_complex.get() |
| } |
| } |
| |
| /// A type that we are in the middle of parsing. |
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| pub struct PartialType { |
| decl: Cursor, |
| id: ItemId, |
| } |
| |
| impl PartialType { |
| /// Construct a new `PartialType`. |
| pub fn new(decl: Cursor, id: ItemId) -> PartialType { |
| // assert!(decl == decl.canonical()); |
| PartialType { |
| decl: decl, |
| id: id, |
| } |
| } |
| |
| /// The cursor pointing to this partial type's declaration location. |
| pub fn decl(&self) -> &Cursor { |
| &self.decl |
| } |
| |
| /// The item ID allocated for this type. This is *NOT* a key for an entry in |
| /// the context's item set yet! |
| pub fn id(&self) -> ItemId { |
| self.id |
| } |
| } |
| |
| impl TemplateDeclaration for PartialType { |
| fn template_params(&self, _ctx: &BindgenContext) -> Option<Vec<ItemId>> { |
| // Maybe at some point we will eagerly parse named types, but for now we |
| // don't and this information is unavailable. |
| None |
| } |
| |
| fn num_template_params(&self, _ctx: &BindgenContext) -> Option<usize> { |
| // Wouldn't it be nice if libclang would reliably give us this |
| // information‽ |
| match self.decl().kind() { |
| clang_sys::CXCursor_ClassTemplate | |
| clang_sys::CXCursor_FunctionTemplate | |
| clang_sys::CXCursor_TypeAliasTemplateDecl => { |
| let mut num_params = 0; |
| self.decl().visit(|c| { |
| match c.kind() { |
| clang_sys::CXCursor_TemplateTypeParameter | |
| clang_sys::CXCursor_TemplateTemplateParameter | |
| clang_sys::CXCursor_NonTypeTemplateParameter => { |
| num_params += 1; |
| } |
| _ => {} |
| }; |
| clang_sys::CXChildVisit_Continue |
| }); |
| Some(num_params) |
| } |
| _ => None, |
| } |
| } |
| } |