2
2
3
3
use crate :: db:: AstDatabase ;
4
4
use base_db:: { CrateId , ProcMacroId } ;
5
+ use tt:: buffer:: { Cursor , TokenBuffer } ;
5
6
6
7
#[ derive( Debug , Clone , Copy , Eq , PartialEq , Hash ) ]
7
8
pub struct ProcMacroExpander {
@@ -43,6 +44,9 @@ impl ProcMacroExpander {
43
44
. clone ( )
44
45
. ok_or_else ( || err ! ( "No derive macro found." ) ) ?;
45
46
47
+ let tt = remove_derive_attrs ( tt)
48
+ . ok_or_else ( || err ! ( "Fail to remove derive for custom derive" ) ) ?;
49
+
46
50
// Proc macros have access to the environment variables of the invoking crate.
47
51
let env = & krate_graph[ calling_crate] . env ;
48
52
@@ -52,3 +56,101 @@ impl ProcMacroExpander {
52
56
}
53
57
}
54
58
}
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