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