22
33use crate :: db:: AstDatabase ;
44use base_db:: { CrateId , ProcMacroId } ;
5+ use tt:: buffer:: { Cursor , TokenBuffer } ;
56
67#[ derive( Debug , Clone , Copy , Eq , PartialEq , Hash ) ]
78pub struct ProcMacroExpander {
@@ -43,6 +44,9 @@ impl ProcMacroExpander {
4344 . clone ( )
4445 . ok_or_else ( || err ! ( "No derive macro found." ) ) ?;
4546
47+ let tt = remove_derive_attrs ( tt)
48+ . ok_or_else ( || err ! ( "Fail to remove derive for custom derive" ) ) ?;
49+
4650 // Proc macros have access to the environment variables of the invoking crate.
4751 let env = & krate_graph[ calling_crate] . env ;
4852
@@ -52,3 +56,101 @@ impl ProcMacroExpander {
5256 }
5357 }
5458}
59+
60+ fn eat_punct ( cursor : & mut Cursor , c : char ) -> bool {
61+ if let Some ( tt:: buffer:: TokenTreeRef :: Leaf ( tt:: Leaf :: Punct ( punct) , _) ) = cursor. token_tree ( ) {
62+ if punct. char == c {
63+ * cursor = cursor. bump ( ) ;
64+ return true ;
65+ }
66+ }
67+ false
68+ }
69+
70+ fn eat_subtree ( cursor : & mut Cursor , kind : tt:: DelimiterKind ) -> bool {
71+ if let Some ( tt:: buffer:: TokenTreeRef :: Subtree ( subtree, _) ) = cursor. token_tree ( ) {
72+ if Some ( kind) == subtree. delimiter_kind ( ) {
73+ * cursor = cursor. bump_subtree ( ) ;
74+ return true ;
75+ }
76+ }
77+ false
78+ }
79+
80+ fn eat_ident ( cursor : & mut Cursor , t : & str ) -> bool {
81+ if let Some ( tt:: buffer:: TokenTreeRef :: Leaf ( tt:: Leaf :: Ident ( ident) , _) ) = cursor. token_tree ( ) {
82+ if t == ident. text . as_str ( ) {
83+ * cursor = cursor. bump ( ) ;
84+ return true ;
85+ }
86+ }
87+ false
88+ }
89+
90+ fn remove_derive_attrs ( tt : & tt:: Subtree ) -> Option < tt:: Subtree > {
91+ let buffer = TokenBuffer :: from_tokens ( & tt. token_trees ) ;
92+ let mut p = buffer. begin ( ) ;
93+ let mut result = tt:: Subtree :: default ( ) ;
94+
95+ while !p. eof ( ) {
96+ let curr = p;
97+
98+ if eat_punct ( & mut p, '#' ) {
99+ eat_punct ( & mut p, '!' ) ;
100+ let parent = p;
101+ if eat_subtree ( & mut p, tt:: DelimiterKind :: Bracket ) {
102+ if eat_ident ( & mut p, "derive" ) {
103+ p = parent. bump ( ) ;
104+ continue ;
105+ }
106+ }
107+ }
108+
109+ result. token_trees . push ( curr. token_tree ( ) ?. cloned ( ) ) ;
110+ p = curr. bump ( ) ;
111+ }
112+
113+ Some ( result)
114+ }
115+
116+ #[ cfg( test) ]
117+ mod tests {
118+ use super :: * ;
119+ use test_utils:: assert_eq_text;
120+
121+ #[ test]
122+ fn test_remove_derive_attrs ( ) {
123+ let tt = mbe:: parse_to_token_tree (
124+ r#"
125+ #[allow(unused)]
126+ #[derive(Copy)]
127+ #[derive(Hello)]
128+ struct A {
129+ bar: u32
130+ }
131+ "# ,
132+ )
133+ . unwrap ( )
134+ . 0 ;
135+ let result = format ! ( "{:#?}" , remove_derive_attrs( & tt) . unwrap( ) ) ;
136+
137+ assert_eq_text ! (
138+ r#"
139+ SUBTREE $
140+ PUNCH # [alone] 0
141+ SUBTREE [] 1
142+ IDENT allow 2
143+ SUBTREE () 3
144+ IDENT unused 4
145+ IDENT struct 15
146+ IDENT A 16
147+ SUBTREE {} 17
148+ IDENT bar 18
149+ PUNCH : [alone] 19
150+ IDENT u32 20
151+ "#
152+ . trim( ) ,
153+ & result
154+ ) ;
155+ }
156+ }
0 commit comments