• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::ir::comp::{BitfieldUnit, CompKind, Field, FieldData, FieldMethods};
2 use crate::ir::context::BindgenContext;
3 use crate::ir::item::{HasTypeParamInArray, IsOpaque, Item, ItemCanonicalName};
4 use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
5 use proc_macro2;
6 
gen_debug_impl( ctx: &BindgenContext, fields: &[Field], item: &Item, kind: CompKind, ) -> proc_macro2::TokenStream7 pub fn gen_debug_impl(
8     ctx: &BindgenContext,
9     fields: &[Field],
10     item: &Item,
11     kind: CompKind,
12 ) -> proc_macro2::TokenStream {
13     let struct_name = item.canonical_name(ctx);
14     let mut format_string = format!("{} {{{{ ", struct_name);
15     let mut tokens = vec![];
16 
17     if item.is_opaque(ctx, &()) {
18         format_string.push_str("opaque");
19     } else {
20         match kind {
21             CompKind::Union => {
22                 format_string.push_str("union");
23             }
24             CompKind::Struct => {
25                 let processed_fields = fields.iter().filter_map(|f| match f {
26                     &Field::DataMember(ref fd) => fd.impl_debug(ctx, ()),
27                     &Field::Bitfields(ref bu) => bu.impl_debug(ctx, ()),
28                 });
29 
30                 for (i, (fstring, toks)) in processed_fields.enumerate() {
31                     if i > 0 {
32                         format_string.push_str(", ");
33                     }
34                     tokens.extend(toks);
35                     format_string.push_str(&fstring);
36                 }
37             }
38         }
39     }
40 
41     format_string.push_str(" }}");
42     tokens.insert(0, quote! { #format_string });
43 
44     let prefix = ctx.trait_prefix();
45 
46     quote! {
47         fn fmt(&self, f: &mut ::#prefix::fmt::Formatter<'_>) -> ::#prefix ::fmt::Result {
48             write!(f, #( #tokens ),*)
49         }
50     }
51 }
52 
53 /// A trait for the things which we can codegen tokens that contribute towards a
54 /// generated `impl Debug`.
55 pub trait ImplDebug<'a> {
56     /// Any extra parameter required by this a particular `ImplDebug` implementation.
57     type Extra;
58 
59     /// Generate a format string snippet to be included in the larger `impl Debug`
60     /// format string, and the code to get the format string's interpolation values.
impl_debug( &self, ctx: &BindgenContext, extra: Self::Extra, ) -> Option<(String, Vec<proc_macro2::TokenStream>)>61     fn impl_debug(
62         &self,
63         ctx: &BindgenContext,
64         extra: Self::Extra,
65     ) -> Option<(String, Vec<proc_macro2::TokenStream>)>;
66 }
67 
68 impl<'a> ImplDebug<'a> for FieldData {
69     type Extra = ();
70 
impl_debug( &self, ctx: &BindgenContext, _: Self::Extra, ) -> Option<(String, Vec<proc_macro2::TokenStream>)>71     fn impl_debug(
72         &self,
73         ctx: &BindgenContext,
74         _: Self::Extra,
75     ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
76         if let Some(name) = self.name() {
77             ctx.resolve_item(self.ty()).impl_debug(ctx, name)
78         } else {
79             None
80         }
81     }
82 }
83 
84 impl<'a> ImplDebug<'a> for BitfieldUnit {
85     type Extra = ();
86 
impl_debug( &self, ctx: &BindgenContext, _: Self::Extra, ) -> Option<(String, Vec<proc_macro2::TokenStream>)>87     fn impl_debug(
88         &self,
89         ctx: &BindgenContext,
90         _: Self::Extra,
91     ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
92         let mut format_string = String::new();
93         let mut tokens = vec![];
94         for (i, bitfield) in self.bitfields().iter().enumerate() {
95             if i > 0 {
96                 format_string.push_str(", ");
97             }
98 
99             if let Some(bitfield_name) = bitfield.name() {
100                 format_string.push_str(&format!("{} : {{:?}}", bitfield_name));
101                 let getter_name = bitfield.getter_name();
102                 let name_ident = ctx.rust_ident_raw(getter_name);
103                 tokens.push(quote! {
104                     self.#name_ident ()
105                 });
106             }
107         }
108 
109         Some((format_string, tokens))
110     }
111 }
112 
113 impl<'a> ImplDebug<'a> for Item {
114     type Extra = &'a str;
115 
impl_debug( &self, ctx: &BindgenContext, name: &str, ) -> Option<(String, Vec<proc_macro2::TokenStream>)>116     fn impl_debug(
117         &self,
118         ctx: &BindgenContext,
119         name: &str,
120     ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
121         let name_ident = ctx.rust_ident(name);
122 
123         // We don't know if blocklisted items `impl Debug` or not, so we can't
124         // add them to the format string we're building up.
125         if !ctx.allowlisted_items().contains(&self.id()) {
126             return None;
127         }
128 
129         let ty = match self.as_type() {
130             Some(ty) => ty,
131             None => {
132                 return None;
133             }
134         };
135 
136         fn debug_print(
137             name: &str,
138             name_ident: proc_macro2::TokenStream,
139         ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
140             Some((
141                 format!("{}: {{:?}}", name),
142                 vec![quote! {
143                     self.#name_ident
144                 }],
145             ))
146         }
147 
148         match *ty.kind() {
149             // Handle the simple cases.
150             TypeKind::Void |
151             TypeKind::NullPtr |
152             TypeKind::Int(..) |
153             TypeKind::Float(..) |
154             TypeKind::Complex(..) |
155             TypeKind::Function(..) |
156             TypeKind::Enum(..) |
157             TypeKind::Reference(..) |
158             TypeKind::UnresolvedTypeRef(..) |
159             TypeKind::ObjCInterface(..) |
160             TypeKind::ObjCId |
161             TypeKind::Comp(..) |
162             TypeKind::ObjCSel => debug_print(name, quote! { #name_ident }),
163 
164             TypeKind::TemplateInstantiation(ref inst) => {
165                 if inst.is_opaque(ctx, self) {
166                     Some((format!("{}: opaque", name), vec![]))
167                 } else {
168                     debug_print(name, quote! { #name_ident })
169                 }
170             }
171 
172             // The generic is not required to implement Debug, so we can not debug print that type
173             TypeKind::TypeParam => {
174                 Some((format!("{}: Non-debuggable generic", name), vec![]))
175             }
176 
177             TypeKind::Array(_, len) => {
178                 // Generics are not required to implement Debug
179                 if self.has_type_param_in_array(ctx) {
180                     Some((
181                         format!("{}: Array with length {}", name, len),
182                         vec![],
183                     ))
184                 } else if len < RUST_DERIVE_IN_ARRAY_LIMIT {
185                     // The simple case
186                     debug_print(name, quote! { #name_ident })
187                 } else {
188                     if ctx.options().use_core {
189                         // There is no String in core; reducing field visibility to avoid breaking
190                         // no_std setups.
191                         Some((format!("{}: [...]", name), vec![]))
192                     } else {
193                         // Let's implement our own print function
194                         Some((
195                             format!("{}: [{{}}]", name),
196                             vec![quote! {
197                                 self.#name_ident
198                                     .iter()
199                                     .enumerate()
200                                     .map(|(i, v)| format!("{}{:?}", if i > 0 { ", " } else { "" }, v))
201                                     .collect::<String>()
202                             }],
203                         ))
204                     }
205                 }
206             }
207             TypeKind::Vector(_, len) => {
208                 if ctx.options().use_core {
209                     // There is no format! in core; reducing field visibility to avoid breaking
210                     // no_std setups.
211                     Some((format!("{}(...)", name), vec![]))
212                 } else {
213                     let self_ids = 0..len;
214                     Some((
215                         format!("{}({{}})", name),
216                         vec![quote! {
217                             #(format!("{:?}", self.#self_ids)),*
218                         }],
219                     ))
220                 }
221             }
222 
223             TypeKind::ResolvedTypeRef(t) |
224             TypeKind::TemplateAlias(t, _) |
225             TypeKind::Alias(t) |
226             TypeKind::BlockPointer(t) => {
227                 // We follow the aliases
228                 ctx.resolve_item(t).impl_debug(ctx, name)
229             }
230 
231             TypeKind::Pointer(inner) => {
232                 let inner_type = ctx.resolve_type(inner).canonical_type(ctx);
233                 match *inner_type.kind() {
234                     TypeKind::Function(ref sig)
235                         if !sig.function_pointers_can_derive() =>
236                     {
237                         Some((format!("{}: FunctionPointer", name), vec![]))
238                     }
239                     _ => debug_print(name, quote! { #name_ident }),
240                 }
241             }
242 
243             TypeKind::Opaque => None,
244         }
245     }
246 }
247