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