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