1use std::collections::HashSet;
2
3use syn::punctuated::Punctuated;
4use syn::{Lifetime, Type};
5
6use crate::usage::Options;
7
8pub type LifetimeSet = HashSet<Lifetime>;
10
11pub type LifetimeRefSet<'a> = HashSet<&'a Lifetime>;
13
14pub trait UsesLifetimes {
17 fn uses_lifetimes<'a>(
22 &self,
23 options: &Options,
24 lifetimes: &'a LifetimeSet,
25 ) -> LifetimeRefSet<'a>;
26
27 fn uses_lifetimes_cloned(&self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet {
29 self.uses_lifetimes(options, lifetimes)
30 .into_iter()
31 .cloned()
32 .collect()
33 }
34}
35
36pub trait CollectLifetimes {
41 fn collect_lifetimes<'a>(
43 self,
44 options: &Options,
45 lifetimes: &'a LifetimeSet,
46 ) -> LifetimeRefSet<'a>;
47
48 fn collect_lifetimes_cloned(self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet;
50}
51
52impl<'i, I, T> CollectLifetimes for T
53where
54 T: IntoIterator<Item = &'i I>,
55 I: 'i + UsesLifetimes,
56{
57 fn collect_lifetimes<'a>(
58 self,
59 options: &Options,
60 lifetimes: &'a LifetimeSet,
61 ) -> LifetimeRefSet<'a> {
62 self.into_iter()
63 .fold(Default::default(), |mut state, value| {
64 state.extend(value.uses_lifetimes(options, lifetimes));
65 state
66 })
67 }
68
69 fn collect_lifetimes_cloned(self, options: &Options, lifetimes: &LifetimeSet) -> LifetimeSet {
70 self.collect_lifetimes(options, lifetimes)
71 .into_iter()
72 .cloned()
73 .collect()
74 }
75}
76
77impl<T: UsesLifetimes> UsesLifetimes for Vec<T> {
78 fn uses_lifetimes<'a>(
79 &self,
80 options: &Options,
81 lifetimes: &'a LifetimeSet,
82 ) -> LifetimeRefSet<'a> {
83 self.collect_lifetimes(options, lifetimes)
84 }
85}
86
87impl<T: UsesLifetimes, U> UsesLifetimes for Punctuated<T, U> {
88 fn uses_lifetimes<'a>(
89 &self,
90 options: &Options,
91 lifetimes: &'a LifetimeSet,
92 ) -> LifetimeRefSet<'a> {
93 self.collect_lifetimes(options, lifetimes)
94 }
95}
96
97impl<T: UsesLifetimes> UsesLifetimes for Option<T> {
98 fn uses_lifetimes<'a>(
99 &self,
100 options: &Options,
101 lifetimes: &'a LifetimeSet,
102 ) -> LifetimeRefSet<'a> {
103 self.as_ref()
104 .map(|v| v.uses_lifetimes(options, lifetimes))
105 .unwrap_or_default()
106 }
107}
108
109impl UsesLifetimes for Lifetime {
110 fn uses_lifetimes<'a>(&self, _: &Options, lifetimes: &'a LifetimeSet) -> LifetimeRefSet<'a> {
111 lifetimes.iter().filter(|lt| *lt == self).collect()
112 }
113}
114
115uses_lifetimes!(syn::AngleBracketedGenericArguments, args);
116uses_lifetimes!(syn::AssocType, ty);
117uses_lifetimes!(syn::BareFnArg, ty);
118uses_lifetimes!(syn::BoundLifetimes, lifetimes);
119uses_lifetimes!(syn::ConstParam, ty);
120uses_lifetimes!(syn::Constraint, bounds);
121uses_lifetimes!(syn::DataEnum, variants);
122uses_lifetimes!(syn::DataStruct, fields);
123uses_lifetimes!(syn::DataUnion, fields);
124uses_lifetimes!(syn::Field, ty);
125uses_lifetimes!(syn::FieldsNamed, named);
126uses_lifetimes!(syn::LifetimeParam, lifetime, bounds);
127uses_lifetimes!(syn::ParenthesizedGenericArguments, inputs, output);
128uses_lifetimes!(syn::Path, segments);
129uses_lifetimes!(syn::PathSegment, arguments);
130uses_lifetimes!(syn::PredicateLifetime, lifetime, bounds);
131uses_lifetimes!(syn::PredicateType, lifetimes, bounded_ty, bounds);
132uses_lifetimes!(syn::QSelf, ty);
133uses_lifetimes!(syn::TraitBound, path, lifetimes);
134uses_lifetimes!(syn::TypeArray, elem);
135uses_lifetimes!(syn::TypeBareFn, inputs, output);
136uses_lifetimes!(syn::TypeGroup, elem);
137uses_lifetimes!(syn::TypeImplTrait, bounds);
138uses_lifetimes!(syn::TypeParam, bounds);
139uses_lifetimes!(syn::TypeParen, elem);
140uses_lifetimes!(syn::TypePtr, elem);
141uses_lifetimes!(syn::TypeReference, lifetime, elem);
142uses_lifetimes!(syn::TypeSlice, elem);
143uses_lifetimes!(syn::TypeTuple, elems);
144uses_lifetimes!(syn::TypeTraitObject, bounds);
145uses_lifetimes!(syn::Variant, fields);
146
147impl UsesLifetimes for syn::Data {
148 fn uses_lifetimes<'a>(
149 &self,
150 options: &Options,
151 lifetimes: &'a LifetimeSet,
152 ) -> LifetimeRefSet<'a> {
153 match *self {
154 syn::Data::Struct(ref v) => v.uses_lifetimes(options, lifetimes),
155 syn::Data::Enum(ref v) => v.uses_lifetimes(options, lifetimes),
156 syn::Data::Union(ref v) => v.uses_lifetimes(options, lifetimes),
157 }
158 }
159}
160
161impl UsesLifetimes for Type {
162 fn uses_lifetimes<'a>(
163 &self,
164 options: &Options,
165 lifetimes: &'a LifetimeSet,
166 ) -> LifetimeRefSet<'a> {
167 match *self {
168 Type::Slice(ref v) => v.uses_lifetimes(options, lifetimes),
169 Type::Array(ref v) => v.uses_lifetimes(options, lifetimes),
170 Type::Ptr(ref v) => v.uses_lifetimes(options, lifetimes),
171 Type::Reference(ref v) => v.uses_lifetimes(options, lifetimes),
172 Type::BareFn(ref v) => v.uses_lifetimes(options, lifetimes),
173 Type::Tuple(ref v) => v.uses_lifetimes(options, lifetimes),
174 Type::Path(ref v) => v.uses_lifetimes(options, lifetimes),
175 Type::Paren(ref v) => v.uses_lifetimes(options, lifetimes),
176 Type::Group(ref v) => v.uses_lifetimes(options, lifetimes),
177 Type::TraitObject(ref v) => v.uses_lifetimes(options, lifetimes),
178 Type::ImplTrait(ref v) => v.uses_lifetimes(options, lifetimes),
179 Type::Macro(_) | Type::Verbatim(_) | Type::Infer(_) | Type::Never(_) => {
180 Default::default()
181 }
182 _ => panic!("Unknown syn::Type: {:?}", self),
183 }
184 }
185}
186
187impl UsesLifetimes for syn::Fields {
188 fn uses_lifetimes<'a>(
189 &self,
190 options: &Options,
191 lifetimes: &'a LifetimeSet,
192 ) -> LifetimeRefSet<'a> {
193 self.collect_lifetimes(options, lifetimes)
194 }
195}
196
197impl UsesLifetimes for syn::TypePath {
198 fn uses_lifetimes<'a>(
199 &self,
200 options: &Options,
201 lifetimes: &'a LifetimeSet,
202 ) -> LifetimeRefSet<'a> {
203 let mut hits = self.path.uses_lifetimes(options, lifetimes);
204
205 if options.include_type_path_qself() {
206 hits.extend(self.qself.uses_lifetimes(options, lifetimes));
207 }
208
209 hits
210 }
211}
212
213impl UsesLifetimes for syn::ReturnType {
214 fn uses_lifetimes<'a>(
215 &self,
216 options: &Options,
217 lifetimes: &'a LifetimeSet,
218 ) -> LifetimeRefSet<'a> {
219 if let syn::ReturnType::Type(_, ref ty) = *self {
220 ty.uses_lifetimes(options, lifetimes)
221 } else {
222 Default::default()
223 }
224 }
225}
226
227impl UsesLifetimes for syn::PathArguments {
228 fn uses_lifetimes<'a>(
229 &self,
230 options: &Options,
231 lifetimes: &'a LifetimeSet,
232 ) -> LifetimeRefSet<'a> {
233 match *self {
234 syn::PathArguments::None => Default::default(),
235 syn::PathArguments::AngleBracketed(ref v) => v.uses_lifetimes(options, lifetimes),
236 syn::PathArguments::Parenthesized(ref v) => v.uses_lifetimes(options, lifetimes),
237 }
238 }
239}
240
241impl UsesLifetimes for syn::WherePredicate {
242 fn uses_lifetimes<'a>(
243 &self,
244 options: &Options,
245 lifetimes: &'a LifetimeSet,
246 ) -> LifetimeRefSet<'a> {
247 match *self {
248 syn::WherePredicate::Type(ref v) => v.uses_lifetimes(options, lifetimes),
249 syn::WherePredicate::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes),
250 _ => panic!("Unknown syn::WherePredicate: {:?}", self),
253 }
254 }
255}
256
257impl UsesLifetimes for syn::GenericArgument {
258 fn uses_lifetimes<'a>(
259 &self,
260 options: &Options,
261 lifetimes: &'a LifetimeSet,
262 ) -> LifetimeRefSet<'a> {
263 match *self {
264 syn::GenericArgument::Type(ref v) => v.uses_lifetimes(options, lifetimes),
265 syn::GenericArgument::AssocType(ref v) => v.uses_lifetimes(options, lifetimes),
266 syn::GenericArgument::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes),
267 syn::GenericArgument::Constraint(ref v) => v.uses_lifetimes(options, lifetimes),
268 syn::GenericArgument::AssocConst(_) | syn::GenericArgument::Const(_) => {
269 Default::default()
270 }
271 _ => panic!("Unknown syn::GenericArgument: {:?}", self),
274 }
275 }
276}
277
278impl UsesLifetimes for syn::GenericParam {
279 fn uses_lifetimes<'a>(
280 &self,
281 options: &Options,
282 lifetimes: &'a LifetimeSet,
283 ) -> LifetimeRefSet<'a> {
284 match *self {
285 syn::GenericParam::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes),
286 syn::GenericParam::Type(ref v) => v.uses_lifetimes(options, lifetimes),
287 syn::GenericParam::Const(ref v) => v.uses_lifetimes(options, lifetimes),
288 }
289 }
290}
291
292impl UsesLifetimes for syn::TypeParamBound {
293 fn uses_lifetimes<'a>(
294 &self,
295 options: &Options,
296 lifetimes: &'a LifetimeSet,
297 ) -> LifetimeRefSet<'a> {
298 match *self {
299 syn::TypeParamBound::Trait(ref v) => v.uses_lifetimes(options, lifetimes),
300 syn::TypeParamBound::Lifetime(ref v) => v.uses_lifetimes(options, lifetimes),
301 _ => panic!("Unknown syn::TypeParamBound: {:?}", self),
304 }
305 }
306}
307
308#[cfg(test)]
309mod tests {
310 use proc_macro2::Span;
311 use syn::{parse_quote, DeriveInput};
312
313 use super::UsesLifetimes;
314 use crate::usage::GenericsExt;
315 use crate::usage::Purpose::*;
316
317 #[test]
318 fn struct_named() {
319 let input: DeriveInput = parse_quote! {
320 struct Foo<'a, 'b: 'a> {
321 parent: &'b Bar,
322 child: &'a Baz,
323 }
324 };
325 let omitted = syn::Lifetime::new("'c", Span::call_site());
326
327 let lifetimes = {
328 let mut lt = input.generics.declared_lifetimes();
329 lt.insert(omitted);
330 lt
331 };
332
333 let matches = input.data.uses_lifetimes(&BoundImpl.into(), &lifetimes);
334 assert_eq!(matches.len(), 2);
335 }
336
337 #[test]
338 fn qself() {
339 let input: DeriveInput = parse_quote! {
340 struct Foo<'a, 'b: 'a> {
341 parent: &'b Bar,
342 child: <Bar<'a> as MyIterator>::Item,
343 }
344 };
345 let lifetimes = input.generics.declared_lifetimes();
346 let matches = input.data.uses_lifetimes(&BoundImpl.into(), &lifetimes);
347 assert_eq!(matches.len(), 1);
348
349 let decl_matches = input.data.uses_lifetimes(&Declare.into(), &lifetimes);
350 assert_eq!(decl_matches.len(), 2);
351 }
352}