hir_def/nameres/
proc_macro.rs1use hir_expand::name::{AsName, Name};
4use intern::sym;
5
6use crate::attr::Attrs;
7use crate::tt::{Leaf, TokenTree, TopSubtree, TtElement};
8
9#[derive(Debug, PartialEq, Eq)]
10pub struct ProcMacroDef {
11 pub name: Name,
12 pub kind: ProcMacroKind,
13}
14
15#[derive(Debug, PartialEq, Eq)]
16pub enum ProcMacroKind {
17 Derive { helpers: Box<[Name]> },
18 Bang,
19 Attr,
20}
21
22impl ProcMacroKind {
23 pub(super) fn to_basedb_kind(&self) -> hir_expand::proc_macro::ProcMacroKind {
24 match self {
25 ProcMacroKind::Derive { .. } => hir_expand::proc_macro::ProcMacroKind::CustomDerive,
26 ProcMacroKind::Bang => hir_expand::proc_macro::ProcMacroKind::Bang,
27 ProcMacroKind::Attr => hir_expand::proc_macro::ProcMacroKind::Attr,
28 }
29 }
30}
31
32impl Attrs {
33 pub fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> {
34 if self.is_proc_macro() {
35 Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Bang })
36 } else if self.is_proc_macro_attribute() {
37 Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr })
38 } else if self.by_key(sym::proc_macro_derive).exists() {
39 let derive = self.parse_proc_macro_derive();
40 Some(match derive {
41 Some((name, helpers)) => {
42 ProcMacroDef { name, kind: ProcMacroKind::Derive { helpers } }
43 }
44 None => ProcMacroDef {
45 name: func_name.clone(),
46 kind: ProcMacroKind::Derive { helpers: Box::default() },
47 },
48 })
49 } else {
50 None
51 }
52 }
53
54 pub fn parse_proc_macro_derive(&self) -> Option<(Name, Box<[Name]>)> {
55 let derive = self.by_key(sym::proc_macro_derive).tt_values().next()?;
56 parse_macro_name_and_helper_attrs(derive)
57 }
58
59 pub fn parse_rustc_builtin_macro(&self) -> Option<(Name, Box<[Name]>)> {
60 let derive = self.by_key(sym::rustc_builtin_macro).tt_values().next()?;
61 parse_macro_name_and_helper_attrs(derive)
62 }
63}
64
65#[rustfmt::skip]
68pub(crate) fn parse_macro_name_and_helper_attrs(tt: &TopSubtree) -> Option<(Name, Box<[Name]>)> {
69 match tt.token_trees().flat_tokens() {
70 [TokenTree::Leaf(Leaf::Ident(trait_name))] => Some((trait_name.as_name(), Box::new([]))),
73
74 [
77 TokenTree::Leaf(Leaf::Ident(trait_name)),
78 TokenTree::Leaf(Leaf::Punct(comma)),
79 TokenTree::Leaf(Leaf::Ident(attributes)),
80 TokenTree::Subtree(_),
81 ..
82 ] if comma.char == ',' && attributes.sym == sym::attributes =>
83 {
84 let helpers = tt::TokenTreesView::new(&tt.token_trees().flat_tokens()[3..]).try_into_subtree()?;
85 let helpers = helpers
86 .iter()
87 .filter(
88 |tt| !matches!(tt, TtElement::Leaf(Leaf::Punct(comma)) if comma.char == ','),
89 )
90 .map(|tt| match tt {
91 TtElement::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()),
92 _ => None,
93 })
94 .collect::<Option<Box<[_]>>>()?;
95
96 Some((trait_name.as_name(), helpers))
97 }
98
99 _ => None,
100 }
101}