diff options
-rw-r--r-- | src/ir/context.rs | 86 | ||||
-rw-r--r-- | src/ir/item.rs | 28 | ||||
-rw-r--r-- | src/ir/ty.rs | 2 |
3 files changed, 98 insertions, 18 deletions
diff --git a/src/ir/context.rs b/src/ir/context.rs index edf42ec8..a2277b39 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -120,9 +120,7 @@ pub struct BindgenContext<'ctx> { /// 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)>, + currently_parsed_types: Vec<PartialType>, /// A HashSet with all the already parsed macro names. This is done to avoid /// hard errors while parsing duplicated macros, as well to allow macro @@ -193,6 +191,26 @@ impl<'ctx> BindgenContext<'ctx> { me } + /// Get the stack of partially parsed types that we are in the middle of + /// parsing. + pub fn currently_parsed_types(&self) -> &[PartialType] { + &self.currently_parsed_types[..] + } + + /// Begin parsing the given partial type, and push it onto the + /// `currently_parsed_types` stack so that we won't infinite recurse if we + /// run into a reference to it while parsing it. + pub fn begin_parsing(&mut self, partial_ty: PartialType) { + self.currently_parsed_types.push(partial_ty); + } + + /// Finish parsing the current partial type, pop it off the + /// `currently_parsed_types` stack, and return it. + pub fn finish_parsing(&mut self) -> PartialType { + self.currently_parsed_types.pop() + .expect("should have been parsing a type, if we finished parsing a type") + } + /// Get the user-provided type chooser by reference, if any. pub fn type_chooser(&self) -> Option<&TypeChooser> { self.options().type_chooser.as_ref().map(|t| &**t) @@ -1156,6 +1174,68 @@ impl<'ctx> BindgenContext<'ctx> { } } +/// A type that we are in the middle of parsing. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct PartialType { + decl: Cursor, + id: ItemId, +} + +impl PartialType { + /// Construct a new `PartialType`. + pub fn new(decl: Cursor, id: ItemId) -> PartialType { + // assert!(decl == decl.canonical()); + PartialType { + decl: decl, + id: id, + } + } + + /// The cursor pointing to this partial type's declaration location. + pub fn decl(&self) -> &Cursor { + &self.decl + } + + /// The item ID allocated for this type. This is *NOT* a key for an entry in + /// the context's item set yet! + pub fn id(&self) -> ItemId { + self.id + } +} + +impl TemplateDeclaration for PartialType { + fn template_params(&self, _ctx: &BindgenContext) -> Option<Vec<ItemId>> { + // Maybe at some point we will eagerly parse named types, but for now we + // don't and this information is unavailable. + None + } + + fn num_template_params(&self, _ctx: &BindgenContext) -> Option<usize> { + // Wouldn't it be nice if libclang would reliably give us this + // information‽ + match self.decl().kind() { + clang_sys::CXCursor_ClassTemplate | + clang_sys::CXCursor_FunctionTemplate | + clang_sys::CXCursor_TypeAliasTemplateDecl => { + let mut num_params = 0; + self.decl().visit(|c| { + match c.kind() { + clang_sys::CXCursor_TemplateTypeParameter | + clang_sys::CXCursor_TemplateTemplateParameter | + clang_sys::CXCursor_NonTypeTemplateParameter => { + num_params += 1; + } + _ => {} + }; + clang_sys::CXChildVisit_Continue + }); + Some(num_params) + } + _ => None, + } + } +} + /// An iterator over whitelisted items. /// /// See `BindgenContext::whitelisted_items` for more information. diff --git a/src/ir/item.rs b/src/ir/item.rs index 3ce228b6..83e2a41f 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -1,7 +1,7 @@ //! Bindgen's core intermediate representation type. use super::annotations::Annotations; -use super::context::{BindgenContext, ItemId}; +use super::context::{BindgenContext, ItemId, PartialType}; use super::derive::{CanDeriveCopy, CanDeriveDebug, CanDeriveDefault}; use super::function::Function; use super::item_kind::ItemKind; @@ -1202,18 +1202,18 @@ impl ClangItemParser for Item { }; if valid_decl { - if let Some(&(_, item_id)) = - ctx.currently_parsed_types - .iter() - .find(|&&(d, _)| d == declaration_to_look_for) { + if let Some(partial) = ctx.currently_parsed_types() + .iter() + .find(|ty| *ty.decl() == declaration_to_look_for) { debug!("Avoiding recursion parsing type: {:?}", ty); - return Ok(item_id); + return Ok(partial.id()); } } let current_module = ctx.current_module(); + let partial_ty = PartialType::new(declaration_to_look_for, id); if valid_decl { - ctx.currently_parsed_types.push((declaration_to_look_for, id)); + ctx.begin_parsing(partial_ty); } let result = Type::from_clang_ty(id, ty, location, parent_id, ctx); @@ -1241,9 +1241,8 @@ impl ClangItemParser for Item { // declaration_to_look_for suspiciously shares a lot of // logic with ir::context, so we should refactor that. if valid_decl { - let (popped_decl, _) = - ctx.currently_parsed_types.pop().unwrap(); - assert_eq!(popped_decl, declaration_to_look_for); + let finished = ctx.finish_parsing(); + assert_eq!(*finished.decl(), declaration_to_look_for); } location.visit(|cur| { @@ -1251,8 +1250,9 @@ impl ClangItemParser for Item { }); if valid_decl { - ctx.currently_parsed_types - .push((declaration_to_look_for, id)); + let partial_ty = + PartialType::new(declaration_to_look_for, id); + ctx.begin_parsing(partial_ty); } } // If we have recursed into the AST all we know, and we still @@ -1279,8 +1279,8 @@ impl ClangItemParser for Item { }; if valid_decl { - let (popped_decl, _) = ctx.currently_parsed_types.pop().unwrap(); - assert_eq!(popped_decl, declaration_to_look_for); + let partial_ty = ctx.finish_parsing(); + assert_eq!(*partial_ty.decl(), declaration_to_look_for); } ret diff --git a/src/ir/ty.rs b/src/ir/ty.rs index 0c90547e..a98ca446 100644 --- a/src/ir/ty.rs +++ b/src/ir/ty.rs @@ -755,7 +755,7 @@ impl Type { potential_id, ty, location); - debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types); + debug!("currently_parsed_types: {:?}", ctx.currently_parsed_types()); let canonical_ty = ty.canonical_type(); |