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 }
13
14 impl CollectLifetimes {
new() -> Self15 pub fn new() -> Self {
16 CollectLifetimes {
17 elided: Vec::new(),
18 explicit: Vec::new(),
19 }
20 }
21
visit_opt_lifetime(&mut self, reference: &Token![&], lifetime: &mut Option<Lifetime>)22 fn visit_opt_lifetime(&mut self, reference: &Token![&], lifetime: &mut Option<Lifetime>) {
23 match lifetime {
24 None => *lifetime = Some(self.next_lifetime(reference.span)),
25 Some(lifetime) => self.visit_lifetime(lifetime),
26 }
27 }
28
visit_lifetime(&mut self, lifetime: &mut Lifetime)29 fn visit_lifetime(&mut self, lifetime: &mut Lifetime) {
30 if lifetime.ident == "_" {
31 *lifetime = self.next_lifetime(lifetime.span());
32 } else {
33 self.explicit.push(lifetime.clone());
34 }
35 }
36
next_lifetime(&mut self, span: Span) -> Lifetime37 fn next_lifetime(&mut self, span: Span) -> Lifetime {
38 let name = format!("'life{}", self.elided.len());
39 let life = Lifetime::new(&name, span);
40 self.elided.push(life.clone());
41 life
42 }
43 }
44
45 impl VisitMut for CollectLifetimes {
visit_receiver_mut(&mut self, arg: &mut Receiver)46 fn visit_receiver_mut(&mut self, arg: &mut Receiver) {
47 if let Some((reference, lifetime)) = &mut arg.reference {
48 self.visit_opt_lifetime(reference, lifetime);
49 } else {
50 visit_mut::visit_type_mut(self, &mut arg.ty);
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