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