1extern crate proc_macro;
6
7use proc_macro2::{TokenStream, TokenTree};
8#[doc(hidden)]
9pub use quote::quote;
10
11pub fn fix(
18 attr: proc_macro::TokenStream,
19 item: proc_macro::TokenStream,
20 target: TokenStream,
21 imports: &[TokenStream],
22 passthru: Option<TokenStream>,
23) -> proc_macro::TokenStream {
24 fix_(attr.into(), item.into(), target, imports, passthru)
25 .unwrap_or_else(|err| err.to_compile_error())
26 .into()
27}
28
29fn fix_(
30 attr: TokenStream,
31 item: TokenStream,
32 target: TokenStream,
33 imports: &[TokenStream],
34 passthru: Option<TokenStream>,
35) -> syn::Result<TokenStream> {
36 let mut item = syn::parse2::<syn::DeriveInput>(item)?;
37 let vis = item.vis.clone();
38 item.vis = syn::parse2(quote!(pub)).unwrap();
39 let ident = &item.ident;
40
41 let unused = item.attrs.iter().any(|attr| {
42 attr.path.is_ident("allow") && {
43 for token in attr.tokens.clone() {
44 if let TokenTree::Group(group) = token {
45 for token in group.stream() {
46 if let TokenTree::Ident(ident) = token {
47 if ident == "unused"
48 || ident == "unused_imports"
49 || ident == "dead_code"
50 {
51 return true;
52 }
53 }
54 }
55 }
56 }
57 false
58 }
59 });
60 let unused = if unused {
61 quote!(#[allow(unused_imports)])
62 } else {
63 quote!()
64 };
65
66 let mod_name = quote::format_ident!("__qualify_derive_{}", ident);
67
68 let passthru = passthru.and_then(|attr_name| {
69 if attr.is_empty() {
70 None
71 } else {
72 Some(quote!(#[#attr_name(#attr)]))
73 }
74 });
75
76 let output = quote! {
77 #[allow(non_snake_case)]
78 mod #mod_name {
79 use super::*;
80 #(
81 #[allow(unused_imports)]
82 use #imports;
83 )*
84 #[derive(#target)]
85 #passthru
86 #item
87 }
88 #unused
89 #vis use #mod_name::#ident;
90 };
91 Ok(output)
92}
93
94#[macro_export]
98macro_rules! declare {
99 ($(#[$meta:meta])* $name:ident derives $target:ty; $(use $imports:ty;)*) => {
100 $crate::declare!(@INTERNAL $(#[$meta])* $name; $target; $($imports),*; None);
101 };
102 ($(#[$meta:meta])* $name:ident derives $target:ty; $(use $imports:ty;)* attr $attr:ident $(;)?) => {
103 $crate::declare!(@INTERNAL $(#[$meta])* $name; $target; $($imports),*; Some($crate::quote!($attr)));
104 };
105 (@INTERNAL $(#[$meta:meta])* $name:ident; $target:ty; $($imports:ty),*; $passthru:expr) => {
106 #[proc_macro_attribute]
107 $(#[$meta])*
108 pub fn $name(attr: ::proc_macro::TokenStream, item: ::proc_macro::TokenStream) -> ::proc_macro::TokenStream {
109 use $crate::quote;
110 $crate::fix(attr, item, quote!($target), &[$(quote!($imports)),*], $passthru)
111 }
112 };
113}