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