1 use fnv::FnvHashSet; 2 use syn::punctuated::Punctuated; 3 use syn::{self, Lifetime, Type}; 4 5 use usage::Options; 6 7 /// A set of lifetimes. 8 pub type LifetimeSet = FnvHashSet<Lifetime>; 9 10 /// A set of references to lifetimes. 11 pub type LifetimeRefSet<'a> = FnvHashSet<&'a Lifetime>; 12 13 /// Searcher for finding lifetimes in a syntax tree. 14 /// This can be used to determine which lifetimes must be emitted in generated code. 15 pub trait UsesLifetimes { 16 /// Returns the subset of the queried lifetimes that are used by the implementing syntax element. 17 /// 18 /// This method only accounts for direct usage by the element; indirect usage via bounds or `where` 19 /// predicates are not detected. uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>20 fn uses_lifetimes<'a>( 21 &self, 22 options: &Options, 23 lifetimes: &'a LifetimeSet, 24 ) -> LifetimeRefSet<'a>; 25 26 /// Find all used lifetimes, then clone them and return that set. uses_lifetimes_cloned(&self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet27 fn uses_lifetimes_cloned(&self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet { 28 self.uses_lifetimes(options, lifetimes) 29 .into_iter() 30 .cloned() 31 .collect() 32 } 33 } 34 35 /// Searcher for finding lifetimes in an iterator. 36 /// 37 /// This trait extends iterators, providing a way to turn a filtered list of fields or variants into a set 38 /// of lifetimes. 39 pub trait CollectLifetimes { 40 /// Consume an iterator, accumulating all lifetimes in the elements which occur in `lifetimes`. collect_lifetimes<'a>( self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>41 fn collect_lifetimes<'a>( 42 self, 43 options: &Options, 44 lifetimes: &'a LifetimeSet, 45 ) -> LifetimeRefSet<'a>; 46 47 /// Consume an iterator using `collect_lifetimes`, then clone all found lifetimes and return that set. collect_lifetimes_cloned(self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet48 fn collect_lifetimes_cloned(self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet; 49 } 50 51 impl<'i, I, T> CollectLifetimes for T 52 where 53 T: IntoIterator<Item = &'i I>, 54 I: 'i + UsesLifetimes, 55 { collect_lifetimes<'a>( self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>56 fn collect_lifetimes<'a>( 57 self, 58 options: &Options, 59 lifetimes: &'a LifetimeSet, 60 ) -> LifetimeRefSet<'a> { 61 self.into_iter() 62 .fold(Default::default(), |mut state, value| { 63 state.extend(value.uses_lifetimes(options, lifetimes)); 64 state 65 }) 66 } 67 collect_lifetimes_cloned(self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet68 fn collect_lifetimes_cloned(self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet { 69 self.collect_lifetimes(options, lifetimes) 70 .into_iter() 71 .cloned() 72 .collect() 73 } 74 } 75 76 impl<T: UsesLifetimes> UsesLifetimes for Vec<T> { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>77 fn uses_lifetimes<'a>( 78 &self, 79 options: &Options, 80 lifetimes: &'a LifetimeSet, 81 ) -> LifetimeRefSet<'a> { 82 self.collect_lifetimes(options, lifetimes) 83 } 84 } 85 86 impl<T: UsesLifetimes, U> UsesLifetimes for Punctuated<T, U> { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>87 fn uses_lifetimes<'a>( 88 &self, 89 options: &Options, 90 lifetimes: &'a LifetimeSet, 91 ) -> LifetimeRefSet<'a> { 92 self.collect_lifetimes(options, lifetimes) 93 } 94 } 95 96 impl<T: UsesLifetimes> UsesLifetimes for Option<T> { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>97 fn uses_lifetimes<'a>( 98 &self, 99 options: &Options, 100 lifetimes: &'a LifetimeSet, 101 ) -> LifetimeRefSet<'a> { 102 self.as_ref() 103 .map(|v| v.uses_lifetimes(options, lifetimes)) 104 .unwrap_or_default() 105 } 106 } 107 108 impl UsesLifetimes for Lifetime { uses_lifetimes<'a>(&self, _: &Options, lifetimes: &'a LifetimeSet) -> LifetimeRefSet<'a>109 fn uses_lifetimes<'a>(&self, _: &Options, lifetimes: &'a LifetimeSet) -> LifetimeRefSet<'a> { 110 lifetimes.iter().filter(|lt| *lt == self).collect() 111 } 112 } 113 114 uses_lifetimes!(syn::AngleBracketedGenericArguments, args); 115 uses_lifetimes!(syn::BareFnArg, ty); 116 uses_lifetimes!(syn::Binding, ty); 117 uses_lifetimes!(syn::BoundLifetimes, lifetimes); 118 uses_lifetimes!(syn::Constraint, bounds); 119 uses_lifetimes!(syn::DataEnum, variants); 120 uses_lifetimes!(syn::DataStruct, fields); 121 uses_lifetimes!(syn::DataUnion, fields); 122 uses_lifetimes!(syn::Field, ty); 123 uses_lifetimes!(syn::FieldsNamed, named); 124 uses_lifetimes!(syn::LifetimeDef, lifetime, bounds); 125 uses_lifetimes!(syn::ParenthesizedGenericArguments, inputs, output); 126 uses_lifetimes!(syn::Path, segments); 127 uses_lifetimes!(syn::PathSegment, arguments); 128 uses_lifetimes!(syn::PredicateEq, lhs_ty, rhs_ty); 129 uses_lifetimes!(syn::PredicateLifetime, lifetime, bounds); 130 uses_lifetimes!(syn::PredicateType, lifetimes, bounded_ty, bounds); 131 uses_lifetimes!(syn::QSelf, ty); 132 uses_lifetimes!(syn::TraitBound, path, lifetimes); 133 uses_lifetimes!(syn::TypeArray, elem); 134 uses_lifetimes!(syn::TypeBareFn, inputs, output); 135 uses_lifetimes!(syn::TypeGroup, elem); 136 uses_lifetimes!(syn::TypeImplTrait, bounds); 137 uses_lifetimes!(syn::TypeParen, elem); 138 uses_lifetimes!(syn::TypePtr, elem); 139 uses_lifetimes!(syn::TypeReference, lifetime, elem); 140 uses_lifetimes!(syn::TypeSlice, elem); 141 uses_lifetimes!(syn::TypeTuple, elems); 142 uses_lifetimes!(syn::TypeTraitObject, bounds); 143 uses_lifetimes!(syn::Variant, fields); 144 145 impl UsesLifetimes for syn::Data { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>146 fn uses_lifetimes<'a>( 147 &self, 148 options: &Options, 149 lifetimes: &'a LifetimeSet, 150 ) -> LifetimeRefSet<'a> { 151 match *self { 152 syn::Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes), 153 syn::Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes), 154 syn::Data::Union(ref v) => v.uses_lifetimes(options, lifetimes), 155 } 156 } 157 } 158 159 impl UsesLifetimes for Type { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>160 fn uses_lifetimes<'a>( 161 &self, 162 options: &Options, 163 lifetimes: &'a LifetimeSet, 164 ) -> LifetimeRefSet<'a> { 165 match *self { 166 Type::Slice(ref v) => v.uses_lifetimes(options, lifetimes), 167 Type::Array(ref v) => v.uses_lifetimes(options, lifetimes), 168 Type::Ptr(ref v) => v.uses_lifetimes(options, lifetimes), 169 Type::Reference(ref v) => v.uses_lifetimes(options, lifetimes), 170 Type::BareFn(ref v) => v.uses_lifetimes(options, lifetimes), 171 Type::Tuple(ref v) => v.uses_lifetimes(options, lifetimes), 172 Type::Path(ref v) => v.uses_lifetimes(options, lifetimes), 173 Type::Paren(ref v) => v.uses_lifetimes(options, lifetimes), 174 Type::Group(ref v) => v.uses_lifetimes(options, lifetimes), 175 Type::TraitObject(ref v) => v.uses_lifetimes(options, lifetimes), 176 Type::ImplTrait(ref v) => v.uses_lifetimes(options, lifetimes), 177 Type::Macro(_) | Type::Verbatim(_) | Type::Infer(_) | Type::Never(_) => { 178 Default::default() 179 } 180 } 181 } 182 } 183 184 impl UsesLifetimes for syn::Fields { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>185 fn uses_lifetimes<'a>( 186 &self, 187 options: &Options, 188 lifetimes: &'a LifetimeSet, 189 ) -> LifetimeRefSet<'a> { 190 self.collect_lifetimes(options, lifetimes) 191 } 192 } 193 194 impl UsesLifetimes for syn::TypePath { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>195 fn uses_lifetimes<'a>( 196 &self, 197 options: &Options, 198 lifetimes: &'a LifetimeSet, 199 ) -> LifetimeRefSet<'a> { 200 let mut hits = self.path.uses_lifetimes(options, lifetimes); 201 202 if options.include_type_path_qself() { 203 hits.extend(self.qself.uses_lifetimes(options, lifetimes)); 204 } 205 206 hits 207 } 208 } 209 210 impl UsesLifetimes for syn::ReturnType { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>211 fn uses_lifetimes<'a>( 212 &self, 213 options: &Options, 214 lifetimes: &'a LifetimeSet, 215 ) -> LifetimeRefSet<'a> { 216 if let syn::ReturnType::Type(_, ref ty) = *self { 217 ty.uses_lifetimes(options, lifetimes) 218 } else { 219 Default::default() 220 } 221 } 222 } 223 224 impl UsesLifetimes for syn::PathArguments { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>225 fn uses_lifetimes<'a>( 226 &self, 227 options: &Options, 228 lifetimes: &'a LifetimeSet, 229 ) -> LifetimeRefSet<'a> { 230 match *self { 231 syn::PathArguments::None => Default::default(), 232 syn::PathArguments::AngleBracketed(ref v) => v.uses_lifetimes(options, lifetimes), 233 syn::PathArguments::Parenthesized(ref v) => v.uses_lifetimes(options, lifetimes), 234 } 235 } 236 } 237 238 impl UsesLifetimes for syn::WherePredicate { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>239 fn uses_lifetimes<'a>( 240 &self, 241 options: &Options, 242 lifetimes: &'a LifetimeSet, 243 ) -> LifetimeRefSet<'a> { 244 match *self { 245 syn::WherePredicate::Type(ref v) => v.uses_lifetimes(options, lifetimes), 246 syn::WherePredicate::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes), 247 syn::WherePredicate::Eq(ref v) => v.uses_lifetimes(options, lifetimes), 248 } 249 } 250 } 251 252 impl UsesLifetimes for syn::GenericArgument { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>253 fn uses_lifetimes<'a>( 254 &self, 255 options: &Options, 256 lifetimes: &'a LifetimeSet, 257 ) -> LifetimeRefSet<'a> { 258 match *self { 259 syn::GenericArgument::Type(ref v) => v.uses_lifetimes(options, lifetimes), 260 syn::GenericArgument::Binding(ref v) => v.uses_lifetimes(options, lifetimes), 261 syn::GenericArgument::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes), 262 syn::GenericArgument::Constraint(ref v) => v.uses_lifetimes(options, lifetimes), 263 syn::GenericArgument::Const(_) => Default::default(), 264 } 265 } 266 } 267 268 impl UsesLifetimes for syn::TypeParamBound { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>269 fn uses_lifetimes<'a>( 270 &self, 271 options: &Options, 272 lifetimes: &'a LifetimeSet, 273 ) -> LifetimeRefSet<'a> { 274 match *self { 275 syn::TypeParamBound::Trait(ref v) => v.uses_lifetimes(options, lifetimes), 276 syn::TypeParamBound::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes), 277 } 278 } 279 } 280 281 #[cfg(test)] 282 mod tests { 283 use proc_macro2::Span; 284 use syn::{self, DeriveInput}; 285 286 use super::UsesLifetimes; 287 use usage::GenericsExt; 288 use usage::Purpose::*; 289 290 #[test] struct_named()291 fn struct_named() { 292 let input: DeriveInput = parse_quote! { 293 struct Foo<'a, 'b: 'a> { 294 parent: &'b Bar, 295 child: &'a Baz, 296 } 297 }; 298 let omitted = syn::Lifetime::new("'c", Span::call_site()); 299 300 let lifetimes = { 301 let mut lt = input.generics.declared_lifetimes(); 302 lt.insert(omitted); 303 lt 304 }; 305 306 let matches = input.data.uses_lifetimes(&BoundImpl.into(), &lifetimes); 307 assert_eq!(matches.len(), 2); 308 } 309 310 #[test] qself()311 fn qself() { 312 let input: DeriveInput = parse_quote! { 313 struct Foo<'a, 'b: 'a> { 314 parent: &'b Bar, 315 child: <Bar<'a> as MyIterator>::Item, 316 } 317 }; 318 let lifetimes = input.generics.declared_lifetimes(); 319 let matches = input.data.uses_lifetimes(&BoundImpl.into(), &lifetimes); 320 assert_eq!(matches.len(), 1); 321 322 let decl_matches = input.data.uses_lifetimes(&Declare.into(), &lifetimes); 323 assert_eq!(decl_matches.len(), 2); 324 } 325 } 326