1
+ use proc_macro2:: { Group , TokenStream , TokenTree } ;
1
2
use std:: mem;
2
3
use syn:: punctuated:: Punctuated ;
3
4
use syn:: visit_mut:: { self , VisitMut } ;
4
5
use syn:: {
5
- ArgSelf , ArgSelfRef , Block , ExprPath , Ident , Item , MethodSig , Path , QSelf , Type , TypePath ,
6
+ ArgSelf , ArgSelfRef , Block , ExprPath , Ident , Item , Macro , MethodSig , Path , QSelf , Type ,
7
+ TypePath ,
6
8
} ;
7
9
8
10
pub fn has_self_in_sig ( sig : & mut MethodSig ) -> bool {
@@ -126,10 +128,7 @@ impl VisitMut for ReplaceReceiver {
126
128
// `Self::method` -> `<Receiver>::method`
127
129
fn visit_expr_path_mut ( & mut self , expr : & mut ExprPath ) {
128
130
if expr. qself . is_none ( ) {
129
- if expr. path . is_ident ( "self" ) {
130
- let ident = & mut expr. path . segments [ 0 ] . ident ;
131
- * ident = Ident :: new ( "_self" , ident. span ( ) ) ;
132
- }
131
+ prepend_underscore_to_self ( & mut expr. path . segments [ 0 ] . ident ) ;
133
132
self . self_to_qself_expr ( & mut expr. qself , & mut expr. path ) ;
134
133
}
135
134
visit_mut:: visit_expr_path_mut ( self , expr) ;
@@ -138,4 +137,45 @@ impl VisitMut for ReplaceReceiver {
138
137
fn visit_item_mut ( & mut self , _: & mut Item ) {
139
138
// Do not recurse into nested items.
140
139
}
140
+
141
+ fn visit_macro_mut ( & mut self , i : & mut Macro ) {
142
+ // We can't tell in general whether `self` inside a macro invocation
143
+ // refers to the self in the argument list or a different self
144
+ // introduced within the macro. Heuristic: if the macro input contains
145
+ // `fn`, then `self` is more likely to refer to something other than the
146
+ // outer function's self argument.
147
+ if !contains_fn ( i. tts . clone ( ) ) {
148
+ i. tts = fold_token_stream ( i. tts . clone ( ) ) ;
149
+ }
150
+ }
151
+ }
152
+
153
+ fn contains_fn ( tts : TokenStream ) -> bool {
154
+ tts. into_iter ( ) . any ( |tt| match tt {
155
+ TokenTree :: Ident ( ident) => ident == "fn" ,
156
+ TokenTree :: Group ( group) => contains_fn ( group. stream ( ) ) ,
157
+ _ => false ,
158
+ } )
159
+ }
160
+
161
+ fn fold_token_stream ( tts : TokenStream ) -> TokenStream {
162
+ tts. into_iter ( )
163
+ . map ( |tt| match tt {
164
+ TokenTree :: Ident ( mut ident) => {
165
+ prepend_underscore_to_self ( & mut ident) ;
166
+ TokenTree :: Ident ( ident)
167
+ }
168
+ TokenTree :: Group ( group) => {
169
+ let content = fold_token_stream ( group. stream ( ) ) ;
170
+ TokenTree :: Group ( Group :: new ( group. delimiter ( ) , content) )
171
+ }
172
+ other => other,
173
+ } )
174
+ . collect ( )
175
+ }
176
+
177
+ fn prepend_underscore_to_self ( ident : & mut Ident ) {
178
+ if ident == "self" {
179
+ * ident = Ident :: new ( "_self" , ident. span ( ) ) ;
180
+ }
141
181
}
0 commit comments