• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{cfg, file, lookup};
2 use anyhow::Result;
3 use proc_macro2::{Ident, Span, TokenStream};
4 use quote::{format_ident, quote};
5 use syn_codegen::{Data, Definitions, Node, Type};
6 
7 const DEBUG_SRC: &str = "../src/gen/debug.rs";
8 
expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream9 fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
10     let type_name = &node.ident;
11     let ident = Ident::new(type_name, Span::call_site());
12 
13     match &node.data {
14         Data::Enum(variants) => {
15             let arms = variants.iter().map(|(variant_name, fields)| {
16                 let variant = Ident::new(variant_name, Span::call_site());
17                 if fields.is_empty() {
18                     quote! {
19                         #ident::#variant => formatter.write_str(#variant_name),
20                     }
21                 } else {
22                     let pats = (0..fields.len())
23                         .map(|i| format_ident!("v{}", i))
24                         .collect::<Vec<_>>();
25                     let mut cfg = None;
26                     if node.ident == "Expr" {
27                         if let Type::Syn(ty) = &fields[0] {
28                             if !lookup::node(defs, ty).features.any.contains("derive") {
29                                 cfg = Some(quote!(#[cfg(feature = "full")]));
30                             }
31                         }
32                     }
33                     quote! {
34                         #cfg
35                         #ident::#variant(#(#pats),*) => {
36                             let mut formatter = formatter.debug_tuple(#variant_name);
37                             #(formatter.field(#pats);)*
38                             formatter.finish()
39                         }
40                     }
41                 }
42             });
43             let nonexhaustive = if node.exhaustive {
44                 None
45             } else if node.ident == "Expr" {
46                 Some(quote! {
47                     #[cfg(any(syn_no_non_exhaustive, not(feature = "full")))]
48                     _ => unreachable!(),
49                 })
50             } else {
51                 Some(quote! {
52                     #[cfg(syn_no_non_exhaustive)]
53                     _ => unreachable!(),
54                 })
55             };
56             quote! {
57                 match self {
58                     #(#arms)*
59                     #nonexhaustive
60                 }
61             }
62         }
63         Data::Struct(fields) => {
64             let fields = fields.keys().map(|f| {
65                 let ident = Ident::new(f, Span::call_site());
66                 quote! {
67                     formatter.field(#f, &self.#ident);
68                 }
69             });
70             quote! {
71                 let mut formatter = formatter.debug_struct(#type_name);
72                 #(#fields)*
73                 formatter.finish()
74             }
75         }
76         Data::Private => unreachable!(),
77     }
78 }
79 
expand_impl(defs: &Definitions, node: &Node) -> TokenStream80 fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
81     let manual_debug = node.data == Data::Private || node.ident == "LitBool";
82     if manual_debug {
83         return TokenStream::new();
84     }
85 
86     let ident = Ident::new(&node.ident, Span::call_site());
87     let cfg_features = cfg::features(&node.features);
88     let body = expand_impl_body(defs, node);
89 
90     quote! {
91         #cfg_features
92         #[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
93         impl Debug for #ident {
94             fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
95                 #body
96             }
97         }
98     }
99 }
100 
generate(defs: &Definitions) -> Result<()>101 pub fn generate(defs: &Definitions) -> Result<()> {
102     let mut impls = TokenStream::new();
103     for node in &defs.types {
104         impls.extend(expand_impl(defs, node));
105     }
106 
107     file::write(
108         DEBUG_SRC,
109         quote! {
110             use crate::*;
111             use std::fmt::{self, Debug};
112 
113             #impls
114         },
115     )?;
116 
117     Ok(())
118 }
119