From c70baa86bcf81e419c21505d531eaea59a41b5af Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Thu, 27 Oct 2016 14:44:27 -0700 Subject: [PATCH] Document the `ir` module --- src/ir/annotations.rs | 22 ++++++++++- src/ir/comp.rs | 87 ++++++++++++++++++++++++++++++++++++++----- src/ir/context.rs | 54 +++++++++++++++++++++++++-- src/ir/enum_ty.rs | 25 +++++++++++-- src/ir/function.rs | 24 +++++++++++- src/ir/int.rs | 38 ++++++++++++++++++- src/ir/item.rs | 64 ++++++++++++++++++++++++------- src/ir/item_kind.rs | 24 ++++++++++++ src/ir/layout.rs | 8 ++++ src/ir/module.rs | 6 +++ src/ir/ty.rs | 49 ++++++++++++++++++++++-- src/ir/var.rs | 9 +++++ src/lib.rs | 2 +- src/parse.rs | 2 +- 14 files changed, 372 insertions(+), 42 deletions(-) diff --git a/src/ir/annotations.rs b/src/ir/annotations.rs index 64ab255dbf..f0d9715e5e 100644 --- a/src/ir/annotations.rs +++ b/src/ir/annotations.rs @@ -1,10 +1,21 @@ +//! Types and functions related to bindgen annotation comments. +//! +//! Users can add annotations in doc comments to types that they would like to +//! replace other types with, mark as opaque, etc. This module deals with all of +//! that stuff. + use clang; +/// What kind of accessor should we provide for a field? #[derive(Copy, PartialEq, Clone, Debug)] pub enum FieldAccessorKind { + /// No accessor. None, + /// Plain accessor. Regular, + /// Unsafe accessor. Unsafe, + /// Immutable accessor. Immutable, } @@ -53,6 +64,8 @@ impl Default for Annotations { } impl Annotations { + /// Construct new annotations for the given cursor and its bindgen comments + /// (if any). pub fn new(cursor: &clang::Cursor) -> Option { let mut anno = Annotations::default(); let mut matched_one = false; @@ -65,10 +78,12 @@ impl Annotations { } } + /// Should this type be hidden? pub fn hide(&self) -> bool { self.hide } + /// Should this type be opaque? pub fn opaque(&self) -> bool { self.opaque } @@ -87,10 +102,10 @@ impl Annotations { /// /// the generated code would look something like: /// - /// ```c++ + /// ``` /// /**
*/ /// struct Bar { - /// int x; + /// x: ::std::os::raw::c_int, /// }; /// ``` /// @@ -99,14 +114,17 @@ impl Annotations { self.use_instead_of.as_ref().map(|s| &**s) } + /// Should we avoid implementing the `Copy` trait? pub fn disallow_copy(&self) -> bool { self.disallow_copy } + /// Should the fields be private? pub fn private_fields(&self) -> Option { self.private_fields } + /// What kind of accessors should we provide for this type's fields? pub fn accessor_kind(&self) -> Option { self.accessor_kind } diff --git a/src/ir/comp.rs b/src/ir/comp.rs index f3bcf866e4..a85836074a 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -1,3 +1,5 @@ +//! Compound types (unions and structs) in our intermediate representation. + use super::annotations::Annotations; use super::context::BindgenContext; use super::layout::Layout; @@ -8,16 +10,23 @@ use std::cmp; use parse::{ClangItemParser, ParseError}; use clang; +/// The kind of compound type. #[derive(Debug, Copy, Clone, PartialEq)] pub enum CompKind { + /// A struct. Struct, + /// A union. Union, } +/// The kind of C++ method. #[derive(Debug, Copy, Clone, PartialEq)] pub enum MethodKind { + /// A static method. Static, + /// A normal method. Normal, + /// A virtual method. Virtual, } @@ -34,6 +43,7 @@ pub struct Method { } impl Method { + /// Construct a new `Method`. fn new(kind: MethodKind, signature: ItemId, is_const: bool) -> Self { Method { kind: kind, @@ -42,22 +52,27 @@ impl Method { } } + /// What kind of method is this? pub fn kind(&self) -> MethodKind { self.kind } + /// Is this a virtual method? pub fn is_virtual(&self) -> bool { self.kind == MethodKind::Virtual } + /// Is this a static method? pub fn is_static(&self) -> bool { self.kind == MethodKind::Static } + /// Get the `ItemId` for the `Function` signature for this method. pub fn signature(&self) -> ItemId { self.signature } + /// Is this a const qualified method? pub fn is_const(&self) -> bool { self.is_const } @@ -81,6 +96,7 @@ pub struct Field { } impl Field { + /// Construct a new `Field`. pub fn new(name: Option, ty: ItemId, comment: Option, @@ -97,48 +113,64 @@ impl Field { } } + /// Get the name of this field. pub fn name(&self) -> Option<&str> { self.name.as_ref().map(|n| &**n) } + /// Get the type of this field. pub fn ty(&self) -> ItemId { self.ty } + /// Get the comment for this field. pub fn comment(&self) -> Option<&str> { self.comment.as_ref().map(|c| &**c) } + /// If this is a bitfield, how many bits does it need? pub fn bitfield(&self) -> Option { self.bitfield } + /// Is this field marked as `mutable`? pub fn is_mutable(&self) -> bool { self.mutable } + /// Get the annotations for this field. pub fn annotations(&self) -> &Annotations { &self.annotations } } - +/// A compound type. +/// +/// Either a struct or union, a compound type is built up from the combination +/// of fields which also are associated with their own (potentially compound) +/// type. #[derive(Debug)] pub struct CompInfo { /// Whether this is a struct or a union. kind: CompKind, + /// The members of this struct or union. fields: Vec, + /// 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, + /// The method declarations inside this class, if in C++ mode. methods: Vec, + /// Vector of classes this one inherits from. base_members: Vec, + /// The parent reference template if any. ref_template: Option, + /// The inner types that were declared inside this class, in something like: /// /// class Foo { @@ -150,23 +182,31 @@ pub struct CompInfo { /// /// static Foo::Bar const = {3}; inner_types: Vec, + /// Set of static constants declared inside this class. inner_vars: Vec, + /// 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. @@ -174,15 +214,18 @@ pub struct CompInfo { /// 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, + /// Used to detect if we've run in a has_destructor cycle while cycling /// around the template arguments. detect_has_destructor_cycle: Cell, } impl CompInfo { + /// Construct a new compound type. pub fn new(kind: CompKind) -> Self { CompInfo { kind: kind, @@ -205,6 +248,7 @@ impl CompInfo { } } + /// Can we derive the `Debug` trait for this compound type? pub fn can_derive_debug(&self, ctx: &BindgenContext, layout: Option) -> bool { // We can reach here recursively via template parameters of a member, // for example. @@ -248,6 +292,7 @@ impl CompInfo { can_derive_debug } + /// Is this compound type unsized? pub fn is_unsized(&self, ctx: &BindgenContext) -> bool { !self.has_vtable(ctx) && self.fields.is_empty() && self.base_members.iter().all(|base| { @@ -261,6 +306,7 @@ impl CompInfo { }) } + /// Does this compound type have a destructor? pub fn has_destructor(&self, ctx: &BindgenContext) -> bool { if self.detect_has_destructor_cycle.get() { warn!("Cycle detected looking for destructors"); @@ -298,6 +344,7 @@ impl CompInfo { has_destructor } + /// Can we derive the `Copy` trait for this type? pub fn can_derive_copy(&self, ctx: &BindgenContext, item: &Item) -> 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 @@ -333,21 +380,24 @@ impl CompInfo { }) } + /// Is this type a template specialization? pub fn is_template_specialization(&self) -> bool { self.ref_template.is_some() } + /// Get the template declaration this specialization is specializing. pub fn specialized_template(&self) -> Option { 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 + /// Compute the layout of this type. + /// + /// This is called as a fallback under some circumstances where LLVM doesn't + /// give us the correct layout. + /// + /// If we're a union without known layout, we try to compute it from our + /// members. This is not ideal, but clang fails to report the size for these + /// kind of unions, see test/headers/template_union.hpp pub fn layout(&self, ctx: &BindgenContext) -> Option { use std::cmp; @@ -371,18 +421,24 @@ impl CompInfo { Some(Layout::new(max_size, max_align)) } + /// Get this type's set of fields. pub fn fields(&self) -> &[Field] { &self.fields } + /// Get this type's set of free template arguments. Empty if this is not a + /// template. pub fn template_args(&self) -> &[ItemId] { &self.template_args } + /// Does this type have any template parameters that aren't types + /// (e.g. int)? pub fn has_non_type_template_params(&self) -> bool { self.has_non_type_template_params } + /// Does this type have a virtual table? pub fn has_vtable(&self, ctx: &BindgenContext) -> bool { self.has_vtable || self.base_members().iter().any(|base| { ctx @@ -393,18 +449,22 @@ impl CompInfo { }) } + /// Get this type's set of methods. pub fn methods(&self) -> &[Method] { &self.methods } + /// What kind of compound type is this? pub fn kind(&self) -> CompKind { self.kind } + /// The set of types that this one inherits from. pub fn base_members(&self) -> &[ItemId] { &self.base_members } + /// Construct a new compound type from a Clang type. pub fn from_ty(potential_id: ItemId, ty: &clang::Type, location: Option, @@ -427,7 +487,6 @@ impl CompInfo { 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() { @@ -686,6 +745,10 @@ impl CompInfo { }) } + /// Do any of the types that participate in this type's "signature" use the + /// named type `ty`? + /// + /// See also documentation for `ir::Item::signature_contains_named_type`. pub fn signature_contains_named_type(&self, ctx: &BindgenContext, ty: &Type) -> bool { @@ -700,18 +763,24 @@ impl CompInfo { }) } + /// Get the set of types that were declared within this compound type + /// (e.g. nested class definitions). pub fn inner_types(&self) -> &[ItemId] { &self.inner_types } + /// Get the set of static variables declared within this compound type. pub fn inner_vars(&self) -> &[ItemId] { &self.inner_vars } + /// Have we found a field with an opaque type that could potentially mess up + /// the layout of this compound type? pub fn found_unknown_attr(&self) -> bool { self.found_unknown_attr } + /// Is this compound type packed? pub fn packed(&self) -> bool { self.packed } diff --git a/src/ir/context.rs b/src/ir/context.rs index 8031f5c08c..77cd118283 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -1,3 +1,5 @@ +//! Common context that is passed around during parsing and codegen. + use super::ty::{Type, TypeKind, FloatKind}; use super::item::{Item, ItemCanonicalName, ItemId}; use super::item_kind::ItemKind; @@ -97,6 +99,7 @@ pub struct BindgenContext<'ctx> { } impl<'ctx> BindgenContext<'ctx> { + /// Construct the context for the given `options`. pub fn new(options: BindgenOptions) -> Self { use clangll; @@ -130,6 +133,10 @@ impl<'ctx> BindgenContext<'ctx> { me } + /// Define a new item. + /// + /// This inserts it into the internal items set, and its type into the + /// internal types set. pub fn add_item(&mut self, item: Item, declaration: Option, @@ -186,10 +193,13 @@ impl<'ctx> BindgenContext<'ctx> { } // TODO: Move all this syntax crap to other part of the code. + + /// Given that we are in the codegen phase, get the syntex context. pub fn ext_cx(&self) -> &ExtCtxt<'ctx> { &self.gen_ctx.expect("Not in gen phase").0 } + /// Given that we are in the codegen phase, get the current syntex span. pub fn span(&self) -> Span { self.span } @@ -220,20 +230,24 @@ impl<'ctx> BindgenContext<'ctx> { self.rust_ident_raw(&self.rust_mangle(name)) } + /// Returns a mangled name as a rust identifier. pub fn rust_ident_raw(&self, name: &S) -> Ident where S: Borrow, { self.ext_cx().ident_of(name.borrow()) } + /// Iterate over all items that have been defined. pub fn items<'a>(&'a self) -> btree_map::Iter<'a, ItemId, Item> { self.items.iter() } + /// Have we collected all unresolved type references yet? pub fn collected_typerefs(&self) -> bool { self.collected_typerefs } + /// Gather all the unresolved type references. fn collect_typerefs(&mut self) -> Vec<(ItemId, clang::Type, Option, Option)> { debug_assert!(!self.collected_typerefs); self.collected_typerefs = true; @@ -255,6 +269,7 @@ impl<'ctx> BindgenContext<'ctx> { typerefs } + /// Collect all of our unresolved type references and resolve them. fn resolve_typerefs(&mut self) { let typerefs = self.collect_typerefs(); @@ -276,6 +291,8 @@ impl<'ctx> BindgenContext<'ctx> { } } + /// Iterate over all items and replace any item that has been named in a + /// `replaces="SomeType"` annotation with the replacement type. fn process_replacements(&mut self) { if self.replacements.is_empty() { return; @@ -322,7 +339,8 @@ impl<'ctx> BindgenContext<'ctx> { } } - // Enters in the generation phase. + /// Enter the code generation phase, invoke the given callback `cb`, and + /// leave the code generation phase. pub fn gen(&mut self, cb: F) -> Out where F: FnOnce(&Self) -> Out { @@ -381,22 +399,36 @@ impl<'ctx> BindgenContext<'ctx> { Item::new(id, None, None, id, ItemKind::Module(module)) } + /// Get the root module. pub fn root_module(&self) -> ItemId { self.root_module } + /// Resolve the given `ItemId` as a type. + /// + /// Panics if there is no item for the given `ItemId` or if the resolved + /// item is not a `Type`. pub fn resolve_type(&self, type_id: ItemId) -> &Type { self.items.get(&type_id).unwrap().kind().expect_type() } + /// Resolve the given `ItemId` as a type, or `None` if there is no item with + /// the given id. + /// + /// Panics if the id resolves to an item that is not a type. pub fn safe_resolve_type(&self, type_id: ItemId) -> Option<&Type> { self.items.get(&type_id).map(|t| t.kind().expect_type()) } + /// Resolve the given `ItemId` into an `Item`, or `None` if no such item + /// exists. pub fn resolve_item_fallible(&self, item_id: ItemId) -> Option<&Item> { self.items.get(&item_id) } + /// Resolve the given `ItemId` into an `Item`. + /// + /// Panics if the given id does not resolve to any item. pub fn resolve_item(&self, item_id: ItemId) -> &Item { match self.items.get(&item_id) { Some(item) => item, @@ -404,6 +436,7 @@ impl<'ctx> BindgenContext<'ctx> { } } + /// Get the current module. pub fn current_module(&self) -> ItemId { self.current_module } @@ -625,29 +658,38 @@ impl<'ctx> BindgenContext<'ctx> { Some(id) } + /// Get the current Clang translation unit that is being processed. pub fn translation_unit(&self) -> &clang::TranslationUnit { &self.translation_unit } + /// Have we parsed the macro named `macro_name` already? pub fn parsed_macro(&self, macro_name: &str) -> bool { self.parsed_macros.contains(macro_name) } + /// Mark the macro named `macro_name` as parsed. pub fn note_parsed_macro(&mut self, macro_name: String) { debug_assert!(!self.parsed_macros.contains(¯o_name)); self.parsed_macros.insert(macro_name); } + /// Are we in the codegen phase? 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. + /// Mark the type with the given `name` as replaced by the type with id + /// `potential_ty`. + /// + /// Replacement types are declared using the `replaces="xxx"` annotation, + /// and implies that the original type is hidden. pub fn replace(&mut self, name: &str, potential_ty: ItemId) { self.replacements.insert(name.into(), potential_ty); } + /// Is the item with the given `name` hidden? Or is the item with the given + /// `name` and `id` replaced by another type, and effectively hidden? pub fn hidden_by_name(&self, name: &str, id: ItemId) -> bool { debug_assert!(self.in_codegen_phase(), "You're not supposed to call this yet"); @@ -655,6 +697,8 @@ impl<'ctx> BindgenContext<'ctx> { self.is_replaced_type(name, id) } + /// Has the item with the given `name` and `id` been replaced by another + /// type? pub fn is_replaced_type(&self, name: &str, id: ItemId) -> bool { match self.replacements.get(name) { Some(replaced_by) if *replaced_by != id => true, @@ -662,12 +706,14 @@ impl<'ctx> BindgenContext<'ctx> { } } + /// Is the type with the given `name` marked as opaque? 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) } + /// Get the options used to configure this bindgen context. pub fn options(&self) -> &BindgenOptions { &self.options } @@ -704,6 +750,8 @@ impl<'ctx> BindgenContext<'ctx> { module_id } + /// Start traversing the module with the given `module_id`, invoke the + /// callback `cb`, and then return to traversing the original module. pub fn with_module(&mut self, module_id: ItemId, cb: F) where F: FnOnce(&mut Self, &mut Vec) { diff --git a/src/ir/enum_ty.rs b/src/ir/enum_ty.rs index c85ee07a2d..aff5130bcb 100644 --- a/src/ir/enum_ty.rs +++ b/src/ir/enum_ty.rs @@ -1,22 +1,27 @@ +//! Intermediate representation for C/C++ enumerations. + use super::item::{Item, ItemId}; use super::ty::TypeKind; use super::context::BindgenContext; use parse::{ClangItemParser, ParseError}; use clang; +/// A C/C++ enumeration. #[derive(Debug)] pub struct Enum { - /// The representation used for this enum. - /// Should be an IntKind type. + /// The representation used for this enum; it should be an `IntKind` type or + /// an alias to one. /// - /// It's None if the enum is a forward declaration and isn't defined - /// anywhere else, see tests/headers/func_ptr_in_struct.h + /// 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, + /// The different variants, with explicit values. variants: Vec, } impl Enum { + /// Construct a new `Enum` with the given representation and variants. pub fn new(repr: Option, variants: Vec) -> Self { Enum { repr: repr, @@ -24,14 +29,17 @@ impl Enum { } } + /// Get this enumeration's representation. pub fn repr(&self) -> Option { self.repr } + /// Get this enumeration's variants. pub fn variants(&self) -> &[EnumVariant] { &self.variants } + /// Construct an enumeration from the given Clang type. pub fn from_ty(ty: &clang::Type, ctx: &mut BindgenContext) -> Result { use clangll::*; @@ -79,19 +87,26 @@ impl Enum { pub struct EnumVariant { /// The name of the variant. name: String, + /// An optional doc comment. comment: Option, + /// The integer value of the variant. val: EnumVariantValue, } +/// A constant value assigned to an enumeration variant. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum EnumVariantValue { + /// A signed constant. Signed(i64), + + /// An unsigned constant. Unsigned(u64), } impl EnumVariant { + /// Construct a new enumeration variant from the given parts. pub fn new(name: String, comment: Option, val: EnumVariantValue) -> Self { EnumVariant { name: name, @@ -100,10 +115,12 @@ impl EnumVariant { } } + /// Get this variant's name. pub fn name(&self) -> &str { &self.name } + /// Get this variant's value. pub fn val(&self) -> EnumVariantValue { self.val } diff --git a/src/ir/function.rs b/src/ir/function.rs index af170935dc..2693eddf3e 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -1,3 +1,5 @@ +//! Intermediate representation for C/C++ functions and methods. + use super::item::{Item, ItemId}; use super::ty::TypeKind; use super::context::BindgenContext; @@ -6,22 +8,27 @@ use clang; use clangll::Enum_CXCallingConv; use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult}; -/// A function declaration , with a signature, arguments, and argument names. +/// A function declaration, with a signature, arguments, and argument names. /// /// The argument names vector must be the same length as the ones in the /// signature. #[derive(Debug)] pub struct Function { + /// The name of this function. name: String, + /// The mangled name, that is, the symbol. mangled_name: Option, + /// The id pointing to the current function signature. signature: ItemId, + /// The doc comment on the function, if any. comment: Option, } impl Function { + /// Construct a new function. pub fn new(name: String, mangled_name: Option, sig: ItemId, @@ -34,14 +41,17 @@ impl Function { } } + /// Get this function's name. pub fn name(&self) -> &str { &self.name } + /// Get this function's name. pub fn mangled_name(&self) -> Option<&str> { self.mangled_name.as_ref().map(|n| &**n) } + /// Get this function's signature. pub fn signature(&self) -> ItemId { self.signature } @@ -52,12 +62,15 @@ impl Function { 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, ItemId)>, + /// Whether this function is variadic. is_variadic: bool, - /// The abi of this function. + + /// The ABI of this function. abi: abi::Abi, } @@ -74,6 +87,7 @@ fn get_abi(cc: Enum_CXCallingConv) -> abi::Abi { } } +/// Get the mangled name for the cursor's referent. pub fn cursor_mangling(cursor: &clang::Cursor) -> Option { // We early return here because libclang may crash in some case // if we pass in a variable inside a partial specialized template. @@ -93,6 +107,7 @@ pub fn cursor_mangling(cursor: &clang::Cursor) -> Option { } impl FunctionSig { + /// Construct a new function signature. pub fn new(return_type: ItemId, arguments: Vec<(Option, ItemId)>, is_variadic: bool, @@ -105,6 +120,7 @@ impl FunctionSig { } } + /// Construct a new function signature from the given Clang type. pub fn from_ty(ty: &clang::Type, cursor: &clang::Cursor, ctx: &mut BindgenContext) -> Result { @@ -176,18 +192,22 @@ impl FunctionSig { Ok(Self::new(ret, args, ty.is_variadic(), abi)) } + /// Get this function signature's return type. pub fn return_type(&self) -> ItemId { self.return_type } + /// Get this function signature's argument (name, type) pairs. pub fn argument_types(&self) -> &[(Option, ItemId)] { &self.argument_types } + /// Get this function signature's ABI. pub fn abi(&self) -> abi::Abi { self.abi } + /// Is this function signature variadic? pub fn is_variadic(&self) -> bool { // Clang reports some functions as variadic when they *might* be // variadic. We do the argument check because rust doesn't codegen well diff --git a/src/ir/int.rs b/src/ir/int.rs index 75e576d48a..ed26acc4cb 100644 --- a/src/ir/int.rs +++ b/src/ir/int.rs @@ -1,24 +1,58 @@ +//! Intermediate representation for integral types. + +/// Which integral type are we dealing with? #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum IntKind { + /// A `bool`. Bool, + + /// A `char`. Char, + + /// An `unsigned char`. UChar, + + /// A `short`. Short, + + /// An `unsigned short`. UShort, + + /// An `int`. Int, + + /// An `unsigned int`. UInt, + + /// A `long`. Long, + + /// An `unsigned long`. ULong, + + /// A `long long`. LongLong, + + /// An `unsigned long long`. ULongLong, - U16, // For Char16 and Wchar - U32, // For Char32 + + /// Either a `char16_t` or a `wchar_t`. + U16, + + /// A `char32_t`. + U32, + + /// An `int128_t` I128, + + /// A `uint128_t`. U128, + // Though now we're at it we could add equivalents for the rust types... } impl IntKind { + /// Is this integral type signed? pub fn is_signed(&self) -> bool { use self::IntKind::*; match *self { diff --git a/src/ir/item.rs b/src/ir/item.rs index 6cb6d7c6b1..8ec4e78abe 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -1,3 +1,5 @@ +//! Bindgen's core intermediate representation type. + use regex::Regex; use super::context::BindgenContext; use super::item_kind::ItemKind; @@ -22,6 +24,7 @@ use clangll; /// This name is required to be safe for Rust, that is, is not expected to /// return any rust keyword from here. pub trait ItemCanonicalName { + /// Get the canonical name for this item. fn canonical_name(&self, ctx: &BindgenContext) -> String; } @@ -35,9 +38,10 @@ pub trait ItemCanonicalName { /// } /// ``` /// -/// For bar, the canonical path is foo::BAR, while the canonical name is just -/// BAR. +/// For bar, the canonical path is `foo::BAR`, while the canonical name is just +/// `BAR`. pub trait ItemCanonicalPath { + /// Get the canonical path for this item. fn canonical_path(&self, ctx: &BindgenContext) -> Vec; } @@ -47,10 +51,10 @@ pub trait ItemCanonicalPath { #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ItemId(usize); -pub static NEXT_ITEM_ID: AtomicUsize = ATOMIC_USIZE_INIT; - impl ItemId { + /// Allocate the next `ItemId`. pub fn next() -> Self { + static NEXT_ITEM_ID: AtomicUsize = ATOMIC_USIZE_INIT; ItemId(NEXT_ITEM_ID.fetch_add(1, Ordering::Relaxed)) } } @@ -76,10 +80,13 @@ impl ItemCanonicalPath for ItemId { /// module, a type, a function, or a variable (see `ItemKind` for more /// information). /// -/// Items form a graph, and each item only stores the id of the parent. +/// Items refer to each other by `ItemId`. Every item has its parent's +/// id. Depending on the kind of item this is, it may also refer to other items, +/// such as a compound type item referring to other types. Collectively, these +/// references form a graph. /// -/// The entry-point of this graph is the "root module", a meta-item used to hold -/// all the top-level items. +/// The entry-point to this graph is the "root module": a meta-item used to hold +/// all top-level items. /// /// An item may have a comment, and annotations (see the `annotations` module). /// @@ -111,6 +118,7 @@ pub struct Item { } impl Item { + /// Construct a new `Item`. pub fn new(id: ItemId, comment: Option, annotations: Option, @@ -128,26 +136,38 @@ impl Item { } } + /// Get this `Item`'s identifier. pub fn id(&self) -> ItemId { self.id } + /// Get this `Item`'s parent's identifier. + /// + /// For the root module, the parent's ID is its own ID. pub fn parent_id(&self) -> ItemId { self.parent_id } + /// Get this `Item`'s comment, if it has any. pub fn comment(&self) -> Option<&str> { self.comment.as_ref().map(|c| &**c) } + /// What kind of item is this? pub fn kind(&self) -> &ItemKind { &self.kind } + /// Get a mutable reference to this item's kind. pub fn kind_mut(&mut self) -> &mut ItemKind { &mut self.kind } + /// Get an identifier that differentiates this item from its siblings. + /// + /// This should stay relatively stable in the face of code motion outside or + /// below this item's lexical scope, meaning that this can be useful for + /// generating relatively stable identifiers within a scope. pub fn local_id(&self, ctx: &BindgenContext) -> usize { if self.local_id.get().is_none() { let parent = ctx.resolve_item(self.parent_id); @@ -202,10 +222,14 @@ impl Item { } } + /// Get a reference to this item's underlying `Type`. Panic if this is some + /// other kind of item. pub fn expect_type(&self) -> &Type { self.kind().expect_type() } + /// Get a reference to this item's underlying `Function`. Panic if this is + /// some other kind of item. pub fn expect_function(&self) -> &Function { self.kind().expect_function() } @@ -214,7 +238,7 @@ impl Item { /// /// This function is used to avoid unused template parameter errors in Rust /// when generating typedef declarations, and also to know whether we need - /// to generate a PhantomData member for a template parameter. + /// to generate a `PhantomData` member for a template parameter. /// /// For example, in code like the following: /// @@ -229,13 +253,13 @@ impl Item { /// }; /// ``` /// - /// Both Foo and Baz contain both `T` and `U` template parameters in their - /// signature: + /// Both `Foo` and `Baz` contain both `T` and `U` template parameters in + /// their signature: /// /// * `Foo` /// * `Bar` /// - /// But the structure for `Foo` would look like: + /// But the Rust structure for `Foo` would look like: /// /// ```rust /// struct Foo { @@ -244,7 +268,7 @@ impl Item { /// } /// ``` /// - /// because non of its member fields contained the `U` type in the + /// because none of its member fields contained the `U` type in the /// signature. Similarly, `Bar` would contain a `PhantomData` type, for /// the same reason. /// @@ -372,12 +396,14 @@ impl Item { } } + /// Get this item's annotations. pub fn annotations(&self) -> &Annotations { &self.annotations } - /// Whether this item should be hidden, either due to annotations, or due to - /// other kind of configuration. + /// Whether this item should be hidden. + /// + /// This may be due to either annotations or to other kind of configuration. pub fn is_hidden(&self, ctx: &BindgenContext) -> bool { debug_assert!(ctx.in_codegen_phase(), "You're not supposed to call this yet"); @@ -385,6 +411,7 @@ impl Item { ctx.hidden_by_name(&self.real_canonical_name(ctx, false, true), self.id) } + /// Is this item opaque? pub fn is_opaque(&self, ctx: &BindgenContext) -> bool { debug_assert!(ctx.in_codegen_phase(), "You're not supposed to call this yet"); @@ -520,10 +547,12 @@ impl Item { static ref RE_ENDS_WITH_BINDGEN_TY: Regex = Regex::new(r"_bindgen_ty(_\d+)+$").unwrap(); static ref RE_ENDS_WITH_BINDGEN_MOD: Regex = Regex::new(r"_bindgen_mod(_\d+)+$").unwrap(); } + let (re, kind) = match *self.kind() { ItemKind::Module(..) => (&*RE_ENDS_WITH_BINDGEN_MOD, "mod"), _ => (&*RE_ENDS_WITH_BINDGEN_TY, "ty"), }; + let parent_name = parent_name.and_then(|n| if n.is_empty() { None } else { Some(n) }); match (parent_name, base_name) { (Some(parent), Some(base)) => format!("{}_{}", parent, base), @@ -539,6 +568,8 @@ impl Item { } } + /// Get a mutable reference to this item's `Module`, or `None` if this is + /// not a `Module` item. pub fn as_module_mut(&mut self) -> Option<&mut Module> { match self.kind { ItemKind::Module(ref mut module) => Some(module), @@ -546,10 +577,15 @@ impl Item { } } + /// Can we derive an implementation of the `Copy` trait for this type? pub fn can_derive_copy(&self, ctx: &BindgenContext) -> bool { self.expect_type().can_derive_copy(ctx, self) } + /// Can we derive an implementation of the `Copy` trait for an array of this + /// type? + /// + /// See `Type::can_derive_copy_in_array` for details. pub fn can_derive_copy_in_array(&self, ctx: &BindgenContext) -> bool { self.expect_type().can_derive_copy_in_array(ctx, self) } diff --git a/src/ir/item_kind.rs b/src/ir/item_kind.rs index a47d23a382..d9e4690cb4 100644 --- a/src/ir/item_kind.rs +++ b/src/ir/item_kind.rs @@ -1,3 +1,5 @@ +//! Different variants of an `Item` in our intermediate representation. + use super::function::Function; use super::module::Module; use super::ty::Type; @@ -21,6 +23,8 @@ pub enum ItemKind { } impl ItemKind { + /// Get a reference to this `ItemKind`'s underying `Module`, or `None` if it + /// is some other kind. pub fn as_module(&self) -> Option<&Module> { match *self { ItemKind::Module(ref module) => Some(module), @@ -28,14 +32,19 @@ impl ItemKind { } } + /// Is this a module? pub fn is_module(&self) -> bool { self.as_module().is_some() } + /// Get a reference to this `ItemKind`'s underying `Module`, or panic if it + /// is some other kind. pub fn expect_module(&self) -> &Module { self.as_module().expect("Not a module") } + /// Get a reference to this `ItemKind`'s underying `Function`, or `None` if + /// it is some other kind. pub fn as_function(&self) -> Option<&Function> { match *self { ItemKind::Function(ref func) => Some(func), @@ -43,14 +52,19 @@ impl ItemKind { } } + /// Is this a function? pub fn is_function(&self) -> bool { self.as_function().is_some() } + /// Get a reference to this `ItemKind`'s underying `Function`, or panic if + /// it is some other kind. pub fn expect_function(&self) -> &Function { self.as_function().expect("Not a function") } + /// Get a reference to this `ItemKind`'s underying `Type`, or `None` if + /// it is some other kind. pub fn as_type(&self) -> Option<&Type> { match *self { ItemKind::Type(ref ty) => Some(ty), @@ -58,6 +72,8 @@ impl ItemKind { } } + /// Get a mutable reference to this `ItemKind`'s underying `Type`, or `None` + /// if it is some other kind. pub fn as_type_mut(&mut self) -> Option<&mut Type> { match *self { ItemKind::Type(ref mut ty) => Some(ty), @@ -65,14 +81,19 @@ impl ItemKind { } } + /// Is this a type? pub fn is_type(&self) -> bool { self.as_type().is_some() } + /// Get a reference to this `ItemKind`'s underying `Type`, or panic if it is + /// some other kind. pub fn expect_type(&self) -> &Type { self.as_type().expect("Not a type") } + /// Get a reference to this `ItemKind`'s underying `Var`, or `None` if it is + /// some other kind. pub fn as_var(&self) -> Option<&Var> { match *self { ItemKind::Var(ref v) => Some(v), @@ -80,10 +101,13 @@ impl ItemKind { } } + /// Is this a variable? pub fn is_var(&self) -> bool { self.as_var().is_some() } + /// Get a reference to this `ItemKind`'s underying `Var`, or panic if it is + /// some other kind. pub fn expect_var(&self) -> &Var { self.as_var().expect("Not a var") } diff --git a/src/ir/layout.rs b/src/ir/layout.rs index d672ebea27..3ac4a5f417 100644 --- a/src/ir/layout.rs +++ b/src/ir/layout.rs @@ -1,13 +1,19 @@ +//! Intermediate representation for the physical layout of some type. /// A type that represents the struct layout of a type. #[derive(Debug, Clone, Copy)] pub struct Layout { + /// The size (in bytes) of this layout. pub size: usize, + /// The alignment (in bytes) of this layout. pub align: usize, + /// Whether this layout's members are packed or not. pub packed: bool, } impl Layout { + /// Construct a new `Layout` with the given `size` and `align`. It is not + /// packed. pub fn new(size: usize, align: usize) -> Self { Layout { size: size, @@ -16,10 +22,12 @@ impl Layout { } } + /// Is this a zero-sized layout? pub fn is_zero(&self) -> bool { self.size == 0 && self.align == 0 } + /// Construct a zero-sized layout. pub fn zero() -> Self { Self::new(0, 0) } diff --git a/src/ir/module.rs b/src/ir/module.rs index 77fee5ef4f..591a4e3af8 100644 --- a/src/ir/module.rs +++ b/src/ir/module.rs @@ -1,3 +1,5 @@ +//! Intermediate representation for modules (AKA C++ namespaces). + use super::context::BindgenContext; use super::item::ItemId; use clang; @@ -14,6 +16,7 @@ pub struct Module { } impl Module { + /// Construct a new `Module`. pub fn new(name: Option) -> Self { Module { name: name, @@ -21,14 +24,17 @@ impl Module { } } + /// Get this module's name. pub fn name(&self) -> Option<&str> { self.name.as_ref().map(|n| &**n) } + /// Get a mutable reference to this module's children. pub fn children_mut(&mut self) -> &mut Vec { &mut self.children_ids } + /// Get this module's children. pub fn children(&self) -> &[ItemId] { &self.children_ids } diff --git a/src/ir/ty.rs b/src/ir/ty.rs index 5765a78c5c..3a17b374c7 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -1,3 +1,5 @@ +//! Everything related to types in our intermediate representation. + use super::comp::CompInfo; use super::enum_ty::Enum; use super::function::FunctionSig; @@ -25,9 +27,16 @@ pub struct Type { is_const: bool, } -pub const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32usize; +/// The maximum number of items in an array for which Rust implements common +/// traits, and so if we have a type containing an array with more than this +/// many items, we won't be able to derive common traits on that type. +/// +/// We need type-level integers yesterday :'( +pub const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32; impl Type { + /// Get the underlying `CompInfo` for this type, or `None` if this is some + /// other kind of type. pub fn as_comp(&self) -> Option<&CompInfo> { match self.kind { TypeKind::Comp(ref ci) => Some(ci), @@ -35,6 +44,7 @@ impl Type { } } + /// Construct a new `Type`. pub fn new(name: Option, layout: Option, kind: TypeKind, @@ -47,18 +57,22 @@ impl Type { } } + /// Which kind of type is this? pub fn kind(&self) -> &TypeKind { &self.kind } + /// Get a mutable reference to this type's kind. pub fn kind_mut(&mut self) -> &mut TypeKind { &mut self.kind } + /// Get this type's name. pub fn name(&self) -> Option<&str> { self.name.as_ref().map(|name| &**name) } + /// Is this a compound type? pub fn is_comp(&self) -> bool { match self.kind { TypeKind::Comp(..) => true, @@ -66,6 +80,7 @@ impl Type { } } + /// Is this a named type? pub fn is_named(&self) -> bool { match self.kind { TypeKind::Named(..) => true, @@ -73,6 +88,7 @@ impl Type { } } + /// Is this a function type? pub fn is_function(&self) -> bool { match self.kind { TypeKind::Function(..) => true, @@ -80,6 +96,7 @@ impl Type { } } + /// Is this either a builtin or named type? pub fn is_builtin_or_named(&self) -> bool { match self.kind { TypeKind::Void | @@ -104,6 +121,7 @@ impl Type { Self::new(Some(name), None, kind, false) } + /// Is this an integer type? pub fn is_integer(&self, ctx: &BindgenContext) -> bool { match self.kind { TypeKind::UnresolvedTypeRef(..) => false, @@ -114,10 +132,12 @@ impl Type { } } + /// Is this a `const` qualified type? pub fn is_const(&self) -> bool { self.is_const } + /// What is the layout of this type? pub fn layout(&self, ctx: &BindgenContext) -> Option { use std::mem; @@ -326,8 +346,11 @@ impl Type { /// The kind of float this type represents. #[derive(Debug, Copy, Clone, PartialEq)] pub enum FloatKind { + /// A `float`. Float, + /// A `double`. Double, + /// A `long double`. LongDouble, } @@ -336,33 +359,46 @@ pub enum FloatKind { pub enum TypeKind { /// The void type. Void, - /// The nullptr_t type. + + /// 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), - /// A templated alias, pointing to an inner Alias type, with template + + /// A templated alias, pointing to an inner `Alias` type, with template /// parameters. TemplateAlias(ItemId, Vec), + /// An array of a type and a lenght. Array(ItemId, usize), + /// A function type, with a given signature. Function(FunctionSig), - /// An enum type. + + /// An `enum` type. Enum(Enum), + /// A pointer to a type. The bool field represents whether it's const or /// not. Pointer(ItemId), + /// A pointer to an Apple block. BlockPointer, + /// A reference to a type, as in: int& foo(). Reference(ItemId), + /// A reference to a template, with different template parameter names. To /// see why this is needed, check out the creation of this variant in /// `Type::from_clang_ty`. @@ -376,6 +412,11 @@ pub enum TypeKind { /// /// see tests/headers/typeref.hpp to see somewhere where this is a problem. UnresolvedTypeRef(clang::Type, Option, /* parent_id */ Option), + + /// An indirection to another type. + /// + /// These are generated after we resolve a forward declaration, or when we + /// replace one type with another. ResolvedTypeRef(ItemId), /// A named type, that is, a template parameter, with an optional default diff --git a/src/ir/var.rs b/src/ir/var.rs index 623a0636ef..3dd975eef1 100644 --- a/src/ir/var.rs +++ b/src/ir/var.rs @@ -1,3 +1,5 @@ +//! Intermediate representation of variables. + use super::item::{Item, ItemId}; use super::context::BindgenContext; use super::ty::TypeKind; @@ -6,6 +8,7 @@ use super::function::cursor_mangling; use parse::{ClangItemParser, ClangSubItemParser, ParseResult, ParseError}; use clang; +/// A `Var` is our intermediate representation of a variable. #[derive(Debug)] pub struct Var { /// The name of the variable. @@ -22,6 +25,7 @@ pub struct Var { } impl Var { + /// Construct a new `Var`. pub fn new(name: String, mangled: Option, ty: ItemId, @@ -37,22 +41,27 @@ impl Var { } } + /// Is this variable `const` qualified? pub fn is_const(&self) -> bool { self.is_const } + /// The value of this constant variable, if any. pub fn val(&self) -> Option { self.val } + /// Get this variable's type. pub fn ty(&self) -> ItemId { self.ty } + /// Get this variable's name. pub fn name(&self) -> &str { &self.name } + /// Get this variable's mangled name. pub fn mangled_name(&self) -> Option<&str> { self.mangled_name.as_ref().map(|n| &**n) } diff --git a/src/lib.rs b/src/lib.rs index 29369d417b..76862721e5 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,7 +54,7 @@ macro_rules! doc_mod { mod clangll; doc_mod!(clang); -mod ir; +doc_mod!(ir); mod parse; mod regex_set; diff --git a/src/parse.rs b/src/parse.rs index d6c36aa456..c71f4c52b5 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -16,7 +16,7 @@ pub enum ParseResult { } pub trait ClangSubItemParser : Sized { - /// The fact that is a reference guarantees it's holded by the context, and + /// The fact that is a reference guarantees it's held by the context, and /// allow returning already existing types. fn parse(cursor: clang::Cursor, context: &mut BindgenContext) -> Result, ParseError>; }