1 use crate::respan::respan;
2 use proc_macro2::{Group, Spacing, Span, TokenStream, TokenTree};
3 use quote::{quote, quote_spanned};
4 use std::iter::FromIterator;
5 use std::mem;
6 use syn::punctuated::Punctuated;
7 use syn::visit_mut::{self, VisitMut};
8 use syn::{
9     parse_quote, Block, Error, ExprPath, ExprStruct, Ident, Item, Macro, PatPath, PatStruct,
10     PatTupleStruct, Path, PathArguments, QSelf, Receiver, Signature, Token, Type, TypePath,
11     WherePredicate,
12 };
13 
has_self_in_sig(sig: &mut Signature) -> bool14 pub fn has_self_in_sig(sig: &mut Signature) -> bool {
15     let mut visitor = HasSelf(false);
16     visitor.visit_signature_mut(sig);
17     visitor.0
18 }
19 
has_self_in_where_predicate(where_predicate: &mut WherePredicate) -> bool20 pub fn has_self_in_where_predicate(where_predicate: &mut WherePredicate) -> bool {
21     let mut visitor = HasSelf(false);
22     visitor.visit_where_predicate_mut(where_predicate);
23     visitor.0
24 }
25 
has_self_in_block(block: &mut Block) -> bool26 pub fn has_self_in_block(block: &mut Block) -> bool {
27     let mut visitor = HasSelf(false);
28     visitor.visit_block_mut(block);
29     visitor.0
30 }
31 
has_self_in_token_stream(tokens: TokenStream) -> bool32 fn has_self_in_token_stream(tokens: TokenStream) -> bool {
33     tokens.into_iter().any(|tt| match tt {
34         TokenTree::Ident(ident) => ident == "Self",
35         TokenTree::Group(group) => has_self_in_token_stream(group.stream()),
36         _ => false,
37     })
38 }
39 
40 struct HasSelf(bool);
41 
42 impl VisitMut for HasSelf {
visit_expr_path_mut(&mut self, expr: &mut ExprPath)43     fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
44         self.0 |= expr.path.segments[0].ident == "Self";
45         visit_mut::visit_expr_path_mut(self, expr);
46     }
47 
visit_pat_path_mut(&mut self, pat: &mut PatPath)48     fn visit_pat_path_mut(&mut self, pat: &mut PatPath) {
49         self.0 |= pat.path.segments[0].ident == "Self";
50         visit_mut::visit_pat_path_mut(self, pat);
51     }
52 
visit_type_path_mut(&mut self, ty: &mut TypePath)53     fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
54         self.0 |= ty.path.segments[0].ident == "Self";
55         visit_mut::visit_type_path_mut(self, ty);
56     }
57 
visit_receiver_mut(&mut self, _arg: &mut Receiver)58     fn visit_receiver_mut(&mut self, _arg: &mut Receiver) {
59         self.0 = true;
60     }
61 
visit_item_mut(&mut self, _: &mut Item)62     fn visit_item_mut(&mut self, _: &mut Item) {
63         // Do not recurse into nested items.
64     }
65 
visit_macro_mut(&mut self, mac: &mut Macro)66     fn visit_macro_mut(&mut self, mac: &mut Macro) {
67         if !contains_fn(mac.tokens.clone()) {
68             self.0 |= has_self_in_token_stream(mac.tokens.clone());
69         }
70     }
71 }
72 
73 pub struct ReplaceReceiver {
74     pub with: Type,
75     pub as_trait: Option<Path>,
76 }
77 
78 impl ReplaceReceiver {
with(ty: Type) -> Self79     pub fn with(ty: Type) -> Self {
80         ReplaceReceiver {
81             with: ty,
82             as_trait: None,
83         }
84     }
85 
with_as_trait(ty: Type, as_trait: Path) -> Self86     pub fn with_as_trait(ty: Type, as_trait: Path) -> Self {
87         ReplaceReceiver {
88             with: ty,
89             as_trait: Some(as_trait),
90         }
91     }
92 
self_ty(&self, span: Span) -> Type93     fn self_ty(&self, span: Span) -> Type {
94         respan(&self.with, span)
95     }
96 
self_to_qself_type(&self, qself: &mut Option<QSelf>, path: &mut Path)97     fn self_to_qself_type(&self, qself: &mut Option<QSelf>, path: &mut Path) {
98         let include_as_trait = true;
99         self.self_to_qself(qself, path, include_as_trait);
100     }
101 
self_to_qself_expr(&self, qself: &mut Option<QSelf>, path: &mut Path)102     fn self_to_qself_expr(&self, qself: &mut Option<QSelf>, path: &mut Path) {
103         let include_as_trait = false;
104         self.self_to_qself(qself, path, include_as_trait);
105     }
106 
self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path, include_as_trait: bool)107     fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path, include_as_trait: bool) {
108         if path.leading_colon.is_some() {
109             return;
110         }
111 
112         let first = &path.segments[0];
113         if first.ident != "Self" || !first.arguments.is_empty() {
114             return;
115         }
116 
117         if path.segments.len() == 1 {
118             self.self_to_expr_path(path);
119             return;
120         }
121 
122         let span = first.ident.span();
123         *qself = Some(QSelf {
124             lt_token: Token![<](span),
125             ty: Box::new(self.self_ty(span)),
126             position: 0,
127             as_token: None,
128             gt_token: Token![>](span),
129         });
130 
131         if include_as_trait && self.as_trait.is_some() {
132             let as_trait = self.as_trait.as_ref().unwrap().clone();
133             path.leading_colon = as_trait.leading_colon;
134             qself.as_mut().unwrap().position = as_trait.segments.len();
135 
136             let segments = mem::replace(&mut path.segments, as_trait.segments);
137             path.segments.push_punct(Default::default());
138             path.segments.extend(segments.into_pairs().skip(1));
139         } else {
140             path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
141 
142             let segments = mem::replace(&mut path.segments, Punctuated::new());
143             path.segments = segments.into_pairs().skip(1).collect();
144         }
145     }
146 
self_to_expr_path(&self, path: &mut Path)147     fn self_to_expr_path(&self, path: &mut Path) {
148         if path.leading_colon.is_some() {
149             return;
150         }
151 
152         let first = &path.segments[0];
153         if first.ident != "Self" || !first.arguments.is_empty() {
154             return;
155         }
156 
157         if let Type::Path(self_ty) = self.self_ty(first.ident.span()) {
158             let variant = mem::replace(path, self_ty.path);
159             for segment in &mut path.segments {
160                 if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
161                     if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
162                         bracketed.colon2_token = Some(Default::default());
163                     }
164                 }
165             }
166             if variant.segments.len() > 1 {
167                 path.segments.push_punct(Default::default());
168                 path.segments.extend(variant.segments.into_pairs().skip(1));
169             }
170         } else {
171             let span = path.segments[0].ident.span();
172             let msg = "Self type of this impl is unsupported in expression position";
173             let error = Error::new(span, msg).to_compile_error();
174             *path = parse_quote!(::core::marker::PhantomData::<#error>);
175         }
176     }
177 
visit_token_stream(&self, tokens: &mut TokenStream) -> bool178     fn visit_token_stream(&self, tokens: &mut TokenStream) -> bool {
179         let mut out = Vec::new();
180         let mut modified = false;
181         let mut iter = tokens.clone().into_iter().peekable();
182         while let Some(tt) = iter.next() {
183             match tt {
184                 TokenTree::Ident(mut ident) => {
185                     modified |= prepend_underscore_to_self(&mut ident);
186                     if ident == "Self" {
187                         modified = true;
188                         if self.as_trait.is_none() {
189                             let ident = Ident::new("AsyncTrait", ident.span());
190                             out.push(TokenTree::Ident(ident));
191                         } else {
192                             let self_ty = self.self_ty(ident.span());
193                             match iter.peek() {
194                                 Some(TokenTree::Punct(p))
195                                     if p.as_char() == ':' && p.spacing() == Spacing::Joint =>
196                                 {
197                                     let next = iter.next().unwrap();
198                                     match iter.peek() {
199                                         Some(TokenTree::Punct(p)) if p.as_char() == ':' => {
200                                             let span = ident.span();
201                                             out.extend(quote_spanned!(span=> <#self_ty>));
202                                         }
203                                         _ => out.extend(quote!(#self_ty)),
204                                     }
205                                     out.push(next);
206                                 }
207                                 _ => out.extend(quote!(#self_ty)),
208                             }
209                         }
210                     } else {
211                         out.push(TokenTree::Ident(ident));
212                     }
213                 }
214                 TokenTree::Group(group) => {
215                     let mut content = group.stream();
216                     modified |= self.visit_token_stream(&mut content);
217                     let mut new = Group::new(group.delimiter(), content);
218                     new.set_span(group.span());
219                     out.push(TokenTree::Group(new));
220                 }
221                 other => out.push(other),
222             }
223         }
224         if modified {
225             *tokens = TokenStream::from_iter(out);
226         }
227         modified
228     }
229 }
230 
231 impl VisitMut for ReplaceReceiver {
232     // `Self` -> `Receiver`
visit_type_mut(&mut self, ty: &mut Type)233     fn visit_type_mut(&mut self, ty: &mut Type) {
234         if let Type::Path(node) = ty {
235             if node.qself.is_none() && node.path.is_ident("Self") {
236                 *ty = self.self_ty(node.path.segments[0].ident.span());
237             } else {
238                 self.visit_type_path_mut(node);
239             }
240         } else {
241             visit_mut::visit_type_mut(self, ty);
242         }
243     }
244 
245     // `Self::Assoc` -> `<Receiver>::Assoc`
visit_type_path_mut(&mut self, ty: &mut TypePath)246     fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
247         if ty.qself.is_none() {
248             self.self_to_qself_type(&mut ty.qself, &mut ty.path);
249         }
250         visit_mut::visit_type_path_mut(self, ty);
251     }
252 
253     // `Self::method` -> `<Receiver>::method`
visit_expr_path_mut(&mut self, expr: &mut ExprPath)254     fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
255         if expr.qself.is_none() {
256             prepend_underscore_to_self(&mut expr.path.segments[0].ident);
257             self.self_to_qself_expr(&mut expr.qself, &mut expr.path);
258         }
259         visit_mut::visit_expr_path_mut(self, expr);
260     }
261 
visit_expr_struct_mut(&mut self, expr: &mut ExprStruct)262     fn visit_expr_struct_mut(&mut self, expr: &mut ExprStruct) {
263         self.self_to_expr_path(&mut expr.path);
264         visit_mut::visit_expr_struct_mut(self, expr);
265     }
266 
visit_pat_path_mut(&mut self, pat: &mut PatPath)267     fn visit_pat_path_mut(&mut self, pat: &mut PatPath) {
268         if pat.qself.is_none() {
269             self.self_to_qself_expr(&mut pat.qself, &mut pat.path);
270         }
271         visit_mut::visit_pat_path_mut(self, pat);
272     }
273 
visit_pat_struct_mut(&mut self, pat: &mut PatStruct)274     fn visit_pat_struct_mut(&mut self, pat: &mut PatStruct) {
275         self.self_to_expr_path(&mut pat.path);
276         visit_mut::visit_pat_struct_mut(self, pat);
277     }
278 
visit_pat_tuple_struct_mut(&mut self, pat: &mut PatTupleStruct)279     fn visit_pat_tuple_struct_mut(&mut self, pat: &mut PatTupleStruct) {
280         self.self_to_expr_path(&mut pat.path);
281         visit_mut::visit_pat_tuple_struct_mut(self, pat);
282     }
283 
visit_item_mut(&mut self, i: &mut Item)284     fn visit_item_mut(&mut self, i: &mut Item) {
285         match i {
286             // Visit `macro_rules!` because locally defined macros can refer to `self`.
287             Item::Macro(i) if i.mac.path.is_ident("macro_rules") => {
288                 self.visit_macro_mut(&mut i.mac)
289             }
290             // Otherwise, do not recurse into nested items.
291             _ => {}
292         }
293     }
294 
visit_macro_mut(&mut self, mac: &mut Macro)295     fn visit_macro_mut(&mut self, mac: &mut Macro) {
296         // We can't tell in general whether `self` inside a macro invocation
297         // refers to the self in the argument list or a different self
298         // introduced within the macro. Heuristic: if the macro input contains
299         // `fn`, then `self` is more likely to refer to something other than the
300         // outer function's self argument.
301         if !contains_fn(mac.tokens.clone()) {
302             self.visit_token_stream(&mut mac.tokens);
303         }
304     }
305 }
306 
contains_fn(tokens: TokenStream) -> bool307 fn contains_fn(tokens: TokenStream) -> bool {
308     tokens.into_iter().any(|tt| match tt {
309         TokenTree::Ident(ident) => ident == "fn",
310         TokenTree::Group(group) => contains_fn(group.stream()),
311         _ => false,
312     })
313 }
314 
prepend_underscore_to_self(ident: &mut Ident) -> bool315 fn prepend_underscore_to_self(ident: &mut Ident) -> bool {
316     let modified = ident == "self";
317     if modified {
318         *ident = Ident::new("_self", ident.span());
319     }
320     modified
321 }
322