1 //! Nameres-specific procedural macro data and helpers.
3 use hir_expand::name::{AsName, Name};
4 use tt::{Leaf, TokenTree};
6 use crate::attr::Attrs;
8 #[derive(Debug, PartialEq, Eq)]
9 pub(super) struct ProcMacroDef {
10 pub(super) name: Name,
11 pub(super) kind: ProcMacroKind,
14 #[derive(Debug, PartialEq, Eq)]
15 pub(super) enum ProcMacroKind {
16 CustomDerive { helpers: Box<[Name]> },
22 pub(super) fn to_basedb_kind(&self) -> base_db::ProcMacroKind {
24 ProcMacroKind::CustomDerive { .. } => base_db::ProcMacroKind::CustomDerive,
25 ProcMacroKind::FnLike => base_db::ProcMacroKind::FuncLike,
26 ProcMacroKind::Attr => base_db::ProcMacroKind::Attr,
33 pub(super) fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> {
34 if self.by_key("proc_macro").exists() {
35 Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::FnLike })
36 } else if self.by_key("proc_macro_attribute").exists() {
37 Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr })
38 } else if self.by_key("proc_macro_derive").exists() {
39 let derive = self.by_key("proc_macro_derive").tt_values().next().unwrap();
41 match &*derive.token_trees {
42 // `#[proc_macro_derive(Trait)]`
43 [TokenTree::Leaf(Leaf::Ident(trait_name))] => Some(ProcMacroDef {
44 name: trait_name.as_name(),
45 kind: ProcMacroKind::CustomDerive { helpers: Box::new([]) },
48 // `#[proc_macro_derive(Trait, attibutes(helper1, helper2, ...))]`
50 TokenTree::Leaf(Leaf::Ident(trait_name)),
51 TokenTree::Leaf(Leaf::Punct(comma)),
52 TokenTree::Leaf(Leaf::Ident(attributes)),
53 TokenTree::Subtree(helpers)
54 ] if comma.char == ',' && attributes.text == "attributes" =>
56 let helpers = helpers.token_trees.iter()
57 .filter(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Punct(comma)) if comma.char == ','))
60 TokenTree::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()),
64 .collect::<Option<Box<[_]>>>()?;
67 name: trait_name.as_name(),
68 kind: ProcMacroKind::CustomDerive { helpers },
73 tracing::trace!("malformed `#[proc_macro_derive]`: {}", derive);