From 268f45a099f2010ac1b69d34bfab32c3a2b026c4 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 18 Mar 2021 19:56:37 +0100 Subject: Record custom derive helpers in `DefMap` Also clean up proc macro attribute parsing a bit --- crates/hir_def/src/nameres/proc_macro.rs | 71 ++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 crates/hir_def/src/nameres/proc_macro.rs (limited to 'crates/hir_def/src/nameres/proc_macro.rs') diff --git a/crates/hir_def/src/nameres/proc_macro.rs b/crates/hir_def/src/nameres/proc_macro.rs new file mode 100644 index 000000000..156598f19 --- /dev/null +++ b/crates/hir_def/src/nameres/proc_macro.rs @@ -0,0 +1,71 @@ +//! 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 { + 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::>>()?; + + Some(ProcMacroDef { + name: trait_name.as_name(), + kind: ProcMacroKind::CustomDerive { helpers }, + }) + } + + _ => { + log::trace!("malformed `#[proc_macro_derive]`: {}", derive); + None + } + } + } else { + None + } + } +} -- cgit v1.2.3