rust/crates/hir_def/src/nameres/proc_macro.rs

72 lines
2.6 KiB
Rust
Raw Normal View History

//! Nameres-specific procedural macro data and helpers.
use hir_expand::name::{AsName, Name};
use tt::{Leaf, TokenTree};
use crate::attr::Attrs;
#[derive(Debug, PartialEq, Eq)]
pub(super) struct ProcMacroDef {
pub(super) name: Name,
pub(super) kind: ProcMacroKind,
}
#[derive(Debug, PartialEq, Eq)]
pub(super) enum ProcMacroKind {
CustomDerive { helpers: Box<[Name]> },
FnLike,
Attr,
}
impl Attrs {
#[rustfmt::skip]
pub(super) fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> {
if self.by_key("proc_macro").exists() {
Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::FnLike })
} else if self.by_key("proc_macro_attribute").exists() {
Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr })
} else if self.by_key("proc_macro_derive").exists() {
let derive = self.by_key("proc_macro_derive").tt_values().next().unwrap();
match &*derive.token_trees {
// `#[proc_macro_derive(Trait)]`
[TokenTree::Leaf(Leaf::Ident(trait_name))] => Some(ProcMacroDef {
name: trait_name.as_name(),
kind: ProcMacroKind::CustomDerive { helpers: Box::new([]) },
}),
// `#[proc_macro_derive(Trait, attibutes(helper1, helper2, ...))]`
[
TokenTree::Leaf(Leaf::Ident(trait_name)),
TokenTree::Leaf(Leaf::Punct(comma)),
TokenTree::Leaf(Leaf::Ident(attributes)),
TokenTree::Subtree(helpers)
] if comma.char == ',' && attributes.text == "attributes" =>
{
let helpers = helpers.token_trees.iter()
.filter(|tt| !matches!(tt, TokenTree::Leaf(Leaf::Punct(comma)) if comma.char == ','))
.map(|tt| {
match tt {
TokenTree::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()),
_ => None
}
})
.collect::<Option<Box<[_]>>>()?;
Some(ProcMacroDef {
name: trait_name.as_name(),
kind: ProcMacroKind::CustomDerive { helpers },
})
}
_ => {
log::trace!("malformed `#[proc_macro_derive]`: {}", derive);
None
}
}
} else {
None
}
}
}