yoke_derive/
visitor.rs
1use std::collections::HashSet;
8use syn::visit::{visit_lifetime, visit_type, visit_type_path, Visit};
9use syn::{Ident, Lifetime, Type, TypePath};
10
11struct TypeVisitor<'a> {
12 typarams: &'a HashSet<Ident>,
14 found_typarams: bool,
16 found_lifetimes: bool,
18}
19
20impl<'ast> Visit<'ast> for TypeVisitor<'_> {
21 fn visit_lifetime(&mut self, lt: &'ast Lifetime) {
22 if lt.ident != "static" {
23 self.found_lifetimes = true;
24 }
25 visit_lifetime(self, lt)
26 }
27 fn visit_type_path(&mut self, ty: &'ast TypePath) {
28 if let Some(ident) = ty.path.get_ident() {
32 if self.typarams.contains(ident) {
33 self.found_typarams = true;
34 }
35 }
36
37 visit_type_path(self, ty)
38 }
39}
40
41pub fn check_type_for_parameters(ty: &Type, typarams: &HashSet<Ident>) -> (bool, bool) {
44 let mut visit = TypeVisitor {
45 typarams,
46 found_typarams: false,
47 found_lifetimes: false,
48 };
49 visit_type(&mut visit, ty);
50
51 (visit.found_typarams, visit.found_lifetimes)
52}
53
54#[cfg(test)]
55mod tests {
56 use proc_macro2::Span;
57 use std::collections::HashSet;
58 use syn::{parse_quote, Ident};
59
60 use super::check_type_for_parameters;
61 fn make_typarams(params: &[&str]) -> HashSet<Ident> {
62 params
63 .iter()
64 .map(|x| Ident::new(x, Span::call_site()))
65 .collect()
66 }
67
68 #[test]
69 fn test_simple_type() {
70 let environment = make_typarams(&["T", "U", "V"]);
71
72 let ty = parse_quote!(Foo<'a, T>);
73 let check = check_type_for_parameters(&ty, &environment);
74 assert_eq!(check, (true, true));
75
76 let ty = parse_quote!(Foo<T>);
77 let check = check_type_for_parameters(&ty, &environment);
78 assert_eq!(check, (true, false));
79
80 let ty = parse_quote!(Foo<'static, T>);
81 let check = check_type_for_parameters(&ty, &environment);
82 assert_eq!(check, (true, false));
83
84 let ty = parse_quote!(Foo<'a>);
85 let check = check_type_for_parameters(&ty, &environment);
86 assert_eq!(check, (false, true));
87
88 let ty = parse_quote!(Foo<'a, Bar<U>, Baz<(V, u8)>>);
89 let check = check_type_for_parameters(&ty, &environment);
90 assert_eq!(check, (true, true));
91
92 let ty = parse_quote!(Foo<'a, W>);
93 let check = check_type_for_parameters(&ty, &environment);
94 assert_eq!(check, (false, true));
95 }
96
97 #[test]
98 fn test_assoc_types() {
99 let environment = make_typarams(&["T"]);
100
101 let ty = parse_quote!(<Foo as SomeTrait<'a, T>>::Output);
102 let check = check_type_for_parameters(&ty, &environment);
103 assert_eq!(check, (true, true));
104
105 let ty = parse_quote!(<Foo as SomeTrait<'static, T>>::Output);
106 let check = check_type_for_parameters(&ty, &environment);
107 assert_eq!(check, (true, false));
108
109 let ty = parse_quote!(<T as SomeTrait<'static, Foo>>::Output);
110 let check = check_type_for_parameters(&ty, &environment);
111 assert_eq!(check, (true, false));
112 }
113}