1 use proc_macro2::Span; 2 use syn::visit_mut::{self, VisitMut}; 3 use syn::{GenericArgument, Lifetime, Receiver, TypeReference}; 4 5 pub struct CollectLifetimes { 6 pub elided: Vec<Lifetime>, 7 pub explicit: Vec<Lifetime>, 8 pub name: &'static str, 9 pub default_span: Span, 10 } 11 12 impl CollectLifetimes { new(name: &'static str, default_span: Span) -> Self13 pub fn new(name: &'static str, default_span: Span) -> Self { 14 CollectLifetimes { 15 elided: Vec::new(), 16 explicit: Vec::new(), 17 name, 18 default_span, 19 } 20 } 21 visit_opt_lifetime(&mut self, lifetime: &mut Option<Lifetime>)22 fn visit_opt_lifetime(&mut self, lifetime: &mut Option<Lifetime>) { 23 match lifetime { 24 None => *lifetime = Some(self.next_lifetime(None)), 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<S: Into<Option<Span>>>(&mut self, span: S) -> Lifetime37 fn next_lifetime<S: Into<Option<Span>>>(&mut self, span: S) -> Lifetime { 38 let name = format!("{}{}", self.name, self.elided.len()); 39 let span = span.into().unwrap_or(self.default_span); 40 let life = Lifetime::new(&name, span); 41 self.elided.push(life.clone()); 42 life 43 } 44 } 45 46 impl VisitMut for CollectLifetimes { visit_receiver_mut(&mut self, arg: &mut Receiver)47 fn visit_receiver_mut(&mut self, arg: &mut Receiver) { 48 if let Some((_, lifetime)) = &mut arg.reference { 49 self.visit_opt_lifetime(lifetime); 50 } 51 } 52 visit_type_reference_mut(&mut self, ty: &mut TypeReference)53 fn visit_type_reference_mut(&mut self, ty: &mut TypeReference) { 54 self.visit_opt_lifetime(&mut ty.lifetime); 55 visit_mut::visit_type_reference_mut(self, ty); 56 } 57 visit_generic_argument_mut(&mut self, gen: &mut GenericArgument)58 fn visit_generic_argument_mut(&mut self, gen: &mut GenericArgument) { 59 if let GenericArgument::Lifetime(lifetime) = gen { 60 self.visit_lifetime(lifetime); 61 } 62 visit_mut::visit_generic_argument_mut(self, gen); 63 } 64 } 65