swc_macros_common/
syn_ext.rs

1use quote::quote;
2use syn::{punctuated::Pair, *};
3
4use crate::def_site;
5
6/// Extension trait for `ItemImpl` (impl block).
7pub trait ItemImplExt {
8    /// Instead of
9    ///
10    /// ```rust,ignore
11    /// let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
12    ///
13    /// let item: Item = Quote::new(def_site::<Span>())
14    ///     .quote_with(smart_quote!(
15    /// Vars {
16    /// Type: type_name,
17    /// impl_generics,
18    /// ty_generics,
19    /// where_clause,
20    /// },
21    /// {
22    /// impl impl_generics ::swc_common::AstNode for Type ty_generics
23    /// where_clause {}
24    /// }
25    /// )).parse();
26    /// ```
27    ///
28    /// You can use this like
29    ///
30    /// ```rust,ignore
31    // let item = Quote::new(def_site::<Span>())
32    ///     .quote_with(smart_quote!(Vars { Type: type_name }, {
33    ///         impl ::swc_common::AstNode for Type {}
34    ///     }))
35    ///     .parse::<ItemImpl>()
36    ///     .with_generics(input.generics);
37    /// ```
38    fn with_generics(self, generics: Generics) -> Self;
39}
40
41impl ItemImplExt for ItemImpl {
42    fn with_generics(mut self, mut generics: Generics) -> Self {
43        // TODO: Check conflicting name
44
45        let need_new_punct = !generics.params.empty_or_trailing();
46        if need_new_punct {
47            generics.params.push_punct(Token![,](def_site()));
48        }
49
50        // Respan
51        if let Some(t) = generics.lt_token {
52            self.generics.lt_token = Some(t)
53        }
54        if let Some(t) = generics.gt_token {
55            self.generics.gt_token = Some(t)
56        }
57
58        let ty = self.self_ty;
59
60        // Handle generics defined on struct, enum, or union.
61        let mut item: ItemImpl = {
62            let (_, ty_generics, _) = generics.split_for_impl();
63            let item = quote! {
64                #ty #ty_generics
65            };
66
67            ItemImpl {
68                generics,
69                self_ty: parse2(item).unwrap(),
70                ..self
71            }
72        };
73
74        // Handle generics added by proc-macro.
75        item.generics
76            .params
77            .extend(self.generics.params.into_pairs());
78
79        item
80    }
81}
82
83pub trait PairExt<T, P>: Sized + Into<Pair<T, P>> {
84    fn map_item<F, NewItem>(self, op: F) -> Pair<NewItem, P>
85    where
86        F: FnOnce(T) -> NewItem,
87    {
88        match self.into() {
89            Pair::Punctuated(t, p) => Pair::Punctuated(op(t), p),
90            Pair::End(t) => Pair::End(op(t)),
91        }
92    }
93}
94
95impl<T, P> PairExt<T, P> for Pair<T, P> {}