4076: Improve remove derive attrs r=matklad a=edwin0cheng

This PR implemented a proper `remove_derive_attrs` function which **merely** remove  any `#[derive(*)]` attributes.

Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
bors[bot] 2020-04-21 18:50:53 +00:00 committed by GitHub
commit 7ab28cacbb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 98 additions and 10 deletions

1
Cargo.lock generated
View file

@ -1012,6 +1012,7 @@ dependencies = [
"ra_prof",
"ra_syntax",
"ra_tt",
"test_utils",
]
[[package]]

View file

@ -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"}

View file

@ -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<tt::Subtree> {
// 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<tt::Subtree> {
let buffer = TokenBuffer::new(&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()?.clone());
p = curr.bump();
}
None
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()
);
}
}