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));
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> {}