| //! Bindgen's core intermediate representation type. |
| |
| use super::annotations::Annotations; |
| use super::context::{BindgenContext, ItemId, PartialType}; |
| use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; |
| use super::function::Function; |
| use super::item_kind::ItemKind; |
| use super::module::Module; |
| use super::traversal::{Trace, Tracer}; |
| use super::ty::{TemplateDeclaration, Type, TypeKind}; |
| use clang; |
| use clang_sys; |
| use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; |
| use std::cell::{Cell, RefCell}; |
| use std::collections::BTreeSet; |
| use std::fmt::Write; |
| use std::iter; |
| |
| /// A trait to get the canonical name from an item. |
| /// |
| /// This is the trait that will eventually isolate all the logic related to name |
| /// mangling and that kind of stuff. |
| /// |
| /// This assumes no nested paths, at some point I'll have to make it a more |
| /// complex thing. |
| /// |
| /// This name is required to be safe for Rust, that is, is not expected to |
| /// return any rust keyword from here. |
| pub trait ItemCanonicalName { |
| /// Get the canonical name for this item. |
| fn canonical_name(&self, ctx: &BindgenContext) -> String; |
| } |
| |
| /// The same, but specifies the path that needs to be followed to reach an item. |
| /// |
| /// To contrast with canonical_name, here's an example: |
| /// |
| /// ```c++ |
| /// namespace foo { |
| /// const BAR = 3; |
| /// } |
| /// ``` |
| /// |
| /// For bar, the canonical path is `vec!["foo", "BAR"]`, while the canonical |
| /// name is just `"BAR"`. |
| pub trait ItemCanonicalPath { |
| /// Get the namespace-aware canonical path for this item. This means that if |
| /// namespaces are disabled, you'll get a single item, and otherwise you get |
| /// the whole path. |
| fn namespace_aware_canonical_path(&self, |
| ctx: &BindgenContext) |
| -> Vec<String>; |
| |
| /// Get the canonical path for this item. |
| fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String>; |
| } |
| |
| /// A trait for iterating over an item and its parents and up its ancestor chain |
| /// up to (but not including) the implicit root module. |
| pub trait ItemAncestors { |
| /// Get an iterable over this item's ancestors. |
| fn ancestors<'a, 'b>(&self, |
| ctx: &'a BindgenContext<'b>) |
| -> ItemAncestorsIter<'a, 'b>; |
| } |
| |
| cfg_if! { |
| if #[cfg(debug_assertions)] { |
| type DebugOnlyItemSet = ItemSet; |
| } else { |
| struct DebugOnlyItemSet; |
| |
| impl DebugOnlyItemSet { |
| fn new() -> Self { |
| DebugOnlyItemSet |
| } |
| |
| fn contains(&self,_id: &ItemId) -> bool { |
| false |
| } |
| |
| fn insert(&mut self, _id: ItemId) {} |
| } |
| } |
| } |
| |
| /// An iterator over an item and its ancestors. |
| pub struct ItemAncestorsIter<'a, 'b> |
| where 'b: 'a, |
| { |
| item: ItemId, |
| ctx: &'a BindgenContext<'b>, |
| seen: DebugOnlyItemSet, |
| } |
| |
| impl<'a, 'b> ItemAncestorsIter<'a, 'b> |
| where 'b: 'a, |
| { |
| fn new(ctx: &'a BindgenContext<'b>, item: ItemId) -> Self { |
| ItemAncestorsIter { |
| item: item, |
| ctx: ctx, |
| seen: DebugOnlyItemSet::new(), |
| } |
| } |
| } |
| |
| impl<'a, 'b> Iterator for ItemAncestorsIter<'a, 'b> |
| where 'b: 'a, |
| { |
| type Item = ItemId; |
| |
| fn next(&mut self) -> Option<Self::Item> { |
| let item = self.ctx.resolve_item(self.item); |
| |
| if item.parent_id() == self.item { |
| None |
| } else { |
| self.item = item.parent_id(); |
| |
| debug_assert!(!self.seen.contains(&item.id())); |
| self.seen.insert(item.id()); |
| |
| Some(item.id()) |
| } |
| } |
| } |
| |
| // Pure convenience |
| impl ItemCanonicalName for ItemId { |
| fn canonical_name(&self, ctx: &BindgenContext) -> String { |
| debug_assert!(ctx.in_codegen_phase(), |
| "You're not supposed to call this yet"); |
| ctx.resolve_item(*self).canonical_name(ctx) |
| } |
| } |
| |
| impl ItemCanonicalPath for ItemId { |
| fn namespace_aware_canonical_path(&self, |
| ctx: &BindgenContext) |
| -> Vec<String> { |
| debug_assert!(ctx.in_codegen_phase(), |
| "You're not supposed to call this yet"); |
| ctx.resolve_item(*self).namespace_aware_canonical_path(ctx) |
| } |
| |
| fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> { |
| debug_assert!(ctx.in_codegen_phase(), |
| "You're not supposed to call this yet"); |
| ctx.resolve_item(*self).canonical_path(ctx) |
| } |
| } |
| |
| impl ItemAncestors for ItemId { |
| fn ancestors<'a, 'b>(&self, |
| ctx: &'a BindgenContext<'b>) |
| -> ItemAncestorsIter<'a, 'b> { |
| ItemAncestorsIter::new(ctx, *self) |
| } |
| } |
| |
| impl ItemAncestors for Item { |
| fn ancestors<'a, 'b>(&self, |
| ctx: &'a BindgenContext<'b>) |
| -> ItemAncestorsIter<'a, 'b> { |
| self.id().ancestors(ctx) |
| } |
| } |
| |
| impl Trace for ItemId { |
| type Extra = (); |
| |
| fn trace<T>(&self, ctx: &BindgenContext, tracer: &mut T, extra: &()) |
| where T: Tracer, |
| { |
| ctx.resolve_item(*self).trace(ctx, tracer, extra); |
| } |
| } |
| |
| impl Trace for Item { |
| type Extra = (); |
| |
| fn trace<T>(&self, ctx: &BindgenContext, tracer: &mut T, _extra: &()) |
| where T: Tracer, |
| { |
| if self.is_hidden(ctx) { |
| return; |
| } |
| |
| match *self.kind() { |
| ItemKind::Type(ref ty) => { |
| // There are some types, like resolved type references, where we |
| // don't want to stop collecting types even though they may be |
| // opaque. |
| if ty.should_be_traced_unconditionally() || |
| !self.is_opaque(ctx) { |
| ty.trace(ctx, tracer, self); |
| } |
| } |
| ItemKind::Function(ref fun) => { |
| // Just the same way, it has not real meaning for a function to |
| // be opaque, so we trace across it. |
| tracer.visit(fun.signature()); |
| } |
| ItemKind::Var(ref var) => { |
| tracer.visit(var.ty()); |
| } |
| ItemKind::Module(_) => { |
| // Module -> children edges are "weak", and we do not want to |
| // trace them. If we did, then whitelisting wouldn't work as |
| // expected: everything in every module would end up |
| // whitelisted. |
| // |
| // TODO: make a new edge kind for module -> children edges and |
| // filter them during whitelisting traversals. |
| } |
| } |
| } |
| } |
| |
| impl CanDeriveDebug for Item { |
| type Extra = (); |
| |
| fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool { |
| ctx.options().derive_debug && |
| match self.kind { |
| ItemKind::Type(ref ty) => { |
| if self.is_opaque(ctx) { |
| ty.layout(ctx) |
| .map_or(true, |l| l.opaque().can_derive_debug(ctx, ())) |
| } else { |
| ty.can_derive_debug(ctx, ()) |
| } |
| } |
| _ => false, |
| } |
| } |
| } |
| |
| impl CanDeriveDefault for Item { |
| type Extra = (); |
| |
| fn can_derive_default(&self, ctx: &BindgenContext, _: ()) -> bool { |
| ctx.options().derive_default && |
| match self.kind { |
| ItemKind::Type(ref ty) => { |
| if self.is_opaque(ctx) { |
| ty.layout(ctx) |
| .map_or(false, |
| |l| l.opaque().can_derive_default(ctx, ())) |
| } else { |
| ty.can_derive_default(ctx, ()) |
| } |
| } |
| _ => false, |
| } |
| } |
| } |
| |
| impl<'a> CanDeriveCopy<'a> for Item { |
| type Extra = (); |
| |
| fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool { |
| match self.kind { |
| ItemKind::Type(ref ty) => { |
| if self.is_opaque(ctx) { |
| ty.layout(ctx) |
| .map_or(true, |l| l.opaque().can_derive_copy(ctx, ())) |
| } else { |
| ty.can_derive_copy(ctx, self) |
| } |
| } |
| _ => false, |
| } |
| } |
| |
| fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool { |
| match self.kind { |
| ItemKind::Type(ref ty) => { |
| if self.is_opaque(ctx) { |
| ty.layout(ctx) |
| .map_or(true, |l| { |
| l.opaque().can_derive_copy_in_array(ctx, ()) |
| }) |
| } else { |
| ty.can_derive_copy_in_array(ctx, self) |
| } |
| } |
| _ => false, |
| } |
| } |
| } |
| |
| /// An item is the base of the bindgen representation, it can be either a |
| /// module, a type, a function, or a variable (see `ItemKind` for more |
| /// information). |
| /// |
| /// Items refer to each other by `ItemId`. Every item has its parent's |
| /// id. Depending on the kind of item this is, it may also refer to other items, |
| /// such as a compound type item referring to other types. Collectively, these |
| /// references form a graph. |
| /// |
| /// The entry-point to this graph is the "root module": a meta-item used to hold |
| /// all top-level items. |
| /// |
| /// An item may have a comment, and annotations (see the `annotations` module). |
| /// |
| /// Note that even though we parse all the types of annotations in comments, not |
| /// all of them apply to every item. Those rules are described in the |
| /// `annotations` module. |
| #[derive(Debug)] |
| pub struct Item { |
| /// This item's id. |
| id: ItemId, |
| |
| /// The item's local id, unique only amongst its siblings. Only used for |
| /// anonymous items. |
| /// |
| /// Lazily initialized in local_id(). |
| /// |
| /// Note that only structs, unions, and enums get a local type id. In any |
| /// case this is an implementation detail. |
| local_id: Cell<Option<usize>>, |
| |
| /// The next local id to use for a child.. |
| next_child_local_id: Cell<usize>, |
| |
| /// A cached copy of the canonical name, as returned by `canonical_name`. |
| /// |
| /// This is a fairly used operation during codegen so this makes bindgen |
| /// considerably faster in those cases. |
| canonical_name_cache: RefCell<Option<String>>, |
| |
| /// A doc comment over the item, if any. |
| comment: Option<String>, |
| /// Annotations extracted from the doc comment, or the default ones |
| /// otherwise. |
| annotations: Annotations, |
| /// An item's parent id. This will most likely be a class where this item |
| /// was declared, or a module, etc. |
| /// |
| /// All the items have a parent, except the root module, in which case the |
| /// parent id is its own id. |
| parent_id: ItemId, |
| /// The item kind. |
| kind: ItemKind, |
| } |
| |
| impl Item { |
| /// Construct a new `Item`. |
| pub fn new(id: ItemId, |
| comment: Option<String>, |
| annotations: Option<Annotations>, |
| parent_id: ItemId, |
| kind: ItemKind) |
| -> Self { |
| debug_assert!(id != parent_id || kind.is_module()); |
| Item { |
| id: id, |
| local_id: Cell::new(None), |
| next_child_local_id: Cell::new(1), |
| canonical_name_cache: RefCell::new(None), |
| parent_id: parent_id, |
| comment: comment, |
| annotations: annotations.unwrap_or_default(), |
| kind: kind, |
| } |
| } |
| |
| /// Get this `Item`'s identifier. |
| pub fn id(&self) -> ItemId { |
| self.id |
| } |
| |
| /// Get this `Item`'s dot attributes. |
| pub fn dot_attributes(&self, ctx: &BindgenContext) -> String { |
| format!("[fontname=\"courier\", label=< \ |
| <table border=\"0\"> \ |
| <tr><td>ItemId({})</td></tr> \ |
| <tr><td>name</td><td>{}</td></tr> \ |
| <tr><td>kind</td><td>{}</td></tr> \ |
| </table> \ |
| >]", |
| self.id.as_usize(), |
| self.name(ctx).get(), |
| self.kind.kind_name()) |
| } |
| |
| /// Get this `Item`'s parent's identifier. |
| /// |
| /// For the root module, the parent's ID is its own ID. |
| pub fn parent_id(&self) -> ItemId { |
| self.parent_id |
| } |
| |
| /// Set this item's parent id. |
| /// |
| /// This is only used so replacements get generated in the proper module. |
| pub fn set_parent_for_replacement(&mut self, id: ItemId) { |
| self.parent_id = id; |
| } |
| |
| /// Get this `Item`'s comment, if it has any. |
| pub fn comment(&self) -> Option<&str> { |
| self.comment.as_ref().map(|c| &**c) |
| } |
| |
| /// What kind of item is this? |
| pub fn kind(&self) -> &ItemKind { |
| &self.kind |
| } |
| |
| /// Get a mutable reference to this item's kind. |
| pub fn kind_mut(&mut self) -> &mut ItemKind { |
| &mut self.kind |
| } |
| |
| /// Get an identifier that differentiates this item from its siblings. |
| /// |
| /// This should stay relatively stable in the face of code motion outside or |
| /// below this item's lexical scope, meaning that this can be useful for |
| /// generating relatively stable identifiers within a scope. |
| pub fn local_id(&self, ctx: &BindgenContext) -> usize { |
| if self.local_id.get().is_none() { |
| let parent = ctx.resolve_item(self.parent_id); |
| let local_id = parent.next_child_local_id.get(); |
| parent.next_child_local_id.set(local_id + 1); |
| self.local_id.set(Some(local_id)); |
| } |
| self.local_id.get().unwrap() |
| } |
| |
| /// Returns whether this item is a top-level item, from the point of view of |
| /// bindgen. |
| /// |
| /// This point of view changes depending on whether namespaces are enabled |
| /// or not. That way, in the following example: |
| /// |
| /// ```c++ |
| /// namespace foo { |
| /// static int var; |
| /// } |
| /// ``` |
| /// |
| /// `var` would be a toplevel item if namespaces are disabled, but won't if |
| /// they aren't. |
| /// |
| /// This function is used to determine when the codegen phase should call |
| /// `codegen` on an item, since any item that is not top-level will be |
| /// generated by its parent. |
| pub fn is_toplevel(&self, ctx: &BindgenContext) -> bool { |
| // FIXME: Workaround for some types falling behind when parsing weird |
| // stl classes, for example. |
| if ctx.options().enable_cxx_namespaces && self.kind().is_module() && |
| self.id() != ctx.root_module() { |
| return false; |
| } |
| |
| let mut parent = self.parent_id; |
| loop { |
| let parent_item = match ctx.resolve_item_fallible(parent) { |
| Some(item) => item, |
| None => return false, |
| }; |
| |
| if parent_item.id() == ctx.root_module() { |
| return true; |
| } else if ctx.options().enable_cxx_namespaces || |
| !parent_item.kind().is_module() { |
| return false; |
| } |
| |
| parent = parent_item.parent_id(); |
| } |
| } |
| |
| /// Get a reference to this item's underlying `Type`. Panic if this is some |
| /// other kind of item. |
| pub fn expect_type(&self) -> &Type { |
| self.kind().expect_type() |
| } |
| |
| /// Get a reference to this item's underlying `Type`, or `None` if this is |
| /// some other kind of item. |
| pub fn as_type(&self) -> Option<&Type> { |
| self.kind().as_type() |
| } |
| |
| /// Is this item a named template type parameter? |
| pub fn is_named(&self) -> bool { |
| self.as_type() |
| .map(|ty| ty.is_named()) |
| .unwrap_or(false) |
| } |
| |
| /// Get a reference to this item's underlying `Function`. Panic if this is |
| /// some other kind of item. |
| pub fn expect_function(&self) -> &Function { |
| self.kind().expect_function() |
| } |
| |
| /// Checks whether an item contains in its "type signature" some named type. |
| /// |
| /// This function is used to avoid unused template parameter errors in Rust |
| /// when generating typedef declarations, and also to know whether we need |
| /// to generate a `PhantomData` member for a template parameter. |
| /// |
| /// For example, in code like the following: |
| /// |
| /// ```c++ |
| /// template<typename T, typename U> |
| /// struct Foo { |
| /// T bar; |
| /// |
| /// struct Baz { |
| /// U bas; |
| /// }; |
| /// }; |
| /// ``` |
| /// |
| /// Both `Foo` and `Baz` contain both `T` and `U` template parameters in |
| /// their signature: |
| /// |
| /// * `Foo<T, U>` |
| /// * `Bar<T, U>` |
| /// |
| /// But the Rust structure for `Foo` would look like: |
| /// |
| /// ```rust |
| /// struct Foo<T, U> { |
| /// bar: T, |
| /// _phantom0: ::std::marker::PhantomData<U>, |
| /// } |
| /// ``` |
| /// |
| /// because none of its member fields contained the `U` type in the |
| /// signature. Similarly, `Bar` would contain a `PhantomData<T>` type, for |
| /// the same reason. |
| /// |
| /// Note that this is somewhat similar to `applicable_template_args`, but |
| /// this also takes into account other kind of types, like arrays, |
| /// (`[T; 40]`), pointers: `*mut T`, etc... |
| /// |
| /// Normally we could do this check just in the `Type` kind, but we also |
| /// need to check the `applicable_template_args` more generally, since we |
| /// could need a type transitively from our parent, see the test added in |
| /// commit 2a3f93074dd2898669dbbce6e97e5cc4405d7cb1. |
| /// |
| /// It's kind of unfortunate (in the sense that it's a sort of complex |
| /// process), but I think it should get all the cases. |
| fn signature_contains_named_type(&self, |
| ctx: &BindgenContext, |
| ty: &Type) |
| -> bool { |
| debug_assert!(ty.is_named()); |
| self.expect_type().signature_contains_named_type(ctx, ty) || |
| self.applicable_template_args(ctx).iter().any(|template| { |
| ctx.resolve_type(*template).signature_contains_named_type(ctx, ty) |
| }) |
| } |
| |
| /// Returns the template arguments that apply to a struct. This is a concept |
| /// needed because of type declarations inside templates, for example: |
| /// |
| /// ```c++ |
| /// template<typename T> |
| /// class Foo { |
| /// typedef T element_type; |
| /// typedef int Bar; |
| /// |
| /// template<typename U> |
| /// class Baz { |
| /// }; |
| /// }; |
| /// ``` |
| /// |
| /// In this case, the applicable template arguments for the different types |
| /// would be: |
| /// |
| /// * `Foo`: [`T`] |
| /// * `Foo::element_type`: [`T`] |
| /// * `Foo::Bar`: [`T`] |
| /// * `Foo::Baz`: [`T`, `U`] |
| /// |
| /// You might notice that we can't generate something like: |
| /// |
| /// ```rust,ignore |
| /// type Foo_Bar<T> = ::std::os::raw::c_int; |
| /// ``` |
| /// |
| /// since that would be invalid Rust. Still, conceptually, `Bar` *could* use |
| /// the template parameter type `T`, and that's exactly what this method |
| /// represents. The unused template parameters get stripped in the |
| /// `signature_contains_named_type` check. |
| pub fn applicable_template_args(&self, |
| ctx: &BindgenContext) |
| -> Vec<ItemId> { |
| let ty = match *self.kind() { |
| ItemKind::Type(ref ty) => ty, |
| _ => return vec![], |
| }; |
| |
| fn parent_contains(ctx: &BindgenContext, |
| parent_template_args: &[ItemId], |
| item: ItemId) |
| -> bool { |
| let item_ty = ctx.resolve_type(item); |
| parent_template_args.iter().any(|parent_item| { |
| let parent_ty = ctx.resolve_type(*parent_item); |
| match (parent_ty.kind(), item_ty.kind()) { |
| (&TypeKind::Named, &TypeKind::Named) => { |
| parent_ty.name() == item_ty.name() |
| } |
| _ => false, |
| } |
| }) |
| } |
| |
| match *ty.kind() { |
| TypeKind::Named => vec![self.id()], |
| TypeKind::Array(inner, _) | |
| TypeKind::Pointer(inner) | |
| TypeKind::Reference(inner) | |
| TypeKind::ResolvedTypeRef(inner) => { |
| ctx.resolve_item(inner).applicable_template_args(ctx) |
| } |
| TypeKind::Alias(inner) => { |
| let parent_args = ctx.resolve_item(self.parent_id()) |
| .applicable_template_args(ctx); |
| let inner = ctx.resolve_item(inner); |
| |
| // Avoid unused type parameters, sigh. |
| parent_args.iter() |
| .cloned() |
| .filter(|arg| { |
| let arg = ctx.resolve_type(*arg); |
| arg.is_named() && |
| inner.signature_contains_named_type(ctx, arg) |
| }) |
| .collect() |
| } |
| // XXX Is this completely correct? Partial template specialization |
| // is hard anyways, sigh... |
| TypeKind::TemplateAlias(_, ref args) | |
| TypeKind::TemplateInstantiation(_, ref args) => args.clone(), |
| // In a template specialization we've got all we want. |
| TypeKind::Comp(ref ci) if ci.is_template_specialization() => { |
| ci.template_args().iter().cloned().collect() |
| } |
| TypeKind::Comp(ref ci) => { |
| let mut parent_template_args = |
| ctx.resolve_item(self.parent_id()) |
| .applicable_template_args(ctx); |
| |
| for ty in ci.template_args() { |
| if !parent_contains(ctx, &parent_template_args, *ty) { |
| parent_template_args.push(*ty); |
| } |
| } |
| |
| parent_template_args |
| } |
| _ => vec![], |
| } |
| } |
| |
| /// Is this item a module? |
| pub fn is_module(&self) -> bool { |
| match self.kind { |
| ItemKind::Module(..) => true, |
| _ => false, |
| } |
| } |
| |
| /// Get this item's annotations. |
| pub fn annotations(&self) -> &Annotations { |
| &self.annotations |
| } |
| |
| /// Whether this item should be hidden. |
| /// |
| /// This may be due to either annotations or to other kind of configuration. |
| pub fn is_hidden(&self, ctx: &BindgenContext) -> bool { |
| debug_assert!(ctx.in_codegen_phase(), |
| "You're not supposed to call this yet"); |
| self.annotations.hide() || |
| ctx.hidden_by_name(&self.canonical_path(ctx), self.id) |
| } |
| |
| /// Is this item opaque? |
| pub fn is_opaque(&self, ctx: &BindgenContext) -> bool { |
| debug_assert!(ctx.in_codegen_phase(), |
| "You're not supposed to call this yet"); |
| self.annotations.opaque() || |
| ctx.opaque_by_name(&self.canonical_path(ctx)) |
| } |
| |
| /// Is this a reference to another type? |
| pub fn is_type_ref(&self) -> bool { |
| self.as_type().map_or(false, |ty| ty.is_type_ref()) |
| } |
| |
| /// Is this item a var type? |
| pub fn is_var(&self) -> bool { |
| match *self.kind() { |
| ItemKind::Var(..) => true, |
| _ => false, |
| } |
| } |
| |
| /// Take out item NameOptions |
| pub fn name<'item, 'ctx>(&'item self, |
| ctx: &'item BindgenContext<'ctx>) |
| -> NameOptions<'item, 'ctx> { |
| NameOptions::new(self, ctx) |
| } |
| |
| /// Get the target item id for name generation. |
| fn name_target(&self, ctx: &BindgenContext) -> ItemId { |
| let mut targets_seen = DebugOnlyItemSet::new(); |
| let mut item = self; |
| |
| loop { |
| debug_assert!(!targets_seen.contains(&item.id())); |
| targets_seen.insert(item.id()); |
| |
| if self.annotations().use_instead_of().is_some() { |
| return self.id(); |
| } |
| |
| match *item.kind() { |
| ItemKind::Type(ref ty) => { |
| match *ty.kind() { |
| // If we're a template specialization, our name is our |
| // parent's name. |
| TypeKind::Comp(ref ci) |
| if ci.is_template_specialization() => { |
| let specialized = |
| ci.specialized_template().unwrap(); |
| item = ctx.resolve_item(specialized); |
| } |
| // Same as above. |
| TypeKind::ResolvedTypeRef(inner) | |
| TypeKind::TemplateInstantiation(inner, _) => { |
| item = ctx.resolve_item(inner); |
| } |
| _ => return item.id(), |
| } |
| } |
| _ => return item.id(), |
| } |
| } |
| } |
| |
| /// Get this function item's name, or `None` if this item is not a function. |
| fn func_name(&self) -> Option<&str> { |
| match *self.kind() { |
| ItemKind::Function(ref func) => Some(func.name()), |
| _ => None, |
| } |
| } |
| |
| /// Get the overload index for this method. If this is not a method, return |
| /// `None`. |
| fn overload_index(&self, ctx: &BindgenContext) -> Option<usize> { |
| self.func_name().and_then(|func_name| { |
| let parent = ctx.resolve_item(self.parent_id()); |
| if let ItemKind::Type(ref ty) = *parent.kind() { |
| if let TypeKind::Comp(ref ci) = *ty.kind() { |
| // All the constructors have the same name, so no need to |
| // resolve and check. |
| return ci.constructors() |
| .iter() |
| .position(|c| *c == self.id()) |
| .or_else(|| { |
| ci.methods() |
| .iter() |
| .filter(|m| { |
| let item = ctx.resolve_item(m.signature()); |
| let func = item.expect_function(); |
| func.name() == func_name |
| }) |
| .position(|m| m.signature() == self.id()) |
| }); |
| } |
| } |
| |
| None |
| }) |
| } |
| |
| /// Get this item's base name (aka non-namespaced name). |
| fn base_name(&self, ctx: &BindgenContext) -> String { |
| if let Some(path) = self.annotations().use_instead_of() { |
| return path.last().unwrap().clone(); |
| } |
| |
| match *self.kind() { |
| ItemKind::Var(ref var) => var.name().to_owned(), |
| ItemKind::Module(ref module) => { |
| module.name() |
| .map(ToOwned::to_owned) |
| .unwrap_or_else(|| { |
| format!("_bindgen_mod_{}", self.exposed_id(ctx)) |
| }) |
| } |
| ItemKind::Type(ref ty) => { |
| let name = match *ty.kind() { |
| TypeKind::ResolvedTypeRef(..) => panic!("should have resolved this in name_target()"), |
| _ => ty.name(), |
| }; |
| name.map(ToOwned::to_owned) |
| .unwrap_or_else(|| { |
| format!("_bindgen_ty_{}", self.exposed_id(ctx)) |
| }) |
| } |
| ItemKind::Function(ref fun) => { |
| let mut name = fun.name().to_owned(); |
| |
| if let Some(idx) = self.overload_index(ctx) { |
| if idx > 0 { |
| write!(&mut name, "{}", idx).unwrap(); |
| } |
| } |
| |
| name |
| } |
| } |
| } |
| |
| /// Get the canonical name without taking into account the replaces |
| /// annotation. |
| /// |
| /// This is the base logic used to implement hiding and replacing via |
| /// annotations, and also to implement proper name mangling. |
| /// |
| /// The idea is that each generated type in the same "level" (read: module |
| /// or namespace) has a unique canonical name. |
| /// |
| /// This name should be derived from the immutable state contained in the |
| /// type and the parent chain, since it should be consistent. |
| pub fn real_canonical_name(&self, |
| ctx: &BindgenContext, |
| opt: &NameOptions) |
| -> String { |
| let target = ctx.resolve_item(self.name_target(ctx)); |
| |
| // Short-circuit if the target has an override, and just use that. |
| if let Some(path) = target.annotations.use_instead_of() { |
| if ctx.options().enable_cxx_namespaces { |
| return path.last().unwrap().clone(); |
| } |
| return path.join("_").to_owned(); |
| } |
| |
| let base_name = target.base_name(ctx); |
| |
| // Named template type arguments are never namespaced, and never |
| // mangled. |
| if target.as_type().map_or(false, |ty| ty.is_named()) { |
| return base_name; |
| } |
| |
| // Concatenate this item's ancestors' names together. |
| let mut names: Vec<_> = target.parent_id() |
| .ancestors(ctx) |
| .filter(|id| *id != ctx.root_module()) |
| .take_while(|id| { |
| // Stop iterating ancestors once we reach a namespace. |
| !opt.within_namespaces || !ctx.resolve_item(*id).is_module() |
| }) |
| .map(|id| { |
| let item = ctx.resolve_item(id); |
| let target = ctx.resolve_item(item.name_target(ctx)); |
| target.base_name(ctx) |
| }) |
| .filter(|name| !name.is_empty()) |
| .collect(); |
| |
| names.reverse(); |
| |
| if !base_name.is_empty() { |
| names.push(base_name); |
| } |
| |
| let name = names.join("_"); |
| |
| ctx.rust_mangle(&name).into_owned() |
| } |
| |
| fn exposed_id(&self, ctx: &BindgenContext) -> String { |
| // Only use local ids for enums, classes, structs and union types. All |
| // other items use their global id. |
| let ty_kind = self.kind().as_type().map(|t| t.kind()); |
| if let Some(ty_kind) = ty_kind { |
| match *ty_kind { |
| TypeKind::Comp(..) | |
| TypeKind::Enum(..) => return self.local_id(ctx).to_string(), |
| _ => {} |
| } |
| } |
| |
| // Note that this `id_` prefix prevents (really unlikely) collisions |
| // between the global id and the local id of an item with the same |
| // parent. |
| format!("id_{}", self.id().as_usize()) |
| } |
| |
| /// Get a reference to this item's `Module`, or `None` if this is not a |
| /// `Module` item. |
| pub fn as_module(&self) -> Option<&Module> { |
| match self.kind { |
| ItemKind::Module(ref module) => Some(module), |
| _ => None, |
| } |
| } |
| |
| /// Get a mutable reference to this item's `Module`, or `None` if this is |
| /// not a `Module` item. |
| pub fn as_module_mut(&mut self) -> Option<&mut Module> { |
| match self.kind { |
| ItemKind::Module(ref mut module) => Some(module), |
| _ => None, |
| } |
| } |
| } |
| |
| /// A set of items. |
| pub type ItemSet = BTreeSet<ItemId>; |
| |
| impl TemplateDeclaration for ItemId { |
| fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> { |
| ctx.resolve_item_fallible(*self) |
| .and_then(|item| item.template_params(ctx)) |
| } |
| } |
| |
| impl TemplateDeclaration for Item { |
| fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> { |
| self.kind.template_params(ctx) |
| } |
| } |
| |
| impl TemplateDeclaration for ItemKind { |
| fn template_params(&self, ctx: &BindgenContext) -> Option<Vec<ItemId>> { |
| match *self { |
| ItemKind::Type(ref ty) => ty.template_params(ctx), |
| // If we start emitting bindings to explicitly instantiated |
| // functions, then we'll need to check ItemKind::Function for |
| // template params. |
| ItemKind::Function(_) | |
| ItemKind::Module(_) | |
| ItemKind::Var(_) => None, |
| } |
| } |
| } |
| |
| // An utility function to handle recursing inside nested types. |
| fn visit_child(cur: clang::Cursor, |
| id: ItemId, |
| ty: &clang::Type, |
| parent_id: Option<ItemId>, |
| ctx: &mut BindgenContext, |
| result: &mut Result<ItemId, ParseError>) |
| -> clang_sys::CXChildVisitResult { |
| use clang_sys::*; |
| if result.is_ok() { |
| return CXChildVisit_Break; |
| } |
| |
| *result = Item::from_ty_with_id(id, ty, Some(cur), parent_id, ctx); |
| |
| match *result { |
| Ok(..) => CXChildVisit_Break, |
| Err(ParseError::Recurse) => { |
| cur.visit(|c| visit_child(c, id, ty, parent_id, ctx, result)); |
| CXChildVisit_Continue |
| } |
| Err(ParseError::Continue) => CXChildVisit_Continue, |
| } |
| } |
| |
| impl ClangItemParser for Item { |
| fn builtin_type(kind: TypeKind, |
| is_const: bool, |
| ctx: &mut BindgenContext) |
| -> ItemId { |
| // Feel free to add more here, I'm just lazy. |
| match kind { |
| TypeKind::Void | |
| TypeKind::Int(..) | |
| TypeKind::Pointer(..) | |
| TypeKind::Float(..) => {} |
| _ => panic!("Unsupported builtin type"), |
| } |
| |
| let ty = Type::new(None, None, kind, is_const); |
| let id = ctx.next_item_id(); |
| let module = ctx.root_module(); |
| ctx.add_item(Item::new(id, None, None, module, ItemKind::Type(ty)), |
| None, |
| None); |
| id |
| } |
| |
| |
| fn parse(cursor: clang::Cursor, |
| parent_id: Option<ItemId>, |
| ctx: &mut BindgenContext) |
| -> Result<ItemId, ParseError> { |
| use ir::function::Function; |
| use ir::module::Module; |
| use ir::var::Var; |
| use clang_sys::*; |
| |
| if !cursor.is_valid() { |
| return Err(ParseError::Continue); |
| } |
| |
| let comment = cursor.raw_comment(); |
| let annotations = Annotations::new(&cursor); |
| |
| let current_module = ctx.current_module(); |
| let relevant_parent_id = parent_id.unwrap_or(current_module); |
| |
| macro_rules! try_parse { |
| ($what:ident) => { |
| match $what::parse(cursor, ctx) { |
| Ok(ParseResult::New(item, declaration)) => { |
| let id = ctx.next_item_id(); |
| |
| ctx.add_item(Item::new(id, comment, annotations, |
| relevant_parent_id, |
| ItemKind::$what(item)), |
| declaration, |
| Some(cursor)); |
| return Ok(id); |
| } |
| Ok(ParseResult::AlreadyResolved(id)) => { |
| return Ok(id); |
| } |
| Err(ParseError::Recurse) => return Err(ParseError::Recurse), |
| Err(ParseError::Continue) => {}, |
| } |
| } |
| } |
| |
| try_parse!(Module); |
| |
| // NOTE: Is extremely important to parse functions and vars **before** |
| // types. Otherwise we can parse a function declaration as a type |
| // (which is legal), and lose functions to generate. |
| // |
| // In general, I'm not totally confident this split between |
| // ItemKind::Function and TypeKind::FunctionSig is totally worth it, but |
| // I guess we can try. |
| try_parse!(Function); |
| try_parse!(Var); |
| |
| // Types are sort of special, so to avoid parsing template classes |
| // twice, handle them separately. |
| { |
| let applicable_cursor = cursor.definition().unwrap_or(cursor); |
| match Self::from_ty(&applicable_cursor.cur_type(), |
| Some(applicable_cursor), |
| parent_id, |
| ctx) { |
| Ok(ty) => return Ok(ty), |
| Err(ParseError::Recurse) => return Err(ParseError::Recurse), |
| Err(ParseError::Continue) => {} |
| } |
| } |
| |
| // Guess how does clang treat extern "C" blocks? |
| if cursor.kind() == CXCursor_UnexposedDecl { |
| Err(ParseError::Recurse) |
| } else { |
| // We whitelist cursors here known to be unhandled, to prevent being |
| // too noisy about this. |
| match cursor.kind() { |
| CXCursor_MacroDefinition | |
| CXCursor_MacroExpansion | |
| CXCursor_UsingDeclaration | |
| CXCursor_UsingDirective | |
| CXCursor_StaticAssert | |
| CXCursor_InclusionDirective => { |
| debug!("Unhandled cursor kind {:?}: {:?}", |
| cursor.kind(), |
| cursor); |
| } |
| _ => { |
| // ignore toplevel operator overloads |
| let spelling = cursor.spelling(); |
| if !spelling.starts_with("operator") { |
| error!("Unhandled cursor kind {:?}: {:?}", |
| cursor.kind(), |
| cursor); |
| } |
| } |
| } |
| |
| Err(ParseError::Continue) |
| } |
| } |
| |
| fn from_ty_or_ref(ty: clang::Type, |
| location: Option<clang::Cursor>, |
| parent_id: Option<ItemId>, |
| ctx: &mut BindgenContext) |
| -> ItemId { |
| let id = ctx.next_item_id(); |
| Self::from_ty_or_ref_with_id(id, ty, location, parent_id, ctx) |
| } |
| |
| /// Parse a C++ type. If we find a reference to a type that has not been |
| /// defined yet, use `UnresolvedTypeRef` as a placeholder. |
| /// |
| /// This logic is needed to avoid parsing items with the incorrect parent |
| /// and it's sort of complex to explain, so I'll just point to |
| /// `tests/headers/typeref.hpp` to see the kind of constructs that forced |
| /// this. |
| /// |
| /// Typerefs are resolved once parsing is completely done, see |
| /// `BindgenContext::resolve_typerefs`. |
| fn from_ty_or_ref_with_id(potential_id: ItemId, |
| ty: clang::Type, |
| location: Option<clang::Cursor>, |
| parent_id: Option<ItemId>, |
| ctx: &mut BindgenContext) |
| -> ItemId { |
| debug!("from_ty_or_ref_with_id: {:?} {:?}, {:?}, {:?}", |
| potential_id, |
| ty, |
| location, |
| parent_id); |
| |
| if ctx.collected_typerefs() { |
| debug!("refs already collected, resolving directly"); |
| return Self::from_ty_with_id(potential_id, |
| &ty, |
| location, |
| parent_id, |
| ctx) |
| .expect("Unable to resolve type"); |
| } |
| |
| if let Some(ty) = |
| ctx.builtin_or_resolved_ty(potential_id, parent_id, &ty, location) { |
| debug!("{:?} already resolved: {:?}", ty, location); |
| return ty; |
| } |
| |
| debug!("New unresolved type reference: {:?}, {:?}", ty, location); |
| |
| let is_const = ty.is_const(); |
| let kind = TypeKind::UnresolvedTypeRef(ty, location, parent_id); |
| let current_module = ctx.current_module(); |
| ctx.add_item(Item::new(potential_id, |
| None, |
| None, |
| parent_id.unwrap_or(current_module), |
| ItemKind::Type(Type::new(None, |
| None, |
| kind, |
| is_const))), |
| Some(clang::Cursor::null()), |
| None); |
| potential_id |
| } |
| |
| |
| fn from_ty(ty: &clang::Type, |
| location: Option<clang::Cursor>, |
| parent_id: Option<ItemId>, |
| ctx: &mut BindgenContext) |
| -> Result<ItemId, ParseError> { |
| let id = ctx.next_item_id(); |
| Self::from_ty_with_id(id, ty, location, parent_id, ctx) |
| } |
| |
| /// This is one of the trickiest methods you'll find (probably along with |
| /// some of the ones that handle templates in `BindgenContext`). |
| /// |
| /// This method parses a type, given the potential id of that type (if |
| /// parsing it was correct), an optional location we're scanning, which is |
| /// critical some times to obtain information, an optional parent item id, |
| /// that will, if it's `None`, become the current module id, and the |
| /// context. |
| fn from_ty_with_id(id: ItemId, |
| ty: &clang::Type, |
| location: Option<clang::Cursor>, |
| parent_id: Option<ItemId>, |
| ctx: &mut BindgenContext) |
| -> Result<ItemId, ParseError> { |
| use clang_sys::*; |
| |
| let decl = { |
| let decl = ty.declaration(); |
| decl.definition().unwrap_or(decl) |
| }; |
| |
| let comment = decl.raw_comment() |
| .or_else(|| location.as_ref().and_then(|l| l.raw_comment())); |
| let annotations = Annotations::new(&decl) |
| .or_else(|| location.as_ref().and_then(|l| Annotations::new(l))); |
| |
| if let Some(ref annotations) = annotations { |
| if let Some(ref replaced) = annotations.use_instead_of() { |
| ctx.replace(replaced, id); |
| } |
| } |
| |
| if let Some(ty) = |
| ctx.builtin_or_resolved_ty(id, parent_id, ty, location) { |
| return Ok(ty); |
| } |
| |
| // First, check we're not recursing. |
| let mut valid_decl = decl.kind() != CXCursor_NoDeclFound; |
| let declaration_to_look_for = if valid_decl { |
| decl.canonical() |
| } else if location.is_some() && |
| location.unwrap().kind() == |
| CXCursor_ClassTemplate { |
| valid_decl = true; |
| location.unwrap() |
| } else { |
| decl |
| }; |
| |
| if valid_decl { |
| if let Some(partial) = ctx.currently_parsed_types() |
| .iter() |
| .find(|ty| *ty.decl() == declaration_to_look_for) { |
| debug!("Avoiding recursion parsing type: {:?}", ty); |
| return Ok(partial.id()); |
| } |
| } |
| |
| let current_module = ctx.current_module(); |
| let partial_ty = PartialType::new(declaration_to_look_for, id); |
| if valid_decl { |
| ctx.begin_parsing(partial_ty); |
| } |
| |
| let result = Type::from_clang_ty(id, ty, location, parent_id, ctx); |
| let relevant_parent_id = parent_id.unwrap_or(current_module); |
| let ret = match result { |
| Ok(ParseResult::AlreadyResolved(ty)) => Ok(ty), |
| Ok(ParseResult::New(item, declaration)) => { |
| ctx.add_item(Item::new(id, |
| comment, |
| annotations, |
| relevant_parent_id, |
| ItemKind::Type(item)), |
| declaration, |
| location); |
| Ok(id) |
| } |
| Err(ParseError::Continue) => Err(ParseError::Continue), |
| Err(ParseError::Recurse) => { |
| debug!("Item::from_ty recursing in the ast"); |
| let mut result = Err(ParseError::Recurse); |
| if let Some(ref location) = location { |
| // Need to pop here, otherwise we'll get stuck. |
| // |
| // TODO: Find a nicer interface, really. Also, the |
| // declaration_to_look_for suspiciously shares a lot of |
| // logic with ir::context, so we should refactor that. |
| if valid_decl { |
| let finished = ctx.finish_parsing(); |
| assert_eq!(*finished.decl(), declaration_to_look_for); |
| } |
| |
| location.visit(|cur| { |
| visit_child(cur, id, ty, parent_id, ctx, &mut result) |
| }); |
| |
| if valid_decl { |
| let partial_ty = |
| PartialType::new(declaration_to_look_for, id); |
| ctx.begin_parsing(partial_ty); |
| } |
| } |
| // If we have recursed into the AST all we know, and we still |
| // haven't found what we've got, let's just make a named type. |
| // |
| // This is what happens with some template members, for example. |
| // |
| // FIXME: Maybe we should restrict this to things with parent? |
| // It's harmless, but if we restrict that, then |
| // tests/headers/nsStyleAutoArray.hpp crashes. |
| if let Err(ParseError::Recurse) = result { |
| warn!("Unknown type, assuming named template type: \ |
| id = {:?}; spelling = {}", |
| id, |
| ty.spelling()); |
| Ok(Self::named_type_with_id(id, |
| ty.spelling(), |
| relevant_parent_id, |
| ctx)) |
| } else { |
| result |
| } |
| } |
| }; |
| |
| if valid_decl { |
| let partial_ty = ctx.finish_parsing(); |
| assert_eq!(*partial_ty.decl(), declaration_to_look_for); |
| } |
| |
| ret |
| } |
| |
| /// A named type is a template parameter, e.g., the "T" in Foo<T>. They're |
| /// always local so it's the only exception when there's no declaration for |
| /// a type. |
| /// |
| /// It must have an id, and must not be the current module id. Ideally we |
| /// could assert the parent id is a Comp(..) type, but that info isn't |
| /// available yet. |
| fn named_type_with_id<S>(id: ItemId, |
| name: S, |
| parent_id: ItemId, |
| ctx: &mut BindgenContext) |
| -> ItemId |
| where S: Into<String>, |
| { |
| // see tests/headers/const_tparam.hpp |
| // and tests/headers/variadic_tname.hpp |
| let name = name.into().replace("const ", "").replace(".", ""); |
| |
| ctx.add_item(Item::new(id, |
| None, |
| None, |
| parent_id, |
| ItemKind::Type(Type::named(name))), |
| None, |
| None); |
| |
| id |
| } |
| |
| fn named_type<S>(name: S, |
| parent_id: ItemId, |
| ctx: &mut BindgenContext) |
| -> ItemId |
| where S: Into<String>, |
| { |
| let id = ctx.next_item_id(); |
| Self::named_type_with_id(id, name, parent_id, ctx) |
| } |
| } |
| |
| impl ItemCanonicalName for Item { |
| fn canonical_name(&self, ctx: &BindgenContext) -> String { |
| debug_assert!(ctx.in_codegen_phase(), |
| "You're not supposed to call this yet"); |
| if self.canonical_name_cache.borrow().is_none() { |
| let in_namespace = ctx.options().enable_cxx_namespaces || |
| ctx.options().disable_name_namespacing; |
| |
| *self.canonical_name_cache.borrow_mut() = if in_namespace { |
| Some(self.name(ctx).within_namespaces().get()) |
| } else { |
| Some(self.name(ctx).get()) |
| }; |
| } |
| return self.canonical_name_cache.borrow().as_ref().unwrap().clone(); |
| } |
| } |
| |
| impl ItemCanonicalPath for Item { |
| fn namespace_aware_canonical_path(&self, |
| ctx: &BindgenContext) |
| -> Vec<String> { |
| let path = self.canonical_path(ctx); |
| if ctx.options().enable_cxx_namespaces { |
| return path; |
| } |
| if ctx.options().disable_name_namespacing { |
| return vec![path.last().unwrap().clone()]; |
| } |
| return vec![path[1..].join("_")]; |
| } |
| |
| fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> { |
| if let Some(path) = self.annotations().use_instead_of() { |
| let mut ret = |
| vec![ctx.resolve_item(ctx.root_module()).name(ctx).get()]; |
| ret.extend_from_slice(path); |
| return ret; |
| } |
| |
| let target = ctx.resolve_item(self.name_target(ctx)); |
| let mut path: Vec<_> = target.ancestors(ctx) |
| .chain(iter::once(ctx.root_module())) |
| .map(|id| ctx.resolve_item(id)) |
| .filter(|item| { |
| item.id() == target.id() || |
| item.as_module().map_or(false, |module| { |
| !module.is_inline() || |
| ctx.options().conservative_inline_namespaces |
| }) |
| }) |
| .map(|item| { |
| ctx.resolve_item(item.name_target(ctx)) |
| .name(ctx) |
| .within_namespaces() |
| .get() |
| }) |
| .collect(); |
| path.reverse(); |
| path |
| } |
| } |
| |
| /// Builder struct for naming variations, which hold inside different |
| /// flags for naming options. |
| #[derive(Debug)] |
| pub struct NameOptions<'item, 'ctx> |
| where 'ctx: 'item, |
| { |
| item: &'item Item, |
| ctx: &'item BindgenContext<'ctx>, |
| within_namespaces: bool, |
| } |
| |
| impl<'item, 'ctx> NameOptions<'item, 'ctx> { |
| /// Construct a new `NameOptions` |
| pub fn new(item: &'item Item, ctx: &'item BindgenContext<'ctx>) -> Self { |
| NameOptions { |
| item: item, |
| ctx: ctx, |
| within_namespaces: false, |
| } |
| } |
| |
| /// Construct the name without the item's containing C++ namespaces mangled |
| /// into it. In other words, the item's name within the item's namespace. |
| pub fn within_namespaces(&mut self) -> &mut Self { |
| self.within_namespaces = true; |
| self |
| } |
| |
| /// Construct a name `String` |
| pub fn get(&self) -> String { |
| self.item.real_canonical_name(self.ctx, self) |
| } |
| } |