diff options
Diffstat (limited to 'src/codegen/derive_debug.rs')
-rw-r--r-- | src/codegen/derive_debug.rs | 244 |
1 files changed, 136 insertions, 108 deletions
diff --git a/src/codegen/derive_debug.rs b/src/codegen/derive_debug.rs index a47d37d1..2fd9cd65 100644 --- a/src/codegen/derive_debug.rs +++ b/src/codegen/derive_debug.rs @@ -1,7 +1,7 @@ use ir::comp::{BitfieldUnit, CompKind, Field, FieldData, FieldMethods}; use ir::context::BindgenContext; use ir::derive::CanTriviallyDeriveDebug; -use ir::item::{IsOpaque, Item, ItemCanonicalName}; +use ir::item::{HasTypeParamInArray, IsOpaque, Item, ItemCanonicalName}; use ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT}; use syntax::ast; use syntax::codemap::DUMMY_SP; @@ -28,12 +28,8 @@ pub fn gen_debug_impl( } CompKind::Struct => { let processed_fields = fields.iter().filter_map(|f| match f { - &Field::DataMember(ref fd) => { - gen_field_data_debug_impl(ctx, fd) - } - &Field::Bitfields(ref bu) => { - gen_bitfield_unit_debug_impl(ctx, bu) - } + &Field::DataMember(ref fd) => fd.impl_debug(ctx, ()), + &Field::Bitfields(ref bu) => bu.impl_debug(ctx, ()), }); @@ -66,132 +62,164 @@ pub fn gen_debug_impl( } } -fn gen_field_data_debug_impl( - ctx: &BindgenContext, - data: &FieldData, -) -> Option<(String, Vec<TokenTree>)> { - if let Some(name) = data.name() { - gen_item_debug_impl(ctx, ctx.resolve_item(data.ty()), name) - } else { - None - } +/// A trait for the things which we can codegen tokens that contribute towards a +/// generated `impl Debug`. +pub trait ImplDebug<'a> { + /// Any extra parameter required by this a particular `ImplDebug` implementation. + type Extra; + + /// Generate a format string snippet to be included in the larger `impl Debug` + /// format string, and the code to get the format string's interpolation values. + fn impl_debug( + &self, + ctx: &BindgenContext, + extra: Self::Extra, + ) -> Option<(String, Vec<TokenTree>)>; } -fn gen_bitfield_unit_debug_impl( - ctx: &BindgenContext, - data: &BitfieldUnit, -) -> Option<(String, Vec<TokenTree>)> { - let mut format_string = String::new(); - let mut tokens = Vec::new(); - for (i, bu) in data.bitfields().iter().enumerate() { - if i > 0 { - format_string.push_str(", "); - tokens.push(TokenTree::Token(DUMMY_SP, Token::Comma)); +impl<'a> ImplDebug<'a> for FieldData { + type Extra = (); + + fn impl_debug( + &self, + ctx: &BindgenContext, + _: Self::Extra, + ) -> Option<(String, Vec<TokenTree>)> { + if let Some(name) = self.name() { + ctx.resolve_item(self.ty()).impl_debug(ctx, name) + } else { + None } - format_string.push_str(&format!("{} : {{:?}}", bu.name())); - let name_ident = ctx.rust_ident_raw(bu.name()); - tokens.extend(quote_tokens!(ctx.ext_cx(), self.$name_ident())); } - - Some((format_string, tokens)) } -fn gen_item_debug_impl( - ctx: &BindgenContext, - item: &Item, - name: &str, -) -> Option<(String, Vec<TokenTree>)> { - let name_ident = ctx.rust_ident_raw(name); - - let ty = match item.as_type() { - Some(ty) => ty, - None => { - return None; - } - }; +impl<'a> ImplDebug<'a> for BitfieldUnit { + type Extra = (); - fn debug_print( + fn impl_debug( + &self, ctx: &BindgenContext, - name: &str, - name_ident: ast::Ident, + _: Self::Extra, ) -> Option<(String, Vec<TokenTree>)> { - Some(( - format!("{}: {{:?}}", name), - quote_tokens!(ctx.ext_cx(), self.$name_ident), - )) + let mut format_string = String::new(); + let mut tokens = Vec::new(); + for (i, bu) in self.bitfields().iter().enumerate() { + if i > 0 { + format_string.push_str(", "); + tokens.push(TokenTree::Token(DUMMY_SP, Token::Comma)); + } + format_string.push_str(&format!("{} : {{:?}}", bu.name())); + let name_ident = ctx.rust_ident_raw(bu.name()); + tokens.extend(quote_tokens!(ctx.ext_cx(), self.$name_ident())); + } + + Some((format_string, tokens)) } +} - match *ty.kind() { - // Handle the simple cases. - TypeKind::Void | - TypeKind::NullPtr | - TypeKind::Int(..) | - TypeKind::Float(..) | - TypeKind::Complex(..) | - TypeKind::Function(..) | - TypeKind::Enum(..) | - TypeKind::Reference(..) | - TypeKind::BlockPointer | - TypeKind::UnresolvedTypeRef(..) | - TypeKind::ObjCInterface(..) | - TypeKind::ObjCId | - TypeKind::Comp(..) | - TypeKind::ObjCSel => debug_print(ctx, name, name_ident), - - TypeKind::TemplateInstantiation(ref inst) => { - if inst.is_opaque(ctx, item) { - Some((format!("{}: opaque", name), vec![])) - } else { - debug_print(ctx, name, name_ident) - } - } +impl<'a> ImplDebug<'a> for Item { + type Extra = &'a str; + + fn impl_debug( + &self, + ctx: &BindgenContext, + name: Self::Extra, + ) -> Option<(String, Vec<TokenTree>)> { + let name_ident = ctx.rust_ident_raw(name); - // The generic is not required to implement Debug, so we can not debug print that type - TypeKind::Named => { - Some((format!("{}: Non-debuggable generic", name), vec![])) + let ty = match self.as_type() { + Some(ty) => ty, + None => { + return None; + } + }; + + fn debug_print( + ctx: &BindgenContext, + name: &str, + name_ident: ast::Ident, + ) -> Option<(String, Vec<TokenTree>)> { + Some(( + format!("{}: {{:?}}", name), + quote_tokens!(ctx.ext_cx(), self.$name_ident), + )) } - TypeKind::Array(_, len) => { - // Generics are not required to implement Debug - if ctx.lookup_item_id_has_type_param_in_array(&item.id()) { - Some((format!("{}: Array with length {}", name, len), vec![])) - } else if len < RUST_DERIVE_IN_ARRAY_LIMIT { - // The simple case - debug_print(ctx, name, name_ident) - } else { - // Let's implement our own print function - Some(( - format!("{}: [{{}}]", name), - quote_tokens!( + match *ty.kind() { + // Handle the simple cases. + TypeKind::Void | + TypeKind::NullPtr | + TypeKind::Int(..) | + TypeKind::Float(..) | + TypeKind::Complex(..) | + TypeKind::Function(..) | + TypeKind::Enum(..) | + TypeKind::Reference(..) | + TypeKind::BlockPointer | + TypeKind::UnresolvedTypeRef(..) | + TypeKind::ObjCInterface(..) | + TypeKind::ObjCId | + TypeKind::Comp(..) | + TypeKind::ObjCSel => debug_print(ctx, name, name_ident), + + TypeKind::TemplateInstantiation(ref inst) => { + if inst.is_opaque(ctx, self) { + Some((format!("{}: opaque", name), vec![])) + } else { + debug_print(ctx, name, name_ident) + } + } + + // The generic is not required to implement Debug, so we can not debug print that type + TypeKind::Named => { + Some((format!("{}: Non-debuggable generic", name), vec![])) + } + + TypeKind::Array(_, len) => { + // Generics are not required to implement Debug + if self.has_type_param_in_array(ctx) { + Some(( + format!("{}: Array with length {}", name, len), + vec![], + )) + } else if len < RUST_DERIVE_IN_ARRAY_LIMIT { + // The simple case + debug_print(ctx, name, name_ident) + } else { + // Let's implement our own print function + Some(( + format!("{}: [{{}}]", name), + quote_tokens!( ctx.ext_cx(), self.$name_ident .iter() .enumerate() .map(|(i, v)| format!("{}{:?}", if i > 0 { ", " } else { "" }, v)) .collect::<String>()), - )) + )) + } } - } - TypeKind::ResolvedTypeRef(t) | - TypeKind::TemplateAlias(t, _) | - TypeKind::Alias(t) => { - // We follow the aliases - gen_item_debug_impl(ctx, ctx.resolve_item(t), name) - } + TypeKind::ResolvedTypeRef(t) | + TypeKind::TemplateAlias(t, _) | + TypeKind::Alias(t) => { + // We follow the aliases + ctx.resolve_item(t).impl_debug(ctx, name) + } - TypeKind::Pointer(inner) => { - let inner_type = ctx.resolve_type(inner).canonical_type(ctx); - match *inner_type.kind() { - TypeKind::Function(ref sig) - if !sig.can_trivially_derive_debug() => - { - Some((format!("{}: FunctionPointer", name), vec![])) + TypeKind::Pointer(inner) => { + let inner_type = ctx.resolve_type(inner).canonical_type(ctx); + match *inner_type.kind() { + TypeKind::Function(ref sig) + if !sig.can_trivially_derive_debug() => + { + Some((format!("{}: FunctionPointer", name), vec![])) + } + _ => debug_print(ctx, name, name_ident), } - _ => debug_print(ctx, name, name_ident), } - } - TypeKind::Opaque => None, + TypeKind::Opaque => None, + } } } |