summaryrefslogtreecommitdiff
path: root/src/ir/context.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir/context.rs')
-rw-r--r--src/ir/context.rs1267
1 files changed, 1267 insertions, 0 deletions
diff --git a/src/ir/context.rs b/src/ir/context.rs
new file mode 100644
index 00000000..b0143bd5
--- /dev/null
+++ b/src/ir/context.rs
@@ -0,0 +1,1267 @@
+//! 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(&current)
+ .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)
+ }
+}