diff options
Diffstat (limited to 'libbindgen/src/ir/context.rs')
-rw-r--r-- | libbindgen/src/ir/context.rs | 1267 |
1 files changed, 0 insertions, 1267 deletions
diff --git a/libbindgen/src/ir/context.rs b/libbindgen/src/ir/context.rs deleted file mode 100644 index b0143bd5..00000000 --- a/libbindgen/src/ir/context.rs +++ /dev/null @@ -1,1267 +0,0 @@ -//! Common context that is passed around during parsing and codegen. - -use BindgenOptions; -use cexpr; -use chooser::TypeChooser; -use clang::{self, Cursor}; -use parse::ClangItemParser; -use std::borrow::Cow; -use std::cell::Cell; -use std::collections::{HashMap, VecDeque, hash_map}; -use std::collections::btree_map::{self, BTreeMap}; -use std::fmt; -use super::derive::{CanDeriveCopy, CanDeriveDebug}; -use super::int::IntKind; -use super::item::{Item, ItemCanonicalPath}; -use super::item_kind::ItemKind; -use super::module::{Module, ModuleKind}; -use super::ty::{FloatKind, Type, TypeKind}; -use super::type_collector::{ItemSet, TypeCollector}; -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<'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. - /// - /// FIXME: Should not be public, though... meh. - pub currently_parsed_types: Vec<(Cursor, ItemId)>, - - /// 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>, -} - -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 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) - -> AssertNoDanglingItemIter<'me, 'ctx> { - assert!(self.in_codegen_phase()); - assert!(self.current_module == self.root_module); - - let mut roots = self.items().map(|(&id, _)| id); - - let mut seen = BTreeMap::<ItemId, ItemId>::new(); - let next_child = roots.next().map(|id| id).unwrap(); - seen.insert(next_child, next_child); - - let to_iterate = seen.iter().map(|(&id, _)| id).rev().collect(); - - AssertNoDanglingItemIter { - ctx: self, - seen: seen, - to_iterate: to_iterate, - } - } - - // 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 - } - - /// This is one of the hackiest methods in all the parsing code. This method - /// is used to allow having templates with another argument names instead of - /// the canonical ones. - /// - /// This is surprisingly difficult to do with libclang, due to the fact that - /// partial template specializations don't provide explicit template - /// argument information. - /// - /// The only way to do this as far as I know, is inspecting manually the - /// AST, looking for TypeRefs inside. This, unfortunately, doesn't work for - /// more complex cases, see the comment on the assertion below. - /// - /// To see an example of what this handles: - /// - /// ```c++ - /// template<typename T> - /// class Incomplete { - /// T p; - /// }; - /// - /// template<typename U> - /// class Foo { - /// Incomplete<U> bar; - /// }; - /// ``` - fn build_template_wrapper(&mut self, - with_id: ItemId, - wrapping: ItemId, - parent_id: ItemId, - ty: &clang::Type, - location: clang::Cursor, - declaration: clang::Cursor) - -> ItemId { - use clang_sys::*; - let mut args = vec![]; - location.visit(|c| { - if c.kind() == CXCursor_TypeRef { - // The `with_id` id will potentially end up unused if we give up - // on this type (for example, its a tricky partial template - // specialization), 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 new_ty = Item::from_ty_or_ref(c.cur_type(), - Some(c), - Some(wrapping), - self); - args.push(new_ty); - } - CXChildVisit_Continue - }); - - let item = { - let wrapping_type = self.resolve_type(wrapping); - if let TypeKind::Comp(ref ci) = *wrapping_type.kind() { - let old_args = ci.template_args(); - - // The following assertion actually fails with partial template - // specialization. But as far as I know there's no way at all to - // grab the specialized types from neither the AST or libclang, - // which sucks. The same happens for specialized type alias - // template declarations, where we have that ugly hack up there. - // - // This flaw was already on the old parser, but I now think it - // has no clear solution (apart from patching libclang to - // somehow expose them, of course). - // - // For an easy example in which there's no way at all of getting - // the `int` type, except manually parsing the spelling: - // - // template<typename T, typename U> - // class Incomplete { - // T d; - // U p; - // }; - // - // template<typename U> - // class Foo { - // Incomplete<U, int> bar; - // }; - // - // debug_assert_eq!(old_args.len(), args.len()); - // - // That being said, this is not so common, so just error! and - // hope for the best, returning the previous type, who knows. - if old_args.len() != args.len() { - error!("Found partial template specialization, \ - expect dragons!"); - return wrapping; - } - } else { - assert_eq!(declaration.kind(), - ::clang_sys::CXCursor_TypeAliasTemplateDecl, - "Expected wrappable type"); - } - - let type_kind = TypeKind::TemplateRef(wrapping, 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()); - Item::new(with_id, None, None, parent_id, ItemKind::Type(ty)) - }; - - // Bypass all the validations in add_item explicitly. - debug!("build_template_wrapper: inserting item: {:?}", item); - debug_assert!(with_id == item.id()); - self.items.insert(with_id, item); - with_id - } - - /// 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); - let mut declaration = ty.declaration(); - if !declaration.is_valid() { - if let Some(location) = location { - if location.is_template_like() { - declaration = location; - } - } - } - let canonical_declaration = declaration.canonical(); - if canonical_declaration.is_valid() { - let id = self.types - .get(&TypeKey::Declaration(canonical_declaration)) - .map(|id| *id) - .or_else(|| { - canonical_declaration.usr() - .and_then(|usr| self.types.get(&TypeKey::USR(usr))) - .map(|id| *id) - }); - if let Some(id) = id { - debug!("Already resolved ty {:?}, {:?}, {:?} {:?}", - id, - declaration, - ty, - location); - - // If the declaration existed, we *might* be done, but it's not - // the case for class templates, where the template arguments - // may vary. - // - // In this case, we create a TemplateRef with the new template - // arguments, pointing to the canonical template. - // - // Note that we only do it if parent_id is some, and we have a - // location for building the new arguments, the template - // argument names don't matter in the global context. - if declaration.is_template_like() && - *ty != canonical_declaration.cur_type() && - location.is_some() && - parent_id.is_some() { - // 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 declaration.kind() == CXCursor_TypeAliasTemplateDecl && - !location.unwrap().contains_cursor(CXCursor_TypeRef) && - ty.canonical_type().is_valid_and_exposed() { - return None; - } - - return Some(self.build_template_wrapper(with_id, - id, - parent_id.unwrap(), - ty, - location.unwrap(), - declaration)); - } - - return Some(self.build_ty_wrapper(with_id, id, parent_id, ty)); - } - } - - debug!("Not resolved, maybe builtin?"); - - // Else, build it. - self.build_builtin_ty(ty, declaration) - } - - // 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, - _declaration: Cursor) - -> 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) - -> WhitelistedItemsIter<'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); - - let seen: ItemSet = roots.collect(); - - // The .rev() preserves the expected ordering traversal, resulting in - // more stable-ish bindgen-generated names for anonymous types (like - // unions). - let to_iterate = seen.iter().cloned().rev().collect(); - - WhitelistedItemsIter { - ctx: self, - seen: seen, - to_iterate: to_iterate, - } - } - - /// 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() - } -} - -/// An iterator over whitelisted items. -/// -/// See `BindgenContext::whitelisted_items` for more information. -pub struct WhitelistedItemsIter<'ctx, 'gen> - where 'gen: 'ctx, -{ - ctx: &'ctx BindgenContext<'gen>, - - // The set of whitelisted items we have seen. If you think of traversing - // whitelisted items like GC tracing, this is the mark bits, and contains - // both black and gray items. - seen: ItemSet, - - // The set of whitelisted items that we have seen but have yet to iterate - // over and collect transitive references from. To return to the GC analogy, - // this is the mark stack, containing the set of gray items which we have - // not finished tracing yet. - to_iterate: Vec<ItemId>, -} - -impl<'ctx, 'gen> Iterator for WhitelistedItemsIter<'ctx, 'gen> - where 'gen: 'ctx, -{ - type Item = ItemId; - - fn next(&mut self) -> Option<Self::Item> { - let id = match self.to_iterate.pop() { - None => return None, - Some(id) => id, - }; - - debug_assert!(self.seen.contains(&id)); - debug_assert!(self.ctx.items.contains_key(&id)); - - let mut sub_types = ItemSet::new(); - id.collect_types(self.ctx, &mut sub_types, &()); - - for id in sub_types { - if self.seen.insert(id) { - self.to_iterate.push(id); - } - } - - Some(id) - } -} - -/// An iterator to find any dangling items. -/// -/// See `BindgenContext::assert_no_dangling_item_traversal` for more -/// information. -pub struct AssertNoDanglingItemIter<'ctx, 'gen> - where 'gen: 'ctx, -{ - ctx: &'ctx BindgenContext<'gen>, - seen: BTreeMap<ItemId, ItemId>, - to_iterate: VecDeque<ItemId>, -} - -impl<'ctx, 'gen> Iterator for AssertNoDanglingItemIter<'ctx, 'gen> - where 'gen: 'ctx, -{ - type Item = ItemId; - - fn next(&mut self) -> Option<Self::Item> { - let id = match self.to_iterate.pop_front() { - None => { - // We've traversed everything reachable from the previous - // root(s), see if we have any more roots. - match self.ctx - .items() - .filter(|&(id, _)| !self.seen.contains_key(id)) - .next() - .map(|(id, _)| *id) { - None => return None, - Some(id) => { - // This is a new root. - self.seen.insert(id, id); - id - } - } - } - Some(id) => id, - }; - - let mut sub_types = ItemSet::new(); - id.collect_types(self.ctx, &mut sub_types, &()); - - if self.ctx.resolve_item_fallible(id).is_none() { - let mut path = vec![]; - let mut current = id; - loop { - let predecessor = *self.seen - .get(¤t) - .expect("We know we found this item id, so it must have a \ - predecessor"); - if predecessor == current { - break; - } - path.push(predecessor); - current = predecessor; - } - path.reverse(); - panic!("Found reference to dangling id = {:?}\nvia path = {:?}", - id, - path); - } - - for sub_id in sub_types { - if self.seen.insert(sub_id, id).is_none() { - // We've never visited this sub item before. - self.to_iterate.push_back(sub_id); - } - } - - Some(id) - } -} |