1 | use std::mem; |
2 | |
3 | use proc_macro2::{Group, Spacing, Span, TokenStream, TokenTree}; |
4 | use quote::{quote, quote_spanned, ToTokens}; |
5 | use syn::{ |
6 | parse::{Parse, ParseBuffer, ParseStream}, |
7 | parse_quote, |
8 | punctuated::Punctuated, |
9 | token, |
10 | visit_mut::{self, VisitMut}, |
11 | Attribute, ExprPath, ExprStruct, Generics, Ident, Item, Lifetime, LifetimeParam, Macro, |
12 | PatStruct, PatTupleStruct, Path, PathArguments, PredicateType, QSelf, Result, Token, Type, |
13 | TypeParamBound, TypePath, Variant, Visibility, WherePredicate, |
14 | }; |
15 | |
16 | pub(crate) type Variants = Punctuated<Variant, Token![,]>; |
17 | |
18 | macro_rules! format_err { |
19 | ($span:expr, $msg:expr $(,)?) => { |
20 | syn::Error::new_spanned(&$span as &dyn quote::ToTokens, &$msg as &dyn std::fmt::Display) |
21 | }; |
22 | ($span:expr, $($tt:tt)*) => { |
23 | format_err!($span, format!($($tt)*)) |
24 | }; |
25 | } |
26 | |
27 | macro_rules! bail { |
28 | ($($tt:tt)*) => { |
29 | return Err(format_err!($($tt)*)) |
30 | }; |
31 | } |
32 | |
33 | macro_rules! parse_quote_spanned { |
34 | ($span:expr => $($tt:tt)*) => { |
35 | syn::parse2(quote::quote_spanned!($span => $($tt)*)).unwrap_or_else(|e| panic!("{}" , e)) |
36 | }; |
37 | } |
38 | |
39 | /// Determines the lifetime names. Ensure it doesn't overlap with any existing |
40 | /// lifetime names. |
41 | pub(crate) fn determine_lifetime_name(lifetime_name: &mut String, generics: &mut Generics) { |
42 | struct CollectLifetimes(Vec<String>); |
43 | |
44 | impl VisitMut for CollectLifetimes { |
45 | fn visit_lifetime_param_mut(&mut self, def: &mut LifetimeParam) { |
46 | self.0.push(def.lifetime.to_string()); |
47 | } |
48 | } |
49 | |
50 | debug_assert!(lifetime_name.starts_with(' \'' )); |
51 | |
52 | let mut lifetimes = CollectLifetimes(Vec::new()); |
53 | lifetimes.visit_generics_mut(generics); |
54 | |
55 | while lifetimes.0.iter().any(|name| name.starts_with(&**lifetime_name)) { |
56 | lifetime_name.push('_' ); |
57 | } |
58 | } |
59 | |
60 | /// Like `insert_lifetime`, but also generates a bound of the form |
61 | /// `OriginalType<A, B>: 'lifetime`. Used when generating the definition |
62 | /// of a projection type |
63 | pub(crate) fn insert_lifetime_and_bound( |
64 | generics: &mut Generics, |
65 | lifetime: Lifetime, |
66 | orig_generics: &Generics, |
67 | orig_ident: &Ident, |
68 | ) -> WherePredicate { |
69 | insert_lifetime(generics, lifetime.clone()); |
70 | |
71 | let orig_type: Type = parse_quote!(#orig_ident #orig_generics); |
72 | let mut punct = Punctuated::new(); |
73 | punct.push(TypeParamBound::Lifetime(lifetime)); |
74 | |
75 | WherePredicate::Type(PredicateType { |
76 | lifetimes: None, |
77 | bounded_ty: orig_type, |
78 | colon_token: <Token![:]>::default(), |
79 | bounds: punct, |
80 | }) |
81 | } |
82 | |
83 | /// Inserts a `lifetime` at position `0` of `generics.params`. |
84 | pub(crate) fn insert_lifetime(generics: &mut Generics, lifetime: Lifetime) { |
85 | generics.lt_token.get_or_insert_with(<Token![<]>::default); |
86 | generics.gt_token.get_or_insert_with(<Token![>]>::default); |
87 | generics.params.insert(0, LifetimeParam::new(lifetime).into()); |
88 | } |
89 | |
90 | /// Determines the visibility of the projected types and projection methods. |
91 | /// |
92 | /// If given visibility is `pub`, returned visibility is `pub(crate)`. |
93 | /// Otherwise, returned visibility is the same as given visibility. |
94 | pub(crate) fn determine_visibility(vis: &Visibility) -> Visibility { |
95 | if let Visibility::Public(token) = vis { |
96 | parse_quote_spanned!(token.span => pub(crate)) |
97 | } else { |
98 | vis.clone() |
99 | } |
100 | } |
101 | |
102 | pub(crate) fn respan<T>(node: &T, span: Span) -> T |
103 | where |
104 | T: ToTokens + Parse, |
105 | { |
106 | let tokens = node.to_token_stream(); |
107 | let respanned = respan_tokens(tokens, span); |
108 | syn::parse2(respanned).unwrap() |
109 | } |
110 | |
111 | fn respan_tokens(tokens: TokenStream, span: Span) -> TokenStream { |
112 | tokens |
113 | .into_iter() |
114 | .map(|mut token| { |
115 | token.set_span(span); |
116 | token |
117 | }) |
118 | .collect() |
119 | } |
120 | |
121 | // ================================================================================================= |
122 | // extension traits |
123 | |
124 | pub(crate) trait SliceExt { |
125 | fn position_exact(&self, ident: &str) -> Result<Option<usize>>; |
126 | fn find(&self, ident: &str) -> Option<&Attribute>; |
127 | } |
128 | |
129 | impl SliceExt for [Attribute] { |
130 | /// # Errors |
131 | /// |
132 | /// - There are multiple specified attributes. |
133 | /// - The `Attribute::tokens` field of the specified attribute is not empty. |
134 | fn position_exact(&self, ident: &str) -> Result<Option<usize>> { |
135 | self.iter() |
136 | .try_fold((0, None), |(i, mut prev), attr| { |
137 | if attr.path().is_ident(ident) { |
138 | if prev.replace(i).is_some() { |
139 | bail!(attr, "duplicate #[{}] attribute" , ident); |
140 | } |
141 | attr.meta.require_path_only()?; |
142 | } |
143 | Ok((i + 1, prev)) |
144 | }) |
145 | .map(|(_, pos)| pos) |
146 | } |
147 | |
148 | fn find(&self, ident: &str) -> Option<&Attribute> { |
149 | self.iter().position(|attr| attr.path().is_ident(ident)).map(|i| &self[i]) |
150 | } |
151 | } |
152 | |
153 | pub(crate) trait ParseBufferExt<'a> { |
154 | fn parenthesized(self) -> Result<ParseBuffer<'a>>; |
155 | } |
156 | |
157 | impl<'a> ParseBufferExt<'a> for ParseStream<'a> { |
158 | fn parenthesized(self) -> Result<ParseBuffer<'a>> { |
159 | let content; |
160 | let _: token::Paren = syn::parenthesized!(content in self); |
161 | Ok(content) |
162 | } |
163 | } |
164 | |
165 | impl<'a> ParseBufferExt<'a> for ParseBuffer<'a> { |
166 | fn parenthesized(self) -> Result<ParseBuffer<'a>> { |
167 | let content; |
168 | let _: token::Paren = syn::parenthesized!(content in self); |
169 | Ok(content) |
170 | } |
171 | } |
172 | |
173 | // ================================================================================================= |
174 | // visitors |
175 | |
176 | // Replace `self`/`Self` with `__self`/`self_ty`. |
177 | // Based on: |
178 | // - https://github.com/dtolnay/async-trait/blob/0.1.35/src/receiver.rs |
179 | // - https://github.com/dtolnay/async-trait/commit/6029cbf375c562ca98fa5748e9d950a8ff93b0e7 |
180 | |
181 | pub(crate) struct ReplaceReceiver<'a>(pub(crate) &'a TypePath); |
182 | |
183 | impl ReplaceReceiver<'_> { |
184 | fn self_ty(&self, span: Span) -> TypePath { |
185 | respan(self.0, span) |
186 | } |
187 | |
188 | fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) { |
189 | if path.leading_colon.is_some() { |
190 | return; |
191 | } |
192 | |
193 | let first = &path.segments[0]; |
194 | if first.ident != "Self" || !first.arguments.is_empty() { |
195 | return; |
196 | } |
197 | |
198 | if path.segments.len() == 1 { |
199 | self.self_to_expr_path(path); |
200 | return; |
201 | } |
202 | |
203 | let span = first.ident.span(); |
204 | *qself = Some(QSelf { |
205 | lt_token: Token![<](span), |
206 | ty: Box::new(self.self_ty(span).into()), |
207 | position: 0, |
208 | as_token: None, |
209 | gt_token: Token![>](span), |
210 | }); |
211 | |
212 | path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap()); |
213 | |
214 | let segments = mem::replace(&mut path.segments, Punctuated::new()); |
215 | path.segments = segments.into_pairs().skip(1).collect(); |
216 | } |
217 | |
218 | fn self_to_expr_path(&self, path: &mut Path) { |
219 | if path.leading_colon.is_some() { |
220 | return; |
221 | } |
222 | |
223 | let first = &path.segments[0]; |
224 | if first.ident != "Self" || !first.arguments.is_empty() { |
225 | return; |
226 | } |
227 | |
228 | let self_ty = self.self_ty(first.ident.span()); |
229 | let variant = mem::replace(path, self_ty.path); |
230 | for segment in &mut path.segments { |
231 | if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments { |
232 | if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() { |
233 | bracketed.colon2_token = Some(<Token![::]>::default()); |
234 | } |
235 | } |
236 | } |
237 | if variant.segments.len() > 1 { |
238 | path.segments.push_punct(<Token![::]>::default()); |
239 | path.segments.extend(variant.segments.into_pairs().skip(1)); |
240 | } |
241 | } |
242 | |
243 | fn visit_token_stream(&self, tokens: &mut TokenStream) -> bool { |
244 | let mut out = Vec::new(); |
245 | let mut modified = false; |
246 | let mut iter = tokens.clone().into_iter().peekable(); |
247 | while let Some(tt) = iter.next() { |
248 | match tt { |
249 | TokenTree::Ident(mut ident) => { |
250 | modified |= prepend_underscore_to_self(&mut ident); |
251 | if ident == "Self" { |
252 | modified = true; |
253 | let self_ty = self.self_ty(ident.span()); |
254 | match iter.peek() { |
255 | Some(TokenTree::Punct(p)) |
256 | if p.as_char() == ':' && p.spacing() == Spacing::Joint => |
257 | { |
258 | let next = iter.next().unwrap(); |
259 | match iter.peek() { |
260 | Some(TokenTree::Punct(p)) if p.as_char() == ':' => { |
261 | let span = ident.span(); |
262 | out.extend(quote_spanned!(span=> <#self_ty>)); |
263 | } |
264 | _ => out.extend(quote!(#self_ty)), |
265 | } |
266 | out.push(next); |
267 | } |
268 | _ => out.extend(quote!(#self_ty)), |
269 | } |
270 | } else { |
271 | out.push(TokenTree::Ident(ident)); |
272 | } |
273 | } |
274 | TokenTree::Group(group) => { |
275 | let mut content = group.stream(); |
276 | modified |= self.visit_token_stream(&mut content); |
277 | let mut new = Group::new(group.delimiter(), content); |
278 | new.set_span(group.span()); |
279 | out.push(TokenTree::Group(new)); |
280 | } |
281 | other => out.push(other), |
282 | } |
283 | } |
284 | if modified { |
285 | *tokens = TokenStream::from_iter(out); |
286 | } |
287 | modified |
288 | } |
289 | } |
290 | |
291 | impl VisitMut for ReplaceReceiver<'_> { |
292 | // `Self` -> `Receiver` |
293 | fn visit_type_mut(&mut self, ty: &mut Type) { |
294 | if let Type::Path(node) = ty { |
295 | if node.qself.is_none() && node.path.is_ident("Self" ) { |
296 | *ty = self.self_ty(node.path.segments[0].ident.span()).into(); |
297 | } else { |
298 | self.visit_type_path_mut(node); |
299 | } |
300 | } else { |
301 | visit_mut::visit_type_mut(self, ty); |
302 | } |
303 | } |
304 | |
305 | // `Self::Assoc` -> `<Receiver>::Assoc` |
306 | fn visit_type_path_mut(&mut self, ty: &mut TypePath) { |
307 | if ty.qself.is_none() { |
308 | self.self_to_qself(&mut ty.qself, &mut ty.path); |
309 | } |
310 | visit_mut::visit_type_path_mut(self, ty); |
311 | } |
312 | |
313 | // `Self::method` -> `<Receiver>::method` |
314 | fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) { |
315 | if expr.qself.is_none() { |
316 | self.self_to_qself(&mut expr.qself, &mut expr.path); |
317 | } |
318 | visit_mut::visit_expr_path_mut(self, expr); |
319 | } |
320 | |
321 | fn visit_expr_struct_mut(&mut self, expr: &mut ExprStruct) { |
322 | self.self_to_expr_path(&mut expr.path); |
323 | visit_mut::visit_expr_struct_mut(self, expr); |
324 | } |
325 | |
326 | fn visit_pat_struct_mut(&mut self, pat: &mut PatStruct) { |
327 | self.self_to_expr_path(&mut pat.path); |
328 | visit_mut::visit_pat_struct_mut(self, pat); |
329 | } |
330 | |
331 | fn visit_pat_tuple_struct_mut(&mut self, pat: &mut PatTupleStruct) { |
332 | self.self_to_expr_path(&mut pat.path); |
333 | visit_mut::visit_pat_tuple_struct_mut(self, pat); |
334 | } |
335 | |
336 | fn visit_path_mut(&mut self, path: &mut Path) { |
337 | if path.segments.len() == 1 { |
338 | // Replace `self`, but not `self::function`. |
339 | prepend_underscore_to_self(&mut path.segments[0].ident); |
340 | } |
341 | for segment in &mut path.segments { |
342 | self.visit_path_arguments_mut(&mut segment.arguments); |
343 | } |
344 | } |
345 | |
346 | fn visit_item_mut(&mut self, item: &mut Item) { |
347 | match item { |
348 | // Visit `macro_rules!` because locally defined macros can refer to `self`. |
349 | Item::Macro(item) if item.mac.path.is_ident("macro_rules" ) => { |
350 | self.visit_macro_mut(&mut item.mac); |
351 | } |
352 | // Otherwise, do not recurse into nested items. |
353 | _ => {} |
354 | } |
355 | } |
356 | |
357 | fn visit_macro_mut(&mut self, mac: &mut Macro) { |
358 | // We can't tell in general whether `self` inside a macro invocation |
359 | // refers to the self in the argument list or a different self |
360 | // introduced within the macro. Heuristic: if the macro input contains |
361 | // `fn`, then `self` is more likely to refer to something other than the |
362 | // outer function's self argument. |
363 | if !contains_fn(mac.tokens.clone()) { |
364 | self.visit_token_stream(&mut mac.tokens); |
365 | } |
366 | } |
367 | } |
368 | |
369 | fn contains_fn(tokens: TokenStream) -> bool { |
370 | tokens.into_iter().any(|tt| match tt { |
371 | TokenTree::Ident(ident) => ident == "fn" , |
372 | TokenTree::Group(group) => contains_fn(group.stream()), |
373 | _ => false, |
374 | }) |
375 | } |
376 | |
377 | pub(crate) fn prepend_underscore_to_self(ident: &mut Ident) -> bool { |
378 | let modified = ident == "self" ; |
379 | if modified { |
380 | *ident = Ident::new("__self" , ident.span()); |
381 | } |
382 | modified |
383 | } |
384 | |