1use crate::ir::comp::{BitfieldUnit, CompKind, Field, FieldData, FieldMethods};
2use crate::ir::context::BindgenContext;
3use crate::ir::item::{HasTypeParamInArray, IsOpaque, Item, ItemCanonicalName};
4use crate::ir::ty::{TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT};
5
6pub(crate) 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`.
54pub(crate) 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.
60 fn impl_debug(
61 &self,
62 ctx: &BindgenContext,
63 extra: Self::Extra,
64 ) -> Option<(String, Vec<proc_macro2::TokenStream>)>;
65}
66
67impl<'a> ImplDebug<'a> for FieldData {
68 type Extra = ();
69
70 fn impl_debug(
71 &self,
72 ctx: &BindgenContext,
73 _: Self::Extra,
74 ) -> Option<(String, Vec<proc_macro2::TokenStream>)> {
75 if let Some(name: &str) = self.name() {
76 ctx.resolve_item(self.ty()).impl_debug(ctx, extra:name)
77 } else {
78 None
79 }
80 }
81}
82
83impl<'a> ImplDebug<'a> for BitfieldUnit {
84 type Extra = ();
85
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
112impl<'a> ImplDebug<'a> for Item {
113 type Extra = &'a str;
114
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