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 _ => panic!("Unknown syn::Type: {:?}", self), 181 } 182 } 183 } 184 185 impl UsesLifetimes for syn::Fields { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>186 fn uses_lifetimes<'a>( 187 &self, 188 options: &Options, 189 lifetimes: &'a LifetimeSet, 190 ) -> LifetimeRefSet<'a> { 191 self.collect_lifetimes(options, lifetimes) 192 } 193 } 194 195 impl UsesLifetimes for syn::TypePath { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>196 fn uses_lifetimes<'a>( 197 &self, 198 options: &Options, 199 lifetimes: &'a LifetimeSet, 200 ) -> LifetimeRefSet<'a> { 201 let mut hits = self.path.uses_lifetimes(options, lifetimes); 202 203 if options.include_type_path_qself() { 204 hits.extend(self.qself.uses_lifetimes(options, lifetimes)); 205 } 206 207 hits 208 } 209 } 210 211 impl UsesLifetimes for syn::ReturnType { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>212 fn uses_lifetimes<'a>( 213 &self, 214 options: &Options, 215 lifetimes: &'a LifetimeSet, 216 ) -> LifetimeRefSet<'a> { 217 if let syn::ReturnType::Type(_, ref ty) = *self { 218 ty.uses_lifetimes(options, lifetimes) 219 } else { 220 Default::default() 221 } 222 } 223 } 224 225 impl UsesLifetimes for syn::PathArguments { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>226 fn uses_lifetimes<'a>( 227 &self, 228 options: &Options, 229 lifetimes: &'a LifetimeSet, 230 ) -> LifetimeRefSet<'a> { 231 match *self { 232 syn::PathArguments::None => Default::default(), 233 syn::PathArguments::AngleBracketed(ref v) => v.uses_lifetimes(options, lifetimes), 234 syn::PathArguments::Parenthesized(ref v) => v.uses_lifetimes(options, lifetimes), 235 } 236 } 237 } 238 239 impl UsesLifetimes for syn::WherePredicate { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>240 fn uses_lifetimes<'a>( 241 &self, 242 options: &Options, 243 lifetimes: &'a LifetimeSet, 244 ) -> LifetimeRefSet<'a> { 245 match *self { 246 syn::WherePredicate::Type(ref v) => v.uses_lifetimes(options, lifetimes), 247 syn::WherePredicate::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes), 248 syn::WherePredicate::Eq(ref v) => v.uses_lifetimes(options, lifetimes), 249 } 250 } 251 } 252 253 impl UsesLifetimes for syn::GenericArgument { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>254 fn uses_lifetimes<'a>( 255 &self, 256 options: &Options, 257 lifetimes: &'a LifetimeSet, 258 ) -> LifetimeRefSet<'a> { 259 match *self { 260 syn::GenericArgument::Type(ref v) => v.uses_lifetimes(options, lifetimes), 261 syn::GenericArgument::Binding(ref v) => v.uses_lifetimes(options, lifetimes), 262 syn::GenericArgument::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes), 263 syn::GenericArgument::Constraint(ref v) => v.uses_lifetimes(options, lifetimes), 264 syn::GenericArgument::Const(_) => Default::default(), 265 } 266 } 267 } 268 269 impl UsesLifetimes for syn::TypeParamBound { uses_lifetimes<'a>( &self, options: &Options, lifetimes: &'a LifetimeSet, ) -> LifetimeRefSet<'a>270 fn uses_lifetimes<'a>( 271 &self, 272 options: &Options, 273 lifetimes: &'a LifetimeSet, 274 ) -> LifetimeRefSet<'a> { 275 match *self { 276 syn::TypeParamBound::Trait(ref v) => v.uses_lifetimes(options, lifetimes), 277 syn::TypeParamBound::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes), 278 } 279 } 280 } 281 282 #[cfg(test)] 283 mod tests { 284 use proc_macro2::Span; 285 use syn::{self, DeriveInput}; 286 287 use super::UsesLifetimes; 288 use usage::GenericsExt; 289 use usage::Purpose::*; 290 291 #[test] struct_named()292 fn struct_named() { 293 let input: DeriveInput = parse_quote! { 294 struct Foo<'a, 'b: 'a> { 295 parent: &'b Bar, 296 child: &'a Baz, 297 } 298 }; 299 let omitted = syn::Lifetime::new("'c", Span::call_site()); 300 301 let lifetimes = { 302 let mut lt = input.generics.declared_lifetimes(); 303 lt.insert(omitted); 304 lt 305 }; 306 307 let matches = input.data.uses_lifetimes(&BoundImpl.into(), &lifetimes); 308 assert_eq!(matches.len(), 2); 309 } 310 311 #[test] qself()312 fn qself() { 313 let input: DeriveInput = parse_quote! { 314 struct Foo<'a, 'b: 'a> { 315 parent: &'b Bar, 316 child: <Bar<'a> as MyIterator>::Item, 317 } 318 }; 319 let lifetimes = input.generics.declared_lifetimes(); 320 let matches = input.data.uses_lifetimes(&BoundImpl.into(), &lifetimes); 321 assert_eq!(matches.len(), 1); 322 323 let decl_matches = input.data.uses_lifetimes(&Declare.into(), &lifetimes); 324 assert_eq!(decl_matches.len(), 2); 325 } 326 } 327