From 4a303366c85850f5af60d21ed53d1c59fc468e29 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Wed, 22 Apr 2020 01:44:21 +0800 Subject: Improve remove dervie attrs --- Cargo.lock | 1 + crates/ra_hir_expand/Cargo.toml | 1 + crates/ra_hir_expand/src/proc_macro.rs | 106 +++++++++++++++++++++++++++++---- 3 files changed, 98 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 37455bc57..3738cfe8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1012,6 +1012,7 @@ dependencies = [ "ra_prof", "ra_syntax", "ra_tt", + "test_utils", ] [[package]] diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml index d6e3c1f76..2cd522766 100644 --- a/crates/ra_hir_expand/Cargo.toml +++ b/crates/ra_hir_expand/Cargo.toml @@ -18,3 +18,4 @@ ra_parser = { path = "../ra_parser" } ra_prof = { path = "../ra_prof" } tt = { path = "../ra_tt", package = "ra_tt" } mbe = { path = "../ra_mbe", package = "ra_mbe" } +test_utils = { path = "../test_utils"} diff --git a/crates/ra_hir_expand/src/proc_macro.rs b/crates/ra_hir_expand/src/proc_macro.rs index 97d1208ec..4e0e069c8 100644 --- a/crates/ra_hir_expand/src/proc_macro.rs +++ b/crates/ra_hir_expand/src/proc_macro.rs @@ -2,6 +2,7 @@ use crate::{db::AstDatabase, LazyMacroId}; use ra_db::{CrateId, ProcMacroId}; +use tt::buffer::{Cursor, TokenBuffer}; #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub struct ProcMacroExpander { @@ -36,22 +37,107 @@ impl ProcMacroExpander { .clone() .ok_or_else(|| err!("No derive macro found."))?; - let tt = remove_derive_atr(tt, &proc_macro.name) + let tt = remove_derive_attrs(tt) .ok_or_else(|| err!("Fail to remove derive for custom derive"))?; proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from) } } -fn remove_derive_atr(tt: &tt::Subtree, _name: &str) -> Option { - // FIXME: proper handle the remove derive - // We assume the first 2 tokens are #[derive(name)] - if tt.token_trees.len() > 2 { - let mut tt = tt.clone(); - tt.token_trees.remove(0); - tt.token_trees.remove(0); - return Some(tt); +fn eat_punct(cursor: &mut Cursor, c: char) -> bool { + if let Some(tt::TokenTree::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::TokenTree::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::TokenTree::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::new(&tt.token_trees); + let mut p = buffer.begin(); + let mut result = tt::Subtree::default(); + + while !p.eof() { + let curr = p; - None + 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()?.clone()); + p = curr.bump(); + } + + Some(result) +} + +#[cfg(test)] +mod test { + 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!( + &result, + 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() + ); + } } -- cgit v1.2.3