From 44b04ebe43534f749bc3a8431449bc019cc9c3b2 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sat, 10 Apr 2021 20:30:28 +0200 Subject: Revert "Rewrite `#[derive]` removal to be based on AST" This reverts commit 7e78aebc8fbbb4043d62949681e4d700f1a2ec46. --- crates/hir_expand/src/proc_macro.rs | 102 ++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'crates/hir_expand/src/proc_macro.rs') diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs index d5643393a..75e950816 100644 --- a/crates/hir_expand/src/proc_macro.rs +++ b/crates/hir_expand/src/proc_macro.rs @@ -2,6 +2,7 @@ use crate::db::AstDatabase; use base_db::{CrateId, ProcMacroId}; +use tt::buffer::{Cursor, TokenBuffer}; #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct ProcMacroExpander { @@ -43,6 +44,9 @@ impl ProcMacroExpander { .clone() .ok_or_else(|| err!("No derive macro found."))?; + let tt = remove_derive_attrs(tt) + .ok_or_else(|| err!("Fail to remove derive for custom derive"))?; + // Proc macros have access to the environment variables of the invoking crate. let env = &krate_graph[calling_crate].env; @@ -52,3 +56,101 @@ impl ProcMacroExpander { } } } + +fn eat_punct(cursor: &mut Cursor, c: char) -> bool { + if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(punct), _)) = cursor.token_tree() { + if punct.char == c { + *cursor = cursor.bump(); + return true; + } + } + false +} + +fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool { + if let Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) = cursor.token_tree() { + if Some(kind) == subtree.delimiter_kind() { + *cursor = cursor.bump_subtree(); + return true; + } + } + false +} + +fn eat_ident(cursor: &mut Cursor, t: &str) -> bool { + if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Ident(ident), _)) = cursor.token_tree() { + if t == ident.text.as_str() { + *cursor = cursor.bump(); + return true; + } + } + false +} + +fn remove_derive_attrs(tt: &tt::Subtree) -> Option { + let buffer = TokenBuffer::from_tokens(&tt.token_trees); + let mut p = buffer.begin(); + let mut result = tt::Subtree::default(); + + while !p.eof() { + let curr = p; + + if eat_punct(&mut p, '#') { + eat_punct(&mut p, '!'); + let parent = p; + if eat_subtree(&mut p, tt::DelimiterKind::Bracket) { + if eat_ident(&mut p, "derive") { + p = parent.bump(); + continue; + } + } + } + + result.token_trees.push(curr.token_tree()?.cloned()); + p = curr.bump(); + } + + Some(result) +} + +#[cfg(test)] +mod tests { + use super::*; + use test_utils::assert_eq_text; + + #[test] + fn test_remove_derive_attrs() { + let tt = mbe::parse_to_token_tree( + r#" + #[allow(unused)] + #[derive(Copy)] + #[derive(Hello)] + struct A { + bar: u32 + } +"#, + ) + .unwrap() + .0; + let result = format!("{:#?}", remove_derive_attrs(&tt).unwrap()); + + assert_eq_text!( + r#" +SUBTREE $ + PUNCH # [alone] 0 + SUBTREE [] 1 + IDENT allow 2 + SUBTREE () 3 + IDENT unused 4 + IDENT struct 15 + IDENT A 16 + SUBTREE {} 17 + IDENT bar 18 + PUNCH : [alone] 19 + IDENT u32 20 +"# + .trim(), + &result + ); + } +} -- cgit v1.2.3