1+ use proc_macro2:: { Group , TokenStream , TokenTree } ;
12use std:: mem;
23use syn:: punctuated:: Punctuated ;
34use syn:: visit_mut:: { self , VisitMut } ;
45use 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 ,
68} ;
79
810pub fn has_self_in_sig ( sig : & mut MethodSig ) -> bool {
@@ -126,10 +128,7 @@ impl VisitMut for ReplaceReceiver {
126128 // `Self::method` -> `<Receiver>::method`
127129 fn visit_expr_path_mut ( & mut self , expr : & mut ExprPath ) {
128130 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 ) ;
133132 self . self_to_qself_expr ( & mut expr. qself , & mut expr. path ) ;
134133 }
135134 visit_mut:: visit_expr_path_mut ( self , expr) ;
@@ -138,4 +137,45 @@ impl VisitMut for ReplaceReceiver {
138137 fn visit_item_mut ( & mut self , _: & mut Item ) {
139138 // Do not recurse into nested items.
140139 }
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+ }
141181}
0 commit comments