1use proc_macro2::TokenStream;
6use quote::{format_ident, quote};
7use syn::{ext::IdentExt as _, parse_quote, spanned::Spanned as _};
8
9use crate::utils::{
10 attr::{self, ParseMultiple as _},
11 Either, Spanning,
12};
13
14use super::{
15 trait_name_to_attribute_name, ContainerAttributes, ContainsGenericsExt as _,
16 FmtAttribute,
17};
18
19pub fn expand(input: &syn::DeriveInput, _: &str) -> syn::Result<TokenStream> {
23 let attr_name = format_ident!("{}", trait_name_to_attribute_name("Debug"));
24
25 let attrs = ContainerAttributes::parse_attrs(&input.attrs, &attr_name)?
26 .map(Spanning::into_inner)
27 .unwrap_or_default();
28 let ident = &input.ident;
29
30 let type_params = input
31 .generics
32 .params
33 .iter()
34 .filter_map(|p| match p {
35 syn::GenericParam::Type(t) => Some(&t.ident),
36 syn::GenericParam::Const(..) | syn::GenericParam::Lifetime(..) => None,
37 })
38 .collect::<Vec<_>>();
39
40 let (bounds, body) = match &input.data {
41 syn::Data::Struct(s) => {
42 expand_struct(attrs, ident, s, &type_params, &attr_name)
43 }
44 syn::Data::Enum(e) => expand_enum(attrs, e, &type_params, &attr_name),
45 syn::Data::Union(_) => {
46 return Err(syn::Error::new(
47 input.span(),
48 "`Debug` cannot be derived for unions",
49 ));
50 }
51 }?;
52
53 let (impl_gens, ty_gens, where_clause) = {
54 let (impl_gens, ty_gens, where_clause) = input.generics.split_for_impl();
55 let mut where_clause = where_clause
56 .cloned()
57 .unwrap_or_else(|| parse_quote! { where });
58 where_clause.predicates.extend(bounds);
59 (impl_gens, ty_gens, where_clause)
60 };
61
62 Ok(quote! {
63 #[allow(unreachable_code)] #[automatically_derived]
65 impl #impl_gens derive_more::core::fmt::Debug for #ident #ty_gens #where_clause {
66 #[inline]
67 fn fmt(
68 &self, __derive_more_f: &mut derive_more::core::fmt::Formatter<'_>
69 ) -> derive_more::core::fmt::Result {
70 #body
71 }
72 }
73 })
74}
75
76fn expand_struct(
80 attrs: ContainerAttributes,
81 ident: &syn::Ident,
82 s: &syn::DataStruct,
83 type_params: &[&syn::Ident],
84 attr_name: &syn::Ident,
85) -> syn::Result<(Vec<syn::WherePredicate>, TokenStream)> {
86 let s = Expansion {
87 attr: &attrs,
88 fields: &s.fields,
89 type_params,
90 ident,
91 attr_name,
92 };
93 s.validate_attrs()?;
94 let bounds = s.generate_bounds()?;
95 let body = s.generate_body()?;
96
97 let vars = s.fields.iter().enumerate().map(|(i, f)| {
98 let var = f.ident.clone().unwrap_or_else(|| format_ident!("_{i}"));
99 let member = f
100 .ident
101 .clone()
102 .map_or_else(|| syn::Member::Unnamed(i.into()), syn::Member::Named);
103 quote! { let #var = &self.#member; }
104 });
105
106 let body = quote! {
107 #( #vars )*
108 #body
109 };
110
111 Ok((bounds, body))
112}
113
114fn expand_enum(
118 mut attrs: ContainerAttributes,
119 e: &syn::DataEnum,
120 type_params: &[&syn::Ident],
121 attr_name: &syn::Ident,
122) -> syn::Result<(Vec<syn::WherePredicate>, TokenStream)> {
123 if let Some(enum_fmt) = attrs.fmt.as_ref() {
124 return Err(syn::Error::new_spanned(
125 enum_fmt,
126 format!(
127 "`#[{attr_name}(\"...\", ...)]` attribute is not allowed on enum, place it on its \
128 variants instead",
129 ),
130 ));
131 }
132
133 let (bounds, match_arms) = e.variants.iter().try_fold(
134 (Vec::new(), TokenStream::new()),
135 |(mut bounds, mut arms), variant| {
136 let ident = &variant.ident;
137
138 attrs.fmt = variant
139 .attrs
140 .iter()
141 .filter(|attr| attr.path().is_ident("debug"))
142 .try_fold(None, |mut attrs, attr| {
143 let attr = attr.parse_args::<FmtAttribute>()?;
144 attrs.replace(attr).map_or(Ok(()), |dup| {
145 Err(syn::Error::new(
146 dup.span(),
147 format!(
148 "multiple `#[{attr_name}(\"...\", ...)]` attributes aren't allowed",
149 ),
150 ))
151 })?;
152 Ok::<_, syn::Error>(attrs)
153 })?;
154
155 let v = Expansion {
156 attr: &attrs,
157 fields: &variant.fields,
158 type_params,
159 ident,
160 attr_name,
161 };
162 v.validate_attrs()?;
163 let arm_body = v.generate_body()?;
164 bounds.extend(v.generate_bounds()?);
165
166 let fields_idents =
167 variant.fields.iter().enumerate().map(|(i, f)| {
168 f.ident.clone().unwrap_or_else(|| format_ident!("_{i}"))
169 });
170 let matcher = match variant.fields {
171 syn::Fields::Named(_) => {
172 quote! { Self::#ident { #( #fields_idents ),* } }
173 }
174 syn::Fields::Unnamed(_) => {
175 quote! { Self::#ident ( #( #fields_idents ),* ) }
176 }
177 syn::Fields::Unit => quote! { Self::#ident },
178 };
179
180 arms.extend([quote! { #matcher => { #arm_body }, }]);
181
182 Ok::<_, syn::Error>((bounds, arms))
183 },
184 )?;
185
186 let body = match_arms
187 .is_empty()
188 .then(|| quote! { match *self {} })
189 .unwrap_or_else(|| quote! { match self { #match_arms } });
190
191 Ok((bounds, body))
192}
193
194type FieldAttribute = Either<attr::Skip, FmtAttribute>;
203
204#[derive(Debug)]
209struct Expansion<'a> {
210 attr: &'a ContainerAttributes,
211
212 ident: &'a syn::Ident,
214
215 fields: &'a syn::Fields,
217
218 type_params: &'a [&'a syn::Ident],
220
221 attr_name: &'a syn::Ident,
223}
224
225impl Expansion<'_> {
226 fn validate_attrs(&self) -> syn::Result<()> {
228 if self.attr.fmt.is_some() {
229 for field_attr in self
230 .fields
231 .iter()
232 .map(|f| FieldAttribute::parse_attrs(&f.attrs, self.attr_name))
233 {
234 if let Some(FieldAttribute::Right(fmt_attr)) =
235 field_attr?.map(Spanning::into_inner)
236 {
237 return Err(syn::Error::new_spanned(
238 fmt_attr,
239 "`#[debug(...)]` attributes are not allowed on fields when \
240 `#[debug(\"...\", ...)]` is specified on struct or variant",
241 ));
242 }
243 }
244 }
245 Ok(())
246 }
247
248 fn generate_body(&self) -> syn::Result<TokenStream> {
252 if let Some(fmt) = &self.attr.fmt {
253 return Ok(
254 if let Some((expr, trait_ident)) =
255 fmt.transparent_call_on_fields(self.fields)
256 {
257 quote! { derive_more::core::fmt::#trait_ident::fmt(#expr, __derive_more_f) }
258 } else {
259 let deref_args = fmt.additional_deref_args(self.fields);
260
261 quote! { derive_more::core::write!(__derive_more_f, #fmt, #(#deref_args),*) }
262 },
263 );
264 };
265
266 match self.fields {
267 syn::Fields::Unit => {
268 let ident = self.ident.to_string();
269 Ok(quote! {
270 derive_more::core::fmt::Formatter::write_str(
271 __derive_more_f,
272 #ident,
273 )
274 })
275 }
276 syn::Fields::Unnamed(unnamed) => {
277 let mut exhaustive = true;
278 let ident_str = self.ident.to_string();
279
280 let out = quote! {
281 &mut derive_more::__private::debug_tuple(
282 __derive_more_f,
283 #ident_str,
284 )
285 };
286 let out = unnamed.unnamed.iter().enumerate().try_fold(
287 out,
288 |out, (i, field)| match FieldAttribute::parse_attrs(
289 &field.attrs,
290 self.attr_name,
291 )?
292 .map(Spanning::into_inner)
293 {
294 Some(FieldAttribute::Left(_skip)) => {
295 exhaustive = false;
296 Ok::<_, syn::Error>(out)
297 }
298 Some(FieldAttribute::Right(fmt_attr)) => {
299 let deref_args = fmt_attr.additional_deref_args(self.fields);
300
301 Ok(quote! {
302 derive_more::__private::DebugTuple::field(
303 #out,
304 &derive_more::core::format_args!(#fmt_attr, #(#deref_args),*),
305 )
306 })
307 }
308 None => {
309 let ident = format_ident!("_{i}");
310 Ok(quote! {
311 derive_more::__private::DebugTuple::field(#out, &#ident)
312 })
313 }
314 },
315 )?;
316 Ok(if exhaustive {
317 quote! { derive_more::__private::DebugTuple::finish(#out) }
318 } else {
319 quote! { derive_more::__private::DebugTuple::finish_non_exhaustive(#out) }
320 })
321 }
322 syn::Fields::Named(named) => {
323 let mut exhaustive = true;
324 let ident = self.ident.to_string();
325
326 let out = quote! {
327 &mut derive_more::core::fmt::Formatter::debug_struct(
328 __derive_more_f,
329 #ident,
330 )
331 };
332 let out = named.named.iter().try_fold(out, |out, field| {
333 let field_ident = field.ident.as_ref().unwrap_or_else(|| {
334 unreachable!("`syn::Fields::Named`");
335 });
336 let field_str = field_ident.unraw().to_string();
337 match FieldAttribute::parse_attrs(&field.attrs, self.attr_name)?
338 .map(Spanning::into_inner)
339 {
340 Some(FieldAttribute::Left(_skip)) => {
341 exhaustive = false;
342 Ok::<_, syn::Error>(out)
343 }
344 Some(FieldAttribute::Right(fmt_attr)) => {
345 let deref_args =
346 fmt_attr.additional_deref_args(self.fields);
347
348 Ok(quote! {
349 derive_more::core::fmt::DebugStruct::field(
350 #out,
351 #field_str,
352 &derive_more::core::format_args!(
353 #fmt_attr, #(#deref_args),*
354 ),
355 )
356 })
357 }
358 None => Ok(quote! {
359 derive_more::core::fmt::DebugStruct::field(
360 #out, #field_str, &#field_ident
361 )
362 }),
363 }
364 })?;
365 Ok(if exhaustive {
366 quote! { derive_more::core::fmt::DebugStruct::finish(#out) }
367 } else {
368 quote! { derive_more::core::fmt::DebugStruct::finish_non_exhaustive(#out) }
369 })
370 }
371 }
372 }
373
374 fn generate_bounds(&self) -> syn::Result<Vec<syn::WherePredicate>> {
376 let mut out = self.attr.bounds.0.clone().into_iter().collect::<Vec<_>>();
377
378 if let Some(fmt) = self.attr.fmt.as_ref() {
379 out.extend(fmt.bounded_types(self.fields).filter_map(
380 |(ty, trait_name)| {
381 if !ty.contains_generics(self.type_params) {
382 return None;
383 }
384
385 let trait_ident = format_ident!("{trait_name}");
386
387 Some(parse_quote! { #ty: derive_more::core::fmt::#trait_ident })
388 },
389 ));
390 Ok(out)
391 } else {
392 self.fields.iter().try_fold(out, |mut out, field| {
393 let ty = &field.ty;
394
395 if !ty.contains_generics(self.type_params) {
396 return Ok(out);
397 }
398
399 match FieldAttribute::parse_attrs(&field.attrs, self.attr_name)?
400 .map(Spanning::into_inner)
401 {
402 Some(FieldAttribute::Right(fmt_attr)) => {
403 out.extend(fmt_attr.bounded_types(self.fields).map(
404 |(ty, trait_name)| {
405 let trait_ident = format_ident!("{trait_name}");
406
407 parse_quote! { #ty: derive_more::core::fmt::#trait_ident }
408 },
409 ));
410 }
411 Some(FieldAttribute::Left(_skip)) => {}
412 None => out.extend([parse_quote! { #ty: derive_more::core::fmt::Debug }]),
413 }
414 Ok(out)
415 })
416 }
417 }
418}