summaryrefslogtreecommitdiff
path: root/src/ir
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir')
-rw-r--r--src/ir/annotations.rs141
-rw-r--r--src/ir/comp.rs718
-rw-r--r--src/ir/context.rs685
-rw-r--r--src/ir/enum_ty.rs110
-rw-r--r--src/ir/function.rs220
-rw-r--r--src/ir/int.rs30
-rw-r--r--src/ir/item.rs681
-rw-r--r--src/ir/item_kind.rs89
-rw-r--r--src/ir/layout.rs26
-rw-r--r--src/ir/mod.rs12
-rw-r--r--src/ir/module.rs52
-rw-r--r--src/ir/ty.rs537
-rw-r--r--src/ir/var.rs160
13 files changed, 3461 insertions, 0 deletions
diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs
new file mode 100644
index 00000000..cc61dbfd
--- /dev/null
+++ b/src/ir/annotations.rs
@@ -0,0 +1,141 @@
+use clang;
+
+#[derive(Copy, PartialEq, Clone, Debug)]
+pub enum FieldAccessorKind {
+ None,
+ Regular,
+ Unsafe,
+ Immutable,
+}
+
+/// Annotations for a given item, or a field.
+#[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.
+ hide: bool,
+ /// Whether this type should be replaced by another. The name must be the
+ /// canonical name that that type would get.
+ use_instead_of: Option<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>,
+}
+
+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
+ }
+ }
+}
+
+impl Annotations {
+ 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
+ }
+ }
+
+ pub fn hide(&self) -> bool {
+ self.hide
+ }
+
+ 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:
+ ///
+ /// ```rust
+ /// /** <div rustbindgen replaces="Bar"></div> */
+ /// struct Bar {
+ /// int x;
+ /// };
+ /// ```
+ ///
+ /// That is, code for `Foo` is used to generate `Bar`.
+ pub fn use_instead_of(&self) -> Option<&str> {
+ self.use_instead_of.as_ref().map(|s| &**s)
+ }
+
+ pub fn disallow_copy(&self) -> bool {
+ self.disallow_copy
+ }
+
+ pub fn private_fields(&self) -> Option<bool> {
+ self.private_fields
+ }
+
+ pub fn accessor_kind(&self) -> Option<FieldAccessorKind> {
+ self.accessor_kind
+ }
+
+ fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) {
+ use clangll::CXComment_HTMLStartTag;
+ if comment.kind() == CXComment_HTMLStartTag &&
+ comment.get_tag_name() == "div" &&
+ comment.get_num_tag_attrs() > 1 &&
+ comment.get_tag_attr_name(0) == "rustbindgen" {
+ *matched = true;
+ for i in 0..comment.get_num_tag_attrs() {
+ let value = comment.get_tag_attr_value(i);
+ let name = comment.get_tag_attr_name(i);
+ match name.as_str() {
+ "opaque" => self.opaque = true,
+ "hide" => self.hide = true,
+ "nocopy" => self.disallow_copy = true,
+ "replaces" => self.use_instead_of = Some(value),
+ "private" => self.private_fields = Some(value != "false"),
+ "accessor"
+ => self.accessor_kind = Some(parse_accessor(&value)),
+ _ => {},
+ }
+ }
+ }
+
+ for i in 0..comment.num_children() {
+ self.parse(&comment.get_child(i), matched);
+ }
+ }
+}
diff --git a/src/ir/comp.rs b/src/ir/comp.rs
new file mode 100644
index 00000000..1e6bf555
--- /dev/null
+++ b/src/ir/comp.rs
@@ -0,0 +1,718 @@
+use super::annotations::Annotations;
+use super::context::BindgenContext;
+use super::context::TypeResolver;
+use super::layout::Layout;
+use super::item::{Item, ItemId};
+use super::ty::{Type, RUST_DERIVE_IN_ARRAY_LIMIT};
+use std::cell::Cell;
+use std::cmp;
+use parse::{ClangItemParser, ParseError};
+use clang;
+
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum CompKind {
+ Struct,
+ Union,
+}
+
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum MethodKind {
+ Static,
+ Normal,
+ 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 {
+ fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self {
+ Method {
+ kind: kind,
+ signature: signature,
+ is_const: is_const,
+ }
+ }
+
+ pub fn kind(&self) -> MethodKind {
+ self.kind
+ }
+
+ pub fn is_virtual(&self) -> bool {
+ self.kind == MethodKind::Virtual
+ }
+
+ pub fn is_static(&self) -> bool {
+ self.kind == MethodKind::Static
+ }
+
+ pub fn signature(&self) -> ItemId {
+ self.signature
+ }
+
+ 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 {
+ 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,
+ }
+ }
+
+ pub fn name(&self) -> Option<&str> {
+ self.name.as_ref().map(|n| &**n)
+ }
+
+ pub fn ty(&self) -> ItemId {
+ self.ty
+ }
+
+ pub fn comment(&self) -> Option<&str> {
+ self.comment.as_ref().map(|c| &**c)
+ }
+
+ pub fn bitfield(&self) -> Option<u32> {
+ self.bitfield
+ }
+
+ pub fn is_mutable(&self) -> bool {
+ self.mutable
+ }
+
+ pub fn annotations(&self) -> &Annotations {
+ &self.annotations
+ }
+}
+
+
+#[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>,
+ /// Vector of classes this one inherits from.
+ base_members: Vec<ItemId>,
+ /// 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 {
+ pub fn new(kind: CompKind) -> Self {
+ CompInfo {
+ kind: kind,
+ fields: vec![],
+ template_args: vec![],
+ methods: 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),
+ }
+ }
+
+ pub fn can_derive_debug(&self, type_resolver: &TypeResolver, layout: Option<Layout>) -> bool {
+ // 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 {
+ let layout = layout.unwrap_or_else(Layout::zero);
+ let size_divisor = cmp::max(1, layout.align);
+ return layout.size / size_divisor <= RUST_DERIVE_IN_ARRAY_LIMIT;
+ }
+
+ self.detect_derive_debug_cycle.set(true);
+
+ let can_derive_debug =
+ self.template_args.iter().all(|ty| {
+ type_resolver.resolve_type(*ty)
+ .can_derive_debug(type_resolver)
+ }) &&
+ self.fields.iter().all(|field| {
+ type_resolver.resolve_type(field.ty)
+ .can_derive_debug(type_resolver)
+ });
+
+ self.detect_derive_debug_cycle.set(false);
+
+ can_derive_debug
+ }
+
+ pub fn is_unsized(&self, type_resolver: &TypeResolver) -> bool {
+ !self.has_vtable(type_resolver) && self.fields.is_empty() &&
+ self.base_members.iter().all(|base| {
+ type_resolver
+ .resolve_type(*base)
+ .canonical_type(type_resolver)
+ .is_unsized(type_resolver)
+ }) &&
+ self.ref_template.map_or(true, |template| {
+ type_resolver.resolve_type(template).is_unsized(type_resolver)
+ })
+ }
+
+ pub fn has_destructor(&self, type_resolver: &TypeResolver) -> 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| {
+ type_resolver.resolve_type(*t).has_destructor(type_resolver)
+ }) ||
+ self.template_args.iter().any(|t| {
+ type_resolver.resolve_type(*t).has_destructor(type_resolver)
+ }) ||
+ self.base_members.iter().any(|t| {
+ type_resolver.resolve_type(*t).has_destructor(type_resolver)
+ }) ||
+ self.fields.iter().any(|field| {
+ type_resolver.resolve_type(field.ty)
+ .has_destructor(type_resolver)
+ })
+ }
+ };
+
+ self.detect_has_destructor_cycle.set(false);
+
+ has_destructor
+ }
+
+ pub fn can_derive_copy(&self, type_resolver: &TypeResolver) -> bool {
+ // 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(type_resolver) {
+ return false;
+ }
+
+ match self.kind {
+ CompKind::Union => true,
+ CompKind::Struct => {
+ // 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| {
+ type_resolver.resolve_type(*t).can_derive_copy(type_resolver)
+ }) &&
+ self.base_members.iter().all(|t| {
+ type_resolver.resolve_type(*t).can_derive_copy(type_resolver)
+ }) &&
+ self.fields.iter().all(|field| {
+ type_resolver.resolve_type(field.ty)
+ .can_derive_copy(type_resolver)
+ })
+ }
+ }
+ }
+
+ pub fn is_template_specialization(&self) -> bool {
+ self.ref_template.is_some()
+ }
+
+ pub fn specialized_template(&self) -> Option<ItemId> {
+ self.ref_template
+ }
+
+ // Computes 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, type_resolver: &TypeResolver) -> 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 = type_resolver.resolve_type(field.ty)
+ .layout(type_resolver);
+
+ 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))
+ }
+
+ pub fn fields(&self) -> &[Field] {
+ &self.fields
+ }
+
+ pub fn template_args(&self) -> &[ItemId] {
+ &self.template_args
+ }
+
+ pub fn has_non_type_template_params(&self) -> bool {
+ self.has_non_type_template_params
+ }
+
+ pub fn has_vtable(&self, type_resolver: &TypeResolver) -> bool {
+ self.has_vtable || self.base_members().iter().any(|base| {
+ type_resolver
+ .resolve_type(*base)
+ .has_vtable(type_resolver)
+ }) || self.ref_template.map_or(false, |template| {
+ type_resolver.resolve_type(template).has_vtable(type_resolver)
+ })
+ }
+
+ pub fn methods(&self) -> &[Method] {
+ &self.methods
+ }
+
+ pub fn kind(&self) -> CompKind {
+ self.kind
+ }
+
+ pub fn base_members(&self) -> &[ItemId] {
+ &self.base_members
+ }
+
+ pub fn from_ty(potential_id: ItemId,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ ctx: &mut BindgenContext) -> Result<Self, ParseError> {
+ use clangll::*;
+ // 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.num_template_args() {
+ // In forward declarations and not specializations, etc, they are in
+ // the ast, we'll meet them in CXCursor_TemplateTypeParameter
+ -1 => vec![],
+ len => {
+ let mut list = Vec::with_capacity(len as usize);
+ for i in 0..len {
+ let arg_type = ty.template_arg_type(i);
+ if arg_type.kind() != CXType_Invalid {
+ let type_id =
+ Item::from_ty_or_ref(arg_type, None, None, ctx);
+
+ list.push(type_id);
+ } else {
+ ci.has_non_type_template_params = true;
+ warn!("warning: Template parameter is not a type");
+ }
+ }
+
+ list
+ }
+ };
+
+ ci.ref_template = Item::parse(cursor.specialized(), None, ctx).ok();
+
+ let mut maybe_anonymous_struct_field = None;
+ cursor.visit(|cur, _other| {
+ if cur.kind() != CXCursor_FieldDecl {
+ if let Some((ty, ref _clang_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 {
+ maybe_anonymous_struct_field = Some((inner, cur.cur_type()));
+ }
+ }
+ 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 default_type =
+ Item::from_ty(&cur.cur_type(), Some(*cur), Some(potential_id), ctx).ok();
+
+ let param = Item::named_type(cur.spelling(), default_type, potential_id, ctx);
+ ci.template_args.push(param);
+ }
+ CXCursor_CXXBaseSpecifier => {
+ if !ci.has_vtable {
+ ci.has_vtable = cur.is_virtual_base();
+ }
+ let type_id = Item::from_ty(&cur.cur_type(), None, None, ctx)
+ .expect("BaseSpecifier");
+ ci.base_members.push(type_id);
+ }
+ CXCursor_CXXMethod => {
+ let is_virtual = cur.method_is_virtual();
+ let is_static = cur.method_is_static();
+ debug_assert!(!(is_static && is_virtual), "How?");
+
+ if !ci.has_vtable {
+ ci.has_vtable = is_virtual;
+ }
+
+ let linkage = cur.linkage();
+ if linkage != CXLinkage_External {
+ return CXChildVisit_Continue;
+ }
+
+ if cur.access_specifier() == CX_CXXPrivate {
+ return CXChildVisit_Continue;
+ }
+
+ let visibility = cur.visibility();
+ if visibility != CXVisibility_Default {
+ return CXChildVisit_Continue;
+ }
+
+ if cur.is_inlined_function() {
+ return CXChildVisit_Continue;
+ }
+
+ let spelling = cur.spelling();
+ if spelling.starts_with("operator") {
+ return CXChildVisit_Continue;
+ }
+
+ // 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 method_signature = Item::parse(*cur, Some(potential_id), ctx)
+ .expect("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
+ };
+ ci.methods.push(Method::new(method_kind, method_signature, is_const));
+ }
+ CXCursor_Destructor => {
+ if cur.method_is_virtual() {
+ // FIXME: Push to the method list?
+ ci.has_vtable = true;
+ }
+ ci.has_destructor = true;
+ }
+ 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;
+ }
+
+ let item = Item::parse(*cur, Some(potential_id), ctx)
+ .expect("VarDecl");
+ ci.inner_vars.push(item);
+ }
+ // Intentionally not handled
+ CXCursor_CXXAccessSpecifier |
+ CXCursor_CXXFinalAttr |
+ CXCursor_Constructor |
+ CXCursor_FunctionTemplate |
+ CXCursor_ConversionFunction => {}
+ _ => {
+ warn!("unhandled composite 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 clangll::*;
+ Ok(match cursor.kind() {
+ CXCursor_UnionDecl => CompKind::Union,
+ CXCursor_ClassDecl |
+ CXCursor_StructDecl => CompKind::Struct,
+ 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);
+ }
+ })
+ }
+
+ pub fn signature_contains_named_type(&self,
+ type_resolver: &TypeResolver,
+ 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| {
+ type_resolver.resolve_type(*arg)
+ .signature_contains_named_type(type_resolver, ty)
+ })
+ }
+
+ pub fn inner_types(&self) -> &[ItemId] {
+ &self.inner_types
+ }
+
+ pub fn inner_vars(&self) -> &[ItemId] {
+ &self.inner_vars
+ }
+
+ pub fn found_unknown_attr(&self) -> bool {
+ self.found_unknown_attr
+ }
+
+ 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, type_resolver: &TypeResolver) -> bool {
+ self.has_vtable(type_resolver) && !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.
+ type_resolver
+ .resolve_type(*base)
+ .canonical_type(type_resolver)
+ .as_comp().map_or(false, |ci| {
+ ci.has_vtable(type_resolver)
+ })
+ })
+ }
+}
diff --git a/src/ir/context.rs b/src/ir/context.rs
new file mode 100644
index 00000000..5ddedda0
--- /dev/null
+++ b/src/ir/context.rs
@@ -0,0 +1,685 @@
+use super::ty::{Type, TypeKind, FloatKind};
+use super::item::{Item, ItemCanonicalName, ItemId};
+use super::item_kind::ItemKind;
+use super::int::IntKind;
+use super::module::Module;
+use clang::{self, Cursor};
+use std::borrow::{Cow, Borrow};
+use std::collections::btree_map::{self, BTreeMap};
+use std::collections::{HashSet, HashMap};
+use std::fmt;
+use syntax::ast::Ident;
+use syntax::codemap::{DUMMY_SP, Span};
+use syntax::ext::base::ExtCtxt;
+use parse::ClangItemParser;
+use BindgenOptions;
+
+// 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>,
+
+ /// Clang cursor to type map. This is needed to be able to associate types
+ /// with item ids during parsing.
+ ///
+ /// The cursor used for storage is the definition cursor.
+ types: HashMap<Cursor, 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.
+ parsed_macros: HashSet<String>,
+
+ /// The active replacements collected from replaces="xxx" annotations.
+ replacements: HashMap<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,
+}
+
+impl<'ctx> BindgenContext<'ctx> {
+ pub fn new(options: BindgenOptions) -> Self {
+ use clangll;
+
+ let index = clang::Index::new(false, true);
+
+ let translation_unit =
+ clang::TranslationUnit::parse(&index, "", &options.clang_args, &[],
+ clangll::CXTranslationUnit_DetailedPreprocessingRecord);
+
+ let root_module = Self::build_root_module();
+ let mut me = BindgenContext {
+ items: Default::default(),
+ types: Default::default(),
+ modules: Default::default(),
+ 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,
+ };
+
+ me.add_item(root_module, None, None);
+
+ me
+ }
+
+ pub fn add_item(&mut self,
+ item: Item,
+ declaration: Option<Cursor>,
+ location: Option<Cursor>) {
+ use clangll::{CXCursor_ClassTemplate, CXCursor_ClassTemplatePartialSpecialization};
+ 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 old_item = self.items.insert(id, item);
+ assert!(old_item.is_none(), "Inserted type twice?");
+
+ if is_type && declaration.is_some() {
+ let declaration = declaration.unwrap();
+ debug_assert_eq!(declaration, declaration.canonical());
+ if declaration.is_valid() {
+ let old = self.types.insert(declaration, id);
+ debug_assert_eq!(old, None);
+ } else if location.is_some() &&
+ (location.unwrap().kind() == CXCursor_ClassTemplate ||
+ location.unwrap().kind() == CXCursor_ClassTemplatePartialSpecialization) {
+ let old = self.types.insert(location.unwrap().canonical(), id);
+ debug_assert_eq!(old, None);
+ } else {
+ // 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());
+ }
+ }
+ }
+
+ // TODO: Move all this syntax crap to other part of the code.
+ pub fn ext_cx(&self) -> &ExtCtxt<'ctx> {
+ &self.gen_ctx.expect("Not in gen phase").0
+ }
+
+ 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))
+ }
+
+ pub fn rust_ident_raw<S>(&self, name: &S) -> Ident
+ where S: Borrow<str>,
+ {
+ self.ext_cx().ident_of(name.borrow())
+ }
+
+ pub fn items<'a>(&'a self) -> btree_map::Iter<'a, ItemId, Item> {
+ self.items.iter()
+ }
+
+ pub fn collected_typerefs(&self) -> bool {
+ self.collected_typerefs
+ }
+
+ fn collect_typerefs(&mut self) -> Vec<(ItemId, clang::Type, Option<clang::Cursor>)> {
+ 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) => {
+ typerefs.push((*id, ty.clone(), loc));
+ }
+ _ => {},
+ };
+ }
+ typerefs
+ }
+
+ fn resolve_typerefs(&mut self) {
+ let typerefs = self.collect_typerefs();
+
+ for (id, ty, loc) in typerefs {
+ let _resolved = {
+ let resolved = Item::from_ty(&ty, loc, None, 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?");
+ }
+ }
+
+ fn process_replacements(&mut self) {
+ if self.replacements.is_empty() {
+ 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() {
+ let ty = match item.kind().as_type() {
+ Some(ty) => ty,
+ None => continue,
+ };
+
+ // canonical_name calls are expensive.
+ let ci = match ty.as_comp() {
+ Some(ci) => ci,
+ None => continue,
+ };
+
+ if ci.is_template_specialization() {
+ continue;
+ }
+
+ if let Some(replacement) = self.replacements.get(&item.canonical_name(self)) {
+ 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 {
+ let mut item = self.items.get_mut(&id).unwrap();
+ *item.kind_mut().as_type_mut().unwrap().kind_mut() =
+ TypeKind::ResolvedTypeRef(replacement);
+ }
+ }
+
+ // Enters in the generation phase.
+ pub fn gen<F, Out>(&mut self, cb: F) -> Out
+ where F: FnOnce(&Self) -> Out
+ {
+ 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::DummyMacroLoader;
+ let mut ctx =
+ GenContext(base::ExtCtxt::new(&sess, vec![], cfg, &mut loader));
+
+ ctx.0.bt_push(ExpnInfo {
+ call_site: self.span,
+ callee: NameAndSpan {
+ format: MacroBang(parse::token::intern("")),
+ 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.resolve_typerefs();
+ self.process_replacements();
+
+ let ret = cb(self);
+ self.gen_ctx = None;
+ ret
+ }
+
+ // 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_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() -> Item {
+ let module = Module::new(Some("root".into()));
+ let id = ItemId::next();
+ Item::new(id, None, None, id, ItemKind::Module(module))
+ }
+
+ pub fn root_module(&self) -> ItemId {
+ self.root_module
+ }
+
+ pub fn resolve_type(&self, type_id: ItemId) -> &Type {
+ self.items.get(&type_id).unwrap().kind().expect_type()
+ }
+
+ pub fn safe_resolve_type(&self, type_id: ItemId) -> Option<&Type> {
+ self.items.get(&type_id).map(|t| t.kind().expect_type())
+ }
+
+ pub fn resolve_item_fallible(&self, item_id: ItemId) -> Option<&Item> {
+ self.items.get(&item_id)
+ }
+
+ 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),
+ }
+ }
+
+ 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:
+ ///
+ /// ```
+ /// template<typename T>
+ /// class Incomplete {
+ /// T p;
+ /// };
+ ///
+ /// template<typename U>
+ /// class Foo {
+ /// Incomplete<U> bar;
+ /// };
+ /// ```
+ fn build_template_wrapper(&mut self,
+ wrapping: ItemId,
+ parent_id: ItemId,
+ ty: &clang::Type,
+ location: clang::Cursor) -> ItemId {
+ use clangll::*;
+ let mut args = vec![];
+ let mut found_invalid_template_ref = false;
+ let self_id = ItemId::next();
+ location.visit(|c, _| {
+ if c.kind() == CXCursor_TemplateRef &&
+ c.cur_type().kind() == CXType_Invalid {
+ found_invalid_template_ref = true;
+ }
+ if c.kind() == CXCursor_TypeRef {
+ let new_ty =
+ Item::from_ty_or_ref(c.cur_type(), Some(*c), Some(self_id), self);
+ args.push(new_ty);
+ }
+ CXChildVisit_Continue
+ });
+
+ let item = {
+ let wrapping_type = self.resolve_type(wrapping);
+ let old_args = match *wrapping_type.kind() {
+ TypeKind::Comp(ref ci) => ci.template_args(),
+ _ => panic!("how?"),
+ };
+ // 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.
+ //
+ // This flaw was already on the old parser, but I now think it has
+ // no clear solution.
+ //
+ // 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;
+ }
+
+ 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(self_id, None, None, parent_id, ItemKind::Type(ty))
+ };
+
+ // Bypass all the validations in add_item explicitly.
+ self.items.insert(self_id, item);
+ self_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,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>) -> Option<ItemId> {
+ use clangll::{CXCursor_ClassTemplate, CXCursor_ClassTemplatePartialSpecialization};
+ 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.kind() == CXCursor_ClassTemplate ||
+ location.kind() == CXCursor_ClassTemplatePartialSpecialization {
+ declaration = location;
+ }
+ }
+ }
+ let canonical_declaration = declaration.canonical();
+ if canonical_declaration.is_valid() {
+ // First lookup to see if we already have it resolved.
+ let id = self.types.get(&canonical_declaration).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.kind() == CXCursor_ClassTemplate ||
+ declaration.kind() == CXCursor_ClassTemplatePartialSpecialization) &&
+ *ty != canonical_declaration.cur_type() &&
+ location.is_some() && parent_id.is_some() {
+ return Some(
+ self.build_template_wrapper(id, parent_id.unwrap(), ty,
+ location.unwrap()));
+ }
+
+ return Some(self.build_ty_wrapper(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,
+ wrapped_id: ItemId,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type) -> ItemId {
+ let id = ItemId::next();
+ 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(id, None, None,
+ parent_id.unwrap_or(self.current_module), ItemKind::Type(ty));
+ self.add_builtin_item(item);
+ id
+ }
+
+ fn build_builtin_ty(&mut self,
+ ty: &clang::Type,
+ _declaration: Cursor) -> Option<ItemId> {
+ use clangll::*;
+ 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_Float => TypeKind::Float(FloatKind::Float),
+ CXType_Double => TypeKind::Float(FloatKind::Double),
+ CXType_LongDouble => TypeKind::Float(FloatKind::LongDouble),
+ _ => 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 = ItemId::next();
+ let item = Item::new(id, None, None, self.root_module, ItemKind::Type(ty));
+ self.add_builtin_item(item);
+ Some(id)
+ }
+
+ pub fn translation_unit(&self) -> &clang::TranslationUnit {
+ &self.translation_unit
+ }
+
+ pub fn parsed_macro(&self, macro_name: &str) -> bool {
+ self.parsed_macros.contains(macro_name)
+ }
+
+ pub fn note_parsed_macro(&mut self, macro_name: String) {
+ debug_assert!(!self.parsed_macros.contains(&macro_name));
+ self.parsed_macros.insert(macro_name);
+ }
+
+ pub fn in_codegen_phase(&self) -> bool {
+ self.gen_ctx.is_some()
+ }
+
+ /// This is a bit of a hack, but it's done so using the replaces="xxx"
+ /// annotation implies hide in the other type.
+ pub fn replace(&mut self, name: &str, potential_ty: ItemId) {
+ self.replacements.insert(name.into(), potential_ty);
+ }
+
+ pub fn hidden_by_name(&self, name: &str) -> bool {
+ debug_assert!(self.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ self.options.hidden_types.contains(name)
+ }
+
+ pub fn opaque_by_name(&self, name: &str) -> bool {
+ debug_assert!(self.in_codegen_phase(),
+ "You're not supposed to call this yet");
+ self.options.opaque_types.contains(name)
+ }
+
+ pub fn options(&self) -> &BindgenOptions {
+ &self.options
+ }
+
+ /// 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 clangll::*;
+ assert!(cursor.kind() == CXCursor_Namespace, "Be a nice person");
+ let cursor = cursor.canonical();
+ let module_id = match self.modules.get(&cursor) {
+ Some(id) => return *id,
+ None => ItemId::next(),
+ };
+
+ let module_name = self.translation_unit
+ .tokens(&cursor).and_then(|tokens| {
+ if tokens.len() <= 1 {
+ None
+ } else {
+ match &*tokens[1].spelling {
+ "{" => None,
+ s => Some(s.to_owned()),
+ }
+ }
+ });
+
+ let module = Module::new(module_name);
+ let module = Item::new(module_id, None, None, self.current_module,
+ ItemKind::Module(module));
+
+ self.add_item(module, None, None);
+
+ module_id
+ }
+
+ pub fn with_module<F>(&mut self, module_id: ItemId, cb: F)
+ where F: FnOnce(&mut Self, &mut Vec<ItemId>)
+ {
+ debug_assert!(self.resolve_item(module_id).kind().is_module(), "Wat");
+
+ let previous_id = self.current_module;
+ self.current_module = module_id;
+
+ let mut children = vec![];
+ cb(self, &mut children);
+
+ self.items.get_mut(&module_id).unwrap()
+ .as_module_mut().expect("Not a module?")
+ .children_mut().extend(children.into_iter());
+
+ self.current_module = previous_id;
+ }
+}
+
+/// This was originally a type that only exposes the resolve_type operation to
+/// its consumers.
+///
+/// Later a made resolve_type public, so... meh. It should go away soon.
+pub type TypeResolver<'ctx> = BindgenContext<'ctx>;
diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs
new file mode 100644
index 00000000..c85ee07a
--- /dev/null
+++ b/src/ir/enum_ty.rs
@@ -0,0 +1,110 @@
+use super::item::{Item, ItemId};
+use super::ty::TypeKind;
+use super::context::BindgenContext;
+use parse::{ClangItemParser, ParseError};
+use clang;
+
+#[derive(Debug)]
+pub struct Enum {
+ /// The representation used for this enum.
+ /// Should be an IntKind type.
+ ///
+ /// 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 {
+ pub fn new(repr: Option<ItemId>, variants: Vec<EnumVariant>) -> Self {
+ Enum {
+ repr: repr,
+ variants: variants,
+ }
+ }
+
+ pub fn repr(&self) -> Option<ItemId> {
+ self.repr
+ }
+
+ pub fn variants(&self) -> &[EnumVariant] {
+ &self.variants
+ }
+
+ pub fn from_ty(ty: &clang::Type,
+ ctx: &mut BindgenContext) -> Result<Self, ParseError> {
+ use clangll::*;
+ if ty.kind() != CXType_Enum {
+ return Err(ParseError::Continue);
+ }
+
+ let declaration = ty.declaration().canonical();
+ let repr = Item::from_ty(&declaration.enum_type(), None, None, ctx).ok();
+ let mut variants = vec![];
+
+ let is_signed = match repr {
+ Some(repr) => {
+ let repr_type = ctx.resolve_type(repr);
+ match *repr_type.canonical_type(ctx).kind() {
+ TypeKind::Int(ref int_kind) => int_kind.is_signed(),
+ ref other => panic!("Since when enums can be non-integers? {:?}", other),
+ }
+ }
+ // Assume signedness since the default type by the C standard is an
+ // int.
+ None => true,
+ };
+
+ declaration.visit(|cursor, _| {
+ if cursor.kind() == CXCursor_EnumConstantDecl {
+ let name = cursor.spelling();
+ let comment = cursor.raw_comment();
+ let val = if is_signed {
+ EnumVariantValue::Signed(cursor.enum_val_signed())
+ } else {
+ EnumVariantValue::Unsigned(cursor.enum_val_unsigned())
+ };
+ variants.push(EnumVariant::new(name, comment, val));
+ }
+ 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,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum EnumVariantValue {
+ Signed(i64),
+ Unsigned(u64),
+}
+
+impl EnumVariant {
+ pub fn new(name: String, comment: Option<String>, val: EnumVariantValue) -> Self {
+ EnumVariant {
+ name: name,
+ comment: comment,
+ val: val,
+ }
+ }
+
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ pub fn val(&self) -> EnumVariantValue {
+ self.val
+ }
+}
diff --git a/src/ir/function.rs b/src/ir/function.rs
new file mode 100644
index 00000000..b95ac57b
--- /dev/null
+++ b/src/ir/function.rs
@@ -0,0 +1,220 @@
+use super::item::{Item, ItemId};
+use super::ty::TypeKind;
+use super::context::BindgenContext;
+use syntax::abi;
+use clang;
+use clangll::Enum_CXCallingConv;
+use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
+
+/// 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 {
+ 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 {
+ 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,
+ }
+ }
+
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ pub fn mangled_name(&self) -> Option<&str> {
+ self.mangled_name.as_ref().map(|n| &**n)
+ }
+
+ 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: Enum_CXCallingConv) -> abi::Abi {
+ use clangll::*;
+ 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),
+ }
+}
+
+pub fn cursor_mangling(cursor: &clang::Cursor) -> Option<String> {
+ let mut mangling = cursor.mangling();
+
+ // Try to undo backend linkage munging (prepended _, generally)
+ if cfg!(target_os = "macos") {
+ mangling.remove(0);
+ }
+
+ if mangling.is_empty() { None } else { Some(mangling) }
+}
+
+impl FunctionSig {
+ 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,
+ }
+ }
+
+ pub fn from_ty(ty: &clang::Type,
+ cursor: &clang::Cursor,
+ ctx: &mut BindgenContext) -> Result<Self, ParseError> {
+ use clangll::*;
+ debug!("FunctionSig::from_ty {:?} {:?}", ty, cursor);
+
+ // 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_CXXMethod => {
+ // For CXCursor_FunctionDecl, cursor.args() is the reliable way
+ // to get parameter names and types.
+ cursor.args().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
+ }
+ };
+
+ if cursor.kind() == CXCursor_CXXMethod {
+ let is_const = cursor.method_is_const();
+ let is_virtual = cursor.method_is_virtual();
+ let is_static = 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 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))
+ }
+
+ pub fn return_type(&self) -> ItemId {
+ self.return_type
+ }
+
+ pub fn argument_types(&self) -> &[(Option<String>, ItemId)] {
+ &self.argument_types
+ }
+
+ pub fn abi(&self) -> abi::Abi {
+ self.abi
+ }
+
+ 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 clangll::*;
+ match cursor.kind() {
+ CXCursor_FunctionDecl |
+ CXCursor_CXXMethod => {},
+ _ => return Err(ParseError::Continue),
+ };
+
+ debug!("Function::parse({:?}, {:?})", cursor, cursor.cur_type());
+
+ // 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)))
+ }
+}
diff --git a/src/ir/int.rs b/src/ir/int.rs
new file mode 100644
index 00000000..d2769b77
--- /dev/null
+++ b/src/ir/int.rs
@@ -0,0 +1,30 @@
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum IntKind {
+ Bool,
+ Char,
+ UChar,
+ Short,
+ UShort,
+ Int,
+ UInt,
+ Long,
+ ULong,
+ LongLong,
+ ULongLong,
+ U16, // For Char16 and Wchar
+ U32, // For Char32
+ // Though now we're at it we could add equivalents for the rust types...
+}
+
+impl IntKind {
+ pub fn is_signed(&self) -> bool {
+ use self::IntKind::*;
+ match *self {
+ Bool | UChar | UShort |
+ UInt | ULong | ULongLong | U16 | U32 => false,
+
+ Char | Short | Int |
+ Long | LongLong => true,
+ }
+ }
+}
diff --git a/src/ir/item.rs b/src/ir/item.rs
new file mode 100644
index 00000000..c9ac71a4
--- /dev/null
+++ b/src/ir/item.rs
@@ -0,0 +1,681 @@
+use super::context::BindgenContext;
+use super::item_kind::ItemKind;
+use super::ty::{Type, TypeKind};
+use super::function::Function;
+use super::module::Module;
+use super::annotations::Annotations;
+use std::fmt;
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
+use clang;
+use clangll;
+
+/// 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 {
+ 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:
+///
+/// ```
+/// namespace foo {
+/// const BAR = 3;
+/// }
+/// ```
+///
+/// For bar, the canonical path is foo::BAR, while the canonical name is just
+/// BAR.
+pub trait ItemCanonicalPath {
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String>;
+}
+
+/// 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 fmt::Display for ItemId {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ try!(write!(fmt, "_bindgen_id_"));
+ self.0.fmt(fmt)
+ }
+}
+
+pub static NEXT_ITEM_ID: AtomicUsize = ATOMIC_USIZE_INIT;
+
+impl ItemId {
+ pub fn next() -> Self {
+ ItemId(NEXT_ITEM_ID.fetch_add(1, Ordering::Relaxed))
+ }
+}
+
+// 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 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)
+ }
+}
+
+#[derive(Debug)]
+pub struct Item {
+ /// This item's id.
+ id: ItemId,
+ /// 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 {
+ 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,
+ parent_id: parent_id,
+ comment: comment,
+ annotations: annotations.unwrap_or_default(),
+ kind: kind,
+ }
+ }
+
+ pub fn id(&self) -> ItemId {
+ self.id
+ }
+
+ pub fn parent_id(&self) -> ItemId {
+ self.parent_id
+ }
+
+ pub fn comment(&self) -> Option<&str> {
+ self.comment.as_ref().map(|c| &**c)
+ }
+
+ pub fn kind(&self) -> &ItemKind {
+ &self.kind
+ }
+
+ pub fn kind_mut(&mut self) -> &mut ItemKind {
+ &mut self.kind
+ }
+
+ 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();
+ }
+ }
+
+ pub fn expect_type(&self) -> &Type {
+ self.kind().expect_type()
+ }
+
+ pub fn expect_function(&self) -> &Function {
+ self.kind().expect_function()
+ }
+
+ 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::Alias(_, inner) |
+ TypeKind::ResolvedTypeRef(inner) => {
+ ctx.resolve_item(inner).applicable_template_args(ctx)
+ }
+ // XXX Is this completely correct? Partial template specialization
+ // is hard anyways, sigh...
+ 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![],
+ }
+ }
+
+ fn is_module(&self) -> bool {
+ match self.kind {
+ ItemKind::Module(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn annotations(&self) -> &Annotations {
+ &self.annotations
+ }
+
+ /// Whether this item should be hidden, either due to annotations, or due 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.real_canonical_name(ctx, false))
+ }
+
+ 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.real_canonical_name(ctx, false))
+ }
+
+ /// Get the canonical name without taking into account the replaces
+ /// annotation.
+ fn real_canonical_name(&self, ctx: &BindgenContext, count_namespaces: bool) -> String {
+ let base_name = match *self.kind() {
+ ItemKind::Type(ref ty) => {
+ match *ty.kind() {
+ // If we're a template specialization, our name is our parent's
+ TypeKind::Comp(ref ci) if ci.is_template_specialization() => {
+ return ci.specialized_template().unwrap().canonical_name(ctx);
+ },
+ // Same as above
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::TemplateRef(inner, _) => {
+ return inner.canonical_name(ctx);
+ }
+ // If we're a named type, we don't need to mangle it, and we
+ // should be able to assert we're not top level.
+ TypeKind::Named(ref name, _) => {
+ return name.to_owned();
+ }
+ _ => {}
+ }
+
+ ty.name().map(ToOwned::to_owned)
+ .unwrap_or_else(|| format!("_bindgen_ty{}", self.id()))
+ }
+ ItemKind::Function(ref fun) => {
+ let mut base = fun.name().to_owned();
+
+ // We might need to deduplicate if we're a method.
+ let parent = ctx.resolve_item(self.parent_id());
+ if let ItemKind::Type(ref ty) = *parent.kind() {
+ if let TypeKind::Comp(ref ci) = *ty.kind() {
+ let mut count = 0;
+ let mut found = false;
+ for method in ci.methods() {
+ if method.signature() == self.id() {
+ found = true;
+ break;
+ }
+ let fun = ctx.resolve_item(method.signature())
+ .expect_function();
+ if fun.name() == base {
+ count += 1;
+ }
+ }
+
+ assert!(found, "Method not found?");
+ if count != 0 {
+ base.push_str(&count.to_string());
+ }
+ }
+ }
+ base
+ }
+ 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.id()))
+ }
+ };
+
+ let parent = ctx.resolve_item(self.parent_id());
+ let parent_is_namespace = parent.is_module();
+ if self.is_toplevel(ctx) || (parent_is_namespace && count_namespaces) {
+ return ctx.rust_mangle(&base_name).into_owned();
+ }
+
+ // TODO: allow modification of the mangling functions, maybe even per
+ // item type?
+ format!("{}_{}", parent.canonical_name(ctx), base_name)
+ }
+
+ pub fn as_module_mut(&mut self) -> Option<&mut Module> {
+ match self.kind {
+ ItemKind::Module(ref mut module) => Some(module),
+ _ => None,
+ }
+ }
+}
+
+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 = ItemId::next();
+ 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>,
+ context: &mut BindgenContext) -> Result<ItemId, ParseError> {
+ use ir::function::Function;
+ use ir::module::Module;
+ use ir::var::Var;
+
+ if !cursor.is_valid() {
+ return Err(ParseError::Continue);
+ }
+
+ let comment = cursor.raw_comment();
+ let annotations = Annotations::new(&cursor);
+
+ // FIXME: The current_module logic is not really accurate. We should be
+ // able to index modules by their Cursor, and locate the proper module
+ // for a given item.
+ //
+ // We don't support modules properly though, so there's no rush for
+ // this.
+ let current_module = context.current_module();
+ macro_rules! try_parse {
+ ($what:ident) => {
+ match $what::parse(cursor, context) {
+ Ok(ParseResult::New(item, declaration)) => {
+ let id = ItemId::next();
+ context.add_item(Item::new(id, comment, annotations,
+ parent_id.unwrap_or(current_module),
+ 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 definition = cursor.definition();
+ let applicable_cursor = if definition.is_valid() {
+ definition
+ } else {
+ cursor
+ };
+ match Self::from_ty(&applicable_cursor.cur_type(),
+ Some(applicable_cursor), parent_id, context)
+ {
+ 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() == clangll::CXCursor_UnexposedDecl {
+ Err(ParseError::Recurse)
+ } else {
+ error!("Unhandled cursor kind: {}", ::clang::kind_to_str(cursor.kind()));
+ Err(ParseError::Continue)
+ }
+ }
+
+ fn from_ty_or_ref(ty: clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ context: &mut BindgenContext) -> ItemId {
+ debug!("from_ty_or_ref: {:?}, {:?}, {:?}", ty, location, parent_id);
+
+ if context.collected_typerefs() {
+ debug!("refs already collected, resolving directly");
+ return Self::from_ty(&ty, location, parent_id, context)
+ .expect("Unable to resolve type");
+ }
+
+ if let Some(ty) = context.builtin_or_resolved_ty(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);
+ let id = ItemId::next();
+ let current_module = context.current_module();
+ context.add_item(Item::new(id, None, None,
+ parent_id.unwrap_or(current_module),
+ ItemKind::Type(Type::new(None, None, kind, is_const))),
+ Some(clang::Cursor::null()),
+ None);
+ id
+ }
+
+
+ fn from_ty(ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ context: &mut BindgenContext) -> Result<ItemId, ParseError> {
+ Self::from_ty_with_id(ItemId::next(), ty, location, parent_id, context)
+ }
+
+ fn from_ty_with_id(id: ItemId,
+ ty: &clang::Type,
+ location: Option<clang::Cursor>,
+ parent_id: Option<ItemId>,
+ context: &mut BindgenContext) -> Result<ItemId, ParseError> {
+ use clangll::*;
+
+ let decl = {
+ let decl = ty.declaration();
+ let definition = decl.definition();
+ if definition.is_valid() {
+ definition
+ } else {
+ 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 replaced) = annotations.as_ref().and_then(|a| a.use_instead_of()) {
+ context.replace(replaced, id);
+ }
+
+ if let Some(ty) = context.builtin_or_resolved_ty(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)) = context.currently_parsed_types.iter().find(|&&(d, _)| d == declaration_to_look_for) {
+ debug!("Avoiding recursion parsing type: {:?}", ty);
+ return Ok(item_id);
+ }
+ }
+
+ let current_module = context.current_module();
+ if valid_decl {
+ context.currently_parsed_types.push((declaration_to_look_for, id));
+ }
+
+ let result = Type::from_clang_ty(id, ty, location, parent_id, context);
+ let ret = match result {
+ Ok(ParseResult::AlreadyResolved(ty)) => Ok(ty),
+ Ok(ParseResult::New(item, declaration)) => {
+ context.add_item(Item::new(id, comment, annotations,
+ parent_id.unwrap_or(current_module),
+ 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, _) = context.currently_parsed_types.pop().unwrap();
+ assert_eq!(popped_decl, declaration_to_look_for);
+ }
+
+ location.visit(|cur, _other| {
+ use clangll::*;
+ result = Item::from_ty_with_id(id, ty, Some(*cur), parent_id, context);
+ match result {
+ Ok(..) => CXChildVisit_Break,
+ Err(ParseError::Recurse) => CXChildVisit_Recurse,
+ Err(ParseError::Continue) => CXChildVisit_Continue,
+ }
+ });
+
+ if valid_decl {
+ context.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 {
+ Ok(Self::named_type_with_id(id, ty.spelling(),
+ None,
+ parent_id.unwrap_or(context.current_module()),
+ context))
+ } else {
+ result
+ }
+ }
+ };
+
+ if valid_decl {
+ let (popped_decl, _) = context.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,
+ default: Option<ItemId>,
+ parent_id: ItemId,
+ context: &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(".", "");
+
+ context.add_item(Item::new(id, None, None, parent_id,
+ ItemKind::Type(Type::named(name, default))),
+ None,
+ None);
+
+ id
+ }
+
+ fn named_type<S>(name: S,
+ default: Option<ItemId>,
+ parent_id: ItemId,
+ context: &mut BindgenContext) -> ItemId
+ where S: Into<String>
+ {
+ Self::named_type_with_id(ItemId::next(), name, default, parent_id, context)
+ }
+}
+
+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 let Some(other_canon_type) = self.annotations.use_instead_of() {
+ return other_canon_type.to_owned();
+ }
+ self.real_canonical_name(ctx, ctx.options().enable_cxx_namespaces)
+ }
+}
+
+impl ItemCanonicalPath for Item {
+ fn canonical_path(&self, ctx: &BindgenContext) -> Vec<String> {
+ if !ctx.options().enable_cxx_namespaces {
+ return vec![self.canonical_name(ctx)];
+ }
+
+ if self.id() == ctx.root_module() {
+ match self.kind {
+ ItemKind::Module(ref module) => {
+ return vec![module.name().unwrap().into()]
+ }
+ _ => panic!("Something has wrong horribly wrong"),
+ }
+ }
+
+ // TODO: This duplicates too much logic with real_canonical_name.
+ if let ItemKind::Type(ref ty) = *self.kind() {
+ match *ty.kind() {
+ TypeKind::Comp(ref ci) if ci.is_template_specialization() => {
+ return ci.specialized_template().unwrap().canonical_path(ctx);
+ },
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::TemplateRef(inner, _) => {
+ return inner.canonical_path(ctx);
+ }
+ TypeKind::Named(ref name, _) => {
+ return vec![name.clone()];
+ }
+ _ => {}
+ }
+ }
+
+ let mut parent_path = self.parent_id().canonical_path(&ctx);
+ parent_path.push(self.real_canonical_name(ctx, true));
+
+ parent_path
+ }
+}
diff --git a/src/ir/item_kind.rs b/src/ir/item_kind.rs
new file mode 100644
index 00000000..b6f317a7
--- /dev/null
+++ b/src/ir/item_kind.rs
@@ -0,0 +1,89 @@
+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 {
+ pub fn as_module(&self) -> Option<&Module> {
+ match *self {
+ ItemKind::Module(ref module) => Some(module),
+ _ => None,
+ }
+ }
+
+ pub fn is_module(&self) -> bool {
+ self.as_module().is_some()
+ }
+
+ pub fn expect_module(&self) -> &Module {
+ self.as_module().expect("Not a module")
+ }
+
+ pub fn as_function(&self) -> Option<&Function> {
+ match *self {
+ ItemKind::Function(ref func) => Some(func),
+ _ => None,
+ }
+ }
+
+ pub fn is_function(&self) -> bool {
+ self.as_function().is_some()
+ }
+
+ pub fn expect_function(&self) -> &Function {
+ self.as_function().expect("Not a function")
+ }
+
+ pub fn as_type(&self) -> Option<&Type> {
+ match *self {
+ ItemKind::Type(ref ty) => Some(ty),
+ _ => None,
+ }
+ }
+
+ pub fn as_type_mut(&mut self) -> Option<&mut Type> {
+ match *self {
+ ItemKind::Type(ref mut ty) => Some(ty),
+ _ => None,
+ }
+ }
+
+ pub fn is_type(&self) -> bool {
+ self.as_type().is_some()
+ }
+
+ pub fn expect_type(&self) -> &Type {
+ self.as_type().expect("Not a type")
+ }
+
+ pub fn as_var(&self) -> Option<&Var> {
+ match *self {
+ ItemKind::Var(ref v) => Some(v),
+ _ => None,
+ }
+ }
+
+ pub fn is_var(&self) -> bool {
+ self.as_var().is_some()
+ }
+
+ pub fn expect_var(&self) -> &Var {
+ self.as_var().expect("Not a var")
+ }
+}
diff --git a/src/ir/layout.rs b/src/ir/layout.rs
new file mode 100644
index 00000000..d672ebea
--- /dev/null
+++ b/src/ir/layout.rs
@@ -0,0 +1,26 @@
+
+/// A type that represents the struct layout of a type.
+#[derive(Debug, Clone, Copy)]
+pub struct Layout {
+ pub size: usize,
+ pub align: usize,
+ pub packed: bool,
+}
+
+impl Layout {
+ pub fn new(size: usize, align: usize) -> Self {
+ Layout {
+ size: size,
+ align: align,
+ packed: false,
+ }
+ }
+
+ pub fn is_zero(&self) -> bool {
+ self.size == 0 && self.align == 0
+ }
+
+ pub fn zero() -> Self {
+ Self::new(0, 0)
+ }
+}
diff --git a/src/ir/mod.rs b/src/ir/mod.rs
new file mode 100644
index 00000000..07ac3059
--- /dev/null
+++ b/src/ir/mod.rs
@@ -0,0 +1,12 @@
+pub mod annotations;
+pub mod comp;
+pub mod context;
+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 var;
diff --git a/src/ir/module.rs b/src/ir/module.rs
new file mode 100644
index 00000000..77fee5ef
--- /dev/null
+++ b/src/ir/module.rs
@@ -0,0 +1,52 @@
+use super::context::BindgenContext;
+use super::item::ItemId;
+use clang;
+use parse::{ClangSubItemParser, ParseError, ParseResult};
+use parse_one;
+
+/// 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 children of this module, just here for convenience.
+ children_ids: Vec<ItemId>,
+}
+
+impl Module {
+ pub fn new(name: Option<String>) -> Self {
+ Module {
+ name: name,
+ children_ids: vec![],
+ }
+ }
+
+ pub fn name(&self) -> Option<&str> {
+ self.name.as_ref().map(|n| &**n)
+ }
+
+ pub fn children_mut(&mut self) -> &mut Vec<ItemId> {
+ &mut self.children_ids
+ }
+
+ pub fn children(&self) -> &[ItemId] {
+ &self.children_ids
+ }
+}
+
+impl ClangSubItemParser for Module {
+ fn parse(cursor: clang::Cursor, ctx: &mut BindgenContext) -> Result<ParseResult<Self>, ParseError> {
+ use clangll::*;
+ match cursor.kind() {
+ CXCursor_Namespace => {
+ let module_id = ctx.module(cursor);
+ ctx.with_module(module_id, |ctx, children| {
+ cursor.visit(|cursor, _| parse_one(ctx, *cursor, Some(module_id), children))
+ });
+
+ Ok(ParseResult::AlreadyResolved(module_id))
+ }
+ _ => Err(ParseError::Continue)
+ }
+ }
+}
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
new file mode 100644
index 00000000..b0448437
--- /dev/null
+++ b/src/ir/ty.rs
@@ -0,0 +1,537 @@
+use super::comp::CompInfo;
+use super::enum_ty::Enum;
+use super::function::FunctionSig;
+use super::item::{Item, ItemId};
+use super::int::IntKind;
+use super::layout::Layout;
+use super::context::BindgenContext;
+use super::context::TypeResolver;
+use parse::{ClangItemParser, ParseResult, ParseError};
+use clang::{self, Cursor};
+
+#[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>,
+ /// Whether this type is marked as opaque.
+ opaque: bool,
+ /// Whether this type is marked as hidden.
+ hide: bool,
+ /// The inner kind of the type
+ kind: TypeKind,
+ /// Whether this type is const-qualified.
+ is_const: bool,
+}
+
+pub const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32usize;
+
+impl Type {
+ pub fn as_comp(&self) -> Option<&CompInfo> {
+ match self.kind {
+ TypeKind::Comp(ref ci) => Some(ci),
+ _ => None,
+ }
+ }
+
+ pub fn new(name: Option<String>,
+ layout: Option<Layout>,
+ kind: TypeKind,
+ is_const: bool) -> Self {
+ Type {
+ name: name,
+ layout: layout,
+ opaque: false,
+ hide: false,
+ kind: kind,
+ is_const: is_const,
+ }
+ }
+
+ pub fn kind(&self) -> &TypeKind {
+ &self.kind
+ }
+
+ pub fn kind_mut(&mut self) -> &mut TypeKind {
+ &mut self.kind
+ }
+
+ pub fn name(&self) -> Option<&str> {
+ self.name.as_ref().map(|name| &**name)
+ }
+
+ pub fn is_comp(&self) -> bool {
+ match self.kind {
+ TypeKind::Comp(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_named(&self) -> bool {
+ match self.kind {
+ TypeKind::Named(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_builtin_or_named(&self) -> bool {
+ match self.kind {
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Function(..) |
+ TypeKind::Array(..) |
+ TypeKind::Reference(..) |
+ TypeKind::Pointer(..) |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Named(..) => true,
+ _ => false,
+ }
+ }
+
+ /// Creates a new named type, with name `name`.
+ pub fn named(name: String, default: Option<ItemId>) -> Self {
+ assert!(!name.is_empty());
+ // TODO: stop duplicating the name, it's stupid.
+ let kind = TypeKind::Named(name.clone(), default);
+ Self::new(Some(name), None, kind, false)
+ }
+
+ pub fn is_integer_literal(&self) -> bool {
+ match *self.kind() {
+ TypeKind::Int(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_const(&self) -> bool {
+ self.is_const
+ }
+
+ pub fn layout(&self, type_resolver: &TypeResolver) -> Option<Layout> {
+ use std::mem;
+
+ self.layout.or_else(|| {
+ match self.kind {
+ TypeKind::Comp(ref ci)
+ => ci.layout(type_resolver),
+ // FIXME(emilio): This is a hack for anonymous union templates.
+ // Use the actual pointer size!
+ TypeKind::Pointer(..)
+ => Some(Layout::new(mem::size_of::<*mut ()>(), mem::align_of::<*mut ()>())),
+ TypeKind::ResolvedTypeRef(inner)
+ => type_resolver.resolve_type(inner).layout(type_resolver),
+ _ => None,
+ }
+ })
+ }
+
+ pub fn is_opaque(&self, _type_resolver: &TypeResolver) -> bool {
+ self.opaque
+ }
+
+ pub fn can_derive_debug(&self, type_resolver: &TypeResolver) -> bool {
+ !self.is_opaque(type_resolver) && match self.kind {
+ TypeKind::Array(t, len) => {
+ len <= RUST_DERIVE_IN_ARRAY_LIMIT &&
+ type_resolver.resolve_type(t).can_derive_debug(type_resolver)
+ }
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::Alias(_, t) => {
+ type_resolver.resolve_type(t).can_derive_debug(type_resolver)
+ }
+ TypeKind::Comp(ref info) => {
+ info.can_derive_debug(type_resolver, self.layout(type_resolver))
+ }
+ _ => true,
+ }
+ }
+
+ // For some reason, deriving copies of an array of a type that is not known
+ // to be copy is a compile error. e.g.:
+ //
+ // #[derive(Copy)]
+ // struct A<T> {
+ // member: T,
+ // }
+ //
+ // is fine, while:
+ //
+ // #[derive(Copy)]
+ // struct A<T> {
+ // member: [T; 1],
+ // }
+ //
+ // is an error.
+ //
+ // That's the point of the existence of can_derive_copy_in_array().
+ pub fn can_derive_copy_in_array(&self, type_resolver: &TypeResolver) -> bool {
+ match self.kind {
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::Alias(_, t) |
+ TypeKind::Array(t, _) => {
+ type_resolver.resolve_type(t)
+ .can_derive_copy_in_array(type_resolver)
+ }
+ TypeKind::Named(..) => false,
+ _ => self.can_derive_copy(type_resolver),
+ }
+ }
+
+ pub fn can_derive_copy(&self, type_resolver: &TypeResolver) -> bool {
+ !self.is_opaque(type_resolver) && match self.kind {
+ TypeKind::Array(t, len) => {
+ len <= RUST_DERIVE_IN_ARRAY_LIMIT &&
+ type_resolver.resolve_type(t).can_derive_copy_in_array(type_resolver)
+ }
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::TemplateRef(t, _) |
+ TypeKind::Alias(_, t) => {
+ type_resolver.resolve_type(t).can_derive_copy(type_resolver)
+ }
+ TypeKind::Comp(ref info) => {
+ info.can_derive_copy(type_resolver)
+ }
+ _ => true,
+ }
+ }
+
+ pub fn has_vtable(&self, type_resolver: &TypeResolver) -> bool {
+ // FIXME: Can we do something about template parameters? Huh...
+ match self.kind {
+ TypeKind::TemplateRef(t, _) |
+ TypeKind::Alias(_, t) |
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::Array(t, _) => {
+ type_resolver.resolve_type(t).has_vtable(type_resolver)
+ }
+ TypeKind::Comp(ref info) => {
+ info.has_vtable(type_resolver)
+ }
+ _ => false,
+ }
+
+ }
+
+ pub fn has_destructor(&self, type_resolver: &TypeResolver) -> bool {
+ self.is_opaque(type_resolver) || match self.kind {
+ TypeKind::TemplateRef(t, _) |
+ TypeKind::Alias(_, t) |
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::Array(t, _) => {
+ type_resolver.resolve_type(t).has_destructor(type_resolver)
+ }
+ TypeKind::Comp(ref info) => {
+ info.has_destructor(type_resolver)
+ }
+ _ => false,
+ }
+ }
+
+ pub fn signature_contains_named_type(&self,
+ type_resolver: &TypeResolver,
+ ty: &Type) -> bool {
+ debug_assert!(ty.is_named());
+ let name = match *ty.kind() {
+ TypeKind::Named(ref name, _) => name,
+ _ => unreachable!(),
+ };
+
+ match self.kind {
+ TypeKind::Named(ref this_name, _)
+ => this_name == name,
+ TypeKind::ResolvedTypeRef(t) |
+ TypeKind::Array(t, _) |
+ TypeKind::Pointer(t)
+ => type_resolver.resolve_type(t)
+ .signature_contains_named_type(type_resolver, ty),
+ TypeKind::TemplateRef(_inner, ref template_args) => {
+ template_args.iter().any(|arg| {
+ type_resolver.resolve_type(*arg)
+ .signature_contains_named_type(type_resolver, ty)
+ })
+ }
+ TypeKind::Comp(ref ci)
+ => ci.signature_contains_named_type(type_resolver, ty),
+ _ => false,
+ }
+ }
+
+ pub fn canonical_type<'tr>(&'tr self, type_resolver: &'tr TypeResolver) -> &'tr Type {
+ match self.kind {
+ TypeKind::Named(..) |
+ TypeKind::Array(..) |
+ TypeKind::Comp(..) |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::Void |
+ TypeKind::NullPtr |
+ TypeKind::Pointer(..) => self,
+
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::Alias(_, inner) |
+ TypeKind::TemplateRef(inner, _)
+ => type_resolver.resolve_type(inner).canonical_type(type_resolver),
+
+ TypeKind::UnresolvedTypeRef(..)
+ => unreachable!("Should have been resolved after parsing!"),
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum FloatKind {
+ Float,
+ Double,
+ LongDouble,
+}
+
+/// The different kinds of types that we can parse.
+///
+/// TODO: The name in the Alias and Named kinds is a bit unsound, should be in
+/// type.name?
+#[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 type alias, with a name, that points to another type.
+ Alias(String, 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 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>),
+ ResolvedTypeRef(ItemId),
+
+ /// A named type, that is, a template parameter, with an optional default
+ /// type.
+ Named(String, Option<ItemId>),
+}
+
+impl Type {
+ pub fn is_unsized(&self, type_resolver: &TypeResolver) -> bool {
+ match self.kind {
+ TypeKind::Void => true,
+ TypeKind::Comp(ref ci) => ci.is_unsized(type_resolver),
+ TypeKind::Array(inner, size) => {
+ size == 0 ||
+ type_resolver.resolve_type(inner).is_unsized(type_resolver)
+ }
+ TypeKind::ResolvedTypeRef(inner) |
+ TypeKind::Alias(_, inner) |
+ TypeKind::TemplateRef(inner, _)
+ => type_resolver.resolve_type(inner).is_unsized(type_resolver),
+ TypeKind::Named(..) |
+ TypeKind::Int(..) |
+ TypeKind::Float(..) |
+ TypeKind::Function(..) |
+ TypeKind::Enum(..) |
+ TypeKind::Reference(..) |
+ TypeKind::NullPtr |
+ TypeKind::Pointer(..) => false,
+
+ TypeKind::UnresolvedTypeRef(..)
+ => unreachable!("Should have been resolved after parsing!"),
+ }
+ }
+
+ 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 clangll::*;
+ if let Some(ty) = ctx.builtin_or_resolved_ty(parent_id, ty, location) {
+ 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().kind() != CXType_Invalid {
+ 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.num_template_args() > 0 {
+ 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_ClassTemplate => {
+ name = location.spelling();
+ let complex =
+ CompInfo::from_ty(potential_id, ty, Some(location), ctx)
+ .expect("C'mon");
+ TypeKind::Comp(complex)
+ }
+ CXCursor_TemplateRef => {
+ let referenced = location.referenced();
+ return Self::from_clang_ty(potential_id,
+ &referenced.cur_type(),
+ Some(referenced),
+ parent_id,
+ ctx);
+ }
+ CXCursor_TypeRef => {
+ let referenced = location.referenced();
+ // FIXME: use potential id?
+ return Ok(ParseResult::AlreadyResolved(
+ Item::from_ty_or_ref(referenced.cur_type(),
+ Some(referenced),
+ parent_id,
+ ctx)));
+ }
+ _ => {
+ if ty.kind() == CXType_Unexposed {
+ warn!("Unexposed type {:?}, recursing inside, loc: {:?}", ty, location);
+ return Err(ParseError::Recurse);
+ }
+
+ error!("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);
+ }
+
+ error!("invalid type `{}`", ty.spelling());
+ return Err(ParseError::Continue);
+ }
+ }
+ // 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(), Some(ty.pointee_type().declaration()), parent_id, ctx);
+ TypeKind::Pointer(inner)
+ }
+ // 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(), Some(ty.pointee_type().declaration()), parent_id, ctx);
+ TypeKind::Reference(inner)
+ }
+ // XXX DependentSizedArray is wrong
+ CXType_VariableArray |
+ CXType_DependentSizedArray |
+ CXType_IncompleteArray => {
+ let inner = Item::from_ty(&ty.elem_type(), 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();
+ 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)
+ }
+ CXType_ConstantArray => {
+ let inner = Item::from_ty(&ty.elem_type(), location, parent_id, ctx)
+ .expect("Not able to resolve array element?");
+ TypeKind::Array(inner, ty.array_size())
+ }
+ #[cfg(not(feature="llvm_stable"))]
+ CXType_Elaborated => {
+ return Self::from_clang_ty(potential_id, &ty.named(),
+ location, parent_id, ctx);
+ }
+ _ => {
+ error!("unsupported type {:?} at {:?}", 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())))
+ }
+}
diff --git a/src/ir/var.rs b/src/ir/var.rs
new file mode 100644
index 00000000..ac59973b
--- /dev/null
+++ b/src/ir/var.rs
@@ -0,0 +1,160 @@
+use super::item::{Item, ItemId};
+use super::context::BindgenContext;
+use super::ty::TypeKind;
+use super::int::IntKind;
+use super::function::cursor_mangling;
+use parse::{ClangItemParser, ClangSubItemParser, ParseResult, ParseError};
+use clang;
+
+#[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,
+ /// TODO: support non-integer constants?
+ /// The integer value of the variable.
+ val: Option<i64>,
+ /// Whether this variable is const.
+ is_const: bool,
+}
+
+impl Var {
+ pub fn new(name: String,
+ mangled: Option<String>,
+ ty: ItemId,
+ val: Option<i64>,
+ is_const: bool) -> Var {
+ assert!(!name.is_empty());
+ Var {
+ name: name,
+ mangled_name: mangled,
+ ty: ty,
+ val: val,
+ is_const: is_const,
+ }
+ }
+
+ pub fn is_const(&self) -> bool {
+ self.is_const
+ }
+
+ pub fn val(&self) -> Option<i64> {
+ self.val
+ }
+
+ pub fn ty(&self) -> ItemId {
+ self.ty
+ }
+
+ pub fn name(&self) -> &str {
+ &self.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,
+ context: &mut BindgenContext) -> Result<ParseResult<Self>, ParseError> {
+ use clangll::*;
+ match cursor.kind() {
+ CXCursor_MacroDefinition => {
+ let value = match parse_int_literal_tokens(&cursor, context.translation_unit(), 1) {
+ None => return Err(ParseError::Continue),
+ Some(v) => v,
+ };
+
+ let name = cursor.spelling();
+ if name.is_empty() {
+ warn!("Empty macro name?");
+ return Err(ParseError::Continue);
+ }
+
+ if context.parsed_macro(&name) {
+ warn!("Duplicated macro definition: {}", name);
+ return Err(ParseError::Continue);
+ }
+ context.note_parsed_macro(name.clone());
+
+ let ty = if value.abs() > u32::max_value() as i64 {
+ Item::builtin_type(TypeKind::Int(IntKind::ULongLong), true, context)
+ } else {
+ Item::builtin_type(TypeKind::Int(IntKind::UInt), true, context)
+ };
+
+ Ok(ParseResult::New(Var::new(name, None, ty, Some(value), 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 = Item::from_ty(&ty, Some(cursor), None, context)
+ .expect("Unable to resolve constant type?");
+
+ let mut value = None;
+
+ // 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.
+ if context.safe_resolve_type(ty).map_or(false, |t| t.is_integer_literal()) {
+ // Try to parse a literal token value
+ cursor.visit(|c, _| {
+ if c.kind() == CXCursor_IntegerLiteral {
+ value =
+ parse_int_literal_tokens(&c,
+ context.translation_unit(),
+ 0);
+ }
+ CXChildVisit_Continue
+ });
+ }
+
+ 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)
+ }
+ }
+ }
+}
+
+fn parse_int_literal_tokens(cursor: &clang::Cursor,
+ unit: &clang::TranslationUnit,
+ which: usize) -> Option<i64> {
+ use clangll::CXToken_Literal;
+ let tokens = match unit.tokens(cursor) {
+ None => return None,
+ Some(tokens) => tokens,
+ };
+
+ if tokens.len() <= which || tokens[which].kind != CXToken_Literal {
+ return None;
+ }
+
+ let s = &tokens[which].spelling;
+ // TODO: try to preserve hex literals?
+ if s.starts_with("0x") {
+ i64::from_str_radix(&s[2..], 16).ok()
+ } else {
+ s.parse().ok()
+ }
+}