diff options
author | Emilio Cobos Álvarez <emilio@crisal.io> | 2017-01-22 12:58:12 +0100 |
---|---|---|
committer | Emilio Cobos Álvarez <emilio@crisal.io> | 2017-01-23 10:22:08 +0100 |
commit | b83da2729fc83663f979da05201920e039ae3c3f (patch) | |
tree | 27e1c8b1b7f0fef74b064740238da843d4cfc1f6 /libbindgen/src | |
parent | 7373a4258f652c23e5fe00ad14740393caa40082 (diff) |
Unify under the `bindgen` name.
Diffstat (limited to 'libbindgen/src')
-rw-r--r-- | libbindgen/src/chooser.rs | 26 | ||||
-rw-r--r-- | libbindgen/src/clang.rs | 1371 | ||||
-rw-r--r-- | libbindgen/src/codegen/helpers.rs | 190 | ||||
-rw-r--r-- | libbindgen/src/codegen/mod.rs | 2341 | ||||
-rw-r--r-- | libbindgen/src/ir/annotations.rs | 188 | ||||
-rw-r--r-- | libbindgen/src/ir/comp.rs | 962 | ||||
-rw-r--r-- | libbindgen/src/ir/context.rs | 1267 | ||||
-rw-r--r-- | libbindgen/src/ir/derive.rs | 67 | ||||
-rw-r--r-- | libbindgen/src/ir/enum_ty.rs | 183 | ||||
-rw-r--r-- | libbindgen/src/ir/function.rs | 318 | ||||
-rw-r--r-- | libbindgen/src/ir/int.rs | 113 | ||||
-rw-r--r-- | libbindgen/src/ir/item.rs | 1370 | ||||
-rw-r--r-- | libbindgen/src/ir/item_kind.rs | 114 | ||||
-rw-r--r-- | libbindgen/src/ir/layout.rs | 91 | ||||
-rw-r--r-- | libbindgen/src/ir/mod.rs | 19 | ||||
-rw-r--r-- | libbindgen/src/ir/module.rs | 78 | ||||
-rw-r--r-- | libbindgen/src/ir/ty.rs | 926 | ||||
-rw-r--r-- | libbindgen/src/ir/type_collector.rs | 22 | ||||
-rw-r--r-- | libbindgen/src/ir/var.rs | 317 | ||||
-rw-r--r-- | libbindgen/src/lib.rs | 808 | ||||
-rw-r--r-- | libbindgen/src/log_stubs.rs | 30 | ||||
-rw-r--r-- | libbindgen/src/parse.rs | 104 | ||||
-rw-r--r-- | libbindgen/src/regex_set.rs | 69 | ||||
-rw-r--r-- | libbindgen/src/uses.rs | 102 |
24 files changed, 0 insertions, 11076 deletions
diff --git a/libbindgen/src/chooser.rs b/libbindgen/src/chooser.rs deleted file mode 100644 index 51392d70..00000000 --- a/libbindgen/src/chooser.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! 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/libbindgen/src/clang.rs b/libbindgen/src/clang.rs deleted file mode 100644 index 491aaa07..00000000 --- a/libbindgen/src/clang.rs +++ /dev/null @@ -1,1371 +0,0 @@ -//! 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/libbindgen/src/codegen/helpers.rs b/libbindgen/src/codegen/helpers.rs deleted file mode 100644 index 06dadab0..00000000 --- a/libbindgen/src/codegen/helpers.rs +++ /dev/null @@ -1,190 +0,0 @@ -//! 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/libbindgen/src/codegen/mod.rs b/libbindgen/src/codegen/mod.rs deleted file mode 100644 index 7451dd11..00000000 --- a/libbindgen/src/codegen/mod.rs +++ /dev/null @@ -1,2341 +0,0 @@ -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/libbindgen/src/ir/annotations.rs b/libbindgen/src/ir/annotations.rs deleted file mode 100644 index 98be0540..00000000 --- a/libbindgen/src/ir/annotations.rs +++ /dev/null @@ -1,188 +0,0 @@ -//! 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/libbindgen/src/ir/comp.rs b/libbindgen/src/ir/comp.rs deleted file mode 100644 index 968bf879..00000000 --- a/libbindgen/src/ir/comp.rs +++ /dev/null @@ -1,962 +0,0 @@ -//! 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/libbindgen/src/ir/context.rs b/libbindgen/src/ir/context.rs deleted file mode 100644 index b0143bd5..00000000 --- a/libbindgen/src/ir/context.rs +++ /dev/null @@ -1,1267 +0,0 @@ -//! Common context that is passed around during parsing and codegen. - -use BindgenOptions; -use cexpr; -use chooser::TypeChooser; -use clang::{self, Cursor}; -use parse::ClangItemParser; -use std::borrow::Cow; -use std::cell::Cell; -use std::collections::{HashMap, VecDeque, hash_map}; -use std::collections::btree_map::{self, BTreeMap}; -use std::fmt; -use super::derive::{CanDeriveCopy, CanDeriveDebug}; -use super::int::IntKind; -use super::item::{Item, ItemCanonicalPath}; -use super::item_kind::ItemKind; -use super::module::{Module, ModuleKind}; -use super::ty::{FloatKind, Type, TypeKind}; -use super::type_collector::{ItemSet, TypeCollector}; -use syntax::ast::Ident; -use syntax::codemap::{DUMMY_SP, Span}; -use syntax::ext::base::ExtCtxt; - -/// A single identifier for an item. -/// -/// TODO: Build stronger abstractions on top of this, like TypeId(ItemId)? -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ItemId(usize); - -impl ItemId { - /// Get a numeric representation of this id. - pub fn as_usize(&self) -> usize { - self.0 - } -} - -impl CanDeriveDebug for ItemId { - type Extra = (); - - fn can_derive_debug(&self, ctx: &BindgenContext, _: ()) -> bool { - ctx.resolve_item(*self).can_derive_debug(ctx, ()) - } -} - -impl<'a> CanDeriveCopy<'a> for ItemId { - type Extra = (); - - fn can_derive_copy(&self, ctx: &BindgenContext, _: ()) -> bool { - ctx.resolve_item(*self).can_derive_copy(ctx, ()) - } - - fn can_derive_copy_in_array(&self, ctx: &BindgenContext, _: ()) -> bool { - ctx.resolve_item(*self).can_derive_copy_in_array(ctx, ()) - } -} - -/// A key used to index a resolved type, so we only process it once. -/// -/// This is almost always a USR string (an unique identifier generated by -/// clang), but it can also be the canonical declaration if the type is unnamed, -/// in which case clang may generate the same USR for multiple nested unnamed -/// types. -#[derive(Eq, PartialEq, Hash, Debug)] -enum TypeKey { - USR(String), - Declaration(Cursor), -} - -// This is just convenience to avoid creating a manual debug impl for the -// context. -struct GenContext<'ctx>(ExtCtxt<'ctx>); - -impl<'ctx> fmt::Debug for GenContext<'ctx> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "GenContext {{ ... }}") - } -} - -/// A context used during parsing and generation of structs. -#[derive(Debug)] -pub struct BindgenContext<'ctx> { - /// The map of all the items parsed so far. - /// - /// It's a BTreeMap because we want the keys to be sorted to have consistent - /// output. - items: BTreeMap<ItemId, Item>, - - /// The next item id to use during this bindings regeneration. - next_item_id: ItemId, - - /// Clang USR to type map. This is needed to be able to associate types with - /// item ids during parsing. - types: HashMap<TypeKey, ItemId>, - - /// A cursor to module map. Similar reason than above. - modules: HashMap<Cursor, ItemId>, - - /// The root module, this is guaranteed to be an item of kind Module. - root_module: ItemId, - - /// Current module being traversed. - current_module: ItemId, - - /// A stack with the current type declarations and types we're parsing. This - /// is needed to avoid infinite recursion when parsing a type like: - /// - /// struct c { struct c* next; }; - /// - /// This means effectively, that a type has a potential ID before knowing if - /// it's a correct type. But that's not important in practice. - /// - /// We could also use the `types` HashMap, but my intention with it is that - /// only valid types and declarations end up there, and this could - /// potentially break that assumption. - /// - /// FIXME: Should not be public, though... meh. - pub currently_parsed_types: Vec<(Cursor, ItemId)>, - - /// A HashSet with all the already parsed macro names. This is done to avoid - /// hard errors while parsing duplicated macros, as well to allow macro - /// expression parsing. - parsed_macros: HashMap<Vec<u8>, cexpr::expr::EvalResult>, - - /// The active replacements collected from replaces="xxx" annotations. - replacements: HashMap<Vec<String>, ItemId>, - - collected_typerefs: bool, - - /// Dummy structures for code generation. - gen_ctx: Option<&'ctx GenContext<'ctx>>, - span: Span, - - /// The clang index for parsing. - index: clang::Index, - - /// The translation unit for parsing. - translation_unit: clang::TranslationUnit, - - /// The options given by the user via cli or other medium. - options: BindgenOptions, - - /// Whether a bindgen complex was generated - generated_bindegen_complex: Cell<bool>, -} - -impl<'ctx> BindgenContext<'ctx> { - /// Construct the context for the given `options`. - pub fn new(options: BindgenOptions) -> Self { - use clang_sys; - - let index = clang::Index::new(false, true); - - let parse_options = - clang_sys::CXTranslationUnit_DetailedPreprocessingRecord; - let translation_unit = - clang::TranslationUnit::parse(&index, - "", - &options.clang_args, - &[], - parse_options) - .expect("TranslationUnit::parse"); - - let root_module = Self::build_root_module(ItemId(0)); - let mut me = BindgenContext { - items: Default::default(), - types: Default::default(), - modules: Default::default(), - next_item_id: ItemId(1), - root_module: root_module.id(), - current_module: root_module.id(), - currently_parsed_types: vec![], - parsed_macros: Default::default(), - replacements: Default::default(), - collected_typerefs: false, - gen_ctx: None, - span: DUMMY_SP, - index: index, - translation_unit: translation_unit, - options: options, - generated_bindegen_complex: Cell::new(false), - }; - - me.add_item(root_module, None, None); - - me - } - - /// Get the user-provided type chooser by reference, if any. - pub fn type_chooser(&self) -> Option<&TypeChooser> { - self.options().type_chooser.as_ref().map(|t| &**t) - } - - /// Define a new item. - /// - /// This inserts it into the internal items set, and its type into the - /// internal types set. - pub fn add_item(&mut self, - item: Item, - declaration: Option<Cursor>, - location: Option<Cursor>) { - debug!("BindgenContext::add_item({:?}, declaration: {:?}, loc: {:?}", - item, - declaration, - location); - debug_assert!(declaration.is_some() || !item.kind().is_type() || - item.kind().expect_type().is_builtin_or_named(), - "Adding a type without declaration?"); - - let id = item.id(); - let is_type = item.kind().is_type(); - let is_unnamed = is_type && item.expect_type().name().is_none(); - - // Be sure to track all the generated children under namespace, even - // those generated after resolving typerefs, etc. - if item.id() != item.parent_id() { - if let Some(mut parent) = self.items.get_mut(&item.parent_id()) { - if let Some(mut module) = parent.as_module_mut() { - module.children_mut().push(item.id()); - } - } - } - - let old_item = self.items.insert(id, item); - assert!(old_item.is_none(), "Inserted type twice?"); - - // Unnamed items can have an USR, but they can't be referenced from - // other sites explicitly and the USR can match if the unnamed items are - // nested, so don't bother tracking them. - if is_type && declaration.is_some() { - let mut declaration = declaration.unwrap(); - if !declaration.is_valid() { - if let Some(location) = location { - if location.is_template_like() { - declaration = location; - } - } - } - declaration = declaration.canonical(); - if !declaration.is_valid() { - // This could happen, for example, with types like `int*` or - // similar. - // - // Fortunately, we don't care about those types being - // duplicated, so we can just ignore them. - debug!("Invalid declaration {:?} found for type {:?}", - declaration, - self.items.get(&id).unwrap().kind().expect_type()); - return; - } - - let key = if is_unnamed { - TypeKey::Declaration(declaration) - } else if let Some(usr) = declaration.usr() { - TypeKey::USR(usr) - } else { - warn!("Valid declaration with no USR: {:?}, {:?}", - declaration, - location); - TypeKey::Declaration(declaration) - }; - - let old = self.types.insert(key, id); - debug_assert_eq!(old, None); - } - } - - // TODO: Move all this syntax crap to other part of the code. - - /// Given that we are in the codegen phase, get the syntex context. - pub fn ext_cx(&self) -> &ExtCtxt<'ctx> { - &self.gen_ctx.expect("Not in gen phase").0 - } - - /// Given that we are in the codegen phase, get the current syntex span. - pub fn span(&self) -> Span { - self.span - } - - /// Mangles a name so it doesn't conflict with any keyword. - pub fn rust_mangle<'a>(&self, name: &'a str) -> Cow<'a, str> { - use syntax::parse::token; - let ident = self.rust_ident_raw(name); - let token = token::Ident(ident); - if token.is_any_keyword() || name.contains("@") || - name.contains("?") || name.contains("$") || - "bool" == name { - let mut s = name.to_owned(); - s = s.replace("@", "_"); - s = s.replace("?", "_"); - s = s.replace("$", "_"); - s.push_str("_"); - return Cow::Owned(s); - } - Cow::Borrowed(name) - } - - /// Returns a mangled name as a rust identifier. - pub fn rust_ident(&self, name: &str) -> Ident { - self.rust_ident_raw(&self.rust_mangle(name)) - } - - /// Returns a mangled name as a rust identifier. - pub fn rust_ident_raw(&self, name: &str) -> Ident { - self.ext_cx().ident_of(name) - } - - /// Iterate over all items that have been defined. - pub fn items<'a>(&'a self) -> btree_map::Iter<'a, ItemId, Item> { - self.items.iter() - } - - /// Have we collected all unresolved type references yet? - pub fn collected_typerefs(&self) -> bool { - self.collected_typerefs - } - - /// Gather all the unresolved type references. - fn collect_typerefs - (&mut self) - -> Vec<(ItemId, clang::Type, Option<clang::Cursor>, Option<ItemId>)> { - debug_assert!(!self.collected_typerefs); - self.collected_typerefs = true; - let mut typerefs = vec![]; - for (id, ref mut item) in &mut self.items { - let kind = item.kind(); - let ty = match kind.as_type() { - Some(ty) => ty, - None => continue, - }; - - match *ty.kind() { - TypeKind::UnresolvedTypeRef(ref ty, loc, parent_id) => { - typerefs.push((*id, ty.clone(), loc, parent_id)); - } - _ => {} - }; - } - typerefs - } - - /// Collect all of our unresolved type references and resolve them. - fn resolve_typerefs(&mut self) { - let typerefs = self.collect_typerefs(); - - for (id, ty, loc, parent_id) in typerefs { - let _resolved = { - let resolved = Item::from_ty(&ty, loc, parent_id, self) - .expect("What happened?"); - let mut item = self.items.get_mut(&id).unwrap(); - - *item.kind_mut().as_type_mut().unwrap().kind_mut() = - TypeKind::ResolvedTypeRef(resolved); - resolved - }; - - // Something in the STL is trolling me. I don't need this assertion - // right now, but worth investigating properly once this lands. - // - // debug_assert!(self.items.get(&resolved).is_some(), "How?"); - } - } - - /// Iterate over all items and replace any item that has been named in a - /// `replaces="SomeType"` annotation with the replacement type. - fn process_replacements(&mut self) { - if self.replacements.is_empty() { - debug!("No replacements to process"); - return; - } - - // FIXME: This is linear, but the replaces="xxx" annotation was already - // there, and for better or worse it's useful, sigh... - // - // We leverage the ResolvedTypeRef thing, though, which is cool :P. - - let mut replacements = vec![]; - - for (id, item) in self.items.iter() { - if item.annotations().use_instead_of().is_some() { - continue; - } - - // Calls to `canonical_name` are expensive, so eagerly filter out - // items that cannot be replaced. - let ty = match item.kind().as_type() { - Some(ty) => ty, - None => continue, - }; - - match *ty.kind() { - TypeKind::Comp(ref ci) if !ci.is_template_specialization() => {} - TypeKind::TemplateAlias(..) | - TypeKind::Alias(..) => {} - _ => continue, - } - - let path = item.canonical_path(self); - let replacement = self.replacements.get(&path[1..]); - - if let Some(replacement) = replacement { - if replacement != id { - // We set this just after parsing the annotation. It's - // very unlikely, but this can happen. - if self.items.get(replacement).is_some() { - replacements.push((*id, *replacement)); - } - } - } - } - - for (id, replacement) in replacements { - debug!("Replacing {:?} with {:?}", id, replacement); - - let new_parent = { - let mut item = self.items.get_mut(&id).unwrap(); - *item.kind_mut().as_type_mut().unwrap().kind_mut() = - TypeKind::ResolvedTypeRef(replacement); - item.parent_id() - }; - - - // Reparent the item. - let old_parent = self.resolve_item(replacement).parent_id(); - - if new_parent == old_parent { - continue; - } - - if let Some(mut module) = self.items - .get_mut(&old_parent) - .unwrap() - .as_module_mut() { - // Deparent the replacement. - let position = module.children() - .iter() - .position(|id| *id == replacement) - .unwrap(); - module.children_mut().remove(position); - } - - if let Some(mut module) = self.items - .get_mut(&new_parent) - .unwrap() - .as_module_mut() { - module.children_mut().push(replacement); - } - - self.items - .get_mut(&replacement) - .unwrap() - .set_parent_for_replacement(new_parent); - self.items - .get_mut(&id) - .unwrap() - .set_parent_for_replacement(old_parent); - } - } - - /// Enter the code generation phase, invoke the given callback `cb`, and - /// leave the code generation phase. - pub fn gen<F, Out>(&mut self, cb: F) -> Out - where F: FnOnce(&Self) -> Out, - { - use aster::symbol::ToSymbol; - use syntax::ext::expand::ExpansionConfig; - use syntax::codemap::{ExpnInfo, MacroBang, NameAndSpan}; - use syntax::ext::base; - use syntax::parse; - use std::mem; - - let cfg = ExpansionConfig::default("xxx".to_owned()); - let sess = parse::ParseSess::new(); - let mut loader = base::DummyResolver; - let mut ctx = GenContext(base::ExtCtxt::new(&sess, cfg, &mut loader)); - - ctx.0.bt_push(ExpnInfo { - call_site: self.span, - callee: NameAndSpan { - format: MacroBang("".to_symbol()), - allow_internal_unstable: false, - span: None, - }, - }); - - // FIXME: This is evil, we should move code generation to use a wrapper - // of BindgenContext instead, I guess. Even though we know it's fine - // because we remove it before the end of this function. - self.gen_ctx = Some(unsafe { mem::transmute(&ctx) }); - - self.assert_no_dangling_references(); - - if !self.collected_typerefs() { - self.resolve_typerefs(); - self.process_replacements(); - } - - let ret = cb(self); - self.gen_ctx = None; - ret - } - - /// This function trying to find any dangling references inside of `items` - fn assert_no_dangling_references(&self) { - if cfg!(feature = "assert_no_dangling_items") { - for _ in self.assert_no_dangling_item_traversal() { - // The iterator's next method does the asserting for us. - } - } - } - - fn assert_no_dangling_item_traversal<'me> - (&'me self) - -> AssertNoDanglingItemIter<'me, 'ctx> { - assert!(self.in_codegen_phase()); - assert!(self.current_module == self.root_module); - - let mut roots = self.items().map(|(&id, _)| id); - - let mut seen = BTreeMap::<ItemId, ItemId>::new(); - let next_child = roots.next().map(|id| id).unwrap(); - seen.insert(next_child, next_child); - - let to_iterate = seen.iter().map(|(&id, _)| id).rev().collect(); - - AssertNoDanglingItemIter { - ctx: self, - seen: seen, - to_iterate: to_iterate, - } - } - - // This deserves a comment. Builtin types don't get a valid declaration, so - // we can't add it to the cursor->type map. - // - // That being said, they're not generated anyway, and are few, so the - // duplication and special-casing is fine. - // - // If at some point we care about the memory here, probably a map TypeKind - // -> builtin type ItemId would be the best to improve that. - fn add_builtin_item(&mut self, item: Item) { - debug!("add_builtin_item: item = {:?}", item); - debug_assert!(item.kind().is_type()); - let id = item.id(); - let old_item = self.items.insert(id, item); - assert!(old_item.is_none(), "Inserted type twice?"); - } - - fn build_root_module(id: ItemId) -> Item { - let module = Module::new(Some("root".into()), ModuleKind::Normal); - Item::new(id, None, None, id, ItemKind::Module(module)) - } - - /// Get the root module. - pub fn root_module(&self) -> ItemId { - self.root_module - } - - /// Resolve the given `ItemId` as a type. - /// - /// Panics if there is no item for the given `ItemId` or if the resolved - /// item is not a `Type`. - pub fn resolve_type(&self, type_id: ItemId) -> &Type { - self.items.get(&type_id).unwrap().kind().expect_type() - } - - /// Resolve the given `ItemId` as a type, or `None` if there is no item with - /// the given id. - /// - /// Panics if the id resolves to an item that is not a type. - pub fn safe_resolve_type(&self, type_id: ItemId) -> Option<&Type> { - self.items.get(&type_id).map(|t| t.kind().expect_type()) - } - - /// Resolve the given `ItemId` into an `Item`, or `None` if no such item - /// exists. - pub fn resolve_item_fallible(&self, item_id: ItemId) -> Option<&Item> { - self.items.get(&item_id) - } - - /// Resolve the given `ItemId` into an `Item`. - /// - /// Panics if the given id does not resolve to any item. - pub fn resolve_item(&self, item_id: ItemId) -> &Item { - match self.items.get(&item_id) { - Some(item) => item, - None => panic!("Not an item: {:?}", item_id), - } - } - - /// Get the current module. - pub fn current_module(&self) -> ItemId { - self.current_module - } - - /// This is one of the hackiest methods in all the parsing code. This method - /// is used to allow having templates with another argument names instead of - /// the canonical ones. - /// - /// This is surprisingly difficult to do with libclang, due to the fact that - /// partial template specializations don't provide explicit template - /// argument information. - /// - /// The only way to do this as far as I know, is inspecting manually the - /// AST, looking for TypeRefs inside. This, unfortunately, doesn't work for - /// more complex cases, see the comment on the assertion below. - /// - /// To see an example of what this handles: - /// - /// ```c++ - /// template<typename T> - /// class Incomplete { - /// T p; - /// }; - /// - /// template<typename U> - /// class Foo { - /// Incomplete<U> bar; - /// }; - /// ``` - fn build_template_wrapper(&mut self, - with_id: ItemId, - wrapping: ItemId, - parent_id: ItemId, - ty: &clang::Type, - location: clang::Cursor, - declaration: clang::Cursor) - -> ItemId { - use clang_sys::*; - let mut args = vec![]; - location.visit(|c| { - if c.kind() == CXCursor_TypeRef { - // The `with_id` id will potentially end up unused if we give up - // on this type (for example, its a tricky partial template - // specialization), so if we pass `with_id` as the parent, it is - // potentially a dangling reference. Instead, use the canonical - // template declaration as the parent. It is already parsed and - // has a known-resolvable `ItemId`. - let new_ty = Item::from_ty_or_ref(c.cur_type(), - Some(c), - Some(wrapping), - self); - args.push(new_ty); - } - CXChildVisit_Continue - }); - - let item = { - let wrapping_type = self.resolve_type(wrapping); - if let TypeKind::Comp(ref ci) = *wrapping_type.kind() { - let old_args = ci.template_args(); - - // The following assertion actually fails with partial template - // specialization. But as far as I know there's no way at all to - // grab the specialized types from neither the AST or libclang, - // which sucks. The same happens for specialized type alias - // template declarations, where we have that ugly hack up there. - // - // This flaw was already on the old parser, but I now think it - // has no clear solution (apart from patching libclang to - // somehow expose them, of course). - // - // For an easy example in which there's no way at all of getting - // the `int` type, except manually parsing the spelling: - // - // template<typename T, typename U> - // class Incomplete { - // T d; - // U p; - // }; - // - // template<typename U> - // class Foo { - // Incomplete<U, int> bar; - // }; - // - // debug_assert_eq!(old_args.len(), args.len()); - // - // That being said, this is not so common, so just error! and - // hope for the best, returning the previous type, who knows. - if old_args.len() != args.len() { - error!("Found partial template specialization, \ - expect dragons!"); - return wrapping; - } - } else { - assert_eq!(declaration.kind(), - ::clang_sys::CXCursor_TypeAliasTemplateDecl, - "Expected wrappable type"); - } - - let type_kind = TypeKind::TemplateRef(wrapping, args); - let name = ty.spelling(); - let name = if name.is_empty() { None } else { Some(name) }; - let ty = Type::new(name, - ty.fallible_layout().ok(), - type_kind, - ty.is_const()); - Item::new(with_id, None, None, parent_id, ItemKind::Type(ty)) - }; - - // Bypass all the validations in add_item explicitly. - debug!("build_template_wrapper: inserting item: {:?}", item); - debug_assert!(with_id == item.id()); - self.items.insert(with_id, item); - with_id - } - - /// Looks up for an already resolved type, either because it's builtin, or - /// because we already have it in the map. - pub fn builtin_or_resolved_ty(&mut self, - with_id: ItemId, - parent_id: Option<ItemId>, - ty: &clang::Type, - location: Option<clang::Cursor>) - -> Option<ItemId> { - use clang_sys::{CXCursor_TypeAliasTemplateDecl, CXCursor_TypeRef}; - debug!("builtin_or_resolved_ty: {:?}, {:?}, {:?}", - ty, - location, - parent_id); - let mut declaration = ty.declaration(); - if !declaration.is_valid() { - if let Some(location) = location { - if location.is_template_like() { - declaration = location; - } - } - } - let canonical_declaration = declaration.canonical(); - if canonical_declaration.is_valid() { - let id = self.types - .get(&TypeKey::Declaration(canonical_declaration)) - .map(|id| *id) - .or_else(|| { - canonical_declaration.usr() - .and_then(|usr| self.types.get(&TypeKey::USR(usr))) - .map(|id| *id) - }); - if let Some(id) = id { - debug!("Already resolved ty {:?}, {:?}, {:?} {:?}", - id, - declaration, - ty, - location); - - // If the declaration existed, we *might* be done, but it's not - // the case for class templates, where the template arguments - // may vary. - // - // In this case, we create a TemplateRef with the new template - // arguments, pointing to the canonical template. - // - // Note that we only do it if parent_id is some, and we have a - // location for building the new arguments, the template - // argument names don't matter in the global context. - if declaration.is_template_like() && - *ty != canonical_declaration.cur_type() && - location.is_some() && - parent_id.is_some() { - // For specialized type aliases, there's no way to get the - // template parameters as of this writing (for a struct - // specialization we wouldn't be in this branch anyway). - // - // Explicitly return `None` if there aren't any - // unspecialized parameters (contains any `TypeRef`) so we - // resolve the canonical type if there is one and it's - // exposed. - // - // This is _tricky_, I know :( - if declaration.kind() == CXCursor_TypeAliasTemplateDecl && - !location.unwrap().contains_cursor(CXCursor_TypeRef) && - ty.canonical_type().is_valid_and_exposed() { - return None; - } - - return Some(self.build_template_wrapper(with_id, - id, - parent_id.unwrap(), - ty, - location.unwrap(), - declaration)); - } - - return Some(self.build_ty_wrapper(with_id, id, parent_id, ty)); - } - } - - debug!("Not resolved, maybe builtin?"); - - // Else, build it. - self.build_builtin_ty(ty, declaration) - } - - // This is unfortunately a lot of bloat, but is needed to properly track - // constness et. al. - // - // We should probably make the constness tracking separate, so it doesn't - // bloat that much, but hey, we already bloat the heck out of builtin types. - fn build_ty_wrapper(&mut self, - with_id: ItemId, - wrapped_id: ItemId, - parent_id: Option<ItemId>, - ty: &clang::Type) - -> ItemId { - let spelling = ty.spelling(); - let is_const = ty.is_const(); - let layout = ty.fallible_layout().ok(); - let type_kind = TypeKind::ResolvedTypeRef(wrapped_id); - let ty = Type::new(Some(spelling), layout, type_kind, is_const); - let item = Item::new(with_id, - None, - None, - parent_id.unwrap_or(self.current_module), - ItemKind::Type(ty)); - self.add_builtin_item(item); - with_id - } - - /// Returns the next item id to be used for an item. - pub fn next_item_id(&mut self) -> ItemId { - let ret = self.next_item_id; - self.next_item_id = ItemId(self.next_item_id.0 + 1); - ret - } - - fn build_builtin_ty(&mut self, - ty: &clang::Type, - _declaration: Cursor) - -> Option<ItemId> { - use clang_sys::*; - let type_kind = match ty.kind() { - CXType_NullPtr => TypeKind::NullPtr, - CXType_Void => TypeKind::Void, - CXType_Bool => TypeKind::Int(IntKind::Bool), - CXType_Int => TypeKind::Int(IntKind::Int), - CXType_UInt => TypeKind::Int(IntKind::UInt), - CXType_SChar | CXType_Char_S => TypeKind::Int(IntKind::Char), - CXType_UChar | CXType_Char_U => TypeKind::Int(IntKind::UChar), - CXType_Short => TypeKind::Int(IntKind::Short), - CXType_UShort => TypeKind::Int(IntKind::UShort), - CXType_WChar | CXType_Char16 => TypeKind::Int(IntKind::U16), - CXType_Char32 => TypeKind::Int(IntKind::U32), - CXType_Long => TypeKind::Int(IntKind::Long), - CXType_ULong => TypeKind::Int(IntKind::ULong), - CXType_LongLong => TypeKind::Int(IntKind::LongLong), - CXType_ULongLong => TypeKind::Int(IntKind::ULongLong), - CXType_Int128 => TypeKind::Int(IntKind::I128), - CXType_UInt128 => TypeKind::Int(IntKind::U128), - CXType_Float => TypeKind::Float(FloatKind::Float), - CXType_Double => TypeKind::Float(FloatKind::Double), - CXType_LongDouble => TypeKind::Float(FloatKind::LongDouble), - CXType_Float128 => TypeKind::Float(FloatKind::Float128), - CXType_Complex => { - let float_type = ty.elem_type() - .expect("Not able to resolve complex type?"); - let float_kind = match float_type.kind() { - CXType_Float => FloatKind::Float, - CXType_Double => FloatKind::Double, - CXType_LongDouble => FloatKind::LongDouble, - _ => panic!("Non floating-type complex?"), - }; - TypeKind::Complex(float_kind) - } - _ => return None, - }; - - let spelling = ty.spelling(); - let is_const = ty.is_const(); - let layout = ty.fallible_layout().ok(); - let ty = Type::new(Some(spelling), layout, type_kind, is_const); - let id = self.next_item_id(); - let item = - Item::new(id, None, None, self.root_module, ItemKind::Type(ty)); - self.add_builtin_item(item); - Some(id) - } - - /// Get the current Clang translation unit that is being processed. - pub fn translation_unit(&self) -> &clang::TranslationUnit { - &self.translation_unit - } - - /// Have we parsed the macro named `macro_name` already? - pub fn parsed_macro(&self, macro_name: &[u8]) -> bool { - self.parsed_macros.contains_key(macro_name) - } - - /// Get the currently parsed macros. - pub fn parsed_macros(&self) -> &HashMap<Vec<u8>, cexpr::expr::EvalResult> { - debug_assert!(!self.in_codegen_phase()); - &self.parsed_macros - } - - /// Mark the macro named `macro_name` as parsed. - pub fn note_parsed_macro(&mut self, - id: Vec<u8>, - value: cexpr::expr::EvalResult) { - self.parsed_macros.insert(id, value); - } - - /// Are we in the codegen phase? - pub fn in_codegen_phase(&self) -> bool { - self.gen_ctx.is_some() - } - - /// Mark the type with the given `name` as replaced by the type with id - /// `potential_ty`. - /// - /// Replacement types are declared using the `replaces="xxx"` annotation, - /// and implies that the original type is hidden. - pub fn replace(&mut self, name: &[String], potential_ty: ItemId) { - match self.replacements.entry(name.into()) { - hash_map::Entry::Vacant(entry) => { - debug!("Defining replacement for {:?} as {:?}", - name, - potential_ty); - entry.insert(potential_ty); - } - hash_map::Entry::Occupied(occupied) => { - warn!("Replacement for {:?} already defined as {:?}; \ - ignoring duplicate replacement definition as {:?}", - name, - occupied.get(), - potential_ty); - } - } - } - - /// Is the item with the given `name` hidden? Or is the item with the given - /// `name` and `id` replaced by another type, and effectively hidden? - pub fn hidden_by_name(&self, path: &[String], id: ItemId) -> bool { - debug_assert!(self.in_codegen_phase(), - "You're not supposed to call this yet"); - self.options.hidden_types.matches(&path[1..].join("::")) || - self.is_replaced_type(path, id) - } - - /// Has the item with the given `name` and `id` been replaced by another - /// type? - pub fn is_replaced_type(&self, path: &[String], id: ItemId) -> bool { - match self.replacements.get(path) { - Some(replaced_by) if *replaced_by != id => true, - _ => false, - } - } - - /// Is the type with the given `name` marked as opaque? - pub fn opaque_by_name(&self, path: &[String]) -> bool { - debug_assert!(self.in_codegen_phase(), - "You're not supposed to call this yet"); - self.options.opaque_types.matches(&path[1..].join("::")) - } - - /// Get the options used to configure this bindgen context. - pub fn options(&self) -> &BindgenOptions { - &self.options - } - - /// Tokenizes a namespace cursor in order to get the name and kind of the - /// namespace, - fn tokenize_namespace(&self, - cursor: &clang::Cursor) - -> (Option<String>, ModuleKind) { - assert_eq!(cursor.kind(), ::clang_sys::CXCursor_Namespace, - "Be a nice person"); - let tokens = match self.translation_unit.tokens(&cursor) { - Some(tokens) => tokens, - None => return (None, ModuleKind::Normal), - }; - - let mut iter = tokens.iter(); - let mut kind = ModuleKind::Normal; - let mut found_namespace_keyword = false; - let mut module_name = None; - while let Some(token) = iter.next() { - match &*token.spelling { - "inline" => { - assert!(!found_namespace_keyword); - assert!(kind != ModuleKind::Inline); - kind = ModuleKind::Inline; - } - "namespace" => { - found_namespace_keyword = true; - } - "{" => { - assert!(found_namespace_keyword); - break; - } - name if found_namespace_keyword => { - module_name = Some(name.to_owned()); - break; - } - _ => { - panic!("Unknown token while processing namespace: {:?}", - token); - } - } - }; - - (module_name, kind) - } - - /// Given a CXCursor_Namespace cursor, return the item id of the - /// corresponding module, or create one on the fly. - pub fn module(&mut self, cursor: clang::Cursor) -> ItemId { - use clang_sys::*; - assert_eq!(cursor.kind(), CXCursor_Namespace, "Be a nice person"); - let cursor = cursor.canonical(); - if let Some(id) = self.modules.get(&cursor) { - return *id; - } - - let (module_name, kind) = self.tokenize_namespace(&cursor); - - let module_id = self.next_item_id(); - let module = Module::new(module_name, kind); - let module = Item::new(module_id, - None, - None, - self.current_module, - ItemKind::Module(module)); - - self.modules.insert(cursor, module.id()); - - self.add_item(module, None, None); - - module_id - } - - /// Start traversing the module with the given `module_id`, invoke the - /// callback `cb`, and then return to traversing the original module. - pub fn with_module<F>(&mut self, module_id: ItemId, cb: F) - where F: FnOnce(&mut Self), - { - debug_assert!(self.resolve_item(module_id).kind().is_module(), "Wat"); - - let previous_id = self.current_module; - self.current_module = module_id; - - cb(self); - - self.current_module = previous_id; - } - - /// Iterate over all (explicitly or transitively) whitelisted items. - /// - /// If no items are explicitly whitelisted, then all items are considered - /// whitelisted. - pub fn whitelisted_items<'me>(&'me self) - -> WhitelistedItemsIter<'me, 'ctx> { - assert!(self.in_codegen_phase()); - assert!(self.current_module == self.root_module); - - let roots = self.items() - .filter(|&(_, item)| { - // If nothing is explicitly whitelisted, then everything is fair - // game. - if self.options().whitelisted_types.is_empty() && - self.options().whitelisted_functions.is_empty() && - self.options().whitelisted_vars.is_empty() { - return true; - } - - // If this is a type that explicitly replaces another, we assume - // you know what you're doing. - if item.annotations().use_instead_of().is_some() { - return true; - } - - let name = item.canonical_path(self)[1..].join("::"); - debug!("whitelisted_items: testing {:?}", name); - match *item.kind() { - ItemKind::Module(..) => true, - ItemKind::Function(_) => { - self.options().whitelisted_functions.matches(&name) - } - ItemKind::Var(_) => { - self.options().whitelisted_vars.matches(&name) - } - ItemKind::Type(ref ty) => { - if self.options().whitelisted_types.matches(&name) { - return true; - } - - let parent = self.resolve_item(item.parent_id()); - if parent.is_module() { - let mut prefix_path = parent.canonical_path(self); - - // Unnamed top-level enums are special and we - // whitelist them via the `whitelisted_vars` filter, - // since they're effectively top-level constants, - // and there's no way for them to be referenced - // consistently. - if let TypeKind::Enum(ref enum_) = *ty.kind() { - if ty.name().is_none() && - enum_.variants().iter().any(|variant| { - prefix_path.push(variant.name().into()); - let name = prefix_path[1..].join("::"); - prefix_path.pop().unwrap(); - self.options() - .whitelisted_vars - .matches(&name) - }) { - return true; - } - } - } - - false - } - } - }) - .map(|(&id, _)| id); - - let seen: ItemSet = roots.collect(); - - // The .rev() preserves the expected ordering traversal, resulting in - // more stable-ish bindgen-generated names for anonymous types (like - // unions). - let to_iterate = seen.iter().cloned().rev().collect(); - - WhitelistedItemsIter { - ctx: self, - seen: seen, - to_iterate: to_iterate, - } - } - - /// Convenient method for getting the prefix to use for most traits in - /// codegen depending on the `use_core` option. - pub fn trait_prefix(&self) -> Ident { - if self.options().use_core { - self.rust_ident_raw("core") - } else { - self.rust_ident_raw("std") - } - } - - /// Call if a binden complex is generated - pub fn generated_bindegen_complex(&self) { - self.generated_bindegen_complex.set(true) - } - - /// Whether we need to generate the binden complex type - pub fn need_bindegen_complex_type(&self) -> bool { - self.generated_bindegen_complex.get() - } -} - -/// An iterator over whitelisted items. -/// -/// See `BindgenContext::whitelisted_items` for more information. -pub struct WhitelistedItemsIter<'ctx, 'gen> - where 'gen: 'ctx, -{ - ctx: &'ctx BindgenContext<'gen>, - - // The set of whitelisted items we have seen. If you think of traversing - // whitelisted items like GC tracing, this is the mark bits, and contains - // both black and gray items. - seen: ItemSet, - - // The set of whitelisted items that we have seen but have yet to iterate - // over and collect transitive references from. To return to the GC analogy, - // this is the mark stack, containing the set of gray items which we have - // not finished tracing yet. - to_iterate: Vec<ItemId>, -} - -impl<'ctx, 'gen> Iterator for WhitelistedItemsIter<'ctx, 'gen> - where 'gen: 'ctx, -{ - type Item = ItemId; - - fn next(&mut self) -> Option<Self::Item> { - let id = match self.to_iterate.pop() { - None => return None, - Some(id) => id, - }; - - debug_assert!(self.seen.contains(&id)); - debug_assert!(self.ctx.items.contains_key(&id)); - - let mut sub_types = ItemSet::new(); - id.collect_types(self.ctx, &mut sub_types, &()); - - for id in sub_types { - if self.seen.insert(id) { - self.to_iterate.push(id); - } - } - - Some(id) - } -} - -/// An iterator to find any dangling items. -/// -/// See `BindgenContext::assert_no_dangling_item_traversal` for more -/// information. -pub struct AssertNoDanglingItemIter<'ctx, 'gen> - where 'gen: 'ctx, -{ - ctx: &'ctx BindgenContext<'gen>, - seen: BTreeMap<ItemId, ItemId>, - to_iterate: VecDeque<ItemId>, -} - -impl<'ctx, 'gen> Iterator for AssertNoDanglingItemIter<'ctx, 'gen> - where 'gen: 'ctx, -{ - type Item = ItemId; - - fn next(&mut self) -> Option<Self::Item> { - let id = match self.to_iterate.pop_front() { - None => { - // We've traversed everything reachable from the previous - // root(s), see if we have any more roots. - match self.ctx - .items() - .filter(|&(id, _)| !self.seen.contains_key(id)) - .next() - .map(|(id, _)| *id) { - None => return None, - Some(id) => { - // This is a new root. - self.seen.insert(id, id); - id - } - } - } - Some(id) => id, - }; - - let mut sub_types = ItemSet::new(); - id.collect_types(self.ctx, &mut sub_types, &()); - - if self.ctx.resolve_item_fallible(id).is_none() { - let mut path = vec![]; - let mut current = id; - loop { - let predecessor = *self.seen - .get(¤t) - .expect("We know we found this item id, so it must have a \ - predecessor"); - if predecessor == current { - break; - } - path.push(predecessor); - current = predecessor; - } - path.reverse(); - panic!("Found reference to dangling id = {:?}\nvia path = {:?}", - id, - path); - } - - for sub_id in sub_types { - if self.seen.insert(sub_id, id).is_none() { - // We've never visited this sub item before. - self.to_iterate.push_back(sub_id); - } - } - - Some(id) - } -} diff --git a/libbindgen/src/ir/derive.rs b/libbindgen/src/ir/derive.rs deleted file mode 100644 index d13a8117..00000000 --- a/libbindgen/src/ir/derive.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! 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/libbindgen/src/ir/enum_ty.rs b/libbindgen/src/ir/enum_ty.rs deleted file mode 100644 index ca4e77db..00000000 --- a/libbindgen/src/ir/enum_ty.rs +++ /dev/null @@ -1,183 +0,0 @@ -//! 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/libbindgen/src/ir/function.rs b/libbindgen/src/ir/function.rs deleted file mode 100644 index 50c442db..00000000 --- a/libbindgen/src/ir/function.rs +++ /dev/null @@ -1,318 +0,0 @@ -//! 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/libbindgen/src/ir/int.rs b/libbindgen/src/ir/int.rs deleted file mode 100644 index 89068e0f..00000000 --- a/libbindgen/src/ir/int.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! 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/libbindgen/src/ir/item.rs b/libbindgen/src/ir/item.rs deleted file mode 100644 index df8fd222..00000000 --- a/libbindgen/src/ir/item.rs +++ /dev/null @@ -1,1370 +0,0 @@ -//! 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/libbindgen/src/ir/item_kind.rs b/libbindgen/src/ir/item_kind.rs deleted file mode 100644 index d9e4690c..00000000 --- a/libbindgen/src/ir/item_kind.rs +++ /dev/null @@ -1,114 +0,0 @@ -//! 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/libbindgen/src/ir/layout.rs b/libbindgen/src/ir/layout.rs deleted file mode 100644 index 033fff62..00000000 --- a/libbindgen/src/ir/layout.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! 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/libbindgen/src/ir/mod.rs b/libbindgen/src/ir/mod.rs deleted file mode 100644 index 73793b16..00000000 --- a/libbindgen/src/ir/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! 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/libbindgen/src/ir/module.rs b/libbindgen/src/ir/module.rs deleted file mode 100644 index 002fe36e..00000000 --- a/libbindgen/src/ir/module.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! 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/libbindgen/src/ir/ty.rs b/libbindgen/src/ir/ty.rs deleted file mode 100644 index c1ed5b64..00000000 --- a/libbindgen/src/ir/ty.rs +++ /dev/null @@ -1,926 +0,0 @@ -//! 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/libbindgen/src/ir/type_collector.rs b/libbindgen/src/ir/type_collector.rs deleted file mode 100644 index 0f10152d..00000000 --- a/libbindgen/src/ir/type_collector.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! 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/libbindgen/src/ir/var.rs b/libbindgen/src/ir/var.rs deleted file mode 100644 index 329393fa..00000000 --- a/libbindgen/src/ir/var.rs +++ /dev/null @@ -1,317 +0,0 @@ -//! 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/libbindgen/src/lib.rs b/libbindgen/src/lib.rs deleted file mode 100644 index 60b750de..00000000 --- a/libbindgen/src/lib.rs +++ /dev/null @@ -1,808 +0,0 @@ -//! 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/libbindgen/src/log_stubs.rs b/libbindgen/src/log_stubs.rs deleted file mode 100644 index 4262e120..00000000 --- a/libbindgen/src/log_stubs.rs +++ /dev/null @@ -1,30 +0,0 @@ -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/libbindgen/src/parse.rs b/libbindgen/src/parse.rs deleted file mode 100644 index 0e4164f0..00000000 --- a/libbindgen/src/parse.rs +++ /dev/null @@ -1,104 +0,0 @@ -//! 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/libbindgen/src/regex_set.rs b/libbindgen/src/regex_set.rs deleted file mode 100644 index dbdb6565..00000000 --- a/libbindgen/src/regex_set.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! 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/libbindgen/src/uses.rs b/libbindgen/src/uses.rs deleted file mode 100644 index 47f72da6..00000000 --- a/libbindgen/src/uses.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! 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(()) - }) -} |