• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use proc_macro2::{Span, TokenStream};
2 use std::mem;
3 use syn::visit_mut::{self, VisitMut};
4 use syn::{
5     parse_quote_spanned, token, Expr, GenericArgument, Lifetime, Receiver, ReturnType, Token, Type,
6     TypeBareFn, TypeImplTrait, TypeParen, TypePtr, TypeReference,
7 };
8 
9 pub struct CollectLifetimes {
10     pub elided: Vec<Lifetime>,
11     pub explicit: Vec<Lifetime>,
12     pub name: &'static str,
13 }
14 
15 impl CollectLifetimes {
new(name: &'static str) -> Self16     pub fn new(name: &'static str) -> Self {
17         CollectLifetimes {
18             elided: Vec::new(),
19             explicit: Vec::new(),
20             name,
21         }
22     }
23 
visit_opt_lifetime(&mut self, reference: Token![&], lifetime: &mut Option<Lifetime>)24     fn visit_opt_lifetime(&mut self, reference: Token![&], lifetime: &mut Option<Lifetime>) {
25         match lifetime {
26             None => *lifetime = Some(self.next_lifetime(reference.span)),
27             Some(lifetime) => self.visit_lifetime(lifetime),
28         }
29     }
30 
visit_lifetime(&mut self, lifetime: &mut Lifetime)31     fn visit_lifetime(&mut self, lifetime: &mut Lifetime) {
32         if lifetime.ident == "_" {
33             *lifetime = self.next_lifetime(lifetime.span());
34         } else {
35             self.explicit.push(lifetime.clone());
36         }
37     }
38 
next_lifetime(&mut self, span: Span) -> Lifetime39     fn next_lifetime(&mut self, span: Span) -> Lifetime {
40         let name = format!("{}{}", self.name, self.elided.len());
41         let life = Lifetime::new(&name, span);
42         self.elided.push(life.clone());
43         life
44     }
45 }
46 
47 impl VisitMut for CollectLifetimes {
visit_receiver_mut(&mut self, arg: &mut Receiver)48     fn visit_receiver_mut(&mut self, arg: &mut Receiver) {
49         if let Some((reference, lifetime)) = &mut arg.reference {
50             self.visit_opt_lifetime(*reference, lifetime);
51         }
52     }
53 
visit_type_reference_mut(&mut self, ty: &mut TypeReference)54     fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) {
55         self.visit_opt_lifetime(ty.and_token, &mut ty.lifetime);
56         visit_mut::visit_type_reference_mut(self, ty);
57     }
58 
visit_generic_argument_mut(&mut self, gen: &mut GenericArgument)59     fn visit_generic_argument_mut(&mut self, gen: &mut GenericArgument) {
60         if let GenericArgument::Lifetime(lifetime) = gen {
61             self.visit_lifetime(lifetime);
62         }
63         visit_mut::visit_generic_argument_mut(self, gen);
64     }
65 }
66 
67 pub struct AddLifetimeToImplTrait;
68 
69 impl VisitMut for AddLifetimeToImplTrait {
visit_type_impl_trait_mut(&mut self, ty: &mut TypeImplTrait)70     fn visit_type_impl_trait_mut(&mut self, ty: &mut TypeImplTrait) {
71         let span = ty.impl_token.span;
72         let lifetime = parse_quote_spanned!(span=> 'async_trait);
73         ty.bounds.insert(0, lifetime);
74         if let Some(punct) = ty.bounds.pairs_mut().next().unwrap().punct_mut() {
75             punct.span = span;
76         }
77         visit_mut::visit_type_impl_trait_mut(self, ty);
78     }
79 
visit_type_reference_mut(&mut self, ty: &mut TypeReference)80     fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) {
81         parenthesize_impl_trait(&mut ty.elem, ty.and_token.span);
82         visit_mut::visit_type_reference_mut(self, ty);
83     }
84 
visit_type_ptr_mut(&mut self, ty: &mut TypePtr)85     fn visit_type_ptr_mut(&mut self, ty: &mut TypePtr) {
86         parenthesize_impl_trait(&mut ty.elem, ty.star_token.span);
87         visit_mut::visit_type_ptr_mut(self, ty);
88     }
89 
visit_type_bare_fn_mut(&mut self, ty: &mut TypeBareFn)90     fn visit_type_bare_fn_mut(&mut self, ty: &mut TypeBareFn) {
91         if let ReturnType::Type(arrow, return_type) = &mut ty.output {
92             parenthesize_impl_trait(return_type, arrow.spans[0]);
93         }
94         visit_mut::visit_type_bare_fn_mut(self, ty);
95     }
96 
visit_expr_mut(&mut self, _e: &mut Expr)97     fn visit_expr_mut(&mut self, _e: &mut Expr) {
98         // Do not recurse into impl Traits inside of an array length expression.
99         //
100         //    fn outer(arg: [u8; { fn inner(_: impl Trait) {}; 0 }]);
101     }
102 }
103 
parenthesize_impl_trait(elem: &mut Type, paren_span: Span)104 fn parenthesize_impl_trait(elem: &mut Type, paren_span: Span) {
105     if let Type::ImplTrait(_) = *elem {
106         let placeholder = Type::Verbatim(TokenStream::new());
107         *elem = Type::Paren(TypeParen {
108             paren_token: token::Paren(paren_span),
109             elem: Box::new(mem::replace(elem, placeholder)),
110         });
111     }
112 }
113