summaryrefslogtreecommitdiff
path: root/src/codegen/derive_debug.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen/derive_debug.rs')
-rw-r--r--src/codegen/derive_debug.rs244
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,
+ }
}
}