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/db.rs | 7 ++- crates/hir_expand/src/input.rs | 87 ------------------------------ crates/hir_expand/src/lib.rs | 1 - crates/hir_expand/src/proc_macro.rs | 102 ++++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 92 deletions(-) delete mode 100644 crates/hir_expand/src/input.rs diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 95dc12744..10fe60821 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs @@ -14,9 +14,9 @@ use syntax::{ }; use crate::{ - ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinDeriveExpander, - BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, HirFileId, HirFileIdRepr, LazyMacroId, - MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, + ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander, + EagerCallLoc, EagerMacroId, HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc, + MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, }; /// Total limit on the number of tokens produced by any macro invocation. @@ -191,7 +191,6 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option { }; let loc = db.lookup_intern_macro(id); let arg = loc.kind.arg(db)?; - let arg = process_macro_input(db, arg, id); Some(arg.green()) } diff --git a/crates/hir_expand/src/input.rs b/crates/hir_expand/src/input.rs deleted file mode 100644 index 8f652cd7c..000000000 --- a/crates/hir_expand/src/input.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! Macro input conditioning. - -use syntax::{ - ast::{self, AttrsOwner}, - AstNode, SyntaxNode, -}; - -use crate::{db::AstDatabase, name::AsName, AttrId, LazyMacroId, MacroCallKind, MacroCallLoc}; - -pub fn process_macro_input(db: &dyn AstDatabase, node: SyntaxNode, id: LazyMacroId) -> SyntaxNode { - let loc: MacroCallLoc = db.lookup_intern_macro(id); - - match loc.kind { - MacroCallKind::FnLike { .. } => node, - MacroCallKind::Derive { derive_attr, .. } => { - let item = match ast::Item::cast(node.clone()) { - Some(item) => item, - None => return node, - }; - - remove_derives_up_to(item, derive_attr).syntax().clone() - } - } -} - -/// Removes `#[derive]` attributes from `item`, up to `attr`. -fn remove_derives_up_to(item: ast::Item, attr: AttrId) -> ast::Item { - let item = item.clone_for_update(); - let idx = attr.0 as usize; - for attr in item.attrs().take(idx + 1) { - if let Some(name) = - attr.path().and_then(|path| path.as_single_segment()).and_then(|seg| seg.name_ref()) - { - if name.as_name().to_string() == "derive" { - attr.syntax().detach(); - } - } - } - item -} - -#[cfg(test)] -mod tests { - use base_db::fixture::WithFixture; - use base_db::SourceDatabase; - use expect_test::{expect, Expect}; - - use crate::test_db::TestDB; - - use super::*; - - fn test_remove_derives_up_to(attr: AttrId, ra_fixture: &str, expect: Expect) { - let (db, file_id) = TestDB::with_single_file(&ra_fixture); - let parsed = db.parse(file_id); - - let mut items: Vec<_> = - parsed.syntax_node().descendants().filter_map(ast::Item::cast).collect(); - assert_eq!(items.len(), 1); - - let item = remove_derives_up_to(items.pop().unwrap(), attr); - expect.assert_eq(&item.to_string()); - } - - #[test] - fn remove_derive() { - test_remove_derives_up_to( - AttrId(2), - r#" -#[allow(unused)] -#[derive(Copy)] -#[derive(Hello)] -#[derive(Clone)] -struct A { - bar: u32 -} - "#, - expect![[r#" -#[allow(unused)] - - -#[derive(Clone)] -struct A { - bar: u32 -}"#]], - ); - } -} diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 7349fdfe4..a0e6aec62 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs @@ -14,7 +14,6 @@ pub mod builtin_macro; pub mod proc_macro; pub mod quote; pub mod eager; -mod input; use either::Either; pub use mbe::{ExpandError, ExpandResult}; 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