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