diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/chooser.rs | 26 | ||||
-rw-r--r-- | src/clang.rs | 1371 | ||||
-rw-r--r-- | src/codegen/helpers.rs | 190 | ||||
-rw-r--r-- | src/codegen/mod.rs | 2341 | ||||
-rw-r--r-- | src/ir/annotations.rs | 188 | ||||
-rw-r--r-- | src/ir/comp.rs | 962 | ||||
-rw-r--r-- | src/ir/context.rs | 1267 | ||||
-rw-r--r-- | src/ir/derive.rs | 67 | ||||
-rw-r--r-- | src/ir/enum_ty.rs | 183 | ||||
-rw-r--r-- | src/ir/function.rs | 318 | ||||
-rw-r--r-- | src/ir/int.rs | 113 | ||||
-rw-r--r-- | src/ir/item.rs | 1370 | ||||
-rw-r--r-- | src/ir/item_kind.rs | 114 | ||||
-rw-r--r-- | src/ir/layout.rs | 91 | ||||
-rw-r--r-- | src/ir/mod.rs | 19 | ||||
-rw-r--r-- | src/ir/module.rs | 78 | ||||
-rw-r--r-- | src/ir/ty.rs | 926 | ||||
-rw-r--r-- | src/ir/type_collector.rs | 22 | ||||
-rw-r--r-- | src/ir/var.rs | 317 | ||||
-rw-r--r-- | src/lib.rs | 808 | ||||
-rw-r--r-- | src/log_stubs.rs | 30 | ||||
-rw-r--r-- | src/main.rs | 59 | ||||
-rw-r--r-- | src/options.rs | 311 | ||||
-rw-r--r-- | src/parse.rs | 104 | ||||
-rw-r--r-- | src/regex_set.rs | 69 | ||||
-rw-r--r-- | src/uses.rs | 102 |
26 files changed, 11446 insertions, 0 deletions
diff --git a/src/chooser.rs b/src/chooser.rs new file mode 100644 index 00000000..51392d70 --- /dev/null +++ b/src/chooser.rs @@ -0,0 +1,26 @@ +//! A public API for more fine-grained customization of bindgen behavior. + +pub use ir::int::IntKind; +pub use ir::enum_ty::{EnumVariantValue, EnumVariantCustomBehavior}; +use std::fmt; + +/// A trait to allow configuring different kinds of types in different +/// situations. +pub trait TypeChooser: fmt::Debug { + /// The integer kind an integer macro should have, given a name and the + /// value of that macro, or `None` if you want the default to be chosen. + fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> { + None + } + + /// This function should return whether, given the a given enum variant + /// name, and value, returns whether this enum variant will forcibly be a + /// constant. + fn enum_variant_behavior(&self, + _enum_name: Option<&str>, + _variant_name: &str, + _variant_value: EnumVariantValue) + -> Option<EnumVariantCustomBehavior> { + None + } +} diff --git a/src/clang.rs b/src/clang.rs new file mode 100644 index 00000000..491aaa07 --- /dev/null +++ b/src/clang.rs @@ -0,0 +1,1371 @@ +//! A higher level Clang API built on top of the generated bindings in the +//! `clang_sys` module. + +#![allow(non_upper_case_globals, dead_code)] + + +use cexpr; +use clang_sys::*; +use std::{mem, ptr, slice}; +use std::ffi::{CStr, CString}; +use std::fmt; +use std::hash::Hash; +use std::hash::Hasher; +use std::os::raw::{c_char, c_int, c_uint, c_ulong}; + +/// A cursor into the Clang AST, pointing to an AST node. +/// +/// We call the AST node pointed to by the cursor the cursor's "referent". +#[derive(Copy, Clone)] +pub struct Cursor { + x: CXCursor, +} + +impl fmt::Debug for Cursor { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, + "Cursor({} kind: {}, loc: {}, usr: {:?})", + self.spelling(), + kind_to_str(self.kind()), + self.location(), + self.usr()) + } +} + +impl Cursor { + /// Get the Unified Symbol Resolution for this cursor's referent, if + /// available. + /// + /// The USR can be used to compare entities across translation units. + pub fn usr(&self) -> Option<String> { + let s = unsafe { cxstring_into_string(clang_getCursorUSR(self.x)) }; + if s.is_empty() { None } else { Some(s) } + } + + /// Is this cursor's referent a declaration? + pub fn is_declaration(&self) -> bool { + unsafe { clang_isDeclaration(self.kind()) != 0 } + } + + /// Get the null cursor, which has no referent. + pub fn null() -> Self { + Cursor { + x: unsafe { clang_getNullCursor() }, + } + } + + /// Get this cursor's referent's spelling. + pub fn spelling(&self) -> String { + unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) } + } + + /// Get this cursor's referent's display name. + /// + /// This is not necessarily a valid identifier. It includes extra + /// information, such as parameters for a function, etc. + pub fn display_name(&self) -> String { + unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) } + } + + /// Get the mangled name of this cursor's referent. + pub fn mangling(&self) -> String { + unsafe { cxstring_into_string(clang_Cursor_getMangling(self.x)) } + } + + /// Get the `Cursor` for this cursor's referent's lexical parent. + /// + /// The lexical parent is the parent of the definition. The semantic parent + /// is the parent of the declaration. Generally, the lexical parent doesn't + /// have any effect on semantics, while the semantic parent does. + /// + /// In the following snippet, the `Foo` class would be the semantic parent + /// of the out-of-line `method` definition, while the lexical parent is the + /// translation unit. + /// + /// ```c++ + /// class Foo { + /// void method(); + /// }; + /// + /// void Foo::method() { /* ... */ } + /// ``` + pub fn lexical_parent(&self) -> Cursor { + unsafe { + Cursor { + x: clang_getCursorLexicalParent(self.x), + } + } + } + + /// Get the referent's semantic parent, if one is available. + /// + /// See documentation for `lexical_parent` for details on semantic vs + /// lexical parents. + pub fn fallible_semantic_parent(&self) -> Option<Cursor> { + let sp = unsafe { + Cursor { + x: clang_getCursorSemanticParent(self.x), + } + }; + if sp == *self || !sp.is_valid() { + return None; + } + Some(sp) + } + + /// Get the referent's semantic parent. + /// + /// See documentation for `lexical_parent` for details on semantic vs + /// lexical parents. + pub fn semantic_parent(&self) -> Cursor { + self.fallible_semantic_parent().unwrap() + } + + /// Return the number of template arguments used by this cursor's referent, + /// if the referent is either a template specialization or + /// declaration. Returns -1 otherwise. + /// + /// NOTE: This may not return `Some` for some non-fully specialized + /// templates, see #193 and #194. + pub fn num_template_args(&self) -> Option<u32> { + let n: c_int = unsafe { clang_Cursor_getNumTemplateArguments(self.x) }; + + if n >= 0 { + Some(n as u32) + } else { + debug_assert_eq!(n, -1); + None + } + } + + /// Get a cursor pointing to this referent's containing translation unit. + /// + /// Note that we shouldn't create a `TranslationUnit` struct here, because + /// bindgen assumes there will only be one of them alive at a time, and + /// disposes it on drop. That can change if this would be required, but I + /// think we can survive fine without it. + pub fn translation_unit(&self) -> Cursor { + assert!(self.is_valid()); + unsafe { + let tu = clang_Cursor_getTranslationUnit(self.x); + let cursor = Cursor { + x: clang_getTranslationUnitCursor(tu), + }; + assert!(cursor.is_valid()); + cursor + } + } + + /// Is the referent a top level construct? + pub fn is_toplevel(&self) -> bool { + let mut semantic_parent = self.fallible_semantic_parent(); + + while semantic_parent.is_some() && + (semantic_parent.unwrap().kind() == CXCursor_Namespace || + semantic_parent.unwrap().kind() == CXCursor_NamespaceAlias || + semantic_parent.unwrap().kind() == CXCursor_NamespaceRef) { + semantic_parent = semantic_parent.unwrap() + .fallible_semantic_parent(); + } + + let tu = self.translation_unit(); + // Yes, this can happen with, e.g., macro definitions. + semantic_parent == tu.fallible_semantic_parent() + } + + /// There are a few kinds of types that we need to treat specially, mainly + /// not tracking the type declaration but the location of the cursor, given + /// clang doesn't expose a proper declaration for these types. + pub fn is_template_like(&self) -> bool { + match self.kind() { + CXCursor_ClassTemplate | + CXCursor_ClassTemplatePartialSpecialization | + CXCursor_TypeAliasTemplateDecl => true, + _ => false, + } + } + + /// Get the kind of referent this cursor is pointing to. + pub fn kind(&self) -> CXCursorKind { + unsafe { clang_getCursorKind(self.x) } + } + + /// Is the referent an anonymous record definition? + pub fn is_anonymous(&self) -> bool { + unsafe { clang_Cursor_isAnonymous(self.x) != 0 } + } + + /// Is the referent a template specialization? + pub fn is_template(&self) -> bool { + self.specialized().is_some() + } + + /// Is the referent a fully specialized template specialization without any + /// remaining free template arguments? + pub fn is_fully_specialized_template(&self) -> bool { + self.is_template() && self.num_template_args().unwrap_or(0) > 0 + } + + /// Is the referent a template specialization that still has remaining free + /// template arguments? + pub fn is_in_non_fully_specialized_template(&self) -> bool { + if self.is_toplevel() { + return false; + } + let parent = self.semantic_parent(); + (parent.is_template() && !parent.is_fully_specialized_template()) || + parent.is_in_non_fully_specialized_template() + } + + /// Is this cursor pointing a valid referent? + pub fn is_valid(&self) -> bool { + unsafe { clang_isInvalid(self.kind()) == 0 } + } + + /// Get the source location for the referent. + pub fn location(&self) -> SourceLocation { + unsafe { + SourceLocation { + x: clang_getCursorLocation(self.x), + } + } + } + + /// Get the source location range for the referent. + pub fn extent(&self) -> CXSourceRange { + unsafe { clang_getCursorExtent(self.x) } + } + + /// Get the raw declaration comment for this referent, if one exists. + pub fn raw_comment(&self) -> Option<String> { + let s = unsafe { + cxstring_into_string(clang_Cursor_getRawCommentText(self.x)) + }; + if s.is_empty() { None } else { Some(s) } + } + + /// Get the referent's parsed comment. + pub fn comment(&self) -> Comment { + unsafe { + Comment { + x: clang_Cursor_getParsedComment(self.x), + } + } + } + + /// Get the referent's type. + pub fn cur_type(&self) -> Type { + unsafe { + Type { + x: clang_getCursorType(self.x), + } + } + } + + /// Given that this cursor's referent is a reference to another type, or is + /// a declaration, get the cursor pointing to the referenced type or type of + /// the declared thing. + pub fn definition(&self) -> Option<Cursor> { + unsafe { + let ret = Cursor { + x: clang_getCursorDefinition(self.x), + }; + + if ret.is_valid() { Some(ret) } else { None } + } + } + + /// Given that this cursor's referent is reference type, get the cursor + /// pointing to the referenced type. + pub fn referenced(&self) -> Option<Cursor> { + unsafe { + let ret = Cursor { + x: clang_getCursorReferenced(self.x), + }; + + if ret.is_valid() { Some(ret) } else { None } + } + } + + /// Get the canonical cursor for this referent. + /// + /// Many types can be declared multiple times before finally being properly + /// defined. This method allows us to get the canonical cursor for the + /// referent type. + pub fn canonical(&self) -> Cursor { + unsafe { + Cursor { + x: clang_getCanonicalCursor(self.x), + } + } + } + + /// Given that this cursor points to a template specialization, get a cursor + /// pointing to the template definition that is being specialized. + pub fn specialized(&self) -> Option<Cursor> { + unsafe { + let ret = Cursor { + x: clang_getSpecializedCursorTemplate(self.x), + }; + if ret.is_valid() { Some(ret) } else { None } + } + } + + /// Assuming that this cursor's referent is a template declaration, get the + /// kind of cursor that would be generated for its specializations. + pub fn template_kind(&self) -> CXCursorKind { + unsafe { clang_getTemplateCursorKind(self.x) } + } + + /// Traverse this cursor's referent and its children. + /// + /// Call the given function on each AST node traversed. + pub fn visit<Visitor>(&self, mut visitor: Visitor) + where Visitor: FnMut(Cursor) -> CXChildVisitResult, + { + unsafe { + clang_visitChildren(self.x, + visit_children::<Visitor>, + mem::transmute(&mut visitor)); + } + } + + /// Returns whether the given location contains a cursor with the given + /// kind in the first level of nesting underneath (doesn't look + /// recursively). + pub fn contains_cursor(&self, kind: CXCursorKind) -> bool { + let mut found = false; + + self.visit(|c| { + if c.kind() == kind { + found = true; + CXChildVisit_Break + } else { + CXChildVisit_Continue + } + }); + + found + } + + /// Is the referent an inlined function? + pub fn is_inlined_function(&self) -> bool { + clang_Cursor_isFunctionInlined::is_loaded() && + unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 } + } + + /// Get the width of this cursor's referent bit field, or `None` if the + /// referent is not a bit field. + pub fn bit_width(&self) -> Option<u32> { + unsafe { + let w = clang_getFieldDeclBitWidth(self.x); + if w == -1 { None } else { Some(w as u32) } + } + } + + /// Get the integer representation type used to hold this cursor's referent + /// enum type. + pub fn enum_type(&self) -> Option<Type> { + unsafe { + let t = Type { + x: clang_getEnumDeclIntegerType(self.x), + }; + if t.is_valid() { Some(t) } else { None } + } + } + + /// Get the signed constant value for this cursor's enum variant referent. + /// + /// Returns None if the cursor's referent is not an enum variant. + pub fn enum_val_signed(&self) -> Option<i64> { + unsafe { + if self.kind() == CXCursor_EnumConstantDecl { + Some(clang_getEnumConstantDeclValue(self.x) as i64) + } else { + None + } + } + } + + /// Get the unsigned constant value for this cursor's enum variant referent. + /// + /// Returns None if the cursor's referent is not an enum variant. + pub fn enum_val_unsigned(&self) -> Option<u64> { + unsafe { + if self.kind() == CXCursor_EnumConstantDecl { + Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64) + } else { + None + } + } + } + + /// Given that this cursor's referent is a `typedef`, get the `Type` that is + /// being aliased. + pub fn typedef_type(&self) -> Option<Type> { + let inner = Type { + x: unsafe { clang_getTypedefDeclUnderlyingType(self.x) }, + }; + + if inner.is_valid() { Some(inner) } else { None } + } + + /// Get the linkage kind for this cursor's referent. + /// + /// This only applies to functions and variables. + pub fn linkage(&self) -> CXLinkageKind { + unsafe { clang_getCursorLinkage(self.x) } + } + + /// Get the visibility of this cursor's referent. + pub fn visibility(&self) -> CXVisibilityKind { + unsafe { clang_getCursorVisibility(self.x) } + } + + /// Given that this cursor's referent is a function, return cursors to its + /// parameters. + pub fn args(&self) -> Option<Vec<Cursor>> { + // XXX: We might want to use and keep num_args + // match self.kind() { + // CXCursor_FunctionDecl | + // CXCursor_CXXMethod => { + unsafe { + let w = clang_Cursor_getNumArguments(self.x); + if w == -1 { + None + } else { + let num = w as u32; + + let mut args = vec![]; + for i in 0..num { + args.push(Cursor { + x: clang_Cursor_getArgument(self.x, i as c_uint), + }); + } + Some(args) + } + } + } + + /// Given that this cursor's referent is a function/method call or + /// declaration, return the number of arguments it takes. + /// + /// Returns -1 if the cursor's referent is not a function/method call or + /// declaration. + pub fn num_args(&self) -> Result<u32, ()> { + unsafe { + let w = clang_Cursor_getNumArguments(self.x); + if w == -1 { Err(()) } else { Ok(w as u32) } + } + } + + /// Get the access specifier for this cursor's referent. + pub fn access_specifier(&self) -> CX_CXXAccessSpecifier { + unsafe { clang_getCXXAccessSpecifier(self.x) } + } + + /// Is this cursor's referent a field declaration that is marked as + /// `mutable`? + pub fn is_mutable_field(&self) -> bool { + unsafe { clang_CXXField_isMutable(self.x) != 0 } + } + + /// Is this cursor's referent a member function that is declared `static`? + pub fn method_is_static(&self) -> bool { + unsafe { clang_CXXMethod_isStatic(self.x) != 0 } + } + + /// Is this cursor's referent a member function that is declared `const`? + pub fn method_is_const(&self) -> bool { + unsafe { clang_CXXMethod_isConst(self.x) != 0 } + } + + /// Is this cursor's referent a member function that is declared `const`? + pub fn method_is_virtual(&self) -> bool { + unsafe { clang_CXXMethod_isVirtual(self.x) != 0 } + } + + /// Is this cursor's referent a struct or class with virtual members? + pub fn is_virtual_base(&self) -> bool { + unsafe { clang_isVirtualBase(self.x) != 0 } + } + + /// Try to evaluate this cursor. + pub fn evaluate(&self) -> Option<EvalResult> { + EvalResult::new(*self) + } +} + +extern "C" fn visit_children<Visitor>(cur: CXCursor, + _parent: CXCursor, + data: CXClientData) + -> CXChildVisitResult + where Visitor: FnMut(Cursor) -> CXChildVisitResult, +{ + let func: &mut Visitor = unsafe { mem::transmute(data) }; + let child = Cursor { + x: cur, + }; + + (*func)(child) +} + +impl PartialEq for Cursor { + fn eq(&self, other: &Cursor) -> bool { + unsafe { clang_equalCursors(self.x, other.x) == 1 } + } +} + +impl Eq for Cursor {} + +impl Hash for Cursor { + fn hash<H: Hasher>(&self, state: &mut H) { + unsafe { clang_hashCursor(self.x) }.hash(state) + } +} + +/// The type of a node in clang's AST. +#[derive(Clone)] +pub struct Type { + x: CXType, +} + +impl PartialEq for Type { + fn eq(&self, other: &Self) -> bool { + unsafe { clang_equalTypes(self.x, other.x) != 0 } + } +} + +impl Eq for Type {} + +impl fmt::Debug for Type { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, + "Type({}, kind: {}, decl: {:?}, canon: {:?})", + self.spelling(), + type_to_str(self.kind()), + self.declaration(), + self.declaration().canonical()) + } +} + +/// An error about the layout of a struct, class, or type. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum LayoutError { + /// Asked for the layout of an invalid type. + Invalid, + /// Asked for the layout of an incomplete type. + Incomplete, + /// Asked for the layout of a dependent type. + Dependent, + /// Asked for the layout of a type that does not have constant size. + NotConstantSize, + /// Asked for the layout of a field in a type that does not have such a + /// field. + InvalidFieldName, + /// An unknown layout error. + Unknown, +} + +impl ::std::convert::From<i32> for LayoutError { + fn from(val: i32) -> Self { + use self::LayoutError::*; + let val = match CXTypeLayoutError::from_raw(val) { + Some(val) => val, + None => return Unknown, + }; + + match val { + CXTypeLayoutError_Invalid => Invalid, + CXTypeLayoutError_Incomplete => Incomplete, + CXTypeLayoutError_Dependent => Dependent, + CXTypeLayoutError_NotConstantSize => NotConstantSize, + CXTypeLayoutError_InvalidFieldName => InvalidFieldName, + _ => Unknown, + } + } +} + +impl Type { + /// Get this type's kind. + pub fn kind(&self) -> CXTypeKind { + self.x.kind + } + + /// Get a cursor pointing to this type's declaration. + pub fn declaration(&self) -> Cursor { + unsafe { + Cursor { + x: clang_getTypeDeclaration(self.x), + } + } + } + + /// Get a raw display name for this type. + pub fn spelling(&self) -> String { + unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) } + } + + /// Is this type const qualified? + pub fn is_const(&self) -> bool { + unsafe { clang_isConstQualifiedType(self.x) != 0 } + } + + /// What is the size of this type? Paper over invalid types by returning `0` + /// for them. + pub fn size(&self) -> usize { + unsafe { + let val = clang_Type_getSizeOf(self.x); + if val < 0 { 0 } else { val as usize } + } + } + + /// What is the size of this type? + pub fn fallible_size(&self) -> Result<usize, LayoutError> { + let val = unsafe { clang_Type_getSizeOf(self.x) }; + if val < 0 { + Err(LayoutError::from(val as i32)) + } else { + Ok(val as usize) + } + } + + /// What is the alignment of this type? Paper over invalid types by + /// returning `0`. + pub fn align(&self) -> usize { + unsafe { + let val = clang_Type_getAlignOf(self.x); + if val < 0 { 0 } else { val as usize } + } + } + + /// What is the alignment of this type? + pub fn fallible_align(&self) -> Result<usize, LayoutError> { + unsafe { + let val = clang_Type_getAlignOf(self.x); + if val < 0 { + Err(LayoutError::from(val as i32)) + } else { + Ok(val as usize) + } + } + } + + /// Get the layout for this type, or an error describing why it does not + /// have a valid layout. + pub fn fallible_layout(&self) -> Result<::ir::layout::Layout, LayoutError> { + use ir::layout::Layout; + let size = try!(self.fallible_size()); + let align = try!(self.fallible_align()); + Ok(Layout::new(size, align)) + } + + /// If this type is a class template specialization, return its + /// template arguments. Otherwise, return None. + pub fn template_args(&self) -> Option<TypeTemplateArgIterator> { + let n = unsafe { clang_Type_getNumTemplateArguments(self.x) }; + if n >= 0 { + Some(TypeTemplateArgIterator { + x: self.x, + length: n as u32, + index: 0, + }) + } else { + debug_assert_eq!(n, -1); + None + } + } + + /// Given that this type is a pointer type, return the type that it points + /// to. + pub fn pointee_type(&self) -> Option<Type> { + match self.kind() { + CXType_Pointer | + CXType_RValueReference | + CXType_LValueReference | + CXType_MemberPointer => { + let ret = Type { + x: unsafe { clang_getPointeeType(self.x) }, + }; + debug_assert!(ret.is_valid()); + Some(ret) + } + _ => None, + } + } + + /// Given that this type is an array, vector, or complex type, return the + /// type of its elements. + pub fn elem_type(&self) -> Option<Type> { + let current_type = Type { + x: unsafe { clang_getElementType(self.x) }, + }; + if current_type.is_valid() { + Some(current_type) + } else { + None + } + } + + /// Given that this type is an array or vector type, return its number of + /// elements. + pub fn num_elements(&self) -> Option<usize> { + let num_elements_returned = unsafe { clang_getNumElements(self.x) }; + if num_elements_returned != -1 { + Some(num_elements_returned as usize) + } else { + None + } + } + + /// Get the canonical version of this type. This sees through `typdef`s and + /// aliases to get the underlying, canonical type. + pub fn canonical_type(&self) -> Type { + unsafe { + Type { + x: clang_getCanonicalType(self.x), + } + } + } + + /// Is this type a variadic function type? + pub fn is_variadic(&self) -> bool { + unsafe { clang_isFunctionTypeVariadic(self.x) != 0 } + } + + /// Given that this type is a function type, get the type of its return + /// value. + pub fn ret_type(&self) -> Option<Type> { + let rt = Type { + x: unsafe { clang_getResultType(self.x) }, + }; + if rt.is_valid() { Some(rt) } else { None } + } + + /// Given that this type is a function type, get its calling convention. If + /// this is not a function type, `CXCallingConv_Invalid` is returned. + pub fn call_conv(&self) -> CXCallingConv { + unsafe { clang_getFunctionTypeCallingConv(self.x) } + } + + /// For elaborated types (types which use `class`, `struct`, or `union` to + /// disambiguate types from local bindings), get the underlying type. + pub fn named(&self) -> Type { + unsafe { + Type { + x: clang_Type_getNamedType(self.x), + } + } + } + + /// Is this a valid type? + pub fn is_valid(&self) -> bool { + self.kind() != CXType_Invalid + } + + /// Is this a valid and exposed type? + pub fn is_valid_and_exposed(&self) -> bool { + self.is_valid() && self.kind() != CXType_Unexposed + } + + /// Is this type a fully specialized template? + pub fn is_fully_specialized_template(&self) -> bool { + // Yep, the spelling of this containing type-parameter is extremely + // nasty... But can happen in <type_traits>. Unfortunately I couldn't + // reduce it enough :( + !self.spelling().contains("type-parameter") && + self.template_args() + .map_or(false, |mut args| { + args.len() > 0 && + !args.any(|t| t.spelling().contains("type-parameter")) + }) + } +} + +/// An iterator for a type's template arguments. +pub struct TypeTemplateArgIterator { + x: CXType, + length: u32, + index: u32, +} + +impl Iterator for TypeTemplateArgIterator { + type Item = Type; + fn next(&mut self) -> Option<Type> { + if self.index < self.length { + let idx = self.index as c_uint; + self.index += 1; + Some(Type { + x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) }, + }) + } else { + None + } + } +} + +impl ExactSizeIterator for TypeTemplateArgIterator { + fn len(&self) -> usize { + assert!(self.index <= self.length); + (self.length - self.index) as usize + } +} + +/// A `SourceLocation` is a file, line, column, and byte offset location for +/// some source text. +pub struct SourceLocation { + x: CXSourceLocation, +} + +impl SourceLocation { + /// Get the (file, line, column, byte offset) tuple for this source + /// location. + pub fn location(&self) -> (File, usize, usize, usize) { + unsafe { + let mut file = mem::zeroed(); + let mut line = 0; + let mut col = 0; + let mut off = 0; + clang_getSpellingLocation(self.x, + &mut file, + &mut line, + &mut col, + &mut off); + (File { + x: file, + }, + line as usize, + col as usize, + off as usize) + } + } +} + +impl fmt::Display for SourceLocation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let (file, line, col, _) = self.location(); + if let Some(name) = file.name() { + write!(f, "{}:{}:{}", name, line, col) + } else { + "builtin definitions".fmt(f) + } + } +} + +/// A comment in the source text. +/// +/// Comments are sort of parsed by Clang, and have a tree structure. +pub struct Comment { + x: CXComment, +} + +impl Comment { + /// What kind of comment is this? + pub fn kind(&self) -> CXCommentKind { + unsafe { clang_Comment_getKind(self.x) } + } + + /// Get this comment's children comment + pub fn get_children(&self) -> CommentChildrenIterator { + CommentChildrenIterator { + parent: self.x, + length: unsafe { clang_Comment_getNumChildren(self.x) }, + index: 0, + } + } + + /// Given that this comment is the start or end of an HTML tag, get its tag + /// name. + pub fn get_tag_name(&self) -> String { + unsafe { cxstring_into_string(clang_HTMLTagComment_getTagName(self.x)) } + } + + /// Given that this comment is an HTML start tag, get its attributes. + pub fn get_tag_attrs(&self) -> CommentAttributesIterator { + CommentAttributesIterator { + x: self.x, + length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) }, + index: 0, + } + } +} + +/// An iterator for a comment's children +pub struct CommentChildrenIterator { + parent: CXComment, + length: c_uint, + index: c_uint, +} + +impl Iterator for CommentChildrenIterator { + type Item = Comment; + fn next(&mut self) -> Option<Comment> { + if self.index < self.length { + let idx = self.index; + self.index += 1; + Some(Comment { + x: unsafe { clang_Comment_getChild(self.parent, idx) }, + }) + } else { + None + } + } +} + +/// An HTML start tag comment attribute +pub struct CommentAttribute { + /// HTML start tag attribute name + pub name: String, + /// HTML start tag attribute value + pub value: String, +} + +/// An iterator for a comment's attributes +pub struct CommentAttributesIterator { + x: CXComment, + length: c_uint, + index: c_uint, +} + +impl Iterator for CommentAttributesIterator { + type Item = CommentAttribute; + fn next(&mut self) -> Option<CommentAttribute> { + if self.index < self.length { + let idx = self.index; + self.index += 1; + Some(CommentAttribute { + name: unsafe { + cxstring_into_string( + clang_HTMLStartTag_getAttrName(self.x, idx)) + }, + value: unsafe { + cxstring_into_string( + clang_HTMLStartTag_getAttrValue(self.x, idx)) + }, + }) + } else { + None + } + } +} + +/// A source file. +pub struct File { + x: CXFile, +} + +impl File { + /// Get the name of this source file. + pub fn name(&self) -> Option<String> { + if self.x.is_null() { + return None; + } + Some(unsafe { cxstring_into_string(clang_getFileName(self.x)) }) + } +} + +fn cxstring_into_string(s: CXString) -> String { + if s.data.is_null() { + return "".to_owned(); + } + unsafe { + let c_str = CStr::from_ptr(clang_getCString(s) as *const _); + let ret = c_str.to_string_lossy().into_owned(); + clang_disposeString(s); + ret + } +} + +/// An `Index` is an environment for a set of translation units that will +/// typically end up linked together in one final binary. +pub struct Index { + x: CXIndex, +} + +impl Index { + /// Construct a new `Index`. + /// + /// The `pch` parameter controls whether declarations in pre-compiled + /// headers are included when enumerating a translation unit's "locals". + /// + /// The `diag` parameter controls whether debugging diagnostics are enabled. + pub fn new(pch: bool, diag: bool) -> Index { + unsafe { + Index { + x: clang_createIndex(pch as c_int, diag as c_int), + } + } + } +} + +impl fmt::Debug for Index { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "Index {{ }}") + } +} + +impl Drop for Index { + fn drop(&mut self) { + unsafe { + clang_disposeIndex(self.x); + } + } +} + +/// A token emitted by clang's lexer. +#[derive(Debug)] +pub struct Token { + /// The kind of token this is. + pub kind: CXTokenKind, + /// A display name for this token. + pub spelling: String, +} + +/// A translation unit (or "compilation unit"). +pub struct TranslationUnit { + x: CXTranslationUnit, +} + +impl fmt::Debug for TranslationUnit { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "TranslationUnit {{ }}") + } +} + +impl TranslationUnit { + /// Parse a source file into a translation unit. + pub fn parse(ix: &Index, + file: &str, + cmd_args: &[String], + unsaved: &[UnsavedFile], + opts: CXTranslationUnit_Flags) + -> Option<TranslationUnit> { + let fname = CString::new(file).unwrap(); + let _c_args: Vec<CString> = + cmd_args.iter().map(|s| CString::new(s.clone()).unwrap()).collect(); + let c_args: Vec<*const c_char> = + _c_args.iter().map(|s| s.as_ptr()).collect(); + let mut c_unsaved: Vec<CXUnsavedFile> = + unsaved.iter().map(|f| f.x).collect(); + let tu = unsafe { + clang_parseTranslationUnit(ix.x, + fname.as_ptr(), + c_args.as_ptr(), + c_args.len() as c_int, + c_unsaved.as_mut_ptr(), + c_unsaved.len() as c_uint, + opts) + }; + if tu.is_null() { + None + } else { + Some(TranslationUnit { + x: tu, + }) + } + } + + /// Get the Clang diagnostic information associated with this translation + /// unit. + pub fn diags(&self) -> Vec<Diagnostic> { + unsafe { + let num = clang_getNumDiagnostics(self.x) as usize; + let mut diags = vec![]; + for i in 0..num { + diags.push(Diagnostic { + x: clang_getDiagnostic(self.x, i as c_uint), + }); + } + diags + } + } + + /// Get a cursor pointing to the root of this translation unit's AST. + pub fn cursor(&self) -> Cursor { + unsafe { + Cursor { + x: clang_getTranslationUnitCursor(self.x), + } + } + } + + /// Is this the null translation unit? + pub fn is_null(&self) -> bool { + self.x.is_null() + } + + /// Invoke Clang's lexer on this translation unit and get the stream of + /// tokens that come out. + pub fn tokens(&self, cursor: &Cursor) -> Option<Vec<Token>> { + let range = cursor.extent(); + let mut tokens = vec![]; + unsafe { + let mut token_ptr = ptr::null_mut(); + let mut num_tokens: c_uint = 0; + clang_tokenize(self.x, range, &mut token_ptr, &mut num_tokens); + if token_ptr.is_null() { + return None; + } + + let token_array = slice::from_raw_parts(token_ptr, + num_tokens as usize); + for &token in token_array.iter() { + let kind = clang_getTokenKind(token); + let spelling = + cxstring_into_string(clang_getTokenSpelling(self.x, token)); + + tokens.push(Token { + kind: kind, + spelling: spelling, + }); + } + clang_disposeTokens(self.x, token_ptr, num_tokens); + } + Some(tokens) + } + + /// Convert a set of tokens from clang into `cexpr` tokens, for further + /// processing. + pub fn cexpr_tokens(&self, + cursor: &Cursor) + -> Option<Vec<cexpr::token::Token>> { + use cexpr::token; + + let mut tokens = match self.tokens(cursor) { + Some(tokens) => tokens, + None => return None, + }; + + // FIXME(emilio): LLVM 3.9 at least always include an extra token for no + // good reason (except if we're at EOF). So we do this kind of hack, + // where we skip known-to-cause problems trailing punctuation and + // trailing keywords. + // + // This is sort of unfortunate, though :(. + // + // I'll try to get it fixed in LLVM if I have the time to submit a + // patch. + let mut trim_last_token = false; + if let Some(token) = tokens.last() { + // The starting of the next macro. + trim_last_token |= token.spelling == "#" && + token.kind == CXToken_Punctuation; + + // A following keyword of any kind, like a following declaration. + trim_last_token |= token.kind == CXToken_Keyword; + } + + if trim_last_token { + tokens.pop().unwrap(); + } + + Some(tokens.into_iter() + .filter_map(|token| { + let kind = match token.kind { + CXToken_Punctuation => token::Kind::Punctuation, + CXToken_Literal => token::Kind::Literal, + CXToken_Identifier => token::Kind::Identifier, + CXToken_Keyword => token::Kind::Keyword, + // NB: cexpr is not too happy about comments inside + // expressions, so we strip them down here. + CXToken_Comment => return None, + _ => { + panic!("Found unexpected token kind: {:?}", token.kind) + } + }; + + Some(token::Token { + kind: kind, + raw: token.spelling.into_bytes().into_boxed_slice(), + }) + }) + .collect::<Vec<_>>()) + } +} + +impl Drop for TranslationUnit { + fn drop(&mut self) { + unsafe { + clang_disposeTranslationUnit(self.x); + } + } +} + + +/// A diagnostic message generated while parsing a translation unit. +pub struct Diagnostic { + x: CXDiagnostic, +} + +impl Diagnostic { + /// Format this diagnostic message as a string, using the given option bit + /// flags. + pub fn format(&self) -> String { + unsafe { + let opts = clang_defaultDiagnosticDisplayOptions(); + cxstring_into_string(clang_formatDiagnostic(self.x, opts)) + } + } + + /// What is the severity of this diagnostic message? + pub fn severity(&self) -> CXDiagnosticSeverity { + unsafe { clang_getDiagnosticSeverity(self.x) } + } +} + +impl Drop for Diagnostic { + /// Destroy this diagnostic message. + fn drop(&mut self) { + unsafe { + clang_disposeDiagnostic(self.x); + } + } +} + +/// A file which has not been saved to disk. +pub struct UnsavedFile { + x: CXUnsavedFile, + name: CString, + contents: CString, +} + +impl UnsavedFile { + /// Construct a new unsaved file with the given `name` and `contents`. + pub fn new(name: &str, contents: &str) -> UnsavedFile { + let name = CString::new(name).unwrap(); + let contents = CString::new(contents).unwrap(); + let x = CXUnsavedFile { + Filename: name.as_ptr(), + Contents: contents.as_ptr(), + Length: contents.as_bytes().len() as c_ulong, + }; + UnsavedFile { + x: x, + name: name, + contents: contents, + } + } +} + +/// Convert a cursor kind into a static string. +pub fn kind_to_str(x: CXCursorKind) -> String { + unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) } +} + +/// Convert a type kind to a static string. +pub fn type_to_str(x: CXTypeKind) -> String { + unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) } +} + +/// Dump the Clang AST to stdout for debugging purposes. +pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult { + fn print_indent(depth: isize, s: &str) { + for _ in 0..depth { + print!("\t"); + } + println!("{}", s); + } + + print_indent(depth, + &format!("(kind: {}, spelling: {}, type: {}", + kind_to_str(c.kind()), + c.spelling(), + type_to_str(c.cur_type().kind()))); + + // Recurse. + c.visit(|s| ast_dump(&s, depth + 1)); + + print_indent(depth, ")"); + + CXChildVisit_Continue +} + +/// Try to extract the clang version to a string +pub fn extract_clang_version() -> String { + unsafe { cxstring_into_string(clang_getClangVersion()) } +} + +/// A wrapper for the result of evaluating an expression. +#[derive(Debug)] +pub struct EvalResult { + x: CXEvalResult, +} + +impl EvalResult { + /// Evaluate `cursor` and return the result. + pub fn new(cursor: Cursor) -> Option<Self> { + if !clang_Cursor_Evaluate::is_loaded() { + return None; + } + + // Clang has an internal assertion we can trigger if we try to evaluate + // a cursor containing a variadic template type reference. Triggering + // the assertion aborts the process, and we don't want that. Clang + // *also* doesn't expose any API for finding variadic vs non-variadic + // template type references, let alone whether a type referenced is a + // template type, instead they seem to show up as type references to an + // unexposed type. Our solution is to just flat out ban all + // `CXType_Unexposed` from evaluation. + let mut found_cant_eval = false; + cursor.visit(|c| { + if c.kind() == CXCursor_TypeRef && + c.cur_type().kind() == CXType_Unexposed { + found_cant_eval = true; + CXChildVisit_Break + } else { + CXChildVisit_Recurse + } + }); + if found_cant_eval { + return None; + } + + Some(EvalResult { + x: unsafe { clang_Cursor_Evaluate(cursor.x) }, + }) + } + + fn kind(&self) -> CXEvalResultKind { + unsafe { clang_EvalResult_getKind(self.x) } + } + + /// Try to get back the result as a double. + pub fn as_double(&self) -> Option<f64> { + match self.kind() { + CXEval_Float => { + Some(unsafe { clang_EvalResult_getAsDouble(self.x) } as f64) + } + _ => None, + } + } + + /// Try to get back the result as an integer. + pub fn as_int(&self) -> Option<i32> { + match self.kind() { + CXEval_Int => { + Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i32) + } + _ => None, + } + } + + /// Evaluates the expression as a literal string, that may or may not be + /// valid utf-8. + pub fn as_literal_string(&self) -> Option<Vec<u8>> { + match self.kind() { + CXEval_StrLiteral => { + let ret = unsafe { + CStr::from_ptr(clang_EvalResult_getAsStr(self.x)) + }; + Some(ret.to_bytes().to_vec()) + } + _ => None, + } + } +} + +impl Drop for EvalResult { + fn drop(&mut self) { + unsafe { clang_EvalResult_dispose(self.x) }; + } +} diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs new file mode 100644 index 00000000..06dadab0 --- /dev/null +++ b/src/codegen/helpers.rs @@ -0,0 +1,190 @@ +//! Helpers for code generation that don't need macro expansion. + +use aster; +use ir::layout::Layout; +use syntax::ast; +use syntax::ptr::P; + + +pub mod attributes { + use aster; + use syntax::ast; + + pub fn repr(which: &str) -> ast::Attribute { + aster::AstBuilder::new().attr().list("repr").words(&[which]).build() + } + + pub fn repr_list(which_ones: &[&str]) -> ast::Attribute { + aster::AstBuilder::new().attr().list("repr").words(which_ones).build() + } + + pub fn derives(which_ones: &[&str]) -> ast::Attribute { + aster::AstBuilder::new().attr().list("derive").words(which_ones).build() + } + + pub fn inline() -> ast::Attribute { + aster::AstBuilder::new().attr().word("inline") + } + + pub fn doc(comment: &str) -> ast::Attribute { + aster::AstBuilder::new().attr().doc(comment) + } + + pub fn link_name(name: &str) -> ast::Attribute { + aster::AstBuilder::new().attr().name_value("link_name").str(name) + } +} + +/// Generates a proper type for a field or type with a given `Layout`, that is, +/// a type with the correct size and alignment restrictions. +pub struct BlobTyBuilder { + layout: Layout, +} + +impl BlobTyBuilder { + pub fn new(layout: Layout) -> Self { + BlobTyBuilder { + layout: layout, + } + } + + pub fn build(self) -> P<ast::Ty> { + let opaque = self.layout.opaque(); + + // FIXME(emilio, #412): We fall back to byte alignment, but there are + // some things that legitimately are more than 8-byte aligned. + // + // Eventually we should be able to `unwrap` here, but... + let ty_name = match opaque.known_rust_type_for_array() { + Some(ty) => ty, + None => { + warn!("Found unknown alignment on code generation!"); + "u8" + } + }; + + let data_len = opaque.array_size().unwrap_or(self.layout.size); + + let inner_ty = aster::AstBuilder::new().ty().path().id(ty_name).build(); + if data_len == 1 { + inner_ty + } else { + aster::ty::TyBuilder::new().array(data_len).build(inner_ty) + } + } +} + +pub mod ast_ty { + use aster; + use ir::context::BindgenContext; + use ir::function::FunctionSig; + use ir::ty::FloatKind; + use syntax::ast; + use syntax::ptr::P; + + pub fn raw_type(ctx: &BindgenContext, name: &str) -> P<ast::Ty> { + let ident = ctx.rust_ident_raw(&name); + match ctx.options().ctypes_prefix { + Some(ref prefix) => { + let prefix = ctx.rust_ident_raw(prefix); + quote_ty!(ctx.ext_cx(), $prefix::$ident) + } + None => quote_ty!(ctx.ext_cx(), ::std::os::raw::$ident), + } + } + + pub fn float_kind_rust_type(ctx: &BindgenContext, + fk: FloatKind) + -> P<ast::Ty> { + // TODO: we probably should just take the type layout into + // account? + // + // Also, maybe this one shouldn't be the default? + // + // FIXME: `c_longdouble` doesn't seem to be defined in some + // systems, so we use `c_double` directly. + match (fk, ctx.options().convert_floats) { + (FloatKind::Float, true) => aster::ty::TyBuilder::new().f32(), + (FloatKind::Double, true) | + (FloatKind::LongDouble, true) => aster::ty::TyBuilder::new().f64(), + (FloatKind::Float, false) => raw_type(ctx, "c_float"), + (FloatKind::Double, false) | + (FloatKind::LongDouble, false) => raw_type(ctx, "c_double"), + (FloatKind::Float128, _) => { + aster::ty::TyBuilder::new().array(16).u8() + } + } + } + + pub fn int_expr(val: i64) -> P<ast::Expr> { + use std::i64; + let expr = aster::AstBuilder::new().expr(); + + // This is not representable as an i64 if it's negative, so we + // special-case it. + // + // Fix in aster incoming. + if val == i64::MIN { + expr.neg().uint(1u64 << 63) + } else { + expr.int(val) + } + } + + pub fn bool_expr(val: bool) -> P<ast::Expr> { + aster::AstBuilder::new().expr().bool(val) + } + + pub fn byte_array_expr(bytes: &[u8]) -> P<ast::Expr> { + let mut vec = Vec::with_capacity(bytes.len() + 1); + for byte in bytes { + vec.push(int_expr(*byte as i64)); + } + vec.push(int_expr(0)); + + let kind = ast::ExprKind::Vec(vec); + + aster::AstBuilder::new().expr().build_expr_kind(kind) + } + + pub fn cstr_expr(mut string: String) -> P<ast::Expr> { + string.push('\0'); + aster::AstBuilder::new() + .expr() + .build_lit(aster::AstBuilder::new().lit().byte_str(string)) + } + + pub fn float_expr(f: f64) -> P<ast::Expr> { + use aster::symbol::ToSymbol; + let mut string = f.to_string(); + + // So it gets properly recognised as a floating point constant. + if !string.contains('.') { + string.push('.'); + } + + let kind = ast::LitKind::FloatUnsuffixed(string.as_str().to_symbol()); + aster::AstBuilder::new().expr().lit().build_lit(kind) + } + + pub fn arguments_from_signature(signature: &FunctionSig, + ctx: &BindgenContext) + -> Vec<P<ast::Expr>> { + // TODO: We need to keep in sync the argument names, so we should unify + // this with the other loop that decides them. + let mut unnamed_arguments = 0; + signature.argument_types() + .iter() + .map(|&(ref name, _ty)| { + let arg_name = match *name { + Some(ref name) => ctx.rust_mangle(name).into_owned(), + None => { + unnamed_arguments += 1; + format!("arg{}", unnamed_arguments) + } + }; + aster::expr::ExprBuilder::new().id(arg_name) + }) + .collect::<Vec<_>>() + } +} diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs new file mode 100644 index 00000000..7451dd11 --- /dev/null +++ b/src/codegen/mod.rs @@ -0,0 +1,2341 @@ +mod helpers; + +use aster; + +use ir::annotations::FieldAccessorKind; +use ir::comp::{Base, CompInfo, CompKind, Field, Method, MethodKind}; +use ir::context::{BindgenContext, ItemId}; +use ir::derive::{CanDeriveCopy, CanDeriveDebug}; +use ir::enum_ty::{Enum, EnumVariant, EnumVariantValue}; +use ir::function::{Function, FunctionSig}; +use ir::int::IntKind; +use ir::item::{Item, ItemAncestors, ItemCanonicalName, ItemCanonicalPath}; +use ir::item_kind::ItemKind; +use ir::layout::Layout; +use ir::module::Module; +use ir::ty::{Type, TypeKind}; +use ir::type_collector::ItemSet; +use ir::var::Var; +use self::helpers::{BlobTyBuilder, attributes}; + +use std::borrow::Cow; +use std::cell::Cell; +use std::collections::{HashSet, VecDeque}; +use std::collections::hash_map::{Entry, HashMap}; +use std::fmt::Write; +use std::iter; +use std::mem; +use std::ops; +use syntax::abi::Abi; +use syntax::ast; +use syntax::codemap::{Span, respan}; +use syntax::ptr::P; + +fn root_import(ctx: &BindgenContext, module: &Item) -> P<ast::Item> { + assert!(ctx.options().enable_cxx_namespaces, "Somebody messed it up"); + assert!(module.is_module()); + + let root = ctx.root_module().canonical_name(ctx); + let root_ident = ctx.rust_ident(&root); + + let super_ = aster::AstBuilder::new().id("super"); + let supers = module.ancestors(ctx) + .filter(|id| ctx.resolve_item(*id).is_module()) + .map(|_| super_.clone()) + .chain(iter::once(super_)); + + let self_ = iter::once(aster::AstBuilder::new().id("self")); + let root_ident = iter::once(root_ident); + + let path = self_.chain(supers).chain(root_ident); + + let use_root = aster::AstBuilder::new() + .item() + .use_() + .ids(path) + .build() + .build(); + + quote_item!(ctx.ext_cx(), #[allow(unused_imports)] $use_root).unwrap() +} + +struct CodegenResult<'a> { + items: Vec<P<ast::Item>>, + + /// A monotonic counter used to add stable unique id's to stuff that doesn't + /// need to be referenced by anything. + codegen_id: &'a Cell<usize>, + + /// Whether an union has been generated at least once. + saw_union: bool, + + items_seen: HashSet<ItemId>, + /// The set of generated function/var names, needed because in C/C++ is + /// legal to do something like: + /// + /// ```c++ + /// extern "C" { + /// void foo(); + /// extern int bar; + /// } + /// + /// extern "C" { + /// void foo(); + /// extern int bar; + /// } + /// ``` + /// + /// Being these two different declarations. + functions_seen: HashSet<String>, + vars_seen: HashSet<String>, + + /// Used for making bindings to overloaded functions. Maps from a canonical + /// function name to the number of overloads we have already codegen'd for + /// that name. This lets us give each overload a unique suffix. + overload_counters: HashMap<String, u32>, +} + +impl<'a> CodegenResult<'a> { + fn new(codegen_id: &'a Cell<usize>) -> Self { + CodegenResult { + items: vec![], + saw_union: false, + codegen_id: codegen_id, + items_seen: Default::default(), + functions_seen: Default::default(), + vars_seen: Default::default(), + overload_counters: Default::default(), + } + } + + fn next_id(&mut self) -> usize { + self.codegen_id.set(self.codegen_id.get() + 1); + self.codegen_id.get() + } + + fn saw_union(&mut self) { + self.saw_union = true; + } + + fn seen(&self, item: ItemId) -> bool { + self.items_seen.contains(&item) + } + + fn set_seen(&mut self, item: ItemId) { + self.items_seen.insert(item); + } + + fn seen_function(&self, name: &str) -> bool { + self.functions_seen.contains(name) + } + + fn saw_function(&mut self, name: &str) { + self.functions_seen.insert(name.into()); + } + + /// Get the overload number for the given function name. Increments the + /// counter internally so the next time we ask for the overload for this + /// name, we get the incremented value, and so on. + fn overload_number(&mut self, name: &str) -> u32 { + let mut counter = + self.overload_counters.entry(name.into()).or_insert(0); + let number = *counter; + *counter += 1; + number + } + + fn seen_var(&self, name: &str) -> bool { + self.vars_seen.contains(name) + } + + fn saw_var(&mut self, name: &str) { + self.vars_seen.insert(name.into()); + } + + fn inner<F>(&mut self, cb: F) -> Vec<P<ast::Item>> + where F: FnOnce(&mut Self), + { + let mut new = Self::new(self.codegen_id); + + cb(&mut new); + + self.saw_union |= new.saw_union; + + new.items + } +} + +impl<'a> ops::Deref for CodegenResult<'a> { + type Target = Vec<P<ast::Item>>; + + fn deref(&self) -> &Self::Target { + &self.items + } +} + +impl<'a> ops::DerefMut for CodegenResult<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.items + } +} + +struct ForeignModBuilder { + inner: ast::ForeignMod, +} + +impl ForeignModBuilder { + fn new(abi: Abi) -> Self { + ForeignModBuilder { + inner: ast::ForeignMod { + abi: abi, + items: vec![], + }, + } + } + + fn with_foreign_item(mut self, item: ast::ForeignItem) -> Self { + self.inner.items.push(item); + self + } + + #[allow(dead_code)] + fn with_foreign_items<I>(mut self, items: I) -> Self + where I: IntoIterator<Item = ast::ForeignItem>, + { + self.inner.items.extend(items.into_iter()); + self + } + + fn build(self, ctx: &BindgenContext) -> P<ast::Item> { + use syntax::codemap::DUMMY_SP; + P(ast::Item { + ident: ctx.rust_ident(""), + id: ast::DUMMY_NODE_ID, + node: ast::ItemKind::ForeignMod(self.inner), + vis: ast::Visibility::Public, + attrs: vec![], + span: DUMMY_SP, + }) + } +} + +/// A trait to convert a rust type into a pointer, optionally const, to the same +/// type. +/// +/// This is done due to aster's lack of pointer builder, I guess I should PR +/// there. +trait ToPtr { + fn to_ptr(self, is_const: bool, span: Span) -> P<ast::Ty>; +} + +impl ToPtr for P<ast::Ty> { + fn to_ptr(self, is_const: bool, span: Span) -> Self { + let ty = ast::TyKind::Ptr(ast::MutTy { + ty: self, + mutbl: if is_const { + ast::Mutability::Immutable + } else { + ast::Mutability::Mutable + }, + }); + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ty, + span: span, + }) + } +} + +trait CodeGenerator { + /// Extra information from the caller. + type Extra; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + extra: &Self::Extra); +} + +impl CodeGenerator for Item { + type Extra = (); + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + _extra: &()) { + if self.is_hidden(ctx) || result.seen(self.id()) { + debug!("<Item as CodeGenerator>::codegen: Ignoring hidden or seen: \ + self = {:?}", self); + return; + } + + debug!("<Item as CodeGenerator>::codegen: self = {:?}", self); + + result.set_seen(self.id()); + + match *self.kind() { + ItemKind::Module(ref module) => { + module.codegen(ctx, result, whitelisted_items, self); + } + ItemKind::Function(ref fun) => { + if ctx.options().codegen_config.functions { + fun.codegen(ctx, result, whitelisted_items, self); + } + } + ItemKind::Var(ref var) => { + if ctx.options().codegen_config.vars { + var.codegen(ctx, result, whitelisted_items, self); + } + } + ItemKind::Type(ref ty) => { + if ctx.options().codegen_config.types { + ty.codegen(ctx, result, whitelisted_items, self); + } + } + } + } +} + +impl CodeGenerator for Module { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + item: &Item) { + debug!("<Module as CodeGenerator>::codegen: item = {:?}", item); + + let codegen_self = |result: &mut CodegenResult, + found_any: &mut bool| { + for child in self.children() { + if whitelisted_items.contains(child) { + *found_any = true; + ctx.resolve_item(*child) + .codegen(ctx, result, whitelisted_items, &()); + } + } + + if item.id() == ctx.root_module() { + let saw_union = result.saw_union; + if saw_union && !ctx.options().unstable_rust { + utils::prepend_union_types(ctx, &mut *result); + } + if ctx.need_bindegen_complex_type() { + utils::prepend_complex_type(ctx, &mut *result); + } + } + }; + + if !ctx.options().enable_cxx_namespaces || + (self.is_inline() && !ctx.options().conservative_inline_namespaces) { + codegen_self(result, &mut false); + return; + } + + let mut found_any = false; + let inner_items = result.inner(|result| { + result.push(root_import(ctx, item)); + codegen_self(result, &mut found_any); + }); + + // Don't bother creating an empty module. + if !found_any { + return; + } + + let module = ast::ItemKind::Mod(ast::Mod { + inner: ctx.span(), + items: inner_items, + }); + + let name = item.canonical_name(ctx); + let item = aster::AstBuilder::new() + .item() + .pub_() + .build_item_kind(name, module); + + result.push(item); + } +} + +impl CodeGenerator for Var { + type Extra = Item; + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + use ir::var::VarType; + debug!("<Var as CodeGenerator>::codegen: item = {:?}", item); + + let canonical_name = item.canonical_name(ctx); + + if result.seen_var(&canonical_name) { + return; + } + result.saw_var(&canonical_name); + + let ty = self.ty().to_rust_ty(ctx); + + if let Some(val) = self.val() { + let const_item = aster::AstBuilder::new() + .item() + .pub_() + .const_(canonical_name) + .expr(); + let item = match *val { + VarType::Bool(val) => { + const_item.build(helpers::ast_ty::bool_expr(val)) + .build(ty) + } + VarType::Int(val) => { + const_item.build(helpers::ast_ty::int_expr(val)).build(ty) + } + VarType::String(ref bytes) => { + // Account the trailing zero. + // + // TODO: Here we ignore the type we just made up, probably + // we should refactor how the variable type and ty id work. + let len = bytes.len() + 1; + let ty = quote_ty!(ctx.ext_cx(), [u8; $len]); + + match String::from_utf8(bytes.clone()) { + Ok(string) => { + const_item.build(helpers::ast_ty::cstr_expr(string)) + .build(quote_ty!(ctx.ext_cx(), &'static $ty)) + } + Err(..) => { + const_item + .build(helpers::ast_ty::byte_array_expr(bytes)) + .build(ty) + } + } + } + VarType::Float(f) => { + const_item.build(helpers::ast_ty::float_expr(f)) + .build(ty) + } + VarType::Char(c) => { + const_item + .build(aster::AstBuilder::new().expr().lit().byte(c)) + .build(ty) + } + }; + + result.push(item); + } else { + let mut attrs = vec![]; + if let Some(mangled) = self.mangled_name() { + attrs.push(attributes::link_name(mangled)); + } else if canonical_name != self.name() { + attrs.push(attributes::link_name(self.name())); + } + + let item = ast::ForeignItem { + ident: ctx.rust_ident_raw(&canonical_name), + attrs: attrs, + node: ast::ForeignItemKind::Static(ty, !self.is_const()), + id: ast::DUMMY_NODE_ID, + span: ctx.span(), + vis: ast::Visibility::Public, + }; + + let item = ForeignModBuilder::new(Abi::C) + .with_foreign_item(item) + .build(ctx); + result.push(item); + } + } +} + +impl CodeGenerator for Type { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + item: &Item) { + debug!("<Type as CodeGenerator>::codegen: item = {:?}", item); + + match *self.kind() { + TypeKind::Void | + TypeKind::NullPtr | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Complex(..) | + TypeKind::Array(..) | + TypeKind::Pointer(..) | + TypeKind::BlockPointer | + TypeKind::Reference(..) | + TypeKind::TemplateRef(..) | + TypeKind::Function(..) | + TypeKind::ResolvedTypeRef(..) | + TypeKind::Named(..) => { + // These items don't need code generation, they only need to be + // converted to rust types in fields, arguments, and such. + return; + } + TypeKind::Comp(ref ci) => { + ci.codegen(ctx, result, whitelisted_items, item) + } + // NB: The code below will pick the correct + // applicable_template_args. + TypeKind::TemplateAlias(ref spelling, inner, _) | + TypeKind::Alias(ref spelling, inner) => { + let inner_item = ctx.resolve_item(inner); + let name = item.canonical_name(ctx); + + // Try to catch the common pattern: + // + // typedef struct foo { ... } foo; + // + // here. + // + if inner_item.canonical_name(ctx) == name { + return; + } + + // If this is a known named type, disallow generating anything + // for it too. + if utils::type_from_named(ctx, spelling, inner).is_some() { + return; + } + + let mut applicable_template_args = + item.applicable_template_args(ctx); + let inner_rust_type = if item.is_opaque(ctx) { + applicable_template_args.clear(); + // Pray if there's no layout. + let layout = self.layout(ctx).unwrap_or_else(Layout::zero); + BlobTyBuilder::new(layout).build() + } else { + inner_item.to_rust_ty(ctx) + }; + + let rust_name = ctx.rust_ident(&name); + let mut typedef = aster::AstBuilder::new().item().pub_(); + + if let Some(comment) = item.comment() { + typedef = typedef.attr().doc(comment); + } + + // We prefer using `pub use` over `pub type` because of: + // https://github.com/rust-lang/rust/issues/26264 + let simple_enum_path = match inner_rust_type.node { + ast::TyKind::Path(None, ref p) => { + if applicable_template_args.is_empty() && + !inner_item.expect_type().canonical_type(ctx).is_builtin_or_named() && + p.segments.iter().all(|p| p.parameters.is_none()) { + Some(p.clone()) + } else { + None + } + }, + _ => None, + }; + + let typedef = if let Some(mut p) = simple_enum_path { + if p.segments.len() == 1 { + p.segments.insert(0, ast::PathSegment { + identifier: ctx.ext_cx().ident_of("self"), + parameters: None, + }); + } + typedef.use_().build(p).as_(rust_name) + } else { + let mut generics = typedef.type_(rust_name).generics(); + for template_arg in applicable_template_args.iter() { + let template_arg = ctx.resolve_type(*template_arg); + if template_arg.is_named() { + let name = template_arg.name().unwrap(); + if name.contains("typename ") { + warn!("Item contained `typename`'d template \ + parameter: {:?}", item); + return; + } + generics = + generics.ty_param_id(template_arg.name().unwrap()); + } + } + generics.build().build_ty(inner_rust_type) + }; + result.push(typedef) + } + TypeKind::Enum(ref ei) => { + ei.codegen(ctx, result, whitelisted_items, item) + } + ref u @ TypeKind::UnresolvedTypeRef(..) => { + unreachable!("Should have been resolved after parsing {:?}!", u) + } + } + } +} + +struct Vtable<'a> { + item_id: ItemId, + #[allow(dead_code)] + methods: &'a [Method], + #[allow(dead_code)] + base_classes: &'a [Base], +} + +impl<'a> Vtable<'a> { + fn new(item_id: ItemId, + methods: &'a [Method], + base_classes: &'a [Base]) + -> Self { + Vtable { + item_id: item_id, + methods: methods, + base_classes: base_classes, + } + } +} + +impl<'a> CodeGenerator for Vtable<'a> { + type Extra = Item; + + fn codegen<'b>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'b>, + _whitelisted_items: &ItemSet, + item: &Item) { + assert_eq!(item.id(), self.item_id); + // For now, generate an empty struct, later we should generate function + // pointers and whatnot. + let vtable = aster::AstBuilder::new() + .item() + .pub_() + .with_attr(attributes::repr("C")) + .struct_(self.canonical_name(ctx)) + .build(); + result.push(vtable); + } +} + +impl<'a> ItemCanonicalName for Vtable<'a> { + fn canonical_name(&self, ctx: &BindgenContext) -> String { + format!("{}__bindgen_vtable", self.item_id.canonical_name(ctx)) + } +} + +impl<'a> ItemToRustTy for Vtable<'a> { + fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> { + aster::ty::TyBuilder::new().id(self.canonical_name(ctx)) + } +} + +struct Bitfield<'a> { + index: usize, + fields: Vec<&'a Field>, +} + +impl<'a> Bitfield<'a> { + fn new(index: usize, fields: Vec<&'a Field>) -> Self { + Bitfield { + index: index, + fields: fields, + } + } + + fn codegen_fields(self, + ctx: &BindgenContext, + fields: &mut Vec<ast::StructField>, + methods: &mut Vec<ast::ImplItem>) { + use aster::struct_field::StructFieldBuilder; + use std::cmp; + let mut total_width = self.fields + .iter() + .fold(0u32, |acc, f| acc + f.bitfield().unwrap()); + + if !total_width.is_power_of_two() || total_width < 8 { + total_width = cmp::max(8, total_width.next_power_of_two()); + } + debug_assert_eq!(total_width % 8, 0); + let total_width_in_bytes = total_width as usize / 8; + + let bitfield_type = + BlobTyBuilder::new(Layout::new(total_width_in_bytes, + total_width_in_bytes)) + .build(); + let field_name = format!("_bitfield_{}", self.index); + let field_ident = ctx.ext_cx().ident_of(&field_name); + let field = StructFieldBuilder::named(&field_name) + .pub_() + .build_ty(bitfield_type.clone()); + fields.push(field); + + + let mut offset = 0; + for field in self.fields { + let width = field.bitfield().unwrap(); + let field_name = field.name() + .map(ToOwned::to_owned) + .unwrap_or_else(|| format!("at_offset_{}", offset)); + + let field_item = ctx.resolve_item(field.ty()); + let field_ty_layout = field_item.kind() + .expect_type() + .layout(ctx) + .expect("Bitfield without layout? Gah!"); + + let field_type = field_item.to_rust_ty(ctx); + let int_type = BlobTyBuilder::new(field_ty_layout).build(); + + let getter_name = ctx.rust_ident(&field_name); + let setter_name = ctx.ext_cx() + .ident_of(&format!("set_{}", &field_name)); + let mask = ((1usize << width) - 1) << offset; + let prefix = ctx.trait_prefix(); + // The transmute is unfortunate, but it's needed for enums in + // bitfields. + let item = quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub fn $getter_name(&self) -> $field_type { + unsafe { + ::$prefix::mem::transmute( + ( + (self.$field_ident & + ($mask as $bitfield_type)) + >> $offset + ) as $int_type + ) + } + } + + #[inline] + pub fn $setter_name(&mut self, val: $field_type) { + self.$field_ident &= !($mask as $bitfield_type); + self.$field_ident |= + (val as $int_type as $bitfield_type << $offset) & + ($mask as $bitfield_type); + } + } + ) + .unwrap(); + + let items = match item.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, items) => items, + _ => unreachable!(), + }; + + methods.extend(items.into_iter()); + offset += width; + } + } +} + +impl CodeGenerator for CompInfo { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + item: &Item) { + use aster::struct_field::StructFieldBuilder; + + debug!("<CompInfo as CodeGenerator>::codegen: item = {:?}", item); + + // Don't output classes with template parameters that aren't types, and + // also don't output template specializations, neither total or partial. + if self.has_non_type_template_params() { + return; + } + + if self.is_template_specialization() { + let layout = item.kind().expect_type().layout(ctx); + + if let Some(layout) = layout { + let fn_name = format!("__bindgen_test_layout_template_{}", + result.next_id()); + let fn_name = ctx.rust_ident_raw(&fn_name); + let ident = item.to_rust_ty(ctx); + let prefix = ctx.trait_prefix(); + let size_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::size_of::<$ident>()); + let align_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::align_of::<$ident>()); + let size = layout.size; + let align = layout.align; + let item = quote_item!(ctx.ext_cx(), + #[test] + fn $fn_name() { + assert_eq!($size_of_expr, $size); + assert_eq!($align_of_expr, $align); + }) + .unwrap(); + result.push(item); + } + return; + } + + let applicable_template_args = item.applicable_template_args(ctx); + + let mut attributes = vec![]; + let mut needs_clone_impl = false; + if let Some(comment) = item.comment() { + attributes.push(attributes::doc(comment)); + } + if self.packed() { + attributes.push(attributes::repr_list(&["C", "packed"])); + } else { + attributes.push(attributes::repr("C")); + } + + let is_union = self.kind() == CompKind::Union; + let mut derives = vec![]; + if item.can_derive_debug(ctx, ()) { + derives.push("Debug"); + } + + if item.can_derive_copy(ctx, ()) && + !item.annotations().disallow_copy() { + derives.push("Copy"); + if !applicable_template_args.is_empty() { + // FIXME: This requires extra logic if you have a big array in a + // templated struct. The reason for this is that the magic: + // fn clone(&self) -> Self { *self } + // doesn't work for templates. + // + // It's not hard to fix though. + derives.push("Clone"); + } else { + needs_clone_impl = true; + } + } + + if !derives.is_empty() { + attributes.push(attributes::derives(&derives)) + } + + let mut template_args_used = + vec![false; applicable_template_args.len()]; + let canonical_name = item.canonical_name(ctx); + let builder = if is_union && ctx.options().unstable_rust { + aster::AstBuilder::new() + .item() + .pub_() + .with_attrs(attributes) + .union_(&canonical_name) + } else { + aster::AstBuilder::new() + .item() + .pub_() + .with_attrs(attributes) + .struct_(&canonical_name) + }; + + // Generate the vtable from the method list if appropriate. + // + // TODO: I don't know how this could play with virtual methods that are + // not in the list of methods found by us, we'll see. Also, could the + // order of the vtable pointers vary? + // + // FIXME: Once we generate proper vtables, we need to codegen the + // vtable, but *not* generate a field for it in the case that + // needs_explicit_vtable is false but has_vtable is true. + // + // Also, we need to generate the vtable in such a way it "inherits" from + // the parent too. + let mut fields = vec![]; + if self.needs_explicit_vtable(ctx) { + let vtable = + Vtable::new(item.id(), self.methods(), self.base_members()); + vtable.codegen(ctx, result, whitelisted_items, item); + + let vtable_type = vtable.to_rust_ty(ctx).to_ptr(true, ctx.span()); + + let vtable_field = StructFieldBuilder::named("vtable_") + .pub_() + .build_ty(vtable_type); + + fields.push(vtable_field); + } + + for (i, base) in self.base_members().iter().enumerate() { + // Virtual bases are already taken into account by the vtable + // pointer. + // + // FIXME(emilio): Is this always right? + if base.is_virtual() { + continue; + } + + let base_ty = ctx.resolve_type(base.ty); + // NB: We won't include unsized types in our base chain because they + // would contribute to our size given the dummy field we insert for + // unsized types. + if base_ty.is_unsized(ctx) { + continue; + } + + for (i, ty_id) in applicable_template_args.iter().enumerate() { + let template_arg_ty = ctx.resolve_type(*ty_id); + if base_ty.signature_contains_named_type(ctx, template_arg_ty) { + template_args_used[i] = true; + } + } + + let inner = base.ty.to_rust_ty(ctx); + let field_name = if i == 0 { + "_base".into() + } else { + format!("_base_{}", i) + }; + + let field = StructFieldBuilder::named(field_name) + .pub_() + .build_ty(inner); + fields.push(field); + } + if is_union { + result.saw_union(); + } + + let layout = item.kind().expect_type().layout(ctx); + + let mut current_bitfield_width = None; + let mut current_bitfield_layout: Option<Layout> = None; + let mut current_bitfield_fields = vec![]; + let mut bitfield_count = 0; + let struct_fields = self.fields(); + let fields_should_be_private = item.annotations() + .private_fields() + .unwrap_or(false); + let struct_accessor_kind = item.annotations() + .accessor_kind() + .unwrap_or(FieldAccessorKind::None); + + let mut methods = vec![]; + let mut anonymous_field_count = 0; + for field in struct_fields { + debug_assert_eq!(current_bitfield_width.is_some(), + current_bitfield_layout.is_some()); + debug_assert_eq!(current_bitfield_width.is_some(), + !current_bitfield_fields.is_empty()); + + let field_ty = ctx.resolve_type(field.ty()); + + // Try to catch a bitfield contination early. + if let (Some(ref mut bitfield_width), Some(width)) = + (current_bitfield_width, field.bitfield()) { + let layout = current_bitfield_layout.unwrap(); + debug!("Testing bitfield continuation {} {} {:?}", + *bitfield_width, width, layout); + if *bitfield_width + width <= (layout.size * 8) as u32 { + *bitfield_width += width; + current_bitfield_fields.push(field); + continue; + } + } + + // Flush the current bitfield. + if current_bitfield_width.is_some() { + debug_assert!(!current_bitfield_fields.is_empty()); + let bitfield_fields = + mem::replace(&mut current_bitfield_fields, vec![]); + bitfield_count += 1; + Bitfield::new(bitfield_count, bitfield_fields) + .codegen_fields(ctx, &mut fields, &mut methods); + current_bitfield_width = None; + current_bitfield_layout = None; + } + debug_assert!(current_bitfield_fields.is_empty()); + + if let Some(width) = field.bitfield() { + let layout = field_ty.layout(ctx) + .expect("Bitfield type without layout?"); + current_bitfield_width = Some(width); + current_bitfield_layout = Some(layout); + current_bitfield_fields.push(field); + continue; + } + + for (i, ty_id) in applicable_template_args.iter().enumerate() { + let template_arg = ctx.resolve_type(*ty_id); + if field_ty.signature_contains_named_type(ctx, template_arg) { + template_args_used[i] = true; + } + } + + let ty = field.ty().to_rust_ty(ctx); + + // NB: In unstable rust we use proper `union` types. + let ty = if is_union && !ctx.options().unstable_rust { + if ctx.options().enable_cxx_namespaces { + quote_ty!(ctx.ext_cx(), root::__BindgenUnionField<$ty>) + } else { + quote_ty!(ctx.ext_cx(), __BindgenUnionField<$ty>) + } + } else { + ty + }; + + let mut attrs = vec![]; + if let Some(comment) = field.comment() { + attrs.push(attributes::doc(comment)); + } + let field_name = match field.name() { + Some(name) => ctx.rust_mangle(name).into_owned(), + None => { + anonymous_field_count += 1; + format!("__bindgen_anon_{}", anonymous_field_count) + } + }; + + let is_private = field.annotations() + .private_fields() + .unwrap_or(fields_should_be_private); + + let accessor_kind = field.annotations() + .accessor_kind() + .unwrap_or(struct_accessor_kind); + + let mut field = StructFieldBuilder::named(&field_name); + + if !is_private { + field = field.pub_(); + } + + let field = field.with_attrs(attrs) + .build_ty(ty.clone()); + + fields.push(field); + + // TODO: Factor the following code out, please! + if accessor_kind == FieldAccessorKind::None { + continue; + } + + let getter_name = + ctx.rust_ident_raw(&format!("get_{}", field_name)); + let mutable_getter_name = + ctx.rust_ident_raw(&format!("get_{}_mut", field_name)); + let field_name = ctx.rust_ident_raw(&field_name); + + let accessor_methods_impl = match accessor_kind { + FieldAccessorKind::None => unreachable!(), + FieldAccessorKind::Regular => { + quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub fn $getter_name(&self) -> &$ty { + &self.$field_name + } + + #[inline] + pub fn $mutable_getter_name(&mut self) -> &mut $ty { + &mut self.$field_name + } + } + ) + } + FieldAccessorKind::Unsafe => { + quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub unsafe fn $getter_name(&self) -> &$ty { + &self.$field_name + } + + #[inline] + pub unsafe fn $mutable_getter_name(&mut self) + -> &mut $ty { + &mut self.$field_name + } + } + ) + } + FieldAccessorKind::Immutable => { + quote_item!(ctx.ext_cx(), + impl X { + #[inline] + pub fn $getter_name(&self) -> &$ty { + &self.$field_name + } + } + ) + } + }; + + match accessor_methods_impl.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => { + methods.extend(items.clone()) + } + _ => unreachable!(), + } + } + + // Flush the last bitfield if any. + // + // FIXME: Reduce duplication with the loop above. + // FIXME: May need to pass current_bitfield_layout too. + if current_bitfield_width.is_some() { + debug_assert!(!current_bitfield_fields.is_empty()); + let bitfield_fields = mem::replace(&mut current_bitfield_fields, + vec![]); + bitfield_count += 1; + Bitfield::new(bitfield_count, bitfield_fields) + .codegen_fields(ctx, &mut fields, &mut methods); + } + debug_assert!(current_bitfield_fields.is_empty()); + + if is_union && !ctx.options().unstable_rust { + let layout = layout.expect("Unable to get layout information?"); + let ty = BlobTyBuilder::new(layout).build(); + let field = StructFieldBuilder::named("bindgen_union_field") + .pub_() + .build_ty(ty); + fields.push(field); + } + + // Yeah, sorry about that. + if item.is_opaque(ctx) { + fields.clear(); + methods.clear(); + for i in 0..template_args_used.len() { + template_args_used[i] = false; + } + + match layout { + Some(l) => { + let ty = BlobTyBuilder::new(l).build(); + let field = + StructFieldBuilder::named("_bindgen_opaque_blob") + .pub_() + .build_ty(ty); + fields.push(field); + } + None => { + warn!("Opaque type without layout! Expect dragons!"); + } + } + } + + // C requires every struct to be addressable, so what C compilers do is + // making the struct 1-byte sized. + // + // NOTE: This check is conveniently here to avoid the dummy fields we + // may add for unused template parameters. + if self.is_unsized(ctx) { + let ty = BlobTyBuilder::new(Layout::new(1, 1)).build(); + let field = StructFieldBuilder::named("_address") + .pub_() + .build_ty(ty); + fields.push(field); + } + + // Append any extra template arguments that nobody has used so far. + for (i, ty) in applicable_template_args.iter().enumerate() { + if !template_args_used[i] { + let name = ctx.resolve_type(*ty).name().unwrap(); + let ident = ctx.rust_ident(name); + let prefix = ctx.trait_prefix(); + let phantom = quote_ty!(ctx.ext_cx(), + ::$prefix::marker::PhantomData<$ident>); + let field = + StructFieldBuilder::named(format!("_phantom_{}", i)) + .pub_() + .build_ty(phantom); + fields.push(field) + } + } + + + let mut generics = aster::AstBuilder::new().generics(); + for template_arg in applicable_template_args.iter() { + // Take into account that here only arrive named types, not + // template specialisations that would need to be + // instantiated. + // + // TODO: Add template args from the parent, here and in + // `to_rust_ty`!! + let template_arg = ctx.resolve_type(*template_arg); + generics = generics.ty_param_id(template_arg.name().unwrap()); + } + + let generics = generics.build(); + + let rust_struct = builder.with_generics(generics.clone()) + .with_fields(fields) + .build(); + result.push(rust_struct); + + // Generate the inner types and all that stuff. + // + // TODO: In the future we might want to be smart, and use nested + // modules, and whatnot. + for ty in self.inner_types() { + let child_item = ctx.resolve_item(*ty); + // assert_eq!(child_item.parent_id(), item.id()); + child_item.codegen(ctx, result, whitelisted_items, &()); + } + + // NOTE: Some unexposed attributes (like alignment attributes) may + // affect layout, so we're bad and pray to the gods for avoid sending + // all the tests to shit when parsing things like max_align_t. + if self.found_unknown_attr() { + warn!("Type {} has an unkown attribute that may affect layout", + canonical_name); + } + + if applicable_template_args.is_empty() && !self.found_unknown_attr() { + for var in self.inner_vars() { + ctx.resolve_item(*var) + .codegen(ctx, result, whitelisted_items, &()); + } + + if let Some(layout) = layout { + let fn_name = format!("bindgen_test_layout_{}", canonical_name); + let fn_name = ctx.rust_ident_raw(&fn_name); + let ident = ctx.rust_ident_raw(&canonical_name); + let prefix = ctx.trait_prefix(); + let size_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::size_of::<$ident>()); + let align_of_expr = quote_expr!(ctx.ext_cx(), + ::$prefix::mem::align_of::<$ident>()); + let size = layout.size; + let align = layout.align; + let item = quote_item!(ctx.ext_cx(), + #[test] + fn $fn_name() { + assert_eq!($size_of_expr, $size); + assert_eq!($align_of_expr, $align); + }) + .unwrap(); + result.push(item); + } + + let mut method_names = Default::default(); + if ctx.options().codegen_config.methods { + for method in self.methods() { + assert!(method.kind() != MethodKind::Constructor); + method.codegen_method(ctx, + &mut methods, + &mut method_names, + result, + whitelisted_items, + self); + } + } + + if ctx.options().codegen_config.constructors { + for sig in self.constructors() { + Method::new(MethodKind::Constructor, + *sig, + /* const */ + false) + .codegen_method(ctx, + &mut methods, + &mut method_names, + result, + whitelisted_items, + self); + } + } + } + + // NB: We can't use to_rust_ty here since for opaque types this tries to + // use the specialization knowledge to generate a blob field. + let ty_for_impl = + aster::AstBuilder::new().ty().path().id(&canonical_name).build(); + if needs_clone_impl { + let impl_ = quote_item!(ctx.ext_cx(), + impl X { + fn clone(&self) -> Self { *self } + } + ); + + let impl_ = match impl_.unwrap().node { + ast::ItemKind::Impl(_, _, _, _, _, ref items) => items.clone(), + _ => unreachable!(), + }; + + let clone_impl = aster::AstBuilder::new() + .item() + .impl_() + .trait_() + .id("Clone") + .build() + .with_generics(generics.clone()) + .with_items(impl_) + .build_ty(ty_for_impl.clone()); + + result.push(clone_impl); + } + + if !methods.is_empty() { + let methods = aster::AstBuilder::new() + .item() + .impl_() + .with_generics(generics) + .with_items(methods) + .build_ty(ty_for_impl); + result.push(methods); + } + } +} + +trait MethodCodegen { + fn codegen_method<'a>(&self, + ctx: &BindgenContext, + methods: &mut Vec<ast::ImplItem>, + method_names: &mut HashMap<String, usize>, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + parent: &CompInfo); +} + +impl MethodCodegen for Method { + fn codegen_method<'a>(&self, + ctx: &BindgenContext, + methods: &mut Vec<ast::ImplItem>, + method_names: &mut HashMap<String, usize>, + result: &mut CodegenResult<'a>, + whitelisted_items: &ItemSet, + _parent: &CompInfo) { + if self.is_virtual() { + return; // FIXME + } + // First of all, output the actual function. + let function_item = ctx.resolve_item(self.signature()); + function_item.codegen(ctx, result, whitelisted_items, &()); + + let function = function_item.expect_function(); + let signature_item = ctx.resolve_item(function.signature()); + let mut name = match self.kind() { + MethodKind::Constructor => "new".into(), + _ => function.name().to_owned(), + }; + + let signature = match *signature_item.expect_type().kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("How in the world?"), + }; + + // Do not generate variadic methods, since rust does not allow + // implementing them, and we don't do a good job at it anyway. + if signature.is_variadic() { + return; + } + + let count = { + let mut count = method_names.entry(name.clone()) + .or_insert(0); + *count += 1; + *count - 1 + }; + + if count != 0 { + name.push_str(&count.to_string()); + } + + let function_name = function_item.canonical_name(ctx); + let mut fndecl = utils::rust_fndecl_from_signature(ctx, signature_item) + .unwrap(); + if !self.is_static() && !self.is_constructor() { + let mutability = if self.is_const() { + ast::Mutability::Immutable + } else { + ast::Mutability::Mutable + }; + + assert!(!fndecl.inputs.is_empty()); + + // FIXME: use aster here. + fndecl.inputs[0] = ast::Arg { + ty: P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::Rptr(None, ast::MutTy { + ty: P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: ast::TyKind::ImplicitSelf, + span: ctx.span() + }), + mutbl: mutability, + }), + span: ctx.span(), + }), + pat: P(ast::Pat { + id: ast::DUMMY_NODE_ID, + node: ast::PatKind::Ident( + ast::BindingMode::ByValue(ast::Mutability::Immutable), + respan(ctx.span(), ctx.ext_cx().ident_of("self")), + None + ), + span: ctx.span(), + }), + id: ast::DUMMY_NODE_ID, + }; + } + + // If it's a constructor, we always return `Self`, and we inject the + // "this" parameter, so there's no need to ask the user for it. + // + // Note that constructors in Clang are represented as functions with + // return-type = void. + if self.is_constructor() { + fndecl.inputs.remove(0); + fndecl.output = + ast::FunctionRetTy::Ty(quote_ty!(ctx.ext_cx(), Self)); + } + + let sig = ast::MethodSig { + unsafety: ast::Unsafety::Unsafe, + abi: Abi::Rust, + decl: P(fndecl), + generics: ast::Generics::default(), + constness: respan(ctx.span(), ast::Constness::NotConst), + }; + + let mut exprs = helpers::ast_ty::arguments_from_signature(&signature, + ctx); + + let mut stmts = vec![]; + + // If it's a constructor, we need to insert an extra parameter with a + // variable called `__bindgen_tmp` we're going to create. + if self.is_constructor() { + let tmp_variable_decl = + quote_stmt!(ctx.ext_cx(), + let mut __bindgen_tmp = ::std::mem::uninitialized()) + .unwrap(); + stmts.push(tmp_variable_decl); + exprs[0] = quote_expr!(ctx.ext_cx(), &mut __bindgen_tmp); + } else if !self.is_static() { + assert!(!exprs.is_empty()); + exprs[0] = if self.is_const() { + quote_expr!(ctx.ext_cx(), &*self) + } else { + quote_expr!(ctx.ext_cx(), &mut *self) + }; + }; + + let call = aster::expr::ExprBuilder::new() + .call() + .id(function_name) + .with_args(exprs) + .build(); + + stmts.push(ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Expr(call), + span: ctx.span(), + }); + + if self.is_constructor() { + stmts.push(quote_stmt!(ctx.ext_cx(), __bindgen_tmp).unwrap()); + } + + let block = ast::Block { + stmts: stmts, + id: ast::DUMMY_NODE_ID, + rules: ast::BlockCheckMode::Default, + span: ctx.span(), + }; + + let mut attrs = vec![]; + attrs.push(attributes::inline()); + + let item = ast::ImplItem { + id: ast::DUMMY_NODE_ID, + ident: ctx.rust_ident(&name), + vis: ast::Visibility::Public, + attrs: attrs, + node: ast::ImplItemKind::Method(sig, P(block)), + defaultness: ast::Defaultness::Final, + span: ctx.span(), + }; + + methods.push(item); + } +} + +/// A helper type to construct enums, either bitfield ones or rust-style ones. +enum EnumBuilder<'a> { + Rust(aster::item::ItemEnumBuilder<aster::invoke::Identity>), + Bitfield { + canonical_name: &'a str, + aster: P<ast::Item>, + }, +} + +impl<'a> EnumBuilder<'a> { + /// Create a new enum given an item builder, a canonical name, a name for + /// the representation, and whether it should be represented as a rust enum. + fn new(aster: aster::item::ItemBuilder<aster::invoke::Identity>, + name: &'a str, + repr_name: &str, + is_rust: bool) + -> Self { + if is_rust { + EnumBuilder::Rust(aster.enum_(name)) + } else { + EnumBuilder::Bitfield { + canonical_name: name, + aster: aster.tuple_struct(name) + .field() + .pub_() + .ty() + .id(repr_name) + .build(), + } + } + } + + /// Add a variant to this enum. + fn with_variant<'b>(self, + ctx: &BindgenContext, + variant: &EnumVariant, + mangling_prefix: Option<&String>, + rust_ty: P<ast::Ty>, + result: &mut CodegenResult<'b>) + -> Self { + let variant_name = ctx.rust_mangle(variant.name()); + let expr = aster::AstBuilder::new().expr(); + let expr = match variant.val() { + EnumVariantValue::Signed(v) => helpers::ast_ty::int_expr(v), + EnumVariantValue::Unsigned(v) => expr.uint(v), + }; + + match self { + EnumBuilder::Rust(b) => { + EnumBuilder::Rust(b.with_variant_(ast::Variant_ { + name: ctx.rust_ident(&*variant_name), + attrs: vec![], + data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), + disr_expr: Some(expr), + })) + } + EnumBuilder::Bitfield { canonical_name, .. } => { + let constant_name = match mangling_prefix { + Some(prefix) => { + Cow::Owned(format!("{}_{}", prefix, variant_name)) + } + None => variant_name, + }; + + let constant = aster::AstBuilder::new() + .item() + .pub_() + .const_(&*constant_name) + .expr() + .call() + .id(canonical_name) + .arg() + .build(expr) + .build() + .build(rust_ty); + result.push(constant); + self + } + } + } + + fn build<'b>(self, + ctx: &BindgenContext, + rust_ty: P<ast::Ty>, + result: &mut CodegenResult<'b>) + -> P<ast::Item> { + match self { + EnumBuilder::Rust(b) => b.build(), + EnumBuilder::Bitfield { canonical_name, aster } => { + let rust_ty_name = ctx.rust_ident_raw(canonical_name); + let prefix = ctx.trait_prefix(); + + let impl_ = quote_item!(ctx.ext_cx(), + impl ::$prefix::ops::BitOr<$rust_ty> for $rust_ty { + type Output = Self; + + #[inline] + fn bitor(self, other: Self) -> Self { + $rust_ty_name(self.0 | other.0) + } + } + ) + .unwrap(); + + result.push(impl_); + aster + } + } + } +} + +impl CodeGenerator for Enum { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + debug!("<Enum as CodeGenerator>::codegen: item = {:?}", item); + + let name = item.canonical_name(ctx); + let enum_ty = item.expect_type(); + let layout = enum_ty.layout(ctx); + + let repr = self.repr().map(|repr| ctx.resolve_type(repr)); + let repr = match repr { + Some(repr) => { + match *repr.canonical_type(ctx).kind() { + TypeKind::Int(int_kind) => int_kind, + _ => panic!("Unexpected type as enum repr"), + } + } + None => { + warn!("Guessing type of enum! Forward declarations of enums \ + shouldn't be legal!"); + IntKind::Int + } + }; + + let signed = repr.is_signed(); + let size = layout.map(|l| l.size) + .or_else(|| repr.known_size()) + .unwrap_or(0); + + let repr_name = match (signed, size) { + (true, 1) => "i8", + (false, 1) => "u8", + (true, 2) => "i16", + (false, 2) => "u16", + (true, 4) => "i32", + (false, 4) => "u32", + (true, 8) => "i64", + (false, 8) => "u64", + _ => { + warn!("invalid enum decl: signed: {}, size: {}", signed, size); + "i32" + } + }; + + let mut builder = aster::AstBuilder::new().item().pub_(); + + let is_bitfield = { + ctx.options().bitfield_enums.matches(&name) || + (enum_ty.name().is_none() && + self.variants() + .iter() + .any(|v| ctx.options().bitfield_enums.matches(&v.name()))) + }; + + let is_rust_enum = !is_bitfield; + + // FIXME: Rust forbids repr with empty enums. Remove this condition when + // this is allowed. + if is_rust_enum { + if !self.variants().is_empty() { + builder = builder.with_attr(attributes::repr(repr_name)); + } + } else { + builder = builder.with_attr(attributes::repr("C")); + } + + if let Some(comment) = item.comment() { + builder = builder.with_attr(attributes::doc(comment)); + } + + let derives = attributes::derives(&["Debug", + "Copy", + "Clone", + "PartialEq", + "Eq", + "Hash"]); + + builder = builder.with_attr(derives); + + fn add_constant<'a>(enum_: &Type, + // Only to avoid recomputing every time. + enum_canonical_name: &str, + // May be the same as "variant" if it's because the + // enum is unnamed and we still haven't seen the + // value. + variant_name: &str, + referenced_name: &str, + enum_rust_ty: P<ast::Ty>, + result: &mut CodegenResult<'a>) { + let constant_name = if enum_.name().is_some() { + format!("{}_{}", enum_canonical_name, variant_name) + } else { + variant_name.into() + }; + + let constant = aster::AstBuilder::new() + .item() + .pub_() + .const_(constant_name) + .expr() + .path() + .ids(&[&*enum_canonical_name, referenced_name]) + .build() + .build(enum_rust_ty); + result.push(constant); + } + + let mut builder = + EnumBuilder::new(builder, &name, repr_name, is_rust_enum); + + // A map where we keep a value -> variant relation. + let mut seen_values = HashMap::<_, String>::new(); + let enum_rust_ty = item.to_rust_ty(ctx); + let is_toplevel = item.is_toplevel(ctx); + + // Used to mangle the constants we generate in the unnamed-enum case. + let parent_canonical_name = if is_toplevel { + None + } else { + Some(item.parent_id().canonical_name(ctx)) + }; + + let constant_mangling_prefix = if enum_ty.name().is_none() { + parent_canonical_name.as_ref().map(|n| &*n) + } else { + Some(&name) + }; + + // NB: We defer the creation of constified variants, in case we find + // another variant with the same value (which is the common thing to + // do). + let mut constified_variants = VecDeque::new(); + + let mut iter = self.variants().iter().peekable(); + while let Some(variant) = iter.next().or_else(|| constified_variants.pop_front()) { + if variant.hidden() { + continue; + } + + if variant.force_constification() && iter.peek().is_some() { + constified_variants.push_back(variant); + continue; + } + + match seen_values.entry(variant.val()) { + Entry::Occupied(ref entry) => { + if is_rust_enum { + let variant_name = ctx.rust_mangle(variant.name()); + let mangled_name = if is_toplevel || + enum_ty.name().is_some() { + variant_name + } else { + let parent_name = parent_canonical_name.as_ref() + .unwrap(); + + Cow::Owned( + format!("{}_{}", parent_name, variant_name)) + }; + + let existing_variant_name = entry.get(); + add_constant(enum_ty, + &name, + &*mangled_name, + existing_variant_name, + enum_rust_ty.clone(), + result); + } else { + builder = builder.with_variant(ctx, + variant, + constant_mangling_prefix, + enum_rust_ty.clone(), + result); + } + } + Entry::Vacant(entry) => { + builder = builder.with_variant(ctx, + variant, + constant_mangling_prefix, + enum_rust_ty.clone(), + result); + + let variant_name = ctx.rust_mangle(variant.name()); + + // If it's an unnamed enum, or constification is enforced, + // we also generate a constant so it can be properly + // accessed. + if (is_rust_enum && enum_ty.name().is_none()) || + variant.force_constification() { + let mangled_name = if is_toplevel { + variant_name.clone() + } else { + let parent_name = parent_canonical_name.as_ref() + .unwrap(); + + Cow::Owned( + format!("{}_{}", parent_name, variant_name)) + }; + + add_constant(enum_ty, + &name, + &mangled_name, + &variant_name, + enum_rust_ty.clone(), + result); + } + + entry.insert(variant_name.into_owned()); + } + } + } + + let enum_ = builder.build(ctx, enum_rust_ty, result); + result.push(enum_); + } +} + +trait ToRustTy { + type Extra; + + fn to_rust_ty(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> P<ast::Ty>; +} + +trait ItemToRustTy { + fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty>; +} + +// Convenience implementation. +impl ItemToRustTy for ItemId { + fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> { + ctx.resolve_item(*self).to_rust_ty(ctx) + } +} + +impl ItemToRustTy for Item { + fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> { + self.kind().expect_type().to_rust_ty(ctx, self) + } +} + +impl ToRustTy for Type { + type Extra = Item; + + fn to_rust_ty(&self, ctx: &BindgenContext, item: &Item) -> P<ast::Ty> { + use self::helpers::ast_ty::*; + + match *self.kind() { + TypeKind::Void => raw_type(ctx, "c_void"), + // TODO: we should do something smart with nullptr, or maybe *const + // c_void is enough? + TypeKind::NullPtr => { + raw_type(ctx, "c_void").to_ptr(true, ctx.span()) + } + TypeKind::Int(ik) => { + match ik { + IntKind::Bool => aster::ty::TyBuilder::new().bool(), + IntKind::Char => raw_type(ctx, "c_char"), + IntKind::UChar => raw_type(ctx, "c_uchar"), + IntKind::Short => raw_type(ctx, "c_short"), + IntKind::UShort => raw_type(ctx, "c_ushort"), + IntKind::Int => raw_type(ctx, "c_int"), + IntKind::UInt => raw_type(ctx, "c_uint"), + IntKind::Long => raw_type(ctx, "c_long"), + IntKind::ULong => raw_type(ctx, "c_ulong"), + IntKind::LongLong => raw_type(ctx, "c_longlong"), + IntKind::ULongLong => raw_type(ctx, "c_ulonglong"), + + IntKind::I8 => aster::ty::TyBuilder::new().i8(), + IntKind::U8 => aster::ty::TyBuilder::new().u8(), + IntKind::I16 => aster::ty::TyBuilder::new().i16(), + IntKind::U16 => aster::ty::TyBuilder::new().u16(), + IntKind::I32 => aster::ty::TyBuilder::new().i32(), + IntKind::U32 => aster::ty::TyBuilder::new().u32(), + IntKind::I64 => aster::ty::TyBuilder::new().i64(), + IntKind::U64 => aster::ty::TyBuilder::new().u64(), + IntKind::Custom { name, .. } => { + let ident = ctx.rust_ident_raw(name); + quote_ty!(ctx.ext_cx(), $ident) + } + // FIXME: This doesn't generate the proper alignment, but we + // can't do better right now. We should be able to use + // i128/u128 when they're available. + IntKind::U128 | IntKind::I128 => { + aster::ty::TyBuilder::new().array(2).u64() + } + } + } + TypeKind::Float(fk) => float_kind_rust_type(ctx, fk), + TypeKind::Complex(fk) => { + let float_path = float_kind_rust_type(ctx, fk); + + ctx.generated_bindegen_complex(); + if ctx.options().enable_cxx_namespaces { + quote_ty!(ctx.ext_cx(), root::__BindgenComplex<$float_path>) + } else { + quote_ty!(ctx.ext_cx(), __BindgenComplex<$float_path>) + } + } + TypeKind::Function(ref fs) => { + let ty = fs.to_rust_ty(ctx, item); + let prefix = ctx.trait_prefix(); + quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>) + } + TypeKind::Array(item, len) => { + let inner = item.to_rust_ty(ctx); + aster::ty::TyBuilder::new().array(len).build(inner) + } + TypeKind::Enum(..) => { + let path = item.namespace_aware_canonical_path(ctx); + aster::AstBuilder::new().ty().path().ids(path).build() + } + TypeKind::TemplateRef(inner, ref template_args) => { + // PS: Sorry for the duplication here. + let mut inner_ty = inner.to_rust_ty(ctx).unwrap(); + + if let ast::TyKind::Path(_, ref mut path) = inner_ty.node { + let template_args = template_args.iter() + .map(|arg| arg.to_rust_ty(ctx)) + .collect::<Vec<_>>(); + + path.segments.last_mut().unwrap().parameters = if template_args.is_empty() { + None + } else { + Some(P(ast::PathParameters::AngleBracketed( + ast::AngleBracketedParameterData { + lifetimes: vec![], + types: P::from_vec(template_args), + bindings: P::from_vec(vec![]), + } + ))) + } + } + + P(inner_ty) + } + TypeKind::ResolvedTypeRef(inner) => inner.to_rust_ty(ctx), + TypeKind::TemplateAlias(ref spelling, inner, _) | + TypeKind::Alias(ref spelling, inner) => { + let applicable_named_args = + item.applicable_template_args(ctx) + .into_iter() + .filter(|arg| ctx.resolve_type(*arg).is_named()) + .collect::<Vec<_>>(); + + if item.is_opaque(ctx) && !applicable_named_args.is_empty() { + // Pray if there's no available layout. + let layout = self.layout(ctx).unwrap_or_else(Layout::zero); + BlobTyBuilder::new(layout).build() + } else if let Some(ty) = utils::type_from_named(ctx, + spelling, + inner) { + ty + } else { + utils::build_templated_path(item, + ctx, + applicable_named_args) + } + } + TypeKind::Comp(ref info) => { + let template_args = item.applicable_template_args(ctx); + if info.has_non_type_template_params() || + (item.is_opaque(ctx) && !template_args.is_empty()) { + return match self.layout(ctx) { + Some(layout) => BlobTyBuilder::new(layout).build(), + None => { + warn!("Couldn't compute layout for a type with non \ + type template params or opaque, expect \ + dragons!"); + aster::AstBuilder::new().ty().unit() + } + }; + } + + utils::build_templated_path(item, ctx, template_args) + } + TypeKind::BlockPointer => { + let void = raw_type(ctx, "c_void"); + void.to_ptr(/* is_const = */ + false, + ctx.span()) + } + TypeKind::Pointer(inner) | + TypeKind::Reference(inner) => { + let inner = ctx.resolve_item(inner); + let inner_ty = inner.expect_type(); + let ty = inner.to_rust_ty(ctx); + + // Avoid the first function pointer level, since it's already + // represented in Rust. + if inner_ty.canonical_type(ctx).is_function() { + ty + } else { + let is_const = self.is_const() || + inner.expect_type().is_const(); + ty.to_ptr(is_const, ctx.span()) + } + } + TypeKind::Named(..) => { + let name = item.canonical_name(ctx); + let ident = ctx.rust_ident(&name); + quote_ty!(ctx.ext_cx(), $ident) + } + ref u @ TypeKind::UnresolvedTypeRef(..) => { + unreachable!("Should have been resolved after parsing {:?}!", u) + } + } + } +} + +impl ToRustTy for FunctionSig { + type Extra = Item; + + fn to_rust_ty(&self, ctx: &BindgenContext, _item: &Item) -> P<ast::Ty> { + // TODO: we might want to consider ignoring the reference return value. + let return_item = ctx.resolve_item(self.return_type()); + let ret = + if let TypeKind::Void = *return_item.kind().expect_type().kind() { + ast::FunctionRetTy::Default(ctx.span()) + } else { + ast::FunctionRetTy::Ty(return_item.to_rust_ty(ctx)) + }; + + let mut unnamed_arguments = 0; + let arguments = self.argument_types().iter().map(|&(ref name, ty)| { + let arg_item = ctx.resolve_item(ty); + let arg_ty = arg_item.kind().expect_type(); + + // From the C90 standard[1]: + // + // A declaration of a parameter as "array of type" shall be + // adjusted to "qualified pointer to type", where the type + // qualifiers (if any) are those specified within the [ and ] of + // the array type derivation. + // + // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html + let arg_ty = if let TypeKind::Array(t, _) = *arg_ty.canonical_type(ctx).kind() { + t.to_rust_ty(ctx).to_ptr(arg_ty.is_const(), ctx.span()) + } else { + arg_item.to_rust_ty(ctx) + }; + + let arg_name = match *name { + Some(ref name) => ctx.rust_mangle(name).into_owned(), + None => { + unnamed_arguments += 1; + format!("arg{}", unnamed_arguments) + } + }; + + assert!(!arg_name.is_empty()); + + ast::Arg { + ty: arg_ty, + pat: aster::AstBuilder::new().pat().id(arg_name), + id: ast::DUMMY_NODE_ID, + } + }).collect::<Vec<_>>(); + + let decl = P(ast::FnDecl { + inputs: arguments, + output: ret, + variadic: self.is_variadic(), + }); + + let fnty = ast::TyKind::BareFn(P(ast::BareFnTy { + unsafety: ast::Unsafety::Unsafe, + abi: self.abi(), + lifetimes: vec![], + decl: decl, + })); + + P(ast::Ty { + id: ast::DUMMY_NODE_ID, + node: fnty, + span: ctx.span(), + }) + } +} + +impl CodeGenerator for Function { + type Extra = Item; + + fn codegen<'a>(&self, + ctx: &BindgenContext, + result: &mut CodegenResult<'a>, + _whitelisted_items: &ItemSet, + item: &Item) { + debug!("<Function as CodeGenerator>::codegen: item = {:?}", item); + + let name = self.name(); + let mut canonical_name = item.canonical_name(ctx); + let mangled_name = self.mangled_name(); + + { + let seen_symbol_name = mangled_name.unwrap_or(&canonical_name); + + // TODO: Maybe warn here if there's a type/argument mismatch, or + // something? + if result.seen_function(seen_symbol_name) { + return; + } + result.saw_function(seen_symbol_name); + } + + let signature_item = ctx.resolve_item(self.signature()); + let signature = signature_item.kind().expect_type().canonical_type(ctx); + let signature = match *signature.kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("Signature kind is not a Function: {:?}", signature), + }; + + let fndecl = utils::rust_fndecl_from_signature(ctx, signature_item); + + let mut attributes = vec![]; + + if let Some(comment) = item.comment() { + attributes.push(attributes::doc(comment)); + } + + if let Some(mangled) = mangled_name { + attributes.push(attributes::link_name(mangled)); + } else if name != canonical_name { + attributes.push(attributes::link_name(name)); + } + + let foreign_item_kind = + ast::ForeignItemKind::Fn(fndecl, ast::Generics::default()); + + // Handle overloaded functions by giving each overload its own unique + // suffix. + let times_seen = result.overload_number(&canonical_name); + if times_seen > 0 { + write!(&mut canonical_name, "{}", times_seen).unwrap(); + } + + let foreign_item = ast::ForeignItem { + ident: ctx.rust_ident_raw(&canonical_name), + attrs: attributes, + node: foreign_item_kind, + id: ast::DUMMY_NODE_ID, + span: ctx.span(), + vis: ast::Visibility::Public, + }; + + let item = ForeignModBuilder::new(signature.abi()) + .with_foreign_item(foreign_item) + .build(ctx); + + result.push(item); + } +} + +pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> { + context.gen(|context| { + let counter = Cell::new(0); + let mut result = CodegenResult::new(&counter); + + debug!("codegen: {:?}", context.options()); + + let whitelisted_items: ItemSet = context.whitelisted_items().collect(); + + if context.options().emit_ir { + for &id in whitelisted_items.iter() { + let item = context.resolve_item(id); + println!("ir: {:?} = {:#?}", id, item); + } + } + + context.resolve_item(context.root_module()) + .codegen(context, &mut result, &whitelisted_items, &()); + + result.items + }) +} + +mod utils { + use aster; + use ir::context::{BindgenContext, ItemId}; + use ir::item::{Item, ItemCanonicalPath}; + use ir::ty::TypeKind; + use std::mem; + use super::ItemToRustTy; + use syntax::ast; + use syntax::ptr::P; + + pub fn prepend_union_types(ctx: &BindgenContext, + result: &mut Vec<P<ast::Item>>) { + let prefix = ctx.trait_prefix(); + + // TODO(emilio): The fmt::Debug impl could be way nicer with + // std::intrinsics::type_name, but... + let union_field_decl = quote_item!(ctx.ext_cx(), + #[repr(C)] + pub struct __BindgenUnionField<T>( + ::$prefix::marker::PhantomData<T>); + ) + .unwrap(); + + let union_field_impl = quote_item!(&ctx.ext_cx(), + impl<T> __BindgenUnionField<T> { + #[inline] + pub fn new() -> Self { + __BindgenUnionField(::$prefix::marker::PhantomData) + } + + #[inline] + pub unsafe fn as_ref(&self) -> &T { + ::$prefix::mem::transmute(self) + } + + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { + ::$prefix::mem::transmute(self) + } + } + ) + .unwrap(); + + let union_field_default_impl = quote_item!(&ctx.ext_cx(), + impl<T> ::$prefix::default::Default for __BindgenUnionField<T> { + #[inline] + fn default() -> Self { + Self::new() + } + } + ) + .unwrap(); + + let union_field_clone_impl = quote_item!(&ctx.ext_cx(), + impl<T> ::$prefix::clone::Clone for __BindgenUnionField<T> { + #[inline] + fn clone(&self) -> Self { + Self::new() + } + } + ) + .unwrap(); + + let union_field_copy_impl = quote_item!(&ctx.ext_cx(), + impl<T> ::$prefix::marker::Copy for __BindgenUnionField<T> {} + ) + .unwrap(); + + let union_field_debug_impl = quote_item!(ctx.ext_cx(), + impl<T> ::std::fmt::Debug for __BindgenUnionField<T> { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) + -> ::std::fmt::Result { + fmt.write_str("__BindgenUnionField") + } + } + ) + .unwrap(); + + let items = vec![ + union_field_decl, union_field_impl, + union_field_default_impl, + union_field_clone_impl, + union_field_copy_impl, + union_field_debug_impl, + ]; + + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + + pub fn prepend_complex_type(ctx: &BindgenContext, + result: &mut Vec<P<ast::Item>>) { + let complex_type = quote_item!(ctx.ext_cx(), + #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] + #[repr(C)] + pub struct __BindgenComplex<T> { + pub re: T, + pub im: T + } + ) + .unwrap(); + + let items = vec![complex_type]; + let old_items = mem::replace(result, items); + result.extend(old_items.into_iter()); + } + + pub fn build_templated_path(item: &Item, + ctx: &BindgenContext, + template_args: Vec<ItemId>) + -> P<ast::Ty> { + let path = item.namespace_aware_canonical_path(ctx); + let builder = aster::AstBuilder::new().ty().path(); + + let template_args = template_args + .iter() + .map(|arg| arg.to_rust_ty(ctx)) + .collect::<Vec<_>>(); + + // XXX: I suck at aster. + if path.len() == 1 { + return builder.segment(&path[0]) + .with_tys(template_args) + .build() + .build(); + } + + let mut builder = builder.id(&path[0]); + for (i, segment) in path.iter().skip(1).enumerate() { + // Take into account the skip(1) + builder = if i == path.len() - 2 { + // XXX Extra clone courtesy of the borrow checker. + builder.segment(&segment) + .with_tys(template_args.clone()) + .build() + } else { + builder.segment(&segment).build() + } + } + + builder.build() + } + + fn primitive_ty(ctx: &BindgenContext, name: &str) -> P<ast::Ty> { + let ident = ctx.rust_ident_raw(&name); + quote_ty!(ctx.ext_cx(), $ident) + } + + pub fn type_from_named(ctx: &BindgenContext, + name: &str, + _inner: ItemId) + -> Option<P<ast::Ty>> { + // FIXME: We could use the inner item to check this is really a + // primitive type but, who the heck overrides these anyway? + Some(match name { + "int8_t" => primitive_ty(ctx, "i8"), + "uint8_t" => primitive_ty(ctx, "u8"), + "int16_t" => primitive_ty(ctx, "i16"), + "uint16_t" => primitive_ty(ctx, "u16"), + "int32_t" => primitive_ty(ctx, "i32"), + "uint32_t" => primitive_ty(ctx, "u32"), + "int64_t" => primitive_ty(ctx, "i64"), + "uint64_t" => primitive_ty(ctx, "u64"), + + "uintptr_t" | "size_t" => primitive_ty(ctx, "usize"), + + "intptr_t" | "ptrdiff_t" | "ssize_t" => primitive_ty(ctx, "isize"), + _ => return None, + }) + } + + pub fn rust_fndecl_from_signature(ctx: &BindgenContext, + sig: &Item) + -> P<ast::FnDecl> { + use codegen::ToRustTy; + + let signature = sig.kind().expect_type().canonical_type(ctx); + let signature = match *signature.kind() { + TypeKind::Function(ref sig) => sig, + _ => panic!("How?"), + }; + + let decl_ty = signature.to_rust_ty(ctx, sig); + match decl_ty.unwrap().node { + ast::TyKind::BareFn(bare_fn) => bare_fn.unwrap().decl, + _ => panic!("How did this happen exactly?"), + } + } +} diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs new file mode 100644 index 00000000..98be0540 --- /dev/null +++ b/src/ir/annotations.rs @@ -0,0 +1,188 @@ +//! Types and functions related to bindgen annotation comments. +//! +//! Users can add annotations in doc comments to types that they would like to +//! replace other types with, mark as opaque, etc. This module deals with all of +//! that stuff. + +use clang; + +/// What kind of accessor should we provide for a field? +#[derive(Copy, PartialEq, Clone, Debug)] +pub enum FieldAccessorKind { + /// No accessor. + None, + /// Plain accessor. + Regular, + /// Unsafe accessor. + Unsafe, + /// Immutable accessor. + Immutable, +} + +/// Annotations for a given item, or a field. +/// +/// You can see the kind of comments that are accepted in the Doxygen +/// documentation: +/// +/// http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html +#[derive(Clone, PartialEq, Debug)] +pub struct Annotations { + /// Whether this item is marked as opaque. Only applies to types. + opaque: bool, + /// Whether this item should be hidden from the output. Only applies to + /// types, or enum variants. + hide: bool, + /// Whether this type should be replaced by another. The name is a + /// namespace-aware path. + use_instead_of: Option<Vec<String>>, + /// Manually disable deriving copy/clone on this type. Only applies to + /// struct or union types. + disallow_copy: bool, + /// Whether fields should be marked as private or not. You can set this on + /// structs (it will apply to all the fields), or individual fields. + private_fields: Option<bool>, + /// The kind of accessor this field will have. Also can be applied to + /// structs so all the fields inside share it by default. + accessor_kind: Option<FieldAccessorKind>, + /// Whether this enum variant should be constified. + /// + /// This is controlled by the `constant` attribute, this way: + /// + /// ```cpp + /// enum Foo { + /// Bar = 0, /**< <div rustbindgen constant></div> */ + /// Baz = 0, + /// }; + /// ``` + /// + /// In that case, bindgen will generate a constant for `Bar` instead of + /// `Baz`. + constify_enum_variant: bool, +} + +fn parse_accessor(s: &str) -> FieldAccessorKind { + match s { + "false" => FieldAccessorKind::None, + "unsafe" => FieldAccessorKind::Unsafe, + "immutable" => FieldAccessorKind::Immutable, + _ => FieldAccessorKind::Regular, + } +} + +impl Default for Annotations { + fn default() -> Self { + Annotations { + opaque: false, + hide: false, + use_instead_of: None, + disallow_copy: false, + private_fields: None, + accessor_kind: None, + constify_enum_variant: false, + } + } +} + +impl Annotations { + /// Construct new annotations for the given cursor and its bindgen comments + /// (if any). + pub fn new(cursor: &clang::Cursor) -> Option<Annotations> { + let mut anno = Annotations::default(); + let mut matched_one = false; + anno.parse(&cursor.comment(), &mut matched_one); + + if matched_one { Some(anno) } else { None } + } + + /// Should this type be hidden? + pub fn hide(&self) -> bool { + self.hide + } + + /// Should this type be opaque? + pub fn opaque(&self) -> bool { + self.opaque + } + + /// For a given type, indicates the type it should replace. + /// + /// For example, in the following code: + /// + /// ```cpp + /// + /// /** <div rustbindgen replaces="Bar"></div> */ + /// struct Foo { int x; }; + /// + /// struct Bar { char foo; }; + /// ``` + /// + /// the generated code would look something like: + /// + /// ``` + /// /** <div rustbindgen replaces="Bar"></div> */ + /// struct Bar { + /// x: ::std::os::raw::c_int, + /// }; + /// ``` + /// + /// That is, code for `Foo` is used to generate `Bar`. + pub fn use_instead_of(&self) -> Option<&[String]> { + self.use_instead_of.as_ref().map(|s| &**s) + } + + /// Should we avoid implementing the `Copy` trait? + pub fn disallow_copy(&self) -> bool { + self.disallow_copy + } + + /// Should the fields be private? + pub fn private_fields(&self) -> Option<bool> { + self.private_fields + } + + /// What kind of accessors should we provide for this type's fields? + pub fn accessor_kind(&self) -> Option<FieldAccessorKind> { + self.accessor_kind + } + + fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) { + use clang_sys::CXComment_HTMLStartTag; + if comment.kind() == CXComment_HTMLStartTag && + comment.get_tag_name() == "div" && + comment.get_tag_attrs() + .next() + .map_or(false, |attr| attr.name == "rustbindgen") { + *matched = true; + for attr in comment.get_tag_attrs() { + match attr.name.as_str() { + "opaque" => self.opaque = true, + "hide" => self.hide = true, + "nocopy" => self.disallow_copy = true, + "replaces" => { + self.use_instead_of = Some(attr.value + .split("::") + .map(Into::into) + .collect()) + } + "private" => { + self.private_fields = Some(attr.value != "false") + } + "accessor" => { + self.accessor_kind = Some(parse_accessor(&attr.value)) + } + "constant" => self.constify_enum_variant = true, + _ => {} + } + } + } + + for child in comment.get_children() { + self.parse(&child, matched); + } + } + + /// Returns whether we've parsed a "constant" attribute. + pub fn constify_enum_variant(&self) -> bool { + self.constify_enum_variant + } +} diff --git a/src/ir/comp.rs b/src/ir/comp.rs new file mode 100644 index 00000000..968bf879 --- /dev/null +++ b/src/ir/comp.rs @@ -0,0 +1,962 @@ +//! Compound types (unions and structs) in our intermediate representation. + +use clang; +use parse::{ClangItemParser, ParseError}; +use std::cell::Cell; +use super::annotations::Annotations; +use super::context::{BindgenContext, ItemId}; +use super::derive::{CanDeriveCopy, CanDeriveDebug}; +use super::item::Item; +use super::layout::Layout; +use super::ty::Type; +use super::type_collector::{ItemSet, TypeCollector}; + +/// The kind of compound type. +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum CompKind { + /// A struct. + Struct, + /// A union. + Union, +} + +/// The kind of C++ method. +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum MethodKind { + /// A constructor. We represent it as method for convenience, to avoid code + /// duplication. + Constructor, + /// A static method. + Static, + /// A normal method. + Normal, + /// A virtual method. + Virtual, +} + +/// A struct representing a C++ method, either static, normal, or virtual. +#[derive(Debug)] +pub struct Method { + kind: MethodKind, + /// The signature of the method. Take into account this is not a `Type` + /// item, but a `Function` one. + /// + /// This is tricky and probably this field should be renamed. + signature: ItemId, + is_const: bool, +} + +impl Method { + /// Construct a new `Method`. + pub fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self { + Method { + kind: kind, + signature: signature, + is_const: is_const, + } + } + + /// What kind of method is this? + pub fn kind(&self) -> MethodKind { + self.kind + } + + /// Is this a constructor? + pub fn is_constructor(&self) -> bool { + self.kind == MethodKind::Constructor + } + + /// Is this a virtual method? + pub fn is_virtual(&self) -> bool { + self.kind == MethodKind::Virtual + } + + /// Is this a static method? + pub fn is_static(&self) -> bool { + self.kind == MethodKind::Static + } + + /// Get the `ItemId` for the `Function` signature for this method. + pub fn signature(&self) -> ItemId { + self.signature + } + + /// Is this a const qualified method? + pub fn is_const(&self) -> bool { + self.is_const + } +} + +/// A struct representing a C++ field. +#[derive(Clone, Debug)] +pub struct Field { + /// The name of the field, empty if it's an unnamed bitfield width. + name: Option<String>, + /// The inner type. + ty: ItemId, + /// The doc comment on the field if any. + comment: Option<String>, + /// Annotations for this field, or the default. + annotations: Annotations, + /// If this field is a bitfield, and how many bits does it contain if it is. + bitfield: Option<u32>, + /// If the C++ field is marked as `mutable` + mutable: bool, +} + +impl Field { + /// Construct a new `Field`. + pub fn new(name: Option<String>, + ty: ItemId, + comment: Option<String>, + annotations: Option<Annotations>, + bitfield: Option<u32>, + mutable: bool) + -> Field { + Field { + name: name, + ty: ty, + comment: comment, + annotations: annotations.unwrap_or_default(), + bitfield: bitfield, + mutable: mutable, + } + } + + /// Get the name of this field. + pub fn name(&self) -> Option<&str> { + self.name.as_ref().map(|n| &**n) + } + + /// Get the type of this field. + pub fn ty(&self) -> ItemId { + self.ty + } + + /// Get the comment for this field. + pub fn comment(&self) -> Option<&str> { + self.comment.as_ref().map(|c| &**c) + } + + /// If this is a bitfield, how many bits does it need? + pub fn bitfield(&self) -> Option<u32> { + self.bitfield + } + + /// Is this field marked as `mutable`? + pub fn is_mutable(&self) -> bool { + self.mutable + } + + /// Get the annotations for this field. + pub fn annotations(&self) -> &Annotations { + &self.annotations + } +} + +impl CanDeriveDebug for Field { + type Extra = (); + + fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool { + self.ty.can_derive_debug(ctx, ()) + } +} + +impl<'a> CanDeriveCopy<'a> for Field { + type Extra = (); + + fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool { + self.ty.can_derive_copy(ctx, ()) + } + + fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool { + self.ty.can_derive_copy_in_array(ctx, ()) + } +} + + +/// The kind of inheritance a base class is using. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum BaseKind { + /// Normal inheritance, like: + /// + /// ```cpp + /// class A : public B {}; + /// ``` + Normal, + /// Virtual inheritance, like: + /// + /// ```cpp + /// class A: public virtual B {}; + /// ``` + Virtual, +} + +/// A base class. +#[derive(Clone, Debug)] +pub struct Base { + /// The type of this base class. + pub ty: ItemId, + /// The kind of inheritance we're doing. + pub kind: BaseKind, +} + +impl Base { + /// Whether this base class is inheriting virtually. + pub fn is_virtual(&self) -> bool { + self.kind == BaseKind::Virtual + } +} + +/// A compound type. +/// +/// Either a struct or union, a compound type is built up from the combination +/// of fields which also are associated with their own (potentially compound) +/// type. +#[derive(Debug)] +pub struct CompInfo { + /// Whether this is a struct or a union. + kind: CompKind, + + /// The members of this struct or union. + fields: Vec<Field>, + + /// The template parameters of this class. These are non-concrete, and + /// should always be a Type(TypeKind::Named(name)), but still they need to + /// be registered with an unique type id in the context. + template_args: Vec<ItemId>, + + /// The method declarations inside this class, if in C++ mode. + methods: Vec<Method>, + + /// The different constructors this struct or class contains. + constructors: Vec<ItemId>, + + /// Vector of classes this one inherits from. + base_members: Vec<Base>, + + /// The parent reference template if any. + ref_template: Option<ItemId>, + + /// The inner types that were declared inside this class, in something like: + /// + /// class Foo { + /// typedef int FooTy; + /// struct Bar { + /// int baz; + /// }; + /// } + /// + /// static Foo::Bar const = {3}; + inner_types: Vec<ItemId>, + + /// Set of static constants declared inside this class. + inner_vars: Vec<ItemId>, + + /// Whether this type should generate an vtable (TODO: Should be able to + /// look at the virtual methods and ditch this field). + has_vtable: bool, + + /// Whether this type has destructor. + has_destructor: bool, + + /// Whether this type has a base type with more than one member. + /// + /// TODO: We should be able to compute this. + has_nonempty_base: bool, + + /// If this type has a template parameter which is not a type (e.g.: a + /// size_t) + has_non_type_template_params: bool, + + /// Whether this struct layout is packed. + packed: bool, + + /// Whether this struct is anonymous. + is_anonymous: bool, + + /// Used to know if we've found an opaque attribute that could cause us to + /// generate a type with invalid layout. This is explicitly used to avoid us + /// generating bad alignments when parsing types like max_align_t. + /// + /// It's not clear what the behavior should be here, if generating the item + /// and pray, or behave as an opaque type. + found_unknown_attr: bool, + + /// Used to detect if we've run in a can_derive_debug cycle while cycling + /// around the template arguments. + detect_derive_debug_cycle: Cell<bool>, + + /// Used to detect if we've run in a has_destructor cycle while cycling + /// around the template arguments. + detect_has_destructor_cycle: Cell<bool>, +} + +impl CompInfo { + /// Construct a new compound type. + pub fn new(kind: CompKind) -> Self { + CompInfo { + kind: kind, + fields: vec![], + template_args: vec![], + methods: vec![], + constructors: vec![], + base_members: vec![], + ref_template: None, + inner_types: vec![], + inner_vars: vec![], + has_vtable: false, + has_destructor: false, + has_nonempty_base: false, + has_non_type_template_params: false, + packed: false, + is_anonymous: false, + found_unknown_attr: false, + detect_derive_debug_cycle: Cell::new(false), + detect_has_destructor_cycle: Cell::new(false), + } + } + + /// Is this compound type unsized? + pub fn is_unsized(&self, ctx: &BindgenContext) -> bool { + !self.has_vtable(ctx) && self.fields.is_empty() && + self.base_members.iter().all(|base| { + ctx.resolve_type(base.ty).canonical_type(ctx).is_unsized(ctx) + }) && + self.ref_template + .map_or(true, |template| ctx.resolve_type(template).is_unsized(ctx)) + } + + /// Does this compound type have a destructor? + pub fn has_destructor(&self, ctx: &BindgenContext) -> bool { + if self.detect_has_destructor_cycle.get() { + warn!("Cycle detected looking for destructors"); + // Assume no destructor, since we don't have an explicit one. + return false; + } + + self.detect_has_destructor_cycle.set(true); + + let has_destructor = self.has_destructor || + match self.kind { + CompKind::Union => false, + CompKind::Struct => { + // NB: We can't rely on a type with type parameters + // not having destructor. + // + // This is unfortunate, but... + self.ref_template.as_ref().map_or(false, |t| { + ctx.resolve_type(*t).has_destructor(ctx) + }) || + self.template_args.iter().any(|t| { + ctx.resolve_type(*t).has_destructor(ctx) + }) || + self.base_members.iter().any(|base| { + ctx.resolve_type(base.ty).has_destructor(ctx) + }) || + self.fields.iter().any(|field| { + ctx.resolve_type(field.ty) + .has_destructor(ctx) + }) + } + }; + + self.detect_has_destructor_cycle.set(false); + + has_destructor + } + + /// Is this type a template specialization? + pub fn is_template_specialization(&self) -> bool { + self.ref_template.is_some() + } + + /// Get the template declaration this specialization is specializing. + pub fn specialized_template(&self) -> Option<ItemId> { + self.ref_template + } + + /// Compute the layout of this type. + /// + /// This is called as a fallback under some circumstances where LLVM doesn't + /// give us the correct layout. + /// + /// If we're a union without known layout, we try to compute it from our + /// members. This is not ideal, but clang fails to report the size for these + /// kind of unions, see test/headers/template_union.hpp + pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> { + use std::cmp; + + // We can't do better than clang here, sorry. + if self.kind == CompKind::Struct { + return None; + } + + let mut max_size = 0; + let mut max_align = 0; + for field in &self.fields { + let field_layout = ctx.resolve_type(field.ty) + .layout(ctx); + + if let Some(layout) = field_layout { + max_size = cmp::max(max_size, layout.size); + max_align = cmp::max(max_align, layout.align); + } + } + + Some(Layout::new(max_size, max_align)) + } + + /// Get this type's set of fields. + pub fn fields(&self) -> &[Field] { + &self.fields + } + + /// Get this type's set of free template arguments. Empty if this is not a + /// template. + pub fn template_args(&self) -> &[ItemId] { + &self.template_args + } + + /// Does this type have any template parameters that aren't types + /// (e.g. int)? + pub fn has_non_type_template_params(&self) -> bool { + self.has_non_type_template_params + } + + /// Does this type have a virtual table? + pub fn has_vtable(&self, ctx: &BindgenContext) -> bool { + self.has_vtable || + self.base_members().iter().any(|base| { + ctx.resolve_type(base.ty) + .has_vtable(ctx) + }) || + self.ref_template.map_or(false, |template| { + ctx.resolve_type(template).has_vtable(ctx) + }) + } + + /// Get this type's set of methods. + pub fn methods(&self) -> &[Method] { + &self.methods + } + + /// Get this type's set of constructors. + pub fn constructors(&self) -> &[ItemId] { + &self.constructors + } + + /// What kind of compound type is this? + pub fn kind(&self) -> CompKind { + self.kind + } + + /// The set of types that this one inherits from. + pub fn base_members(&self) -> &[Base] { + &self.base_members + } + + /// Construct a new compound type from a Clang type. + pub fn from_ty(potential_id: ItemId, + ty: &clang::Type, + location: Option<clang::Cursor>, + ctx: &mut BindgenContext) + -> Result<Self, ParseError> { + use clang_sys::*; + // Sigh... For class templates we want the location, for + // specialisations, we want the declaration... So just try both. + // + // TODO: Yeah, this code reads really bad. + let mut cursor = ty.declaration(); + let mut kind = Self::kind_from_cursor(&cursor); + if kind.is_err() { + if let Some(location) = location { + kind = Self::kind_from_cursor(&location); + cursor = location; + } + } + + let kind = try!(kind); + + debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor); + + let mut ci = CompInfo::new(kind); + ci.is_anonymous = cursor.is_anonymous(); + ci.template_args = match ty.template_args() { + // In forward declarations and not specializations, + // etc, they are in + // the ast, we'll meet them in + // CXCursor_TemplateTypeParameter + None => vec![], + Some(arg_types) => { + let num_arg_types = arg_types.len(); + let mut specialization = true; + + let args = arg_types.filter(|t| t.kind() != CXType_Invalid) + .filter_map(|t| { + if t.spelling().starts_with("type-parameter") { + specialization = false; + None + } else { + Some(Item::from_ty_or_ref(t, None, None, ctx)) + } + }) + .collect::<Vec<_>>(); + + if specialization && args.len() != num_arg_types { + ci.has_non_type_template_params = true; + warn!("warning: Template parameter is not a type"); + } + + if specialization { args } else { vec![] } + } + }; + + ci.ref_template = cursor.specialized() + .and_then(|c| Item::parse(c, None, ctx).ok()); + + let mut maybe_anonymous_struct_field = None; + cursor.visit(|cur| { + if cur.kind() != CXCursor_FieldDecl { + if let Some((ty, _)) = maybe_anonymous_struct_field { + let field = Field::new(None, ty, None, None, None, false); + ci.fields.push(field); + } + maybe_anonymous_struct_field = None; + } + + match cur.kind() { + CXCursor_FieldDecl => { + match maybe_anonymous_struct_field.take() { + Some((ty, clang_ty)) => { + let mut used = false; + cur.visit(|child| { + if child.cur_type() == clang_ty { + used = true; + } + CXChildVisit_Continue + }); + if !used { + let field = Field::new(None, + ty, + None, + None, + None, + false); + ci.fields.push(field); + } + } + None => {} + } + + let bit_width = cur.bit_width(); + let field_type = Item::from_ty_or_ref(cur.cur_type(), + Some(cur), + Some(potential_id), + ctx); + + let comment = cur.raw_comment(); + let annotations = Annotations::new(&cur); + let name = cur.spelling(); + let is_mutable = cursor.is_mutable_field(); + + // Name can be empty if there are bitfields, for example, + // see tests/headers/struct_with_bitfields.h + assert!(!name.is_empty() || bit_width.is_some(), + "Empty field name?"); + + let name = if name.is_empty() { None } else { Some(name) }; + + let field = Field::new(name, + field_type, + comment, + annotations, + bit_width, + is_mutable); + ci.fields.push(field); + + // No we look for things like attributes and stuff. + cur.visit(|cur| { + if cur.kind() == CXCursor_UnexposedAttr { + ci.found_unknown_attr = true; + } + CXChildVisit_Continue + }); + + } + CXCursor_UnexposedAttr => { + ci.found_unknown_attr = true; + } + CXCursor_EnumDecl | + CXCursor_TypeAliasDecl | + CXCursor_TypedefDecl | + CXCursor_StructDecl | + CXCursor_UnionDecl | + CXCursor_ClassTemplate | + CXCursor_ClassDecl => { + let inner = Item::parse(cur, Some(potential_id), ctx) + .expect("Inner ClassDecl"); + if !ci.inner_types.contains(&inner) { + ci.inner_types.push(inner); + } + // A declaration of an union or a struct without name could + // also be an unnamed field, unfortunately. + if cur.spelling().is_empty() && + cur.kind() != CXCursor_EnumDecl { + let ty = cur.cur_type(); + maybe_anonymous_struct_field = Some((inner, ty)); + } + } + CXCursor_PackedAttr => { + ci.packed = true; + } + CXCursor_TemplateTypeParameter => { + // Yes! You can arrive here with an empty template parameter + // name! Awesome, isn't it? + // + // see tests/headers/empty_template_param_name.hpp + if cur.spelling().is_empty() { + return CXChildVisit_Continue; + } + + let param = + Item::named_type(cur.spelling(), potential_id, ctx); + ci.template_args.push(param); + } + CXCursor_CXXBaseSpecifier => { + let is_virtual_base = cur.is_virtual_base(); + ci.has_vtable |= is_virtual_base; + + let kind = if is_virtual_base { + BaseKind::Virtual + } else { + BaseKind::Normal + }; + + let type_id = Item::from_ty_or_ref(cur.cur_type(), + Some(cur), + None, + ctx); + ci.base_members.push(Base { + ty: type_id, + kind: kind, + }); + } + CXCursor_Constructor | + CXCursor_Destructor | + CXCursor_CXXMethod => { + let is_virtual = cur.method_is_virtual(); + let is_static = cur.method_is_static(); + debug_assert!(!(is_static && is_virtual), "How?"); + + ci.has_destructor |= cur.kind() == CXCursor_Destructor; + ci.has_vtable |= is_virtual; + + // This used to not be here, but then I tried generating + // stylo bindings with this (without path filters), and + // cried a lot with a method in gfx/Point.h + // (ToUnknownPoint), that somehow was causing the same type + // to be inserted in the map two times. + // + // I couldn't make a reduced test case, but anyway... + // Methods of template functions not only use to be inlined, + // but also instantiated, and we wouldn't be able to call + // them, so just bail out. + if !ci.template_args.is_empty() { + return CXChildVisit_Continue; + } + + // NB: This gets us an owned `Function`, not a + // `FunctionSig`. + let signature = match Item::parse(cur, Some(potential_id), ctx) { + Ok(item) if ctx.resolve_item(item).kind().is_function() => item, + _ => return CXChildVisit_Continue, + }; + + match cur.kind() { + CXCursor_Constructor => { + ci.constructors.push(signature); + } + // TODO(emilio): Bind the destructor? + CXCursor_Destructor => {} + CXCursor_CXXMethod => { + let is_const = cur.method_is_const(); + let method_kind = if is_static { + MethodKind::Static + } else if is_virtual { + MethodKind::Virtual + } else { + MethodKind::Normal + }; + + let method = + Method::new(method_kind, signature, is_const); + + ci.methods.push(method); + } + _ => unreachable!("How can we see this here?"), + } + } + CXCursor_NonTypeTemplateParameter => { + ci.has_non_type_template_params = true; + } + CXCursor_VarDecl => { + let linkage = cur.linkage(); + if linkage != CXLinkage_External && + linkage != CXLinkage_UniqueExternal { + return CXChildVisit_Continue; + } + + let visibility = cur.visibility(); + if visibility != CXVisibility_Default { + return CXChildVisit_Continue; + } + + if let Ok(item) = Item::parse(cur, + Some(potential_id), + ctx) { + ci.inner_vars.push(item); + } + } + // Intentionally not handled + CXCursor_CXXAccessSpecifier | + CXCursor_CXXFinalAttr | + CXCursor_FunctionTemplate | + CXCursor_ConversionFunction => {} + _ => { + warn!("unhandled comp member `{}` (kind {:?}) in `{}` ({})", + cur.spelling(), + cur.kind(), + cursor.spelling(), + cur.location()); + } + } + CXChildVisit_Continue + }); + + if let Some((ty, _)) = maybe_anonymous_struct_field { + let field = Field::new(None, ty, None, None, None, false); + ci.fields.push(field); + } + + Ok(ci) + } + + fn kind_from_cursor(cursor: &clang::Cursor) + -> Result<CompKind, ParseError> { + use clang_sys::*; + Ok(match cursor.kind() { + CXCursor_UnionDecl => CompKind::Union, + CXCursor_ClassDecl | + CXCursor_StructDecl => CompKind::Struct, + CXCursor_CXXBaseSpecifier | + CXCursor_ClassTemplatePartialSpecialization | + CXCursor_ClassTemplate => { + match cursor.template_kind() { + CXCursor_UnionDecl => CompKind::Union, + _ => CompKind::Struct, + } + } + _ => { + warn!("Unknown kind for comp type: {:?}", cursor); + return Err(ParseError::Continue); + } + }) + } + + /// Do any of the types that participate in this type's "signature" use the + /// named type `ty`? + /// + /// See also documentation for `ir::Item::signature_contains_named_type`. + pub fn signature_contains_named_type(&self, + ctx: &BindgenContext, + ty: &Type) + -> bool { + // We don't generate these, so rather don't make the codegen step to + // think we got it covered. + if self.has_non_type_template_params() { + return false; + } + self.template_args.iter().any(|arg| { + ctx.resolve_type(*arg) + .signature_contains_named_type(ctx, ty) + }) + } + + /// Get the set of types that were declared within this compound type + /// (e.g. nested class definitions). + pub fn inner_types(&self) -> &[ItemId] { + &self.inner_types + } + + /// Get the set of static variables declared within this compound type. + pub fn inner_vars(&self) -> &[ItemId] { + &self.inner_vars + } + + /// Have we found a field with an opaque type that could potentially mess up + /// the layout of this compound type? + pub fn found_unknown_attr(&self) -> bool { + self.found_unknown_attr + } + + /// Is this compound type packed? + pub fn packed(&self) -> bool { + self.packed + } + + /// Returns whether this type needs an explicit vtable because it has + /// virtual methods and none of its base classes has already a vtable. + pub fn needs_explicit_vtable(&self, ctx: &BindgenContext) -> bool { + self.has_vtable(ctx) && + !self.base_members.iter().any(|base| { + // NB: Ideally, we could rely in all these types being `comp`, and + // life would be beautiful. + // + // Unfortunately, given the way we implement --match-pat, and also + // that you can inherit from templated types, we need to handle + // other cases here too. + ctx.resolve_type(base.ty) + .canonical_type(ctx) + .as_comp() + .map_or(false, |ci| ci.has_vtable(ctx)) + }) + } +} + +impl CanDeriveDebug for CompInfo { + type Extra = Option<Layout>; + + fn can_derive_debug(&self, + ctx: &BindgenContext, + layout: Option<Layout>) + -> bool { + if self.has_non_type_template_params() { + return layout.map_or(false, |l| l.opaque().can_derive_debug(ctx, ())); + } + + // We can reach here recursively via template parameters of a member, + // for example. + if self.detect_derive_debug_cycle.get() { + warn!("Derive debug cycle detected!"); + return true; + } + + if self.kind == CompKind::Union { + if ctx.options().unstable_rust { + return false; + } + + return layout.unwrap_or_else(Layout::zero) + .opaque() + .can_derive_debug(ctx, ()); + } + + self.detect_derive_debug_cycle.set(true); + + let can_derive_debug = { + self.base_members + .iter() + .all(|base| base.ty.can_derive_debug(ctx, ())) && + self.template_args + .iter() + .all(|id| id.can_derive_debug(ctx, ())) && + self.fields + .iter() + .all(|f| f.can_derive_debug(ctx, ())) && + self.ref_template.map_or(true, |id| id.can_derive_debug(ctx, ())) + }; + + self.detect_derive_debug_cycle.set(false); + + can_derive_debug + } +} + +impl<'a> CanDeriveCopy<'a> for CompInfo { + type Extra = (&'a Item, Option<Layout>); + + fn can_derive_copy(&self, + ctx: &BindgenContext, + (item, layout): (&Item, Option<Layout>)) + -> bool { + if self.has_non_type_template_params() { + return layout.map_or(false, |l| l.opaque().can_derive_copy(ctx, ())); + } + + // NOTE: Take into account that while unions in C and C++ are copied by + // default, the may have an explicit destructor in C++, so we can't + // defer this check just for the union case. + if self.has_destructor(ctx) { + return false; + } + + if self.kind == CompKind::Union { + if !ctx.options().unstable_rust { + // NOTE: If there's no template parameters we can derive copy + // unconditionally, since arrays are magical for rustc, and + // __BindgenUnionField always implements copy. + return true; + } + + // https://github.com/rust-lang/rust/issues/36640 + if !self.template_args.is_empty() || self.ref_template.is_some() || + !item.applicable_template_args(ctx).is_empty() { + return false; + } + } + + // With template args, use a safe subset of the types, + // since copyability depends on the types itself. + self.ref_template + .as_ref() + .map_or(true, |t| t.can_derive_copy(ctx, ())) && + self.base_members + .iter() + .all(|base| base.ty.can_derive_copy(ctx, ())) && + self.fields.iter().all(|field| field.can_derive_copy(ctx, ())) + } + + fn can_derive_copy_in_array(&self, + ctx: &BindgenContext, + extra: (&Item, Option<Layout>)) + -> bool { + self.can_derive_copy(ctx, extra) + } +} + +impl TypeCollector for CompInfo { + type Extra = Item; + + fn collect_types(&self, + context: &BindgenContext, + types: &mut ItemSet, + item: &Item) { + if let Some(template) = self.specialized_template() { + types.insert(template); + } + + let applicable_template_args = item.applicable_template_args(context); + for arg in applicable_template_args { + types.insert(arg); + } + + for base in self.base_members() { + types.insert(base.ty); + } + + for field in self.fields() { + types.insert(field.ty()); + } + + for &ty in self.inner_types() { + types.insert(ty); + } + + for &var in self.inner_vars() { + types.insert(var); + } + + // FIXME(emilio): Methods, VTable? + } +} 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(¤t) + .expect("We know we found this item id, so it must have a \ + predecessor"); + if predecessor == current { + break; + } + path.push(predecessor); + current = predecessor; + } + path.reverse(); + panic!("Found reference to dangling id = {:?}\nvia path = {:?}", + id, + path); + } + + for sub_id in sub_types { + if self.seen.insert(sub_id, id).is_none() { + // We've never visited this sub item before. + self.to_iterate.push_back(sub_id); + } + } + + Some(id) + } +} diff --git a/src/ir/derive.rs b/src/ir/derive.rs new file mode 100644 index 00000000..d13a8117 --- /dev/null +++ b/src/ir/derive.rs @@ -0,0 +1,67 @@ +//! Traits for determining whether we can derive traits for a thing or not. + +use super::context::BindgenContext; + +/// A trait that encapsulates the logic for whether or not we can derive `Debug` +/// for a given thing. +/// +/// This should ideally be a no-op that just returns `true`, but instead needs +/// to be a recursive method that checks whether all the proper members can +/// derive debug or not, because of the limit rust has on 32 items as max in the +/// array. +pub trait CanDeriveDebug { + /// Implementations can define this type to get access to any extra + /// information required to determine whether they can derive `Debug`. If + /// extra information is unneeded, then this should simply be the unit type. + type Extra; + + /// Return `true` if `Debug` can be derived for this thing, `false` + /// otherwise. + fn can_derive_debug(&self, + ctx: &BindgenContext, + extra: Self::Extra) + -> bool; +} + +/// A trait that encapsulates the logic for whether or not we can derive `Copy` +/// for a given thing. +pub trait CanDeriveCopy<'a> { + /// Implementations can define this type to get access to any extra + /// information required to determine whether they can derive `Copy`. If + /// extra information is unneeded, then this should simply be the unit type. + type Extra; + + /// Return `true` if `Copy` can be derived for this thing, `false` + /// otherwise. + fn can_derive_copy(&'a self, + ctx: &'a BindgenContext, + extra: Self::Extra) + -> bool; + + /// For some reason, deriving copies of an array of a type that is not known + /// to be `Copy` is a compile error. e.g.: + /// + /// ```rust + /// #[derive(Copy, Clone)] + /// struct A<T> { + /// member: T, + /// } + /// ``` + /// + /// is fine, while: + /// + /// ```rust,ignore + /// #[derive(Copy, Clone)] + /// struct A<T> { + /// member: [T; 1], + /// } + /// ``` + /// + /// is an error. + /// + /// That's the whole point of the existence of `can_derive_copy_in_array`. + fn can_derive_copy_in_array(&'a self, + ctx: &'a BindgenContext, + extra: Self::Extra) + -> bool; +} diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs new file mode 100644 index 00000000..ca4e77db --- /dev/null +++ b/src/ir/enum_ty.rs @@ -0,0 +1,183 @@ +//! Intermediate representation for C/C++ enumerations. + +use clang; +use ir::annotations::Annotations; +use parse::{ClangItemParser, ParseError}; +use super::context::{BindgenContext, ItemId}; +use super::item::Item; +use super::ty::TypeKind; + +/// An enum representing custom handling that can be given to a variant. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum EnumVariantCustomBehavior { + /// This variant will be constified, that is, forced to generate a constant. + Constify, + /// This variant will be hidden entirely from the resulting enum. + Hide, +} + +/// A C/C++ enumeration. +#[derive(Debug)] +pub struct Enum { + /// The representation used for this enum; it should be an `IntKind` type or + /// an alias to one. + /// + /// It's `None` if the enum is a forward declaration and isn't defined + /// anywhere else, see `tests/headers/func_ptr_in_struct.h`. + repr: Option<ItemId>, + + /// The different variants, with explicit values. + variants: Vec<EnumVariant>, +} + +impl Enum { + /// Construct a new `Enum` with the given representation and variants. + pub fn new(repr: Option<ItemId>, variants: Vec<EnumVariant>) -> Self { + Enum { + repr: repr, + variants: variants, + } + } + + /// Get this enumeration's representation. + pub fn repr(&self) -> Option<ItemId> { + self.repr + } + + /// Get this enumeration's variants. + pub fn variants(&self) -> &[EnumVariant] { + &self.variants + } + + /// Construct an enumeration from the given Clang type. + pub fn from_ty(ty: &clang::Type, + ctx: &mut BindgenContext) + -> Result<Self, ParseError> { + use clang_sys::*; + if ty.kind() != CXType_Enum { + return Err(ParseError::Continue); + } + + let declaration = ty.declaration().canonical(); + let repr = declaration.enum_type() + .and_then(|et| Item::from_ty(&et, None, None, ctx).ok()); + let mut variants = vec![]; + + // Assume signedness since the default type by the C standard is an int. + let is_signed = + repr.and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx)) + .map_or(true, |ty| { + match *ty.kind() { + TypeKind::Int(ref int_kind) => int_kind.is_signed(), + ref other => { + panic!("Since when enums can be non-integers? {:?}", + other) + } + } + }); + + let type_name = ty.spelling(); + let type_name = if type_name.is_empty() { None } else { Some(type_name) }; + let type_name = type_name.as_ref().map(String::as_str); + + declaration.visit(|cursor| { + if cursor.kind() == CXCursor_EnumConstantDecl { + let value = if is_signed { + cursor.enum_val_signed().map(EnumVariantValue::Signed) + } else { + cursor.enum_val_unsigned().map(EnumVariantValue::Unsigned) + }; + if let Some(val) = value { + let name = cursor.spelling(); + let custom_behavior = ctx.type_chooser() + .and_then(|t| { + t.enum_variant_behavior(type_name, &name, val) + }) + .or_else(|| { + Annotations::new(&cursor).and_then(|anno| { + if anno.hide() { + Some(EnumVariantCustomBehavior::Hide) + } else if anno.constify_enum_variant() { + Some(EnumVariantCustomBehavior::Constify) + } else { + None + } + }) + }); + + let comment = cursor.raw_comment(); + variants.push( + EnumVariant::new(name, comment, val, custom_behavior)); + } + } + CXChildVisit_Continue + }); + Ok(Enum::new(repr, variants)) + } +} + +/// A single enum variant, to be contained only in an enum. +#[derive(Debug)] +pub struct EnumVariant { + /// The name of the variant. + name: String, + + /// An optional doc comment. + comment: Option<String>, + + /// The integer value of the variant. + val: EnumVariantValue, + + /// The custom behavior this variant may have, if any. + custom_behavior: Option<EnumVariantCustomBehavior>, +} + +/// A constant value assigned to an enumeration variant. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum EnumVariantValue { + /// A signed constant. + Signed(i64), + + /// An unsigned constant. + Unsigned(u64), +} + +impl EnumVariant { + /// Construct a new enumeration variant from the given parts. + pub fn new(name: String, + comment: Option<String>, + val: EnumVariantValue, + custom_behavior: Option<EnumVariantCustomBehavior>) + -> Self { + EnumVariant { + name: name, + comment: comment, + val: val, + custom_behavior: custom_behavior, + } + } + + /// Get this variant's name. + pub fn name(&self) -> &str { + &self.name + } + + /// Get this variant's value. + pub fn val(&self) -> EnumVariantValue { + self.val + } + + /// Returns whether this variant should be enforced to be a constant by code + /// generation. + pub fn force_constification(&self) -> bool { + self.custom_behavior + .map_or(false, |b| b == EnumVariantCustomBehavior::Constify) + } + + /// Returns whether the current variant should be hidden completely from the + /// resulting rust enum. + pub fn hidden(&self) -> bool { + self.custom_behavior + .map_or(false, |b| b == EnumVariantCustomBehavior::Hide) + } +} diff --git a/src/ir/function.rs b/src/ir/function.rs new file mode 100644 index 00000000..50c442db --- /dev/null +++ b/src/ir/function.rs @@ -0,0 +1,318 @@ +//! Intermediate representation for C/C++ functions and methods. + +use clang; +use clang_sys::CXCallingConv; +use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; +use super::context::{BindgenContext, ItemId}; +use super::item::Item; +use super::ty::TypeKind; +use super::type_collector::{ItemSet, TypeCollector}; +use syntax::abi; + +/// A function declaration, with a signature, arguments, and argument names. +/// +/// The argument names vector must be the same length as the ones in the +/// signature. +#[derive(Debug)] +pub struct Function { + /// The name of this function. + name: String, + + /// The mangled name, that is, the symbol. + mangled_name: Option<String>, + + /// The id pointing to the current function signature. + signature: ItemId, + + /// The doc comment on the function, if any. + comment: Option<String>, +} + +impl Function { + /// Construct a new function. + pub fn new(name: String, + mangled_name: Option<String>, + sig: ItemId, + comment: Option<String>) + -> Self { + Function { + name: name, + mangled_name: mangled_name, + signature: sig, + comment: comment, + } + } + + /// Get this function's name. + pub fn name(&self) -> &str { + &self.name + } + + /// Get this function's name. + pub fn mangled_name(&self) -> Option<&str> { + self.mangled_name.as_ref().map(|n| &**n) + } + + /// Get this function's signature. + pub fn signature(&self) -> ItemId { + self.signature + } +} + +/// A function signature. +#[derive(Debug)] +pub struct FunctionSig { + /// The return type of the function. + return_type: ItemId, + + /// The type of the arguments, optionally with the name of the argument when + /// declared. + argument_types: Vec<(Option<String>, ItemId)>, + + /// Whether this function is variadic. + is_variadic: bool, + + /// The ABI of this function. + abi: abi::Abi, +} + +fn get_abi(cc: CXCallingConv) -> abi::Abi { + use clang_sys::*; + match cc { + CXCallingConv_Default => abi::Abi::C, + CXCallingConv_C => abi::Abi::C, + CXCallingConv_X86StdCall => abi::Abi::Stdcall, + CXCallingConv_X86FastCall => abi::Abi::Fastcall, + CXCallingConv_AAPCS => abi::Abi::Aapcs, + CXCallingConv_X86_64Win64 => abi::Abi::Win64, + other => panic!("unsupported calling convention: {:?}", other), + } +} + +/// Get the mangled name for the cursor's referent. +pub fn cursor_mangling(cursor: &clang::Cursor) -> Option<String> { + // We early return here because libclang may crash in some case + // if we pass in a variable inside a partial specialized template. + // See servo/rust-bindgen#67. + if cursor.is_in_non_fully_specialized_template() { + return None; + } + + let mut mangling = cursor.mangling(); + if mangling.is_empty() { + return None; + } + + // Try to undo backend linkage munging (prepended _, generally) + if cfg!(target_os = "macos") { + mangling.remove(0); + } + + Some(mangling) +} + +impl FunctionSig { + /// Construct a new function signature. + pub fn new(return_type: ItemId, + arguments: Vec<(Option<String>, ItemId)>, + is_variadic: bool, + abi: abi::Abi) + -> Self { + FunctionSig { + return_type: return_type, + argument_types: arguments, + is_variadic: is_variadic, + abi: abi, + } + } + + /// Construct a new function signature from the given Clang type. + pub fn from_ty(ty: &clang::Type, + cursor: &clang::Cursor, + ctx: &mut BindgenContext) + -> Result<Self, ParseError> { + use clang_sys::*; + debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor); + + // Skip function templates + if cursor.kind() == CXCursor_FunctionTemplate { + return Err(ParseError::Continue); + } + + // Don't parse operatorxx functions in C++ + let spelling = cursor.spelling(); + if spelling.starts_with("operator") { + return Err(ParseError::Continue); + } + + let cursor = if cursor.is_valid() { + *cursor + } else { + ty.declaration() + }; + + let mut args: Vec<_> = match cursor.kind() { + CXCursor_FunctionDecl | + CXCursor_Constructor | + CXCursor_CXXMethod => { + // For CXCursor_FunctionDecl, cursor.args() is the reliable way + // to get parameter names and types. + cursor.args() + .unwrap() + .iter() + .map(|arg| { + let arg_ty = arg.cur_type(); + let name = arg.spelling(); + let name = + if name.is_empty() { None } else { Some(name) }; + let ty = Item::from_ty(&arg_ty, Some(*arg), None, ctx) + .expect("Argument?"); + (name, ty) + }) + .collect() + } + _ => { + // For non-CXCursor_FunctionDecl, visiting the cursor's children + // is the only reliable way to get parameter names. + let mut args = vec![]; + cursor.visit(|c| { + if c.kind() == CXCursor_ParmDecl { + let ty = + Item::from_ty(&c.cur_type(), Some(c), None, ctx) + .expect("ParmDecl?"); + let name = c.spelling(); + let name = + if name.is_empty() { None } else { Some(name) }; + args.push((name, ty)); + } + CXChildVisit_Continue + }); + args + } + }; + + let is_method = cursor.kind() == CXCursor_CXXMethod; + let is_constructor = cursor.kind() == CXCursor_Constructor; + if (is_constructor || is_method) && + cursor.lexical_parent() != cursor.semantic_parent() { + // Only parse constructors once. + return Err(ParseError::Continue); + } + + if is_method || is_constructor { + let is_const = is_method && cursor.method_is_const(); + let is_virtual = is_method && cursor.method_is_virtual(); + let is_static = is_method && cursor.method_is_static(); + if !is_static && !is_virtual { + let class = Item::parse(cursor.semantic_parent(), None, ctx) + .expect("Expected to parse the class"); + let ptr = + Item::builtin_type(TypeKind::Pointer(class), is_const, ctx); + args.insert(0, (Some("this".into()), ptr)); + } else if is_virtual { + let void = Item::builtin_type(TypeKind::Void, false, ctx); + let ptr = + Item::builtin_type(TypeKind::Pointer(void), false, ctx); + args.insert(0, (Some("this".into()), ptr)); + } + } + + let ty_ret_type = try!(ty.ret_type().ok_or(ParseError::Continue)); + let ret = try!(Item::from_ty(&ty_ret_type, None, None, ctx)); + let abi = get_abi(ty.call_conv()); + + Ok(Self::new(ret, args, ty.is_variadic(), abi)) + } + + /// Get this function signature's return type. + pub fn return_type(&self) -> ItemId { + self.return_type + } + + /// Get this function signature's argument (name, type) pairs. + pub fn argument_types(&self) -> &[(Option<String>, ItemId)] { + &self.argument_types + } + + /// Get this function signature's ABI. + pub fn abi(&self) -> abi::Abi { + self.abi + } + + /// Is this function signature variadic? + pub fn is_variadic(&self) -> bool { + // Clang reports some functions as variadic when they *might* be + // variadic. We do the argument check because rust doesn't codegen well + // variadic functions without an initial argument. + self.is_variadic && !self.argument_types.is_empty() + } +} + +impl ClangSubItemParser for Function { + fn parse(cursor: clang::Cursor, + context: &mut BindgenContext) + -> Result<ParseResult<Self>, ParseError> { + use clang_sys::*; + match cursor.kind() { + // FIXME(emilio): Generate destructors properly. + CXCursor_FunctionDecl | + CXCursor_Constructor | + CXCursor_CXXMethod => {} + _ => return Err(ParseError::Continue), + }; + + debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type()); + + let visibility = cursor.visibility(); + if visibility != CXVisibility_Default { + return Err(ParseError::Continue); + } + + if cursor.access_specifier() == CX_CXXPrivate { + return Err(ParseError::Continue); + } + + if cursor.is_inlined_function() { + return Err(ParseError::Continue); + } + + let linkage = cursor.linkage(); + if linkage != CXLinkage_External && linkage != CXLinkage_UniqueExternal { + return Err(ParseError::Continue); + } + + // Grab the signature using Item::from_ty. + let sig = try!(Item::from_ty(&cursor.cur_type(), + Some(cursor), + None, + context)); + + let name = cursor.spelling(); + assert!(!name.is_empty(), "Empty function name?"); + + let mut mangled_name = cursor_mangling(&cursor); + if mangled_name.as_ref() == Some(&name) { + mangled_name = None; + } + + let comment = cursor.raw_comment(); + + let function = Self::new(name, mangled_name, sig, comment); + Ok(ParseResult::New(function, Some(cursor))) + } +} + +impl TypeCollector for FunctionSig { + type Extra = Item; + + fn collect_types(&self, + _context: &BindgenContext, + types: &mut ItemSet, + _item: &Item) { + types.insert(self.return_type()); + + for &(_, ty) in self.argument_types() { + types.insert(ty); + } + } +} diff --git a/src/ir/int.rs b/src/ir/int.rs new file mode 100644 index 00000000..89068e0f --- /dev/null +++ b/src/ir/int.rs @@ -0,0 +1,113 @@ +//! Intermediate representation for integral types. + +/// Which integral type are we dealing with? +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum IntKind { + /// A `bool`. + Bool, + + /// A `char`. + Char, + + /// An `unsigned char`. + UChar, + + /// A `short`. + Short, + + /// An `unsigned short`. + UShort, + + /// An `int`. + Int, + + /// An `unsigned int`. + UInt, + + /// A `long`. + Long, + + /// An `unsigned long`. + ULong, + + /// A `long long`. + LongLong, + + /// An `unsigned long long`. + ULongLong, + + /// A 8-bit signed integer. + I8, + + /// A 8-bit unsigned integer. + U8, + + /// A 16-bit signed integer. + I16, + + /// Either a `char16_t` or a `wchar_t`. + U16, + + /// A 32-bit signed integer. + I32, + + /// A 32-bit unsigned integer. + U32, + + /// A 64-bit signed integer. + I64, + + /// A 64-bit unsigned integer. + U64, + + /// An `int128_t` + I128, + + /// A `uint128_t`. + U128, + + /// A custom integer type, used to allow custom macro types depending on + /// range. + Custom { + /// The name of the type, which would be used without modification. + name: &'static str, + /// Whether the type is signed or not. + is_signed: bool, + }, +} + +impl IntKind { + /// Is this integral type signed? + pub fn is_signed(&self) -> bool { + use self::IntKind::*; + match *self { + Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 | + U32 | U64 | U128 => false, + + Char | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 | + I128 => true, + + Custom { is_signed, .. } => is_signed, + } + } + + /// If this type has a known size, return it (in bytes). This is to + /// alleviate libclang sometimes not giving us a layout (like in the case + /// when an enum is defined inside a class with template parameters). + pub fn known_size(&self) -> Option<usize> { + use self::IntKind::*; + Some(match *self { + Bool | UChar | Char | U8 | I8 => 1, + U16 | I16 => 2, + U32 | I32 => 4, + U64 | I64 => 8, + I128 | U128 => 16, + _ => return None, + }) + } + + /// Whether this type's signedness matches the value. + pub fn signedness_matches(&self, val: i64) -> bool { + val >= 0 || self.is_signed() + } +} diff --git a/src/ir/item.rs b/src/ir/item.rs new file mode 100644 index 00000000..df8fd222 --- /dev/null +++ b/src/ir/item.rs @@ -0,0 +1,1370 @@ +//! Bindgen's core intermediate representation type. + +use clang; +use clang_sys; +use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; +use std::cell::{Cell, RefCell}; +use std::fmt::Write; +use std::iter; +use super::annotations::Annotations; +use super::context::{BindgenContext, ItemId}; +use super::derive::{CanDeriveCopy, CanDeriveDebug}; +use super::function::Function; +use super::item_kind::ItemKind; +use super::module::Module; +use super::ty::{Type, TypeKind}; +use super::type_collector::{ItemSet, TypeCollector}; + +/// 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 TypeCollector for ItemId { + type Extra = (); + + fn collect_types(&self, + ctx: &BindgenContext, + types: &mut ItemSet, + extra: &()) { + ctx.resolve_item(*self).collect_types(ctx, types, extra); + } +} + +impl TypeCollector for Item { + type Extra = (); + + fn collect_types(&self, + ctx: &BindgenContext, + types: &mut ItemSet, + _extra: &()) { + if self.is_hidden(ctx) || types.contains(&self.id()) { + 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.collect_types(ctx, types, 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. + types.insert(fun.signature()); + } + ItemKind::Var(ref var) => { + types.insert(var.ty()); + } + _ => {} // FIXME. + } + } +} + +impl CanDeriveDebug for Item { + type Extra = (); + + fn can_derive_debug(&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_debug(ctx, ())) + } else { + ty.can_derive_debug(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 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() + } + + /// 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(ref n), &TypeKind::Named(ref i)) => { + n == i + } + _ => 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::TemplateRef(_, 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::TemplateRef(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, + } + } +} + +// 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(&(_, item_id)) = ctx.currently_parsed_types + .iter() + .find(|&&(d, _)| d == declaration_to_look_for) { + debug!("Avoiding recursion parsing type: {:?}", ty); + return Ok(item_id); + } + } + + let current_module = ctx.current_module(); + if valid_decl { + ctx.currently_parsed_types.push((declaration_to_look_for, id)); + } + + 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 (popped_decl, _) = + ctx.currently_parsed_types.pop().unwrap(); + assert_eq!(popped_decl, declaration_to_look_for); + } + + location.visit(|cur| { + visit_child(cur, id, ty, parent_id, ctx, &mut result) + }); + + if valid_decl { + ctx.currently_parsed_types + .push((declaration_to_look_for, id)); + } + } + // 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 (popped_decl, _) = ctx.currently_parsed_types.pop().unwrap(); + assert_eq!(popped_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) + } +} diff --git a/src/ir/item_kind.rs b/src/ir/item_kind.rs new file mode 100644 index 00000000..d9e4690c --- /dev/null +++ b/src/ir/item_kind.rs @@ -0,0 +1,114 @@ +//! Different variants of an `Item` in our intermediate representation. + +use super::function::Function; +use super::module::Module; +use super::ty::Type; +use super::var::Var; + +/// A item we parse and translate. +#[derive(Debug)] +pub enum ItemKind { + /// A module, created implicitly once (the root module), or via C++ + /// namespaces. + Module(Module), + + /// A type declared in any of the multiple ways it can be declared. + Type(Type), + + /// A function or method declaration. + Function(Function), + + /// A variable declaration, most likely a static. + Var(Var), +} + +impl ItemKind { + /// Get a reference to this `ItemKind`'s underying `Module`, or `None` if it + /// is some other kind. + pub fn as_module(&self) -> Option<&Module> { + match *self { + ItemKind::Module(ref module) => Some(module), + _ => None, + } + } + + /// Is this a module? + pub fn is_module(&self) -> bool { + self.as_module().is_some() + } + + /// Get a reference to this `ItemKind`'s underying `Module`, or panic if it + /// is some other kind. + pub fn expect_module(&self) -> &Module { + self.as_module().expect("Not a module") + } + + /// Get a reference to this `ItemKind`'s underying `Function`, or `None` if + /// it is some other kind. + pub fn as_function(&self) -> Option<&Function> { + match *self { + ItemKind::Function(ref func) => Some(func), + _ => None, + } + } + + /// Is this a function? + pub fn is_function(&self) -> bool { + self.as_function().is_some() + } + + /// Get a reference to this `ItemKind`'s underying `Function`, or panic if + /// it is some other kind. + pub fn expect_function(&self) -> &Function { + self.as_function().expect("Not a function") + } + + /// Get a reference to this `ItemKind`'s underying `Type`, or `None` if + /// it is some other kind. + pub fn as_type(&self) -> Option<&Type> { + match *self { + ItemKind::Type(ref ty) => Some(ty), + _ => None, + } + } + + /// Get a mutable reference to this `ItemKind`'s underying `Type`, or `None` + /// if it is some other kind. + pub fn as_type_mut(&mut self) -> Option<&mut Type> { + match *self { + ItemKind::Type(ref mut ty) => Some(ty), + _ => None, + } + } + + /// Is this a type? + pub fn is_type(&self) -> bool { + self.as_type().is_some() + } + + /// Get a reference to this `ItemKind`'s underying `Type`, or panic if it is + /// some other kind. + pub fn expect_type(&self) -> &Type { + self.as_type().expect("Not a type") + } + + /// Get a reference to this `ItemKind`'s underying `Var`, or `None` if it is + /// some other kind. + pub fn as_var(&self) -> Option<&Var> { + match *self { + ItemKind::Var(ref v) => Some(v), + _ => None, + } + } + + /// Is this a variable? + pub fn is_var(&self) -> bool { + self.as_var().is_some() + } + + /// Get a reference to this `ItemKind`'s underying `Var`, or panic if it is + /// some other kind. + pub fn expect_var(&self) -> &Var { + self.as_var().expect("Not a var") + } +} diff --git a/src/ir/layout.rs b/src/ir/layout.rs new file mode 100644 index 00000000..033fff62 --- /dev/null +++ b/src/ir/layout.rs @@ -0,0 +1,91 @@ +//! Intermediate representation for the physical layout of some type. + +use std::cmp; +use super::context::BindgenContext; +use super::derive::{CanDeriveCopy, CanDeriveDebug}; +use super::ty::RUST_DERIVE_IN_ARRAY_LIMIT; + +/// A type that represents the struct layout of a type. +#[derive(Debug, Clone, Copy)] +pub struct Layout { + /// The size (in bytes) of this layout. + pub size: usize, + /// The alignment (in bytes) of this layout. + pub align: usize, + /// Whether this layout's members are packed or not. + pub packed: bool, +} + +impl Layout { + /// Construct a new `Layout` with the given `size` and `align`. It is not + /// packed. + pub fn new(size: usize, align: usize) -> Self { + Layout { + size: size, + align: align, + packed: false, + } + } + + /// Is this a zero-sized layout? + pub fn is_zero(&self) -> bool { + self.size == 0 && self.align == 0 + } + + /// Construct a zero-sized layout. + pub fn zero() -> Self { + Self::new(0, 0) + } + + /// Get this layout as an opaque type. + pub fn opaque(&self) -> Opaque { + Opaque(*self) + } +} + +/// When we are treating a type as opaque, it is just a blob with a `Layout`. +pub struct Opaque(pub Layout); + +impl Opaque { + /// Return the known rust type we should use to create a correctly-aligned + /// field with this layout. + pub fn known_rust_type_for_array(&self) -> Option<&'static str> { + Some(match self.0.align { + 8 => "u64", + 4 => "u32", + 2 => "u16", + 1 => "u8", + _ => return None, + }) + } + + /// Return the array size that an opaque type for this layout should have if + /// we know the correct type for it, or `None` otherwise. + pub fn array_size(&self) -> Option<usize> { + if self.known_rust_type_for_array().is_some() { + Some(self.0.size / cmp::max(self.0.align, 1)) + } else { + None + } + } +} + +impl CanDeriveDebug for Opaque { + type Extra = (); + + fn can_derive_debug(&self, _: &BindgenContext, _: ()) -> bool { + self.array_size().map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) + } +} + +impl<'a> CanDeriveCopy<'a> for Opaque { + type Extra = (); + + fn can_derive_copy(&self, _: &BindgenContext, _: ()) -> bool { + self.array_size().map_or(false, |size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) + } + + fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool { + self.can_derive_copy(ctx, ()) + } +} diff --git a/src/ir/mod.rs b/src/ir/mod.rs new file mode 100644 index 00000000..73793b16 --- /dev/null +++ b/src/ir/mod.rs @@ -0,0 +1,19 @@ +//! The ir module defines bindgen's intermediate representation. +//! +//! Parsing C/C++ generates the IR, while code generation outputs Rust code from +//! the IR. + +pub mod annotations; +pub mod comp; +pub mod context; +pub mod derive; +pub mod enum_ty; +pub mod function; +pub mod int; +pub mod item; +pub mod item_kind; +pub mod layout; +pub mod module; +pub mod ty; +pub mod type_collector; +pub mod var; diff --git a/src/ir/module.rs b/src/ir/module.rs new file mode 100644 index 00000000..002fe36e --- /dev/null +++ b/src/ir/module.rs @@ -0,0 +1,78 @@ +//! Intermediate representation for modules (AKA C++ namespaces). + +use clang; +use parse::{ClangSubItemParser, ParseError, ParseResult}; +use parse_one; +use super::context::{BindgenContext, ItemId}; + +/// Whether this module is inline or not. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ModuleKind { + /// This module is not inline. + Normal, + /// This module is inline, as in `inline namespace foo {}`. + Inline, +} + +/// A module, as in, a C++ namespace. +#[derive(Clone, Debug)] +pub struct Module { + /// The name of the module, or none if it's anonymous. + name: Option<String>, + /// The kind of module this is. + kind: ModuleKind, + /// The children of this module, just here for convenience. + children_ids: Vec<ItemId>, +} + +impl Module { + /// Construct a new `Module`. + pub fn new(name: Option<String>, kind: ModuleKind) -> Self { + Module { + name: name, + kind: kind, + children_ids: vec![], + } + } + + /// Get this module's name. + pub fn name(&self) -> Option<&str> { + self.name.as_ref().map(|n| &**n) + } + + /// Get a mutable reference to this module's children. + pub fn children_mut(&mut self) -> &mut Vec<ItemId> { + &mut self.children_ids + } + + /// Get this module's children. + pub fn children(&self) -> &[ItemId] { + &self.children_ids + } + + /// Whether this namespace is inline. + pub fn is_inline(&self) -> bool { + self.kind == ModuleKind::Inline + } +} + +impl ClangSubItemParser for Module { + fn parse(cursor: clang::Cursor, + ctx: &mut BindgenContext) + -> Result<ParseResult<Self>, ParseError> { + use clang_sys::*; + match cursor.kind() { + CXCursor_Namespace => { + let module_id = ctx.module(cursor); + ctx.with_module(module_id, |ctx| { + cursor.visit(|cursor| { + parse_one(ctx, cursor, Some(module_id)) + }) + }); + + Ok(ParseResult::AlreadyResolved(module_id)) + } + _ => Err(ParseError::Continue), + } + } +} diff --git a/src/ir/ty.rs b/src/ir/ty.rs new file mode 100644 index 00000000..c1ed5b64 --- /dev/null +++ b/src/ir/ty.rs @@ -0,0 +1,926 @@ +//! Everything related to types in our intermediate representation. + +use clang::{self, Cursor}; +use parse::{ClangItemParser, ParseError, ParseResult}; +use super::comp::CompInfo; +use super::context::{BindgenContext, ItemId}; +use super::derive::{CanDeriveCopy, CanDeriveDebug}; +use super::enum_ty::Enum; +use super::function::FunctionSig; +use super::int::IntKind; +use super::item::Item; +use super::layout::Layout; +use super::type_collector::{ItemSet, TypeCollector}; + +/// The base representation of a type in bindgen. +/// +/// A type has an optional name, which if present cannot be empty, a `layout` +/// (size, alignment and packedness) if known, a `Kind`, which determines which +/// kind of type it is, and whether the type is const. +#[derive(Debug)] +pub struct Type { + /// The name of the type, or None if it was an unnamed struct or union. + name: Option<String>, + /// The layout of the type, if known. + layout: Option<Layout>, + /// The inner kind of the type + kind: TypeKind, + /// Whether this type is const-qualified. + is_const: bool, +} + +/// The maximum number of items in an array for which Rust implements common +/// traits, and so if we have a type containing an array with more than this +/// many items, we won't be able to derive common traits on that type. +/// +/// We need type-level integers yesterday :'( +pub const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32; + +impl Type { + /// Get the underlying `CompInfo` for this type, or `None` if this is some + /// other kind of type. + pub fn as_comp(&self) -> Option<&CompInfo> { + match self.kind { + TypeKind::Comp(ref ci) => Some(ci), + _ => None, + } + } + + /// Construct a new `Type`. + pub fn new(name: Option<String>, + layout: Option<Layout>, + kind: TypeKind, + is_const: bool) + -> Self { + Type { + name: name, + layout: layout, + kind: kind, + is_const: is_const, + } + } + + /// Which kind of type is this? + pub fn kind(&self) -> &TypeKind { + &self.kind + } + + /// Overrides the kind of the item. This is mostly a template alias + /// implementation detail, and debug assertions guard it like so. + pub fn set_kind(&mut self, kind: TypeKind) { + if cfg!(debug_assertions) { + match (&self.kind, &kind) { + (&TypeKind::Alias(ref alias_name, alias_inner), + &TypeKind::TemplateAlias(ref name, inner, _)) => { + assert_eq!(alias_name, name); + assert_eq!(alias_inner, inner); + } + _ => panic!("Unexpected kind in `set_kind`!"), + }; + } + self.kind = kind; + } + + /// Get a mutable reference to this type's kind. + pub fn kind_mut(&mut self) -> &mut TypeKind { + &mut self.kind + } + + /// Get this type's name. + pub fn name(&self) -> Option<&str> { + self.name.as_ref().map(|name| &**name) + } + + /// Is this a compound type? + pub fn is_comp(&self) -> bool { + match self.kind { + TypeKind::Comp(..) => true, + _ => false, + } + } + + /// Is this a named type? + pub fn is_named(&self) -> bool { + match self.kind { + TypeKind::Named(..) => true, + _ => false, + } + } + + /// Is this a template alias type? + pub fn is_template_alias(&self) -> bool { + match self.kind { + TypeKind::TemplateAlias(..) => true, + _ => false, + } + } + + /// Is this a function type? + pub fn is_function(&self) -> bool { + match self.kind { + TypeKind::Function(..) => true, + _ => false, + } + } + + /// Is this an enum type? + pub fn is_enum(&self) -> bool { + match self.kind { + TypeKind::Enum(..) => true, + _ => false, + } + } + + /// Is this either a builtin or named type? + pub fn is_builtin_or_named(&self) -> bool { + match self.kind { + TypeKind::Void | + TypeKind::NullPtr | + TypeKind::Function(..) | + TypeKind::Array(..) | + TypeKind::Reference(..) | + TypeKind::Pointer(..) | + TypeKind::BlockPointer | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Named(..) => true, + _ => false, + } + } + + /// Creates a new named type, with name `name`. + pub fn named(name: String) -> Self { + assert!(!name.is_empty()); + // TODO: stop duplicating the name, it's stupid. + let kind = TypeKind::Named(name.clone()); + Self::new(Some(name), None, kind, false) + } + + /// Is this a floating point type? + pub fn is_float(&self) -> bool { + match self.kind { + TypeKind::Float(..) => true, + _ => false, + } + } + + /// Is this a boolean type? + pub fn is_bool(&self) -> bool { + match self.kind { + TypeKind::Int(IntKind::Bool) => true, + _ => false, + } + } + + /// Is this an integer type? + pub fn is_integer(&self) -> bool { + match self.kind { + TypeKind::Int(..) => true, + _ => false, + } + } + + /// Is this a `const` qualified type? + pub fn is_const(&self) -> bool { + self.is_const + } + + /// Is this a reference to another type? + pub fn is_type_ref(&self) -> bool { + match self.kind { + TypeKind::ResolvedTypeRef(_) | + TypeKind::UnresolvedTypeRef(_, _, _) => true, + _ => false, + } + } + + /// What is the layout of this type? + pub fn layout(&self, ctx: &BindgenContext) -> Option<Layout> { + use std::mem; + + self.layout.or_else(|| { + match self.kind { + TypeKind::Comp(ref ci) => ci.layout(ctx), + // FIXME(emilio): This is a hack for anonymous union templates. + // Use the actual pointer size! + TypeKind::Pointer(..) | + TypeKind::BlockPointer => { + Some(Layout::new(mem::size_of::<*mut ()>(), + mem::align_of::<*mut ()>())) + } + TypeKind::ResolvedTypeRef(inner) => { + ctx.resolve_type(inner).layout(ctx) + } + _ => None, + } + }) + } + + /// Whether this type has a vtable. + pub fn has_vtable(&self, ctx: &BindgenContext) -> bool { + // FIXME: Can we do something about template parameters? Huh... + match self.kind { + TypeKind::TemplateRef(t, _) | + TypeKind::TemplateAlias(_, t, _) | + TypeKind::Alias(_, t) | + TypeKind::ResolvedTypeRef(t) => ctx.resolve_type(t).has_vtable(ctx), + TypeKind::Comp(ref info) => info.has_vtable(ctx), + _ => false, + } + + } + + /// Returns whether this type has a destructor. + pub fn has_destructor(&self, ctx: &BindgenContext) -> bool { + match self.kind { + TypeKind::TemplateRef(t, _) | + TypeKind::TemplateAlias(_, t, _) | + TypeKind::Alias(_, t) | + TypeKind::ResolvedTypeRef(t) => { + ctx.resolve_type(t).has_destructor(ctx) + } + TypeKind::Comp(ref info) => info.has_destructor(ctx), + _ => false, + } + } + + /// See the comment in `Item::signature_contains_named_type`. + pub fn signature_contains_named_type(&self, + ctx: &BindgenContext, + ty: &Type) + -> bool { + let name = match *ty.kind() { + TypeKind::Named(ref name) => name, + ref other @ _ => unreachable!("Not a named type: {:?}", other), + }; + + match self.kind { + TypeKind::Named(ref this_name) => this_name == name, + TypeKind::ResolvedTypeRef(t) | + TypeKind::Array(t, _) | + TypeKind::Pointer(t) | + TypeKind::Alias(_, t) => { + ctx.resolve_type(t) + .signature_contains_named_type(ctx, ty) + } + TypeKind::Function(ref sig) => { + sig.argument_types().iter().any(|&(_, arg)| { + ctx.resolve_type(arg) + .signature_contains_named_type(ctx, ty) + }) || + ctx.resolve_type(sig.return_type()) + .signature_contains_named_type(ctx, ty) + } + TypeKind::TemplateAlias(_, _, ref template_args) | + TypeKind::TemplateRef(_, ref template_args) => { + template_args.iter().any(|arg| { + ctx.resolve_type(*arg) + .signature_contains_named_type(ctx, ty) + }) + } + TypeKind::Comp(ref ci) => ci.signature_contains_named_type(ctx, ty), + _ => false, + } + } + + /// See safe_canonical_type. + pub fn canonical_type<'tr>(&'tr self, + ctx: &'tr BindgenContext) + -> &'tr Type { + self.safe_canonical_type(ctx) + .expect("Should have been resolved after parsing!") + } + + /// Returns the canonical type of this type, that is, the "inner type". + /// + /// For example, for a `typedef`, the canonical type would be the + /// `typedef`ed type, for a template specialization, would be the template + /// its specializing, and so on. Return None if the type is unresolved. + pub fn safe_canonical_type<'tr>(&'tr self, + ctx: &'tr BindgenContext) + -> Option<&'tr Type> { + match self.kind { + TypeKind::Named(..) | + TypeKind::Array(..) | + TypeKind::Comp(..) | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Complex(..) | + TypeKind::Function(..) | + TypeKind::Enum(..) | + TypeKind::Reference(..) | + TypeKind::Void | + TypeKind::NullPtr | + TypeKind::BlockPointer | + TypeKind::Pointer(..) => Some(self), + + TypeKind::ResolvedTypeRef(inner) | + TypeKind::Alias(_, inner) | + TypeKind::TemplateAlias(_, inner, _) | + TypeKind::TemplateRef(inner, _) => { + ctx.resolve_type(inner).safe_canonical_type(ctx) + } + + TypeKind::UnresolvedTypeRef(..) => None, + } + } + + /// There are some types we don't want to stop at when finding an opaque + /// item, so we can arrive to the proper item that needs to be generated. + pub fn should_be_traced_unconditionally(&self) -> bool { + match self.kind { + TypeKind::Function(..) | + TypeKind::Pointer(..) | + TypeKind::Array(..) | + TypeKind::Reference(..) | + TypeKind::TemplateRef(..) | + TypeKind::ResolvedTypeRef(..) => true, + _ => false, + } + } +} + +impl CanDeriveDebug for Type { + type Extra = (); + + fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool { + match self.kind { + TypeKind::Array(t, len) => { + len <= RUST_DERIVE_IN_ARRAY_LIMIT && t.can_derive_debug(ctx, ()) + } + TypeKind::ResolvedTypeRef(t) | + TypeKind::TemplateAlias(_, t, _) | + TypeKind::Alias(_, t) => t.can_derive_debug(ctx, ()), + TypeKind::Comp(ref info) => { + info.can_derive_debug(ctx, self.layout(ctx)) + } + _ => true, + } + } +} + +impl<'a> CanDeriveCopy<'a> for Type { + type Extra = &'a Item; + + fn can_derive_copy(&self, ctx: &BindgenContext, item: &Item) -> bool { + match self.kind { + TypeKind::Array(t, len) => { + len <= RUST_DERIVE_IN_ARRAY_LIMIT && + t.can_derive_copy_in_array(ctx, ()) + } + TypeKind::ResolvedTypeRef(t) | + TypeKind::TemplateAlias(_, t, _) | + TypeKind::TemplateRef(t, _) | + TypeKind::Alias(_, t) => t.can_derive_copy(ctx, ()), + TypeKind::Comp(ref info) => { + info.can_derive_copy(ctx, (item, self.layout(ctx))) + } + _ => true, + } + } + + fn can_derive_copy_in_array(&self, + ctx: &BindgenContext, + item: &Item) + -> bool { + match self.kind { + TypeKind::ResolvedTypeRef(t) | + TypeKind::TemplateAlias(_, t, _) | + TypeKind::Alias(_, t) | + TypeKind::Array(t, _) => t.can_derive_copy_in_array(ctx, ()), + TypeKind::Named(..) => false, + _ => self.can_derive_copy(ctx, item), + } + } +} + +/// The kind of float this type represents. +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum FloatKind { + /// A `float`. + Float, + /// A `double`. + Double, + /// A `long double`. + LongDouble, + /// A `__float128`. + Float128, +} + +/// The different kinds of types that we can parse. +#[derive(Debug)] +pub enum TypeKind { + /// The void type. + Void, + + /// The `nullptr_t` type. + NullPtr, + + /// A compound type, that is, a class, struct, or union. + Comp(CompInfo), + + /// An integer type, of a given kind. `bool` and `char` are also considered + /// integers. + Int(IntKind), + + /// A floating point type. + Float(FloatKind), + + /// A complex floating point type. + Complex(FloatKind), + + /// A type alias, with a name, that points to another type. + Alias(String, ItemId), + + /// A templated alias, pointing to an inner type, just as `Alias`, but with + /// template parameters. + TemplateAlias(String, ItemId, Vec<ItemId>), + + /// An array of a type and a lenght. + Array(ItemId, usize), + + /// A function type, with a given signature. + Function(FunctionSig), + + /// An `enum` type. + Enum(Enum), + + /// A pointer to a type. The bool field represents whether it's const or + /// not. + Pointer(ItemId), + + /// A pointer to an Apple block. + BlockPointer, + + /// A reference to a type, as in: int& foo(). + Reference(ItemId), + + /// A reference to a template, with different template parameter names. To + /// see why this is needed, check out the creation of this variant in + /// `Type::from_clang_ty`. + TemplateRef(ItemId, Vec<ItemId>), + + /// A reference to a yet-to-resolve type. This stores the clang cursor + /// itself, and postpones its resolution. + /// + /// These are gone in a phase after parsing where these are mapped to + /// already known types, and are converted to ResolvedTypeRef. + /// + /// see tests/headers/typeref.hpp to see somewhere where this is a problem. + UnresolvedTypeRef(clang::Type, + Option<clang::Cursor>, + /* parent_id */ + Option<ItemId>), + + /// An indirection to another type. + /// + /// These are generated after we resolve a forward declaration, or when we + /// replace one type with another. + ResolvedTypeRef(ItemId), + + /// A named type, that is, a template parameter. + Named(String), +} + +impl Type { + /// Whether this type is unsized, that is, has no members. This is used to + /// derive whether we should generate a dummy `_address` field for structs, + /// to comply to the C and C++ layouts, that specify that every type needs + /// to be addressable. + pub fn is_unsized(&self, ctx: &BindgenContext) -> bool { + debug_assert!(ctx.in_codegen_phase(), "Not yet"); + + match self.kind { + TypeKind::Void => true, + TypeKind::Comp(ref ci) => ci.is_unsized(ctx), + TypeKind::Array(inner, size) => { + size == 0 || ctx.resolve_type(inner).is_unsized(ctx) + } + TypeKind::ResolvedTypeRef(inner) | + TypeKind::Alias(_, inner) | + TypeKind::TemplateAlias(_, inner, _) | + TypeKind::TemplateRef(inner, _) => { + ctx.resolve_type(inner).is_unsized(ctx) + } + TypeKind::Named(..) | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Complex(..) | + TypeKind::Function(..) | + TypeKind::Enum(..) | + TypeKind::Reference(..) | + TypeKind::NullPtr | + TypeKind::BlockPointer | + TypeKind::Pointer(..) => false, + + TypeKind::UnresolvedTypeRef(..) => { + unreachable!("Should have been resolved after parsing!"); + } + } + } + + /// This is another of the nasty methods. This one is the one that takes + /// care of the core logic of converting a clang type to a `Type`. + /// + /// It's sort of nasty and full of special-casing, but hopefully the + /// comments in every special case justify why they're there. + pub fn from_clang_ty(potential_id: ItemId, + ty: &clang::Type, + location: Option<Cursor>, + parent_id: Option<ItemId>, + ctx: &mut BindgenContext) + -> Result<ParseResult<Self>, ParseError> { + use clang_sys::*; + { + let already_resolved = + ctx.builtin_or_resolved_ty(potential_id, + parent_id, + ty, + location); + if let Some(ty) = already_resolved { + debug!("{:?} already resolved: {:?}", ty, location); + return Ok(ParseResult::AlreadyResolved(ty)); + } + } + + let layout = ty.fallible_layout().ok(); + let cursor = ty.declaration(); + let mut name = cursor.spelling(); + + debug!("from_clang_ty: {:?}, ty: {:?}, loc: {:?}", + potential_id, + ty, + location); + debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types); + + let canonical_ty = ty.canonical_type(); + let kind = match ty.kind() { + CXType_Unexposed if *ty != canonical_ty && + canonical_ty.kind() != CXType_Invalid => { + debug!("Looking for canonical type: {:?}", canonical_ty); + return Self::from_clang_ty(potential_id, + &canonical_ty, + location, + parent_id, + ctx); + } + CXType_Unexposed | CXType_Invalid => { + // For some reason Clang doesn't give us any hint in some + // situations where we should generate a function pointer (see + // tests/headers/func_ptr_in_struct.h), so we do a guess here + // trying to see if it has a valid return type. + if ty.ret_type().is_some() { + let signature = try!(FunctionSig::from_ty(ty, + &location.unwrap_or(cursor), + ctx)); + TypeKind::Function(signature) + // Same here, with template specialisations we can safely + // assume this is a Comp(..) + } else if ty.is_fully_specialized_template() { + debug!("Template specialization: {:?}", ty); + let complex = + CompInfo::from_ty(potential_id, ty, location, ctx) + .expect("C'mon"); + TypeKind::Comp(complex) + } else if let Some(location) = location { + match location.kind() { + CXCursor_ClassTemplatePartialSpecialization | + CXCursor_CXXBaseSpecifier | + CXCursor_ClassTemplate => { + if location.kind() == CXCursor_CXXBaseSpecifier { + // In the case we're parsing a base specifier + // inside an unexposed or invalid type, it means + // that we're parsing one of two things: + // + // * A template parameter. + // * A complex class that isn't exposed. + // + // This means, unfortunately, that there's no + // good way to differentiate between them. + // + // Probably we could try to look at the + // declaration and complicate more this logic, + // but we'll keep it simple... if it's a valid + // C++ identifier, we'll consider it as a + // template parameter. + // + // This is because: + // + // * We expect every other base that is a + // proper identifier (that is, a simple + // struct/union declaration), to be exposed, + // so this path can't be reached in that + // case. + // + // * Quite conveniently, complex base + // specifiers preserve their full names (that + // is: Foo<T> instead of Foo). We can take + // advantage of this. + // + // If we find some edge case where this doesn't + // work (which I guess is unlikely, see the + // different test cases[1][2][3][4]), we'd need + // to find more creative ways of differentiating + // these two cases. + // + // [1]: inherit_named.hpp + // [2]: forward-inherit-struct-with-fields.hpp + // [3]: forward-inherit-struct.hpp + // [4]: inherit-namespaced.hpp + if location.spelling() + .chars() + .all(|c| c.is_alphanumeric() || c == '_') { + return Err(ParseError::Recurse); + } + } else { + name = location.spelling(); + } + let complex = CompInfo::from_ty(potential_id, + ty, + Some(location), + ctx) + .expect("C'mon"); + TypeKind::Comp(complex) + } + CXCursor_TypeAliasTemplateDecl => { + debug!("TypeAliasTemplateDecl"); + + // We need to manually unwind this one. + let mut inner = Err(ParseError::Continue); + let mut args = vec![]; + + location.visit(|cur| { + match cur.kind() { + CXCursor_TypeAliasDecl => { + let current = cur.cur_type(); + + debug_assert!(current.kind() == + CXType_Typedef); + + name = current.spelling(); + + let inner_ty = cur.typedef_type() + .expect("Not valid Type?"); + inner = + Item::from_ty(&inner_ty, + Some(cur), + Some(potential_id), + ctx); + } + CXCursor_TemplateTypeParameter => { + // See the comment in src/ir/comp.rs + // about the same situation. + if cur.spelling().is_empty() { + return CXChildVisit_Continue; + } + + let param = + Item::named_type(cur.spelling(), + potential_id, + ctx); + args.push(param); + } + _ => {} + } + CXChildVisit_Continue + }); + + let inner_type = match inner { + Ok(inner) => inner, + Err(..) => { + error!("Failed to parse template alias \ + {:?}", + location); + return Err(ParseError::Continue); + } + }; + + TypeKind::TemplateAlias(name.clone(), + inner_type, + args) + } + CXCursor_TemplateRef => { + let referenced = location.referenced().unwrap(); + let referenced_ty = referenced.cur_type(); + + debug!("TemplateRef: location = {:?}; referenced = \ + {:?}; referenced_ty = {:?}", + location, + referenced, + referenced_ty); + + return Self::from_clang_ty(potential_id, + &referenced_ty, + Some(referenced), + parent_id, + ctx); + } + CXCursor_TypeRef => { + let referenced = location.referenced().unwrap(); + let referenced_ty = referenced.cur_type(); + let declaration = referenced_ty.declaration(); + + debug!("TypeRef: location = {:?}; referenced = \ + {:?}; referenced_ty = {:?}", + location, + referenced, + referenced_ty); + + let item = + Item::from_ty_or_ref_with_id(potential_id, + referenced_ty, + Some(declaration), + parent_id, + ctx); + return Ok(ParseResult::AlreadyResolved(item)); + } + CXCursor_NamespaceRef => { + return Err(ParseError::Continue); + } + _ => { + if ty.kind() == CXType_Unexposed { + warn!("Unexposed type {:?}, recursing inside, \ + loc: {:?}", + ty, + location); + return Err(ParseError::Recurse); + } + + // If the type name is empty we're probably + // over-recursing to find a template parameter name + // or something like that, so just don't be too + // noisy with it since it causes confusion, see for + // example the discussion in: + // + // https://github.com/jamesmunns/teensy3-rs/issues/9 + if !ty.spelling().is_empty() { + warn!("invalid type {:?}", ty); + } else { + warn!("invalid type {:?}", ty); + } + return Err(ParseError::Continue); + } + } + } else { + // TODO: Don't duplicate this! + if ty.kind() == CXType_Unexposed { + warn!("Unexposed type {:?}, recursing inside", ty); + return Err(ParseError::Recurse); + } + + if !ty.spelling().is_empty() { + warn!("invalid type {:?}", ty); + } else { + warn!("invalid type {:?}", ty); + } + return Err(ParseError::Continue); + } + } + CXType_Auto => { + if canonical_ty == *ty { + debug!("Couldn't find deduced type: {:?}", ty); + return Err(ParseError::Continue); + } + + return Self::from_clang_ty(potential_id, + &canonical_ty, + location, + parent_id, + ctx); + } + // NOTE: We don't resolve pointers eagerly because the pointee type + // might not have been parsed, and if it contains templates or + // something else we might get confused, see the comment inside + // TypeRef. + // + // We might need to, though, if the context is already in the + // process of resolving them. + CXType_MemberPointer | + CXType_Pointer => { + let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(), + location, + parent_id, + ctx); + TypeKind::Pointer(inner) + } + CXType_BlockPointer => TypeKind::BlockPointer, + // XXX: RValueReference is most likely wrong, but I don't think we + // can even add bindings for that, so huh. + CXType_RValueReference | + CXType_LValueReference => { + let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(), + location, + parent_id, + ctx); + TypeKind::Reference(inner) + } + // XXX DependentSizedArray is wrong + CXType_VariableArray | + CXType_DependentSizedArray | + CXType_IncompleteArray => { + let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(), + location, + parent_id, + ctx) + .expect("Not able to resolve array element?"); + TypeKind::Pointer(inner) + } + CXType_FunctionNoProto | + CXType_FunctionProto => { + let signature = try!(FunctionSig::from_ty(ty, + &location.unwrap_or(cursor), + ctx)); + TypeKind::Function(signature) + } + CXType_Typedef => { + let inner = cursor.typedef_type().expect("Not valid Type?"); + let inner = + Item::from_ty_or_ref(inner, location, parent_id, ctx); + TypeKind::Alias(ty.spelling(), inner) + } + CXType_Enum => { + let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?"); + TypeKind::Enum(enum_) + } + CXType_Record => { + let complex = + CompInfo::from_ty(potential_id, ty, location, ctx) + .expect("Not a complex type?"); + TypeKind::Comp(complex) + } + // FIXME: We stub vectors as arrays since in 99% of the cases the + // layout is going to be correct, and there's no way we can generate + // vector types properly in Rust for now. + // + // That being said, that should be fixed eventually. + CXType_Vector | + CXType_ConstantArray => { + let inner = Item::from_ty(ty.elem_type().as_ref().unwrap(), + location, + parent_id, + ctx) + .expect("Not able to resolve array element?"); + TypeKind::Array(inner, ty.num_elements().unwrap()) + } + CXType_Elaborated => { + return Self::from_clang_ty(potential_id, + &ty.named(), + location, + parent_id, + ctx); + } + _ => { + error!("unsupported type: kind = {:?}; ty = {:?}; at {:?}", + ty.kind(), + ty, + location); + return Err(ParseError::Continue); + } + }; + + let name = if name.is_empty() { None } else { Some(name) }; + let is_const = ty.is_const(); + + let ty = Type::new(name, layout, kind, is_const); + // TODO: maybe declaration.canonical()? + Ok(ParseResult::New(ty, Some(cursor.canonical()))) + } +} + +impl TypeCollector for Type { + type Extra = Item; + + fn collect_types(&self, + context: &BindgenContext, + types: &mut ItemSet, + item: &Item) { + match *self.kind() { + TypeKind::Pointer(inner) | + TypeKind::Reference(inner) | + TypeKind::Array(inner, _) | + TypeKind::Alias(_, inner) | + TypeKind::ResolvedTypeRef(inner) => { + types.insert(inner); + } + + TypeKind::TemplateAlias(_, inner, ref template_args) | + TypeKind::TemplateRef(inner, ref template_args) => { + types.insert(inner); + for &item in template_args { + types.insert(item); + } + } + TypeKind::Comp(ref ci) => ci.collect_types(context, types, item), + TypeKind::Function(ref sig) => { + sig.collect_types(context, types, item) + } + TypeKind::Named(_) => {} + // FIXME: Pending types! + ref other @ _ => { + debug!("<Type as TypeCollector>::collect_types: Ignoring: \ + {:?}", + other); + } + } + } +} diff --git a/src/ir/type_collector.rs b/src/ir/type_collector.rs new file mode 100644 index 00000000..0f10152d --- /dev/null +++ b/src/ir/type_collector.rs @@ -0,0 +1,22 @@ +//! Collecting type items. + +use std::collections::BTreeSet; +use super::context::{BindgenContext, ItemId}; + +/// A set of items. +pub type ItemSet = BTreeSet<ItemId>; + +/// Collect all the type items referenced by this item. +pub trait TypeCollector { + /// If a particular type needs extra information beyond what it has in + /// `self` and `context` to find its referenced type items, its + /// implementation can define this associated type, forcing callers to pass + /// the needed information through. + type Extra; + + /// Add each type item referenced by `self` into the `types` set. + fn collect_types(&self, + context: &BindgenContext, + types: &mut ItemSet, + extra: &Self::Extra); +} diff --git a/src/ir/var.rs b/src/ir/var.rs new file mode 100644 index 00000000..329393fa --- /dev/null +++ b/src/ir/var.rs @@ -0,0 +1,317 @@ +//! Intermediate representation of variables. + +use cexpr; +use clang; +use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; +use std::num::Wrapping; +use super::context::{BindgenContext, ItemId}; +use super::function::cursor_mangling; +use super::int::IntKind; +use super::item::Item; +use super::ty::{FloatKind, TypeKind}; + +/// The type for a constant variable. +#[derive(Debug)] +pub enum VarType { + /// A boolean. + Bool(bool), + /// An integer. + Int(i64), + /// A floating point number. + Float(f64), + /// A character. + Char(u8), + /// A string, not necessarily well-formed utf-8. + String(Vec<u8>), +} + +/// A `Var` is our intermediate representation of a variable. +#[derive(Debug)] +pub struct Var { + /// The name of the variable. + name: String, + /// The mangled name of the variable. + mangled_name: Option<String>, + /// The type of the variable. + ty: ItemId, + /// The value of the variable, that needs to be suitable for `ty`. + val: Option<VarType>, + /// Whether this variable is const. + is_const: bool, +} + +impl Var { + /// Construct a new `Var`. + pub fn new(name: String, + mangled: Option<String>, + ty: ItemId, + val: Option<VarType>, + is_const: bool) + -> Var { + assert!(!name.is_empty()); + Var { + name: name, + mangled_name: mangled, + ty: ty, + val: val, + is_const: is_const, + } + } + + /// Is this variable `const` qualified? + pub fn is_const(&self) -> bool { + self.is_const + } + + /// The value of this constant variable, if any. + pub fn val(&self) -> Option<&VarType> { + self.val.as_ref() + } + + /// Get this variable's type. + pub fn ty(&self) -> ItemId { + self.ty + } + + /// Get this variable's name. + pub fn name(&self) -> &str { + &self.name + } + + /// Get this variable's mangled name. + pub fn mangled_name(&self) -> Option<&str> { + self.mangled_name.as_ref().map(|n| &**n) + } +} + +impl ClangSubItemParser for Var { + fn parse(cursor: clang::Cursor, + ctx: &mut BindgenContext) + -> Result<ParseResult<Self>, ParseError> { + use clang_sys::*; + use cexpr::expr::EvalResult; + use cexpr::literal::CChar; + match cursor.kind() { + CXCursor_MacroDefinition => { + let value = parse_macro(ctx, &cursor, ctx.translation_unit()); + + let (id, value) = match value { + Some(v) => v, + None => return Err(ParseError::Continue), + }; + + assert!(!id.is_empty(), "Empty macro name?"); + + let previously_defined = ctx.parsed_macro(&id); + + // NB: It's important to "note" the macro even if the result is + // not an integer, otherwise we might loose other kind of + // derived macros. + ctx.note_parsed_macro(id.clone(), value.clone()); + + if previously_defined { + let name = String::from_utf8(id).unwrap(); + warn!("Duplicated macro definition: {}", name); + return Err(ParseError::Continue); + } + + // NOTE: Unwrapping, here and above, is safe, because the + // identifier of a token comes straight from clang, and we + // enforce utf8 there, so we should have already panicked at + // this point. + let name = String::from_utf8(id).unwrap(); + let (type_kind, val) = match value { + EvalResult::Invalid => return Err(ParseError::Continue), + EvalResult::Float(f) => { + (TypeKind::Float(FloatKind::Float), VarType::Float(f)) + } + EvalResult::Char(c) => { + let c = match c { + CChar::Char(c) => { + assert_eq!(c.len_utf8(), 1); + c as u8 + } + CChar::Raw(c) => { + assert!(c <= ::std::u8::MAX as u64); + c as u8 + } + }; + + (TypeKind::Int(IntKind::U8), VarType::Char(c)) + } + EvalResult::Str(val) => { + let char_ty = + Item::builtin_type(TypeKind::Int(IntKind::U8), + true, + ctx); + (TypeKind::Pointer(char_ty), VarType::String(val)) + } + EvalResult::Int(Wrapping(value)) => { + let kind = ctx.type_chooser() + .and_then(|c| c.int_macro(&name, value)) + .unwrap_or_else(|| { + if value < 0 { + if value < i32::min_value() as i64 { + IntKind::LongLong + } else { + IntKind::Int + } + } else if value > u32::max_value() as i64 { + IntKind::ULongLong + } else { + IntKind::UInt + } + }); + + (TypeKind::Int(kind), VarType::Int(value)) + } + }; + + let ty = Item::builtin_type(type_kind, true, ctx); + + Ok(ParseResult::New(Var::new(name, None, ty, Some(val), true), + Some(cursor))) + } + CXCursor_VarDecl => { + let name = cursor.spelling(); + if name.is_empty() { + warn!("Empty constant name?"); + return Err(ParseError::Continue); + } + + let ty = cursor.cur_type(); + + // XXX this is redundant, remove! + let is_const = ty.is_const(); + + let ty = match Item::from_ty(&ty, Some(cursor), None, ctx) { + Ok(ty) => ty, + Err(e) => { + assert_eq!(ty.kind(), CXType_Auto, + "Couldn't resolve constant type, and it \ + wasn't an nondeductible auto type!"); + return Err(e); + } + }; + + // Note: Ty might not be totally resolved yet, see + // tests/headers/inner_const.hpp + // + // That's fine because in that case we know it's not a literal. + let canonical_ty = ctx.safe_resolve_type(ty) + .and_then(|t| t.safe_canonical_type(ctx)); + + let is_integer = canonical_ty.map_or(false, |t| t.is_integer()); + let is_float = canonical_ty.map_or(false, |t| t.is_float()); + + // TODO: We could handle `char` more gracefully. + // TODO: Strings, though the lookup is a bit more hard (we need + // to look at the canonical type of the pointee too, and check + // is char, u8, or i8 I guess). + let value = if is_integer { + let kind = match *canonical_ty.unwrap().kind() { + TypeKind::Int(kind) => kind, + _ => unreachable!(), + }; + + let mut val = cursor.evaluate() + .and_then(|v| v.as_int()) + .map(|val| val as i64); + if val.is_none() || !kind.signedness_matches(val.unwrap()) { + let tu = ctx.translation_unit(); + val = get_integer_literal_from_cursor(&cursor, tu); + } + + val.map(|val| { + if kind == IntKind::Bool { + VarType::Bool(val != 0) + } else { + VarType::Int(val) + } + }) + } else if is_float { + cursor.evaluate() + .and_then(|v| v.as_double()) + .map(VarType::Float) + } else { + cursor.evaluate() + .and_then(|v| v.as_literal_string()) + .map(VarType::String) + }; + + let mangling = cursor_mangling(&cursor); + let var = Var::new(name, mangling, ty, value, is_const); + + Ok(ParseResult::New(var, Some(cursor))) + } + _ => { + /* TODO */ + Err(ParseError::Continue) + } + } + } +} + +/// Try and parse a macro using all the macros parsed until now. +fn parse_macro(ctx: &BindgenContext, + cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option<(Vec<u8>, cexpr::expr::EvalResult)> { + use cexpr::{expr, nom}; + + let cexpr_tokens = match unit.cexpr_tokens(cursor) { + None => return None, + Some(tokens) => tokens, + }; + + let parser = expr::IdentifierParser::new(ctx.parsed_macros()); + let result = parser.macro_definition(&cexpr_tokens); + + match result { + nom::IResult::Done(_, (id, val)) => Some((id.into(), val)), + _ => None, + } +} + +fn parse_int_literal_tokens(cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option<i64> { + use cexpr::{expr, nom}; + use cexpr::expr::EvalResult; + + let cexpr_tokens = match unit.cexpr_tokens(cursor) { + None => return None, + Some(tokens) => tokens, + }; + + // TODO(emilio): We can try to parse other kinds of literals. + match expr::expr(&cexpr_tokens) { + nom::IResult::Done(_, EvalResult::Int(Wrapping(val))) => Some(val), + _ => None, + } +} + +fn get_integer_literal_from_cursor(cursor: &clang::Cursor, + unit: &clang::TranslationUnit) + -> Option<i64> { + use clang_sys::*; + let mut value = None; + cursor.visit(|c| { + match c.kind() { + CXCursor_IntegerLiteral | + CXCursor_UnaryOperator => { + value = parse_int_literal_tokens(&c, unit); + } + CXCursor_UnexposedExpr => { + value = get_integer_literal_from_cursor(&c, unit); + } + _ => (), + } + if value.is_some() { + CXChildVisit_Break + } else { + CXChildVisit_Continue + } + }); + value +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..60b750de --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,808 @@ +//! Generate Rust bindings for C and C++ libraries. +//! +//! Provide a C/C++ header file, receive Rust FFI code to call into C/C++ +//! functions and use types defined in the header. +//! +//! See the [Builder](./struct.Builder.html) struct for usage. + +#![deny(missing_docs)] +#![deny(warnings)] +#![deny(unused_extern_crates)] + +// We internally use the deprecated BindgenOptions all over the place. Once we +// remove its `pub` declaration, we can un-deprecate it and remove this pragma. +#![allow(deprecated)] + +// To avoid rather annoying warnings when matching with CXCursor_xxx as a +// constant. +#![allow(non_upper_case_globals)] + +#[macro_use] +#[allow(unused_extern_crates)] +extern crate cfg_if; +extern crate cexpr; +extern crate syntex_syntax as syntax; +extern crate aster; +extern crate quasi; +extern crate clang_sys; +extern crate regex; +#[macro_use] +extern crate lazy_static; + +#[cfg(feature = "logging")] +#[macro_use] +extern crate log; + +#[cfg(not(feature = "logging"))] +#[macro_use] +mod log_stubs; + +// A macro to declare an internal module for which we *must* provide +// documentation for. If we are building with the "docs_" feature, then the +// module is declared public, and our `#![deny(missing_docs)]` pragma applies to +// it. This feature is used in CI, so we won't let anything slip by +// undocumented. Normal builds, however, will leave the module private, so that +// we don't expose internals to library consumers. +macro_rules! doc_mod { + ($m:ident, $doc_mod_name:ident) => { + cfg_if! { + if #[cfg(feature = "docs_")] { + pub mod $doc_mod_name { + //! Autogenerated documentation module. + pub use super::$m::*; + } + } else { + } + } + }; +} + +mod clang; +mod ir; +mod parse; +mod regex_set; +mod uses; + +pub mod chooser; + +#[cfg(rustfmt)] +mod codegen; + +doc_mod!(clang, clang_docs); +doc_mod!(ir, ir_docs); +doc_mod!(parse, parse_docs); +doc_mod!(regex_set, regex_set_docs); +doc_mod!(uses, uses_docs); + +mod codegen { + include!(concat!(env!("OUT_DIR"), "/codegen.rs")); +} + +use ir::context::{BindgenContext, ItemId}; +use ir::item::Item; +use parse::{ClangItemParser, ParseError}; +use regex_set::RegexSet; + +use std::fs::OpenOptions; +use std::io::{self, Write}; +use std::path::Path; +use std::sync::{Arc, Mutex}; + +use syntax::ast; +use syntax::codemap::{DUMMY_SP, Span}; +use syntax::print::pp::eof; +use syntax::print::pprust; +use syntax::ptr::P; + +/// A type used to indicate which kind of items do we have to generate. +/// +/// TODO(emilio): Use `bitflags!` +#[derive(Debug, Clone)] +pub struct CodegenConfig { + /// Whether to generate functions. + pub functions: bool, + /// Whether to generate types. + pub types: bool, + /// Whether to generate constants. + pub vars: bool, + /// Whether to generate methods. + pub methods: bool, + /// Whether to generate constructors. + pub constructors: bool, +} + +impl CodegenConfig { + /// Generate all kinds of items. + pub fn all() -> Self { + CodegenConfig { + functions: true, + types: true, + vars: true, + methods: true, + constructors: true, + } + } + + /// Generate nothing. + pub fn nothing() -> Self { + CodegenConfig { + functions: false, + types: false, + vars: false, + methods: false, + constructors: false, + } + } +} + +impl Default for CodegenConfig { + fn default() -> Self { + CodegenConfig::all() + } +} + +/// Configure and generate Rust bindings for a C/C++ header. +/// +/// This is the main entry point to the library. +/// +/// ```ignore +/// use bindgen::builder; +/// +/// // Configure and generate bindings. +/// let bindings = try!(builder().header("path/to/input/header") +/// .whitelisted_type("SomeCoolClass") +/// .whitelisted_function("do_some_cool_thing") +/// .generate()); +/// +/// // Write the generated bindings to an output file. +/// try!(bindings.write_to_file("path/to/output.rs")); +/// ``` +#[derive(Debug,Default)] +pub struct Builder { + options: BindgenOptions, +} + +/// Construct a new [`Builder`](./struct.Builder.html). +pub fn builder() -> Builder { + Default::default() +} + +impl Builder { + /// Set the input C/C++ header. + pub fn header<T: Into<String>>(mut self, header: T) -> Builder { + let header = header.into(); + self.options.input_header = Some(header); + self + } + + /// Generate a C/C++ file that includes the header and has dummy uses of + /// every type defined in the header. + pub fn dummy_uses<T: Into<String>>(mut self, dummy_uses: T) -> Builder { + self.options.dummy_uses = Some(dummy_uses.into()); + self + } + + /// Hide the given type from the generated bindings. + pub fn hide_type<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.hidden_types.insert(arg); + self + } + + /// Treat the given type as opaque in the generated bindings. + pub fn opaque_type<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.opaque_types.insert(arg); + self + } + + /// Whitelist the given type so that it (and all types that it transitively + /// refers to) appears in the generated bindings. + pub fn whitelisted_type<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.whitelisted_types.insert(arg); + self + } + + /// Whitelist the given function so that it (and all types that it + /// transitively refers to) appears in the generated bindings. + pub fn whitelisted_function<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.whitelisted_functions.insert(arg); + self + } + + /// Whitelist the given variable so that it (and all types that it + /// transitively refers to) appears in the generated bindings. + pub fn whitelisted_var<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.whitelisted_vars.insert(arg); + self + } + + /// Mark the given enum (or set of enums, if using a pattern) as being + /// bitfield-like. + /// + /// This makes bindgen generate a type that isn't a rust `enum`. + pub fn bitfield_enum<T: AsRef<str>>(mut self, arg: T) -> Builder { + self.options.bitfield_enums.insert(arg); + self + } + + /// Add a string to prepend to the generated bindings. The string is passed + /// through without any modification. + pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Builder { + self.options.raw_lines.push(arg.into()); + self + } + + /// Add an argument to be passed straight through to clang. + pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder { + self.options.clang_args.push(arg.into()); + self + } + + /// Make the generated bindings link the given shared library. + pub fn link<T: Into<String>>(mut self, library: T) -> Builder { + self.options.links.push((library.into(), LinkType::Default)); + self + } + + /// Make the generated bindings link the given static library. + pub fn link_static<T: Into<String>>(mut self, library: T) -> Builder { + self.options.links.push((library.into(), LinkType::Static)); + self + } + + /// Make the generated bindings link the given framework. + pub fn link_framework<T: Into<String>>(mut self, library: T) -> Builder { + self.options.links.push((library.into(), LinkType::Framework)); + self + } + + /// Emit bindings for builtin definitions (for example `__builtin_va_list`) + /// in the generated Rust. + pub fn emit_builtins(mut self) -> Builder { + self.options.builtins = true; + self + } + + /// Avoid converting floats to f32/f64 by default. + pub fn no_convert_floats(mut self) -> Self { + self.options.convert_floats = false; + self + } + + /// Emit Clang AST. + pub fn emit_clang_ast(mut self) -> Builder { + self.options.emit_ast = true; + self + } + + /// Emit IR. + pub fn emit_ir(mut self) -> Builder { + self.options.emit_ir = true; + self + } + + /// Enable C++ namespaces. + pub fn enable_cxx_namespaces(mut self) -> Builder { + self.options.enable_cxx_namespaces = true; + self + } + + /// Disable auto-namespacing of names if namespaces are disabled. + /// + /// By default, if namespaces are disabled, bindgen tries to mangle the + /// names to from `foo::bar::Baz` to look like `foo_bar_Baz`, instead of + /// just `Baz`. + /// + /// This option disables that behavior. + /// + /// Note that this intentionally doesn't change the names using for + /// whitelisting and blacklisting, that should still be mangled with the + /// namespaces. + /// + /// Note, also, that using this option may cause duplicated names to be + /// generated. + pub fn disable_name_namespacing(mut self) -> Builder { + self.options.disable_name_namespacing = true; + self + } + + /// Treat inline namespaces conservatively. + /// + /// This is tricky, because in C++ is technically legal to override an item + /// defined in an inline namespace: + /// + /// ```cpp + /// inline namespace foo { + /// using Bar = int; + /// } + /// using Bar = long; + /// ``` + /// + /// Even though referencing `Bar` is a compiler error. + /// + /// We want to support this (arguably esoteric) use case, but we don't want + /// to make the rest of bindgen users pay an usability penalty for that. + /// + /// To support this, we need to keep all the inline namespaces around, but + /// then bindgen usage is a bit more difficult, because you cannot + /// reference, e.g., `std::string` (you'd need to use the proper inline + /// namespace). + /// + /// We could complicate a lot of the logic to detect name collisions, and if + /// not detected generate a `pub use inline_ns::*` or something like that. + /// + /// That's probably something we can do if we see this option is needed in a + /// lot of cases, to improve it's usability, but my guess is that this is + /// not going to be too useful. + pub fn conservative_inline_namespaces(mut self) -> Builder { + self.options.conservative_inline_namespaces = true; + self + } + + /// Ignore functions. + pub fn ignore_functions(mut self) -> Builder { + self.options.codegen_config.functions = false; + self + } + + /// Ignore methods. + pub fn ignore_methods(mut self) -> Builder { + self.options.codegen_config.methods = false; + self + } + + /// Avoid generating any unstable Rust in the generated bindings. + pub fn no_unstable_rust(mut self) -> Builder { + self.options.unstable_rust = false; + self + } + + /// Use core instead of libstd in the generated bindings. + pub fn use_core(mut self) -> Builder { + self.options.use_core = true; + self + } + + /// Use the given prefix for the raw types instead of `::std::os::raw`. + pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder { + self.options.ctypes_prefix = Some(prefix.into()); + self + } + + /// Allows configuring types in different situations, see the `TypeChooser` + /// documentation. + pub fn type_chooser(mut self, cb: Box<chooser::TypeChooser>) -> Self { + self.options.type_chooser = Some(cb); + self + } + + /// Choose what to generate using a CodegenConfig. + pub fn with_codegen_config(mut self, config: CodegenConfig) -> Self { + self.options.codegen_config = config; + self + } + + /// Generate the Rust bindings using the options built up thus far. + pub fn generate<'ctx>(self) -> Result<Bindings<'ctx>, ()> { + Bindings::generate(self.options, None) + } +} + +/// Configuration options for generated bindings. +/// +/// Deprecated: use a `Builder` instead. +#[derive(Debug)] +#[deprecated] +pub struct BindgenOptions { + /// The set of types that have been blacklisted and should not appear + /// anywhere in the generated code. + pub hidden_types: RegexSet, + + /// The set of types that should be treated as opaque structures in the + /// generated code. + pub opaque_types: RegexSet, + + /// The set of types that we should have bindings for in the generated + /// code. + /// + /// This includes all types transitively reachable from any type in this + /// set. One might think of whitelisted types/vars/functions as GC roots, + /// and the generated Rust code as including everything that gets marked. + pub whitelisted_types: RegexSet, + + /// Whitelisted functions. See docs for `whitelisted_types` for more. + pub whitelisted_functions: RegexSet, + + /// Whitelisted variables. See docs for `whitelisted_types` for more. + pub whitelisted_vars: RegexSet, + + /// The enum patterns to mark an enum as bitfield. + pub bitfield_enums: RegexSet, + + /// Whether we should generate builtins or not. + pub builtins: bool, + + /// The set of libraries we should link in the generated Rust code. + pub links: Vec<(String, LinkType)>, + + /// True if we should dump the Clang AST for debugging purposes. + pub emit_ast: bool, + + /// True if we should dump our internal IR for debugging purposes. + pub emit_ir: bool, + + /// True if we should emulate C++ namespaces with Rust modules in the + /// generated bindings. + pub enable_cxx_namespaces: bool, + + /// True if we should avoid mangling names with namespaces. + pub disable_name_namespacing: bool, + + /// True if we shold derive Debug trait implementations for C/C++ structures + /// and types. + pub derive_debug: bool, + + /// True if we can use unstable Rust code in the bindings, false if we + /// cannot. + pub unstable_rust: bool, + + /// True if we should avoid using libstd to use libcore instead. + pub use_core: bool, + + /// An optional prefix for the "raw" types, like `c_int`, `c_void`... + pub ctypes_prefix: Option<String>, + + /// True if we should generate constant names that are **directly** under + /// namespaces. + pub namespaced_constants: bool, + + /// True if we should use MSVC name mangling rules. + pub msvc_mangling: bool, + + /// Whether we should convert float types to f32/f64 types. + pub convert_floats: bool, + + /// The set of raw lines to prepend to the generated Rust code. + pub raw_lines: Vec<String>, + + /// The set of arguments to pass straight through to Clang. + pub clang_args: Vec<String>, + + /// The input header file. + pub input_header: Option<String>, + + /// Generate a dummy C/C++ file that includes the header and has dummy uses + /// of all types defined therein. See the `uses` module for more. + pub dummy_uses: Option<String>, + + /// A user-provided type chooser to allow customizing different kinds of + /// situations. + pub type_chooser: Option<Box<chooser::TypeChooser>>, + + /// Which kind of items should we generate? By default, we'll generate all + /// of them. + pub codegen_config: CodegenConfig, + + /// Whether to treat inline namespaces conservatively. + /// + /// See the builder method description for more details. + pub conservative_inline_namespaces: bool, +} + +impl BindgenOptions { + fn build(&mut self) { + self.whitelisted_vars.build(); + self.whitelisted_types.build(); + self.whitelisted_functions.build(); + self.hidden_types.build(); + self.opaque_types.build(); + self.bitfield_enums.build(); + } +} + +impl Default for BindgenOptions { + fn default() -> BindgenOptions { + BindgenOptions { + hidden_types: Default::default(), + opaque_types: Default::default(), + whitelisted_types: Default::default(), + whitelisted_functions: Default::default(), + whitelisted_vars: Default::default(), + bitfield_enums: Default::default(), + builtins: false, + links: vec![], + emit_ast: false, + emit_ir: false, + derive_debug: true, + enable_cxx_namespaces: false, + disable_name_namespacing: false, + unstable_rust: true, + use_core: false, + ctypes_prefix: None, + namespaced_constants: true, + msvc_mangling: false, + convert_floats: true, + raw_lines: vec![], + clang_args: vec![], + input_header: None, + dummy_uses: None, + type_chooser: None, + codegen_config: CodegenConfig::all(), + conservative_inline_namespaces: false, + } + } +} + +/// The linking type to use with a given library. +/// +/// TODO: #104: This is ignored at the moment, but shouldn't be. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum LinkType { + /// Use shared library linking. This is the default. + Default, + /// Use static linking. + Static, + /// The library is an OSX framework. + Framework, +} + +fn ensure_libclang_is_loaded() { + if clang_sys::is_loaded() { + return; + } + + // XXX (issue #350): Ensure that our dynamically loaded `libclang` + // doesn't get dropped prematurely, nor is loaded multiple times + // across different threads. + + lazy_static! { + static ref LIBCLANG: Mutex<Option<Arc<clang_sys::SharedLibrary>>> = { + Mutex::new(None) + }; + } + + let mut libclang = LIBCLANG.lock().unwrap(); + if !clang_sys::is_loaded() { + if libclang.is_none() { + // TODO(emilio): Return meaningful error (breaking). + clang_sys::load().expect("Unable to find libclang"); + *libclang = Some(clang_sys::get_library() + .expect("We just loaded libclang and it had \ + better still be here!")); + } else { + clang_sys::set_library(libclang.clone()); + } + } +} + +/// Generated Rust bindings. +#[derive(Debug)] +pub struct Bindings<'ctx> { + context: BindgenContext<'ctx>, + module: ast::Mod, +} + +impl<'ctx> Bindings<'ctx> { + /// Generate bindings for the given options. + /// + /// Deprecated - use a `Builder` instead + #[deprecated] + pub fn generate(mut options: BindgenOptions, + span: Option<Span>) + -> Result<Bindings<'ctx>, ()> { + let span = span.unwrap_or(DUMMY_SP); + ensure_libclang_is_loaded(); + + options.build(); + + // TODO: Make this path fixup configurable? + if let Some(clang) = clang_sys::support::Clang::find(None) { + // If --target is specified, assume caller knows what they're doing + // and don't mess with include paths for them + let has_target_arg = options.clang_args + .iter() + .rposition(|arg| arg.starts_with("--target")) + .is_some(); + if !has_target_arg { + // TODO: distinguish C and C++ paths? C++'s should be enough, I + // guess. + for path in clang.cpp_search_paths.into_iter() { + if let Ok(path) = path.into_os_string().into_string() { + options.clang_args.push("-isystem".to_owned()); + options.clang_args.push(path); + } + } + } + } + + if let Some(h) = options.input_header.as_ref() { + options.clang_args.push(h.clone()) + } + + let mut context = BindgenContext::new(options); + try!(parse(&mut context)); + + let module = ast::Mod { + inner: span, + items: codegen::codegen(&mut context), + }; + + Ok(Bindings { + context: context, + module: module, + }) + } + + /// Convert these bindings into a Rust AST. + pub fn into_ast(self) -> Vec<P<ast::Item>> { + self.module.items + } + + /// Convert these bindings into source text (with raw lines prepended). + pub fn to_string(&self) -> String { + let mut mod_str = vec![]; + { + let ref_writer = Box::new(mod_str.by_ref()) as Box<Write>; + self.write(ref_writer).expect("Could not write bindings to string"); + } + String::from_utf8(mod_str).unwrap() + } + + /// Write these bindings as source text to a file. + pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { + let file = try!(OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open(path)); + self.write(Box::new(file)) + } + + /// Write these bindings as source text to the given `Write`able. + pub fn write<'a>(&self, mut writer: Box<Write + 'a>) -> io::Result<()> { + try!(writer.write("/* automatically generated by rust-bindgen */\n\n" + .as_bytes())); + + for line in self.context.options().raw_lines.iter() { + try!(writer.write(line.as_bytes())); + try!(writer.write("\n".as_bytes())); + } + if !self.context.options().raw_lines.is_empty() { + try!(writer.write("\n".as_bytes())); + } + + let mut ps = pprust::rust_printer(writer); + try!(ps.print_mod(&self.module, &[])); + try!(ps.print_remaining_comments()); + try!(eof(&mut ps.s)); + ps.s.out.flush() + } + + /// Generate and write dummy uses of all the types we parsed, if we've been + /// requested to do so in the options. + /// + /// See the `uses` module for more information. + pub fn write_dummy_uses(&mut self) -> io::Result<()> { + let file = + if let Some(ref dummy_path) = self.context.options().dummy_uses { + Some(try!(OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open(dummy_path))) + } else { + None + }; + + if let Some(file) = file { + try!(uses::generate_dummy_uses(&mut self.context, file)); + } + + Ok(()) + } +} + +/// Determines whether the given cursor is in any of the files matched by the +/// options. +fn filter_builtins(ctx: &BindgenContext, cursor: &clang::Cursor) -> bool { + let (file, _, _, _) = cursor.location().location(); + + match file.name() { + None => ctx.options().builtins, + Some(..) => true, + } +} + +/// Parse one `Item` from the Clang cursor. +pub fn parse_one(ctx: &mut BindgenContext, + cursor: clang::Cursor, + parent: Option<ItemId>) + -> clang_sys::CXChildVisitResult { + if !filter_builtins(ctx, &cursor) { + return CXChildVisit_Continue; + } + + use clang_sys::CXChildVisit_Continue; + match Item::parse(cursor, parent, ctx) { + Ok(..) => {} + Err(ParseError::Continue) => {} + Err(ParseError::Recurse) => { + cursor.visit(|child| parse_one(ctx, child, parent)); + } + } + CXChildVisit_Continue +} + +/// Parse the Clang AST into our `Item` internal representation. +fn parse(context: &mut BindgenContext) -> Result<(), ()> { + use clang_sys::*; + + let mut any_error = false; + for d in context.translation_unit().diags().iter() { + let msg = d.format(); + let is_err = d.severity() >= CXDiagnostic_Error; + println!("{}, err: {}", msg, is_err); + any_error |= is_err; + } + + if any_error { + return Err(()); + } + + let cursor = context.translation_unit().cursor(); + if context.options().emit_ast { + cursor.visit(|cur| clang::ast_dump(&cur, 0)); + } + + let root = context.root_module(); + context.with_module(root, |context| { + cursor.visit(|cursor| parse_one(context, cursor, None)) + }); + + assert!(context.current_module() == context.root_module(), + "How did this happen?"); + Ok(()) +} + +/// Extracted Clang version data +#[derive(Debug)] +pub struct ClangVersion { + /// Major and minor semvar, if parsing was successful + pub parsed: Option<(u32, u32)>, + /// full version string + pub full: String, +} + +/// Get the major and the minor semvar numbers of Clang's version +pub fn clang_version() -> ClangVersion { + if !clang_sys::is_loaded() { + // TODO(emilio): Return meaningful error (breaking). + clang_sys::load().expect("Unable to find libclang"); + } + + let raw_v: String = clang::extract_clang_version(); + let split_v: Option<Vec<&str>> = raw_v.split_whitespace() + .nth(2) + .map(|v| v.split('.').collect()); + match split_v { + Some(v) => { + if v.len() >= 2 { + let maybe_major = v[0].parse::<u32>(); + let maybe_minor = v[1].parse::<u32>(); + match (maybe_major, maybe_minor) { + (Ok(major), Ok(minor)) => { + return ClangVersion { + parsed: Some((major, minor)), + full: raw_v.clone(), + } + } + _ => {} + } + } + } + None => {} + }; + ClangVersion { + parsed: None, + full: raw_v.clone(), + } +} diff --git a/src/log_stubs.rs b/src/log_stubs.rs new file mode 100644 index 00000000..4262e120 --- /dev/null +++ b/src/log_stubs.rs @@ -0,0 +1,30 @@ +macro_rules! log { + (target: $target:expr, $lvl:expr, $($arg)+) => { + let _ = $target; + let _ = log!($lvl, $($arg)+); + }; + ($lvl:expr, $($arg:tt)+) => { + let _ = $lvl; + let _ = format_args!($($arg)+); + }; +} +macro_rules! error { + (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }; + ($($arg:tt)*) => { log!("", $($arg)*); }; +} +macro_rules! warn { + (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }; + ($($arg:tt)*) => { log!("", $($arg)*); }; +} +macro_rules! info { + (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }; + ($($arg:tt)*) => { log!("", $($arg)*); }; +} +macro_rules! debug { + (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }; + ($($arg:tt)*) => { log!("", $($arg)*); }; +} +macro_rules! trace { + (target: $target:expr, $($arg:tt)*) => { log!($target, $($arg)*); }; + ($($arg:tt)*) => { log!("", $($arg)*); }; +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 00000000..a7bd9618 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,59 @@ +extern crate bindgen; +extern crate env_logger; +#[macro_use] +extern crate log; +extern crate clang_sys; +extern crate clap; +extern crate rustc_serialize; + +use bindgen::clang_version; +use std::env; + +mod options; +use options::builder_from_flags; + +pub fn main() { + log::set_logger(|max_log_level| { + use env_logger::Logger; + let env_logger = Logger::new(); + max_log_level.set(env_logger.filter()); + Box::new(env_logger) + }) + .expect("Failed to set logger."); + + let bind_args: Vec<_> = env::args().collect(); + + let version = clang_version(); + let expected_version = if cfg!(feature = "llvm_stable") { + (3, 8) + } else { + (3, 9) + }; + + info!("Clang Version: {}", version.full); + + match version.parsed { + None => warn!("Couldn't parse libclang version"), + Some(version) if version != expected_version => { + warn!("Using clang {:?}, expected {:?}", + version, + expected_version); + } + _ => {} + } + + match builder_from_flags(bind_args.into_iter()) { + Ok((builder, output)) => { + let mut bindings = builder.generate() + .expect("Unable to generate bindings"); + bindings.write(output) + .expect("Unable to write output"); + bindings.write_dummy_uses() + .expect("Unable to write dummy uses to file."); + } + Err(error) => { + println!("{}", error); + std::process::exit(1); + } + }; +} diff --git a/src/options.rs b/src/options.rs new file mode 100644 index 00000000..3456bfea --- /dev/null +++ b/src/options.rs @@ -0,0 +1,311 @@ +use clap::{App, Arg}; +use bindgen::{Builder, CodegenConfig, builder}; +use std::fs::File; +use std::io::{self, Error, ErrorKind}; + +/// Construct a new [`Builder`](./struct.Builder.html) from command line flags. +pub fn builder_from_flags<I>(args: I) + -> Result<(Builder, Box<io::Write>), io::Error> + where I: Iterator<Item = String>, +{ + let matches = App::new("bindgen") + .version(env!("CARGO_PKG_VERSION")) + .about("Generates Rust bindings from C/C++ headers.") + .usage("bindgen [FLAGS] [OPTIONS] <header> -- <clang-args>...") + .args(&[ + Arg::with_name("header") + .help("C or C++ header file") + .required(true), + Arg::with_name("bitfield-enum") + .long("bitfield-enum") + .help("Mark any enum whose name matches <regex> as a set of \ + bitfield flags instead of an enumeration.") + .value_name("regex") + .takes_value(true) + .multiple(true) + .number_of_values(1), + Arg::with_name("blacklist-type") + .long("blacklist-type") + .help("Mark a type as hidden.") + .value_name("type") + .takes_value(true) + .multiple(true) + .number_of_values(1), + Arg::with_name("builtins") + .long("builtins") + .help("Output bindings for builtin definitions, e.g. \ + __builtin_va_list."), + Arg::with_name("ctypes-prefix") + .long("ctypes-prefix") + .help("Use the given prefix before raw types instead of \ + ::std::os::raw.") + .value_name("prefix") + .takes_value(true), + // All positional arguments after the end of options marker, `--` + Arg::with_name("clang-args") + .multiple(true), + Arg::with_name("dummy-uses") + .long("dummy-uses") + .help("For testing purposes, generate a C/C++ file containing \ + dummy uses of all types defined in the input header.") + .takes_value(true), + Arg::with_name("emit-clang-ast") + .long("emit-clang-ast") + .help("Output the Clang AST for debugging purposes."), + Arg::with_name("emit-ir") + .long("emit-ir") + .help("Output our internal IR for debugging purposes."), + Arg::with_name("enable-cxx-namespaces") + .long("enable-cxx-namespaces") + .help("Enable support for C++ namespaces."), + Arg::with_name("disable-name-namespacing") + .long("disable-name-namespacing") + .help("Disable name namespacing if namespaces are disabled."), + Arg::with_name("framework") + .long("framework-link") + .help("Link to framework.") + .takes_value(true) + .multiple(true) + .number_of_values(1), + Arg::with_name("ignore-functions") + .long("ignore-functions") + .help("Do not generate bindings for functions or methods. This \ + is useful when you only care about struct layouts."), + Arg::with_name("generate") + .long("generate") + .help("Generate a given kind of items, split by commas. \ + Valid values are \"functions\",\"types\", \"vars\" and \ + \"methods\".") + .takes_value(true), + Arg::with_name("ignore-methods") + .long("ignore-methods") + .help("Do not generate bindings for methods."), + Arg::with_name("dynamic") + .short("l") + .long("link") + .help("Link to dynamic library.") + .takes_value(true) + .multiple(true) + .number_of_values(1), + Arg::with_name("no-convert-floats") + .long("no-convert-floats") + .help("Don't automatically convert floats to f32/f64."), + Arg::with_name("no-unstable-rust") + .long("no-unstable-rust") + .help("Do not generate unstable Rust code.") + .multiple(true), // FIXME: Pass legacy test suite + Arg::with_name("opaque-type") + .long("opaque-type") + .help("Mark a type as opaque.") + .value_name("type") + .takes_value(true) + .multiple(true) + .number_of_values(1), + Arg::with_name("output") + .short("o") + .long("output") + .help("Write Rust bindings to <output>.") + .takes_value(true), + Arg::with_name("raw-line") + .long("raw-line") + .help("Add a raw line of Rust code at the beginning of output.") + .takes_value(true) + .multiple(true) + .number_of_values(1), + Arg::with_name("static") + .long("static-link") + .help("Link to static library.") + .takes_value(true) + .multiple(true) + .number_of_values(1), + Arg::with_name("use-core") + .long("use-core") + .help("Use types from Rust core instead of std."), + Arg::with_name("conservative-inline-namespaces") + .long("conservative-inline-namespaces") + .help("Conservatively generate inline namespaces to avoid name \ + conflicts."), + Arg::with_name("use-msvc-mangling") + .long("use-msvc-mangling") + .help("MSVC C++ ABI mangling. DEPRECATED: Has no effect."), + Arg::with_name("whitelist-function") + .long("whitelist-function") + .help("Whitelist all the free-standing functions matching \ + <regex>. Other non-whitelisted functions will not be \ + generated.") + .value_name("regex") + .takes_value(true) + .multiple(true) + .number_of_values(1), + Arg::with_name("whitelist-type") + .long("whitelist-type") + .help("Whitelist the type. Other non-whitelisted types will \ + not be generated.") + .value_name("type") + .takes_value(true) + .multiple(true) + .number_of_values(1), + Arg::with_name("whitelist-var") + .long("whitelist-var") + .help("Whitelist all the free-standing variables matching \ + <regex>. Other non-whitelisted variables will not be \ + generated.") + .value_name("regex") + .takes_value(true) + .multiple(true) + .number_of_values(1), + ]) // .args() + .get_matches_from(args); + + let mut builder = builder(); + + if let Some(header) = matches.value_of("header") { + builder = builder.header(header); + } else { + return Err(Error::new(ErrorKind::Other, "Header not found")); + } + + if let Some(bitfields) = matches.values_of("bitfield-enum") { + for regex in bitfields { + builder = builder.bitfield_enum(regex); + } + } + + if let Some(hidden_types) = matches.values_of("blacklist-type") { + for ty in hidden_types { + builder = builder.hide_type(ty); + } + } + + if matches.is_present("builtins") { + builder = builder.emit_builtins(); + } + + if let Some(prefix) = matches.value_of("ctypes-prefix") { + builder = builder.ctypes_prefix(prefix); + } + + if let Some(dummy) = matches.value_of("dummy-uses") { + builder = builder.dummy_uses(dummy); + } + + if let Some(links) = matches.values_of("dynamic") { + for library in links { + builder = builder.link(library); + } + } + + if let Some(what_to_generate) = matches.value_of("generate") { + let mut config = CodegenConfig::nothing(); + for what in what_to_generate.split(",") { + match what { + "functions" => config.functions = true, + "types" => config.types = true, + "vars" => config.vars = true, + "methods" => config.methods = true, + _ => { + return Err(Error::new(ErrorKind::Other, + "Unknown generate item")); + } + } + } + builder = builder.with_codegen_config(config); + } + + if matches.is_present("emit-clang-ast") { + builder = builder.emit_clang_ast(); + } + + if matches.is_present("emit-ir") { + builder = builder.emit_ir(); + } + + if matches.is_present("enable-cxx-namespaces") { + builder = builder.enable_cxx_namespaces(); + } + + if matches.is_present("disable-name-namespacing") { + builder = builder.disable_name_namespacing(); + } + + if let Some(links) = matches.values_of("framework") { + for framework in links { + builder = builder.link_framework(framework); + } + } + + if matches.is_present("ignore-functions") { + builder = builder.ignore_functions(); + } + + if matches.is_present("ignore-methods") { + builder = builder.ignore_methods(); + } + + if matches.is_present("no-unstable-rust") { + builder = builder.no_unstable_rust(); + } + + if matches.is_present("no-convert-floats") { + builder = builder.no_convert_floats(); + } + + if let Some(opaque_types) = matches.values_of("opaque-type") { + for ty in opaque_types { + builder = builder.opaque_type(ty); + } + } + + if let Some(lines) = matches.values_of("raw-line") { + for line in lines { + builder = builder.raw_line(line); + } + } + + if let Some(links) = matches.values_of("static") { + for library in links { + builder = builder.link_static(library); + } + } + + if matches.is_present("use-core") { + builder = builder.use_core(); + } + + if matches.is_present("conservative-inline-namespaces") { + builder = builder.conservative_inline_namespaces(); + } + + if let Some(whitelist) = matches.values_of("whitelist-function") { + for regex in whitelist { + builder = builder.whitelisted_function(regex); + } + } + + if let Some(whitelist) = matches.values_of("whitelist-type") { + for regex in whitelist { + builder = builder.whitelisted_type(regex); + } + } + + if let Some(whitelist) = matches.values_of("whitelist-var") { + for regex in whitelist { + builder = builder.whitelisted_var(regex); + } + } + + if let Some(args) = matches.values_of("clang-args") { + for arg in args { + builder = builder.clang_arg(arg); + } + } + + let output = if let Some(path) = matches.value_of("output") { + let file = try!(File::create(path)); + Box::new(io::BufWriter::new(file)) as Box<io::Write> + } else { + Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write> + }; + + Ok((builder, output)) +} diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 00000000..0e4164f0 --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,104 @@ +//! Common traits and types related to parsing our IR from Clang cursors. + +use clang; +use ir::context::{BindgenContext, ItemId}; +use ir::ty::TypeKind; + +/// Not so much an error in the traditional sense, but a control flow message +/// when walking over Clang's AST with a cursor. +#[derive(Debug)] +pub enum ParseError { + /// Recurse down the current AST node's children. + Recurse, + /// Continue on to the next sibling AST node, or back up to the parent's + /// siblings if we've exhausted all of this node's siblings (and so on). + Continue, +} + +/// The result of parsing a Clang AST node. +#[derive(Debug)] +pub enum ParseResult<T> { + /// We've already resolved this item before, here is the extant `ItemId` for + /// it. + AlreadyResolved(ItemId), + + /// This is a newly parsed item. If the cursor is `Some`, it points to the + /// AST node where the new `T` was declared. + New(T, Option<clang::Cursor>), +} + +/// An intermediate representation "sub-item" (i.e. one of the types contained +/// inside an `ItemKind` variant) that can be parsed from a Clang cursor. +pub trait ClangSubItemParser: Sized { + /// Attempt to parse this type from the given cursor. + /// + /// The fact that is a reference guarantees it's held by the context, and + /// allow returning already existing types. + fn parse(cursor: clang::Cursor, + context: &mut BindgenContext) + -> Result<ParseResult<Self>, ParseError>; +} + +/// An intermediate representation item that can be parsed from a Clang cursor. +pub trait ClangItemParser: Sized { + /// Parse this item from the given Clang cursor. + fn parse(cursor: clang::Cursor, + parent: Option<ItemId>, + context: &mut BindgenContext) + -> Result<ItemId, ParseError>; + + /// Parse this item from the given Clang type. + fn from_ty(ty: &clang::Type, + location: Option<clang::Cursor>, + parent: Option<ItemId>, + ctx: &mut BindgenContext) + -> Result<ItemId, ParseError>; + + /// Identical to `from_ty`, but use the given `id` as the `ItemId` for the + /// newly parsed item. + fn from_ty_with_id(id: ItemId, + ty: &clang::Type, + location: Option<clang::Cursor>, + parent: Option<ItemId>, + ctx: &mut BindgenContext) + -> Result<ItemId, ParseError>; + + /// Parse this item from the given Clang type, or if we haven't resolved all + /// the other items this one depends on, an unresolved reference. + fn from_ty_or_ref(ty: clang::Type, + location: Option<clang::Cursor>, + parent_id: Option<ItemId>, + context: &mut BindgenContext) + -> ItemId; + + /// Identical to `from_ty_or_ref`, but use the given `potential_id` as the + /// `ItemId` for the newly parsed item. + fn from_ty_or_ref_with_id(potential_id: ItemId, + ty: clang::Type, + location: Option<clang::Cursor>, + parent_id: Option<ItemId>, + context: &mut BindgenContext) + -> ItemId; + + /// Create a named template type. + fn named_type<S>(name: S, + parent: ItemId, + context: &mut BindgenContext) + -> ItemId + where S: Into<String>; + + /// Identical to `named_type`, but use `id` as the resulting item's + /// `ItemId`. + fn named_type_with_id<S>(id: ItemId, + name: S, + parent: ItemId, + context: &mut BindgenContext) + -> ItemId + where S: Into<String>; + + /// Create a builtin type. + fn builtin_type(kind: TypeKind, + is_const: bool, + context: &mut BindgenContext) + -> ItemId; +} diff --git a/src/regex_set.rs b/src/regex_set.rs new file mode 100644 index 00000000..dbdb6565 --- /dev/null +++ b/src/regex_set.rs @@ -0,0 +1,69 @@ +//! A type that represents the union of a set of regular expressions. + +use regex::RegexSet as RxSet; + +// Yeah, I'm aware this is sorta crappy, should be cheaper to compile a regex +// ORing all the patterns, I guess... + +/// A dynamic set of regular expressions. +#[derive(Debug)] +pub struct RegexSet { + items: Vec<String>, + set: Option<RxSet>, +} + +impl RegexSet { + /// Is this set empty? + pub fn is_empty(&self) -> bool { + self.items.is_empty() + } + + /// Extend this set with every regex in the iterator. + pub fn extend<I, S>(&mut self, iter: I) + where I: IntoIterator<Item = S>, + S: AsRef<str> + { + for s in iter.into_iter() { + self.insert(s) + } + } + + /// Insert a new regex into this set. + pub fn insert<S>(&mut self, string: S) + where S: AsRef<str> + { + self.items.push(format!("^{}$", string.as_ref())); + self.set = None; + } + + /// Construct a RegexSet from the set of entries we've accumulated. + /// + /// Must be called before calling `matches()`, or it will always return + /// false. + pub fn build(&mut self) { + self.set = match RxSet::new(&self.items) { + Ok(x) => Some(x), + Err(e) => { + error!("Invalid regex in {:?}: {:?}", self.items, e); + None + }, + } + } + + /// Does the given `string` match any of the regexes in this set? + pub fn matches<S>(&self, string: S) -> bool + where S: AsRef<str> + { + let s = string.as_ref(); + self.set.as_ref().map(|set| set.is_match(s)).unwrap_or(false) + } +} + +impl Default for RegexSet { + fn default() -> Self { + RegexSet { + items: vec![], + set: None, + } + } +} diff --git a/src/uses.rs b/src/uses.rs new file mode 100644 index 00000000..47f72da6 --- /dev/null +++ b/src/uses.rs @@ -0,0 +1,102 @@ +//! Take in our IR and output a C/C++ file with dummy uses of each IR type. +//! +//! Say that we had this C++ header, `header.hpp`: +//! +//! ```c++ +//! class Point { +//! int x; +//! int y; +//! } +//! +//! enum Bar { +//! THIS, +//! THAT, +//! OTHER +//! } +//! ``` +//! +//! If we generated dummy uses for this header, we would get a `.cpp` file like +//! this: +//! +//! ```c++ +//! #include "header.hpp" +//! +//! void dummy(Point*) {} +//! void dummy(Bar*) {} +//! ``` +//! +//! This is useful because we can compile this `.cpp` file into an object file, +//! and then compare its debugging information to the debugging information +//! generated for our Rust bindings. These two sets of debugging information had +//! better agree on the C/C++ types' physical layout, or else our bindings are +//! incorrect! +//! +//! "But you still haven't explained why we have to generate the dummy uses" you +//! complain. Well if the types are never used, then they are elided when the +//! C/C++ compiler generates debugging information. + +use ir::context::BindgenContext; +use ir::item::{Item, ItemAncestors, ItemCanonicalName}; +use std::io; + +// Like `canonical_path`, except we always take namespaces into account, ignore +// the generated names of anonymous items, and return a `String`. +// +// TODO: Would it be easier to try and demangle the USR? +fn namespaced_name(ctx: &BindgenContext, item: &Item) -> String { + let mut names: Vec<_> = item.ancestors(ctx) + .map(|id| ctx.resolve_item(id).canonical_name(ctx)) + .filter(|name| !name.starts_with("_bindgen_")) + .collect(); + names.reverse(); + names.join("::") +} + +/// Generate the dummy uses for all the items in the given context, and write +/// the dummy uses to `dest`. +pub fn generate_dummy_uses<W>(ctx: &mut BindgenContext, + mut dest: W) + -> io::Result<()> + where W: io::Write, +{ + ctx.gen(|ctx| { + let input_header = ctx.options() + .input_header + .as_ref() + .expect("Should not generate dummy uses without an input header"); + + try!(writeln!(dest, "/* automatically generated by rust-bindgen */")); + try!(writeln!(dest, "")); + try!(writeln!(dest, "#include \"{}\"", input_header)); + try!(writeln!(dest, "")); + + let type_items = ctx.whitelisted_items() + .map(|id| ctx.resolve_item(id)) + .filter(|item| { + // We only want type items. + if let Some(ty) = item.kind().as_type() { + // However, we don't want anonymous types, as we can't + // generate dummy uses for them. + ty.name().is_some() && + // Nor do we want builtin types or named template type + // arguments. Again, we can't generate dummy uses for + // these. + !ty.is_builtin_or_named() && + // And finally, we won't be creating any dummy + // specializations, so ignore template declarations and + // partial specializations. + item.applicable_template_args(ctx).is_empty() + } else { + false + } + }) + .map(|item| namespaced_name(ctx, item)) + .enumerate(); + + for (idx, name) in type_items { + try!(writeln!(dest, "void dummy{}({}*) {{ }}", idx, name)); + } + + Ok(()) + }) +} |