1 // vim: tw=80
2 //! Proc Macros for use with Mockall
3 //!
4 //! You probably don't want to use this crate directly. Instead, you should use
5 //! its reexports via the [`mockall`](https://docs.rs/mockall/latest/mockall)
6 //! crate.
7
8 #![cfg_attr(feature = "nightly_derive", feature(proc_macro_diagnostic))]
9 #![cfg_attr(test, deny(warnings))]
10
11 use cfg_if::cfg_if;
12 use proc_macro2::{Span, TokenStream};
13 use quote::{ToTokens, format_ident, quote};
14 use std::{
15 env,
16 hash::BuildHasherDefault
17 };
18 use syn::{
19 *,
20 punctuated::Punctuated,
21 spanned::Spanned
22 };
23
24 mod automock;
25 mod mock_function;
26 mod mock_item;
27 mod mock_item_struct;
28 mod mock_trait;
29 mod mockable_item;
30 mod mockable_struct;
31 use crate::automock::Attrs;
32 use crate::mockable_struct::MockableStruct;
33 use crate::mock_item::MockItem;
34 use crate::mock_item_struct::MockItemStruct;
35 use crate::mockable_item::MockableItem;
36
37 extern crate proc_macro;
38
39 // Define deterministic aliases for these common types.
40 type HashMap<K, V> = std::collections::HashMap<K, V, BuildHasherDefault<std::collections::hash_map::DefaultHasher>>;
41 type HashSet<K> = std::collections::HashSet<K, BuildHasherDefault<std::collections::hash_map::DefaultHasher>>;
42
43 cfg_if! {
44 // proc-macro2's Span::unstable method requires the nightly feature, and it
45 // doesn't work in test mode.
46 // https://github.com/alexcrichton/proc-macro2/issues/159
47 if #[cfg(all(feature = "nightly_derive", not(test)))] {
48 fn compile_error(span: Span, msg: &str) {
49 span.unstable()
50 .error(msg)
51 .emit();
52 }
53 } else {
54 fn compile_error(_span: Span, msg: &str) {
55 panic!("{msg}. More information may be available when mockall is built with the \"nightly\" feature.");
56 }
57 }
58 }
59
60 /// Does this Attribute represent Mockall's "concretize" pseudo-attribute?
is_concretize(attr: &Attribute) -> bool61 fn is_concretize(attr: &Attribute) -> bool {
62 if attr.path().segments.last().unwrap().ident == "concretize" {
63 true
64 } else if attr.path().is_ident("cfg_attr") {
65 match &attr.meta {
66 Meta::List(ml) => {
67 ml.tokens.to_string().contains("concretize")
68 },
69 // cfg_attr should always contain a list
70 _ => false,
71 }
72 } else {
73 false
74 }
75 }
76
77 /// replace generic arguments with concrete trait object arguments
concretize_args(gen: &Generics, args: &Punctuated<FnArg, Token![,]>) -> (Generics, Vec<FnArg>, Vec<TokenStream>)78 fn concretize_args(gen: &Generics, args: &Punctuated<FnArg, Token![,]>) ->
79 (Generics, Vec<FnArg>, Vec<TokenStream>)
80 {
81 let mut hm = HashMap::default();
82
83 let mut save_types = |ident: &Ident, tpb: &Punctuated<TypeParamBound, Token![+]>| {
84 if !tpb.is_empty() {
85 if let Ok(newty) = parse2::<Type>(quote!(&(dyn #tpb))) {
86 // substitute T arguments
87 let subst_ty: Type = parse2(quote!(#ident)).unwrap();
88 hm.insert(subst_ty, (newty.clone(), None));
89
90 // substitute &T arguments
91 let subst_ty: Type = parse2(quote!(&#ident)).unwrap();
92 hm.insert(subst_ty, (newty, None));
93 } else {
94 compile_error(tpb.span(),
95 "Type cannot be made into a trait object");
96 }
97
98 if let Ok(newty) = parse2::<Type>(quote!(&mut (dyn #tpb))) {
99 // substitute &mut T arguments
100 let subst_ty: Type = parse2(quote!(&mut #ident)).unwrap();
101 hm.insert(subst_ty, (newty, None));
102 } else {
103 compile_error(tpb.span(),
104 "Type cannot be made into a trait object");
105 }
106
107 // I wish we could substitute &[T] arguments. But there's no way
108 // for the mock method to turn &[T] into &[&dyn T].
109 if let Ok(newty) = parse2::<Type>(quote!(&[&(dyn #tpb)])) {
110 let subst_ty: Type = parse2(quote!(&[#ident])).unwrap();
111 hm.insert(subst_ty, (newty, Some(tpb.clone())));
112 } else {
113 compile_error(tpb.span(),
114 "Type cannot be made into a trait object");
115 }
116 }
117 };
118
119 for g in gen.params.iter() {
120 if let GenericParam::Type(tp) = g {
121 save_types(&tp.ident, &tp.bounds);
122 // else there had better be a where clause
123 }
124 }
125 if let Some(wc) = &gen.where_clause {
126 for pred in wc.predicates.iter() {
127 if let WherePredicate::Type(pt) = pred {
128 let bounded_ty = &pt.bounded_ty;
129 if let Ok(ident) = parse2::<Ident>(quote!(#bounded_ty)) {
130 save_types(&ident, &pt.bounds);
131 } else {
132 // We can't yet handle where clauses this complicated
133 }
134 }
135 }
136 }
137
138 let outg = Generics {
139 lt_token: None,
140 gt_token: None,
141 params: Punctuated::new(),
142 where_clause: None
143 };
144 let outargs: Vec<FnArg> = args.iter().map(|arg| {
145 if let FnArg::Typed(pt) = arg {
146 let mut immutable_pt = pt.clone();
147 demutify_arg(&mut immutable_pt);
148 if let Some((newty, _)) = hm.get(&pt.ty) {
149 FnArg::Typed(PatType {
150 attrs: Vec::default(),
151 pat: immutable_pt.pat,
152 colon_token: pt.colon_token,
153 ty: Box::new(newty.clone())
154 })
155 } else {
156 FnArg::Typed(PatType {
157 attrs: Vec::default(),
158 pat: immutable_pt.pat,
159 colon_token: pt.colon_token,
160 ty: pt.ty.clone()
161 })
162 }
163 } else {
164 arg.clone()
165 }
166 }).collect();
167
168 // Finally, Reference any concretizing arguments
169 // use filter_map to remove the &self argument
170 let call_exprs = args.iter().filter_map(|arg| {
171 match arg {
172 FnArg::Typed(pt) => {
173 let mut pt2 = pt.clone();
174 demutify_arg(&mut pt2);
175 let pat = &pt2.pat;
176 if pat_is_self(pat) {
177 None
178 } else if let Some((_, newbound)) = hm.get(&pt.ty) {
179 if let Type::Reference(tr) = &*pt.ty {
180 if let Type::Slice(_ts) = &*tr.elem {
181 // Assume _ts is the generic type or we wouldn't be
182 // here
183 Some(quote!(
184 &(0..#pat.len())
185 .map(|__mockall_i| &#pat[__mockall_i] as &(dyn #newbound))
186 .collect::<Vec<_>>()
187 ))
188 } else {
189 Some(quote!(#pat))
190 }
191 } else {
192 Some(quote!(&#pat))
193 }
194 } else {
195 Some(quote!(#pat))
196 }
197 },
198 FnArg::Receiver(_) => None,
199 }
200 }).collect();
201 (outg, outargs, call_exprs)
202 }
203
deanonymize_lifetime(lt: &mut Lifetime)204 fn deanonymize_lifetime(lt: &mut Lifetime) {
205 if lt.ident == "_" {
206 lt.ident = format_ident!("static");
207 }
208 }
209
deanonymize_path(path: &mut Path)210 fn deanonymize_path(path: &mut Path) {
211 for seg in path.segments.iter_mut() {
212 match &mut seg.arguments {
213 PathArguments::None => (),
214 PathArguments::AngleBracketed(abga) => {
215 for ga in abga.args.iter_mut() {
216 if let GenericArgument::Lifetime(lt) = ga {
217 deanonymize_lifetime(lt)
218 }
219 }
220 },
221 _ => compile_error(seg.arguments.span(),
222 "Methods returning functions are TODO"),
223 }
224 }
225 }
226
227 /// Replace any references to the anonymous lifetime `'_` with `'static`.
deanonymize(literal_type: &mut Type)228 fn deanonymize(literal_type: &mut Type) {
229 match literal_type {
230 Type::Array(ta) => deanonymize(ta.elem.as_mut()),
231 Type::BareFn(tbf) => {
232 if let ReturnType::Type(_, ref mut bt) = tbf.output {
233 deanonymize(bt.as_mut());
234 }
235 for input in tbf.inputs.iter_mut() {
236 deanonymize(&mut input.ty);
237 }
238 },
239 Type::Group(tg) => deanonymize(tg.elem.as_mut()),
240 Type::Infer(_) => (),
241 Type::Never(_) => (),
242 Type::Paren(tp) => deanonymize(tp.elem.as_mut()),
243 Type::Path(tp) => {
244 if let Some(ref mut qself) = tp.qself {
245 deanonymize(qself.ty.as_mut());
246 }
247 deanonymize_path(&mut tp.path);
248 },
249 Type::Ptr(tptr) => deanonymize(tptr.elem.as_mut()),
250 Type::Reference(tr) => {
251 if let Some(lt) = tr.lifetime.as_mut() {
252 deanonymize_lifetime(lt)
253 }
254 deanonymize(tr.elem.as_mut());
255 },
256 Type::Slice(s) => deanonymize(s.elem.as_mut()),
257 Type::TraitObject(tto) => {
258 for tpb in tto.bounds.iter_mut() {
259 match tpb {
260 TypeParamBound::Trait(tb) => deanonymize_path(&mut tb.path),
261 TypeParamBound::Lifetime(lt) => deanonymize_lifetime(lt),
262 _ => ()
263 }
264 }
265 },
266 Type::Tuple(tt) => {
267 for ty in tt.elems.iter_mut() {
268 deanonymize(ty)
269 }
270 }
271 x => compile_error(x.span(), "Unimplemented type for deanonymize")
272 }
273 }
274
275 // If there are any closures in the argument list, turn them into boxed
276 // functions
declosurefy(gen: &Generics, args: &Punctuated<FnArg, Token![,]>) -> (Generics, Vec<FnArg>, Vec<TokenStream>)277 fn declosurefy(gen: &Generics, args: &Punctuated<FnArg, Token![,]>) ->
278 (Generics, Vec<FnArg>, Vec<TokenStream>)
279 {
280 let mut hm = HashMap::default();
281
282 let mut save_fn_types = |ident: &Ident, tpb: &TypeParamBound| {
283 if let TypeParamBound::Trait(tb) = tpb {
284 let fident = &tb.path.segments.last().unwrap().ident;
285 if ["Fn", "FnMut", "FnOnce"].iter().any(|s| fident == *s) {
286 let newty: Type = parse2(quote!(Box<dyn #tb>)).unwrap();
287 let subst_ty: Type = parse2(quote!(#ident)).unwrap();
288 assert!(hm.insert(subst_ty, newty).is_none(),
289 "A generic parameter had two Fn bounds?");
290 }
291 }
292 };
293
294 // First, build a HashMap of all Fn generic types
295 for g in gen.params.iter() {
296 if let GenericParam::Type(tp) = g {
297 for tpb in tp.bounds.iter() {
298 save_fn_types(&tp.ident, tpb);
299 }
300 }
301 }
302 if let Some(wc) = &gen.where_clause {
303 for pred in wc.predicates.iter() {
304 if let WherePredicate::Type(pt) = pred {
305 let bounded_ty = &pt.bounded_ty;
306 if let Ok(ident) = parse2::<Ident>(quote!(#bounded_ty)) {
307 for tpb in pt.bounds.iter() {
308 save_fn_types(&ident, tpb);
309 }
310 } else {
311 // We can't yet handle where clauses this complicated
312 }
313 }
314 }
315 }
316
317 // Then remove those types from both the Generics' params and where clause
318 let should_remove = |ident: &Ident| {
319 let ty: Type = parse2(quote!(#ident)).unwrap();
320 hm.contains_key(&ty)
321 };
322 let params = gen.params.iter()
323 .filter(|g| {
324 if let GenericParam::Type(tp) = g {
325 !should_remove(&tp.ident)
326 } else {
327 true
328 }
329 }).cloned()
330 .collect::<Punctuated<_, _>>();
331 let mut wc2 = gen.where_clause.clone();
332 if let Some(wc) = &mut wc2 {
333 wc.predicates = wc.predicates.iter()
334 .filter(|wp| {
335 if let WherePredicate::Type(pt) = wp {
336 let bounded_ty = &pt.bounded_ty;
337 if let Ok(ident) = parse2::<Ident>(quote!(#bounded_ty)) {
338 !should_remove(&ident)
339 } else {
340 // We can't yet handle where clauses this complicated
341 true
342 }
343 } else {
344 true
345 }
346 }).cloned()
347 .collect::<Punctuated<_, _>>();
348 if wc.predicates.is_empty() {
349 wc2 = None;
350 }
351 }
352 let outg = Generics {
353 lt_token: if params.is_empty() { None } else { gen.lt_token },
354 gt_token: if params.is_empty() { None } else { gen.gt_token },
355 params,
356 where_clause: wc2
357 };
358
359 // Next substitute Box<Fn> into the arguments
360 let outargs = args.iter().map(|arg| {
361 if let FnArg::Typed(pt) = arg {
362 let mut immutable_pt = pt.clone();
363 demutify_arg(&mut immutable_pt);
364 if let Some(newty) = hm.get(&pt.ty) {
365 FnArg::Typed(PatType {
366 attrs: Vec::default(),
367 pat: immutable_pt.pat,
368 colon_token: pt.colon_token,
369 ty: Box::new(newty.clone())
370 })
371 } else {
372 FnArg::Typed(PatType {
373 attrs: Vec::default(),
374 pat: immutable_pt.pat,
375 colon_token: pt.colon_token,
376 ty: pt.ty.clone()
377 })
378 }
379 } else {
380 arg.clone()
381 }
382 }).collect();
383
384 // Finally, Box any closure arguments
385 // use filter_map to remove the &self argument
386 let callargs = args.iter().filter_map(|arg| {
387 match arg {
388 FnArg::Typed(pt) => {
389 let mut pt2 = pt.clone();
390 demutify_arg(&mut pt2);
391 let pat = &pt2.pat;
392 if pat_is_self(pat) {
393 None
394 } else if hm.contains_key(&pt.ty) {
395 Some(quote!(Box::new(#pat)))
396 } else {
397 Some(quote!(#pat))
398 }
399 },
400 FnArg::Receiver(_) => None,
401 }
402 }).collect();
403 (outg, outargs, callargs)
404 }
405
406 /// Replace any "impl trait" types with "Box<dyn trait>" or equivalent.
deimplify(rt: &mut ReturnType)407 fn deimplify(rt: &mut ReturnType) {
408 if let ReturnType::Type(_, ty) = rt {
409 if let Type::ImplTrait(ref tit) = &**ty {
410 let needs_pin = tit.bounds
411 .iter()
412 .any(|tpb| {
413 if let TypeParamBound::Trait(tb) = tpb {
414 if let Some(seg) = tb.path.segments.last() {
415 seg.ident == "Future" || seg.ident == "Stream"
416 } else {
417 // It might still be a Future, but we can't guess
418 // what names it might be imported under. Too bad.
419 false
420 }
421 } else {
422 false
423 }
424 });
425 let bounds = &tit.bounds;
426 if needs_pin {
427 *ty = parse2(quote!(::std::pin::Pin<Box<dyn #bounds>>)).unwrap();
428 } else {
429 *ty = parse2(quote!(Box<dyn #bounds>)).unwrap();
430 }
431 }
432 }
433 }
434
435 /// Remove any generics that place constraints on Self.
dewhereselfify(generics: &mut Generics)436 fn dewhereselfify(generics: &mut Generics) {
437 if let Some(ref mut wc) = &mut generics.where_clause {
438 let new_predicates = wc.predicates.iter()
439 .filter(|wp| match wp {
440 WherePredicate::Type(pt) => {
441 pt.bounded_ty != parse2(quote!(Self)).unwrap()
442 },
443 _ => true
444 }).cloned()
445 .collect::<Punctuated<WherePredicate, Token![,]>>();
446 wc.predicates = new_predicates;
447 }
448 if generics.where_clause.as_ref()
449 .map(|wc| wc.predicates.is_empty())
450 .unwrap_or(false)
451 {
452 generics.where_clause = None;
453 }
454 }
455
456 /// Remove any mutability qualifiers from a method's argument list
demutify(inputs: &mut Punctuated<FnArg, token::Comma>)457 fn demutify(inputs: &mut Punctuated<FnArg, token::Comma>) {
458 for arg in inputs.iter_mut() {
459 match arg {
460 FnArg::Receiver(r) => if r.reference.is_none() {
461 r.mutability = None
462 },
463 FnArg::Typed(pt) => demutify_arg(pt),
464 }
465 }
466 }
467
468 /// Remove any "mut" from a method argument's binding.
demutify_arg(arg: &mut PatType)469 fn demutify_arg(arg: &mut PatType) {
470 match *arg.pat {
471 Pat::Wild(_) => {
472 compile_error(arg.span(),
473 "Mocked methods must have named arguments");
474 },
475 Pat::Ident(ref mut pat_ident) => {
476 if let Some(r) = &pat_ident.by_ref {
477 compile_error(r.span(),
478 "Mockall does not support by-reference argument bindings");
479 }
480 if let Some((_at, subpat)) = &pat_ident.subpat {
481 compile_error(subpat.span(),
482 "Mockall does not support subpattern bindings");
483 }
484 pat_ident.mutability = None;
485 },
486 _ => {
487 compile_error(arg.span(), "Unsupported argument type");
488 }
489 };
490 }
491
deselfify_path(path: &mut Path, actual: &Ident, generics: &Generics)492 fn deselfify_path(path: &mut Path, actual: &Ident, generics: &Generics) {
493 for seg in path.segments.iter_mut() {
494 if seg.ident == "Self" {
495 seg.ident = actual.clone();
496 if let PathArguments::None = seg.arguments {
497 if !generics.params.is_empty() {
498 let args = generics.params.iter()
499 .map(|gp| {
500 match gp {
501 GenericParam::Type(tp) => {
502 let ident = tp.ident.clone();
503 GenericArgument::Type(
504 Type::Path(
505 TypePath {
506 qself: None,
507 path: Path::from(ident)
508 }
509 )
510 )
511 },
512 GenericParam::Lifetime(ld) =>{
513 GenericArgument::Lifetime(
514 ld.lifetime.clone()
515 )
516 }
517 _ => unimplemented!(),
518 }
519 }).collect::<Punctuated<_, _>>();
520 seg.arguments = PathArguments::AngleBracketed(
521 AngleBracketedGenericArguments {
522 colon2_token: None,
523 lt_token: generics.lt_token.unwrap(),
524 args,
525 gt_token: generics.gt_token.unwrap(),
526 }
527 );
528 }
529 } else {
530 compile_error(seg.arguments.span(),
531 "Type arguments after Self are unexpected");
532 }
533 }
534 if let PathArguments::AngleBracketed(abga) = &mut seg.arguments
535 {
536 for arg in abga.args.iter_mut() {
537 match arg {
538 GenericArgument::Type(ty) =>
539 deselfify(ty, actual, generics),
540 GenericArgument::AssocType(at) =>
541 deselfify(&mut at.ty, actual, generics),
542 _ => /* Nothing to do */(),
543 }
544 }
545 }
546 }
547 }
548
549 /// Replace any references to `Self` in `literal_type` with `actual`.
550 /// `generics` is the Generics field of the parent struct. Useful for
551 /// constructor methods.
deselfify(literal_type: &mut Type, actual: &Ident, generics: &Generics)552 fn deselfify(literal_type: &mut Type, actual: &Ident, generics: &Generics) {
553 match literal_type {
554 Type::Slice(s) => {
555 deselfify(s.elem.as_mut(), actual, generics);
556 },
557 Type::Array(a) => {
558 deselfify(a.elem.as_mut(), actual, generics);
559 },
560 Type::Ptr(p) => {
561 deselfify(p.elem.as_mut(), actual, generics);
562 },
563 Type::Reference(r) => {
564 deselfify(r.elem.as_mut(), actual, generics);
565 },
566 Type::Tuple(tuple) => {
567 for elem in tuple.elems.iter_mut() {
568 deselfify(elem, actual, generics);
569 }
570 }
571 Type::Path(type_path) => {
572 if let Some(ref mut qself) = type_path.qself {
573 deselfify(qself.ty.as_mut(), actual, generics);
574 }
575 deselfify_path(&mut type_path.path, actual, generics);
576 },
577 Type::Paren(p) => {
578 deselfify(p.elem.as_mut(), actual, generics);
579 },
580 Type::Group(g) => {
581 deselfify(g.elem.as_mut(), actual, generics);
582 },
583 Type::Macro(_) | Type::Verbatim(_) => {
584 compile_error(literal_type.span(),
585 "mockall_derive does not support this type as a return argument");
586 },
587 Type::TraitObject(tto) => {
588 // Change types like `dyn Self` into `dyn MockXXX`.
589 for bound in tto.bounds.iter_mut() {
590 if let TypeParamBound::Trait(t) = bound {
591 deselfify_path(&mut t.path, actual, generics);
592 }
593 }
594 },
595 Type::ImplTrait(_) => {
596 /* Should've already been flagged as a compile_error */
597 },
598 Type::BareFn(_) => {
599 /* Bare functions can't have Self arguments. Nothing to do */
600 },
601 Type::Infer(_) | Type::Never(_) =>
602 {
603 /* Nothing to do */
604 },
605 _ => compile_error(literal_type.span(), "Unsupported type"),
606 }
607 }
608
609 /// Change any `Self` in a method's arguments' types with `actual`.
610 /// `generics` is the Generics field of the parent struct.
deselfify_args( args: &mut Punctuated<FnArg, Token![,]>, actual: &Ident, generics: &Generics)611 fn deselfify_args(
612 args: &mut Punctuated<FnArg, Token![,]>,
613 actual: &Ident,
614 generics: &Generics)
615 {
616 for arg in args.iter_mut() {
617 match arg {
618 FnArg::Receiver(r) => {
619 if r.colon_token.is_some() {
620 deselfify(r.ty.as_mut(), actual, generics)
621 }
622 },
623 FnArg::Typed(pt) => deselfify(pt.ty.as_mut(), actual, generics)
624 }
625 }
626 }
627
find_ident_from_path(path: &Path) -> (Ident, PathArguments)628 fn find_ident_from_path(path: &Path) -> (Ident, PathArguments) {
629 if path.segments.len() != 1 {
630 compile_error(path.span(),
631 "mockall_derive only supports structs defined in the current module");
632 return (Ident::new("", path.span()), PathArguments::None);
633 }
634 let last_seg = path.segments.last().unwrap();
635 (last_seg.ident.clone(), last_seg.arguments.clone())
636 }
637
find_lifetimes_in_tpb(bound: &TypeParamBound) -> HashSet<Lifetime>638 fn find_lifetimes_in_tpb(bound: &TypeParamBound) -> HashSet<Lifetime> {
639 let mut ret = HashSet::default();
640 match bound {
641 TypeParamBound::Lifetime(lt) => {
642 ret.insert(lt.clone());
643 },
644 TypeParamBound::Trait(tb) => {
645 ret.extend(find_lifetimes_in_path(&tb.path));
646 },
647 _ => ()
648 };
649 ret
650 }
651
find_lifetimes_in_path(path: &Path) -> HashSet<Lifetime>652 fn find_lifetimes_in_path(path: &Path) -> HashSet<Lifetime> {
653 let mut ret = HashSet::default();
654 for seg in path.segments.iter() {
655 if let PathArguments::AngleBracketed(abga) = &seg.arguments {
656 for arg in abga.args.iter() {
657 match arg {
658 GenericArgument::Lifetime(lt) => {
659 ret.insert(lt.clone());
660 },
661 GenericArgument::Type(ty) => {
662 ret.extend(find_lifetimes(ty));
663 },
664 GenericArgument::AssocType(at) => {
665 ret.extend(find_lifetimes(&at.ty));
666 },
667 GenericArgument::Constraint(c) => {
668 for bound in c.bounds.iter() {
669 ret.extend(find_lifetimes_in_tpb(bound));
670 }
671 },
672 GenericArgument::Const(_) => (),
673 _ => ()
674 }
675 }
676 }
677 }
678 ret
679 }
680
find_lifetimes(ty: &Type) -> HashSet<Lifetime>681 fn find_lifetimes(ty: &Type) -> HashSet<Lifetime> {
682 match ty {
683 Type::Array(ta) => find_lifetimes(ta.elem.as_ref()),
684 Type::Group(tg) => find_lifetimes(tg.elem.as_ref()),
685 Type::Infer(_ti) => HashSet::default(),
686 Type::Never(_tn) => HashSet::default(),
687 Type::Paren(tp) => find_lifetimes(tp.elem.as_ref()),
688 Type::Path(tp) => {
689 let mut ret = find_lifetimes_in_path(&tp.path);
690 if let Some(qs) = &tp.qself {
691 ret.extend(find_lifetimes(qs.ty.as_ref()));
692 }
693 ret
694 },
695 Type::Ptr(tp) => find_lifetimes(tp.elem.as_ref()),
696 Type::Reference(tr) => {
697 let mut ret = find_lifetimes(tr.elem.as_ref());
698 if let Some(lt) = &tr.lifetime {
699 ret.insert(lt.clone());
700 }
701 ret
702 },
703 Type::Slice(ts) => find_lifetimes(ts.elem.as_ref()),
704 Type::TraitObject(tto) => {
705 let mut ret = HashSet::default();
706 for bound in tto.bounds.iter() {
707 ret.extend(find_lifetimes_in_tpb(bound));
708 }
709 ret
710 }
711 Type::Tuple(tt) => {
712 let mut ret = HashSet::default();
713 for ty in tt.elems.iter() {
714 ret.extend(find_lifetimes(ty));
715 }
716 ret
717 },
718 Type::ImplTrait(tit) => {
719 let mut ret = HashSet::default();
720 for tpb in tit.bounds.iter() {
721 ret.extend(find_lifetimes_in_tpb(tpb));
722 }
723 ret
724 },
725 _ => {
726 compile_error(ty.span(), "unsupported type in this context");
727 HashSet::default()
728 }
729 }
730 }
731
732
733 struct AttrFormatter<'a>{
734 attrs: &'a [Attribute],
735 async_trait: bool,
736 doc: bool,
737 }
738
739 impl<'a> AttrFormatter<'a> {
new(attrs: &'a [Attribute]) -> AttrFormatter<'a>740 fn new(attrs: &'a [Attribute]) -> AttrFormatter<'a> {
741 Self {
742 attrs,
743 async_trait: true,
744 doc: true
745 }
746 }
747
async_trait(&mut self, allowed: bool) -> &mut Self748 fn async_trait(&mut self, allowed: bool) -> &mut Self {
749 self.async_trait = allowed;
750 self
751 }
752
doc(&mut self, allowed: bool) -> &mut Self753 fn doc(&mut self, allowed: bool) -> &mut Self {
754 self.doc = allowed;
755 self
756 }
757
758 // XXX This logic requires that attributes are imported with their
759 // standard names.
760 #[allow(clippy::needless_bool)]
761 #[allow(clippy::if_same_then_else)]
format(&mut self) -> Vec<Attribute>762 fn format(&mut self) -> Vec<Attribute> {
763 self.attrs.iter()
764 .filter(|attr| {
765 let i = attr.path().segments.last().map(|ps| &ps.ident);
766 if is_concretize(attr) {
767 // Internally used attribute. Never emit.
768 false
769 } else if i.is_none() {
770 false
771 } else if *i.as_ref().unwrap() == "derive" {
772 // We can't usefully derive any traits. Ignore them
773 false
774 } else if *i.as_ref().unwrap() == "doc" {
775 self.doc
776 } else if *i.as_ref().unwrap() == "async_trait" {
777 self.async_trait
778 } else if *i.as_ref().unwrap() == "instrument" {
779 // We can't usefully instrument the mock method, so just
780 // ignore this attribute.
781 // https://docs.rs/tracing/0.1.23/tracing/attr.instrument.html
782 false
783 } else if *i.as_ref().unwrap() == "link_name" {
784 // This shows up sometimes when mocking ffi functions. We
785 // must not emit it on anything that isn't an ffi definition
786 false
787 } else {
788 true
789 }
790 }).cloned()
791 .collect()
792 }
793 }
794
795 /// Determine if this Pat is any kind of `self` binding
pat_is_self(pat: &Pat) -> bool796 fn pat_is_self(pat: &Pat) -> bool {
797 if let Pat::Ident(pi) = pat {
798 pi.ident == "self"
799 } else {
800 false
801 }
802 }
803
804 /// Add `levels` `super::` to the path. Return the number of levels added.
supersuperfy_path(path: &mut Path, levels: usize) -> usize805 fn supersuperfy_path(path: &mut Path, levels: usize) -> usize {
806 if let Some(t) = path.segments.last_mut() {
807 match &mut t.arguments {
808 PathArguments::None => (),
809 PathArguments::AngleBracketed(ref mut abga) => {
810 for arg in abga.args.iter_mut() {
811 match arg {
812 GenericArgument::Type(ref mut ty) => {
813 *ty = supersuperfy(ty, levels);
814 },
815 GenericArgument::AssocType(ref mut at) => {
816 at.ty = supersuperfy(&at.ty, levels);
817 },
818 GenericArgument::Constraint(ref mut constraint) => {
819 supersuperfy_bounds(&mut constraint.bounds, levels);
820 },
821 _ => (),
822 }
823 }
824 },
825 PathArguments::Parenthesized(ref mut pga) => {
826 for input in pga.inputs.iter_mut() {
827 *input = supersuperfy(input, levels);
828 }
829 if let ReturnType::Type(_, ref mut ty) = pga.output {
830 *ty = Box::new(supersuperfy(ty, levels));
831 }
832 },
833 }
834 }
835 if let Some(t) = path.segments.first() {
836 if t.ident == "super" {
837 let mut ident = format_ident!("super");
838 ident.set_span(path.segments.span());
839 let ps = PathSegment {
840 ident,
841 arguments: PathArguments::None
842 };
843 for _ in 0..levels {
844 path.segments.insert(0, ps.clone());
845 }
846 levels
847 } else {
848 0
849 }
850 } else {
851 0
852 }
853 }
854
855 /// Replace any references to `super::X` in `original` with `super::super::X`.
supersuperfy(original: &Type, levels: usize) -> Type856 fn supersuperfy(original: &Type, levels: usize) -> Type {
857 let mut output = original.clone();
858 fn recurse(t: &mut Type, levels: usize) {
859 match t {
860 Type::Slice(s) => {
861 recurse(s.elem.as_mut(), levels);
862 },
863 Type::Array(a) => {
864 recurse(a.elem.as_mut(), levels);
865 },
866 Type::Ptr(p) => {
867 recurse(p.elem.as_mut(), levels);
868 },
869 Type::Reference(r) => {
870 recurse(r.elem.as_mut(), levels);
871 },
872 Type::BareFn(bfn) => {
873 if let ReturnType::Type(_, ref mut bt) = bfn.output {
874 recurse(bt.as_mut(), levels);
875 }
876 for input in bfn.inputs.iter_mut() {
877 recurse(&mut input.ty, levels);
878 }
879 },
880 Type::Tuple(tuple) => {
881 for elem in tuple.elems.iter_mut() {
882 recurse(elem, levels);
883 }
884 }
885 Type::Path(type_path) => {
886 let added = supersuperfy_path(&mut type_path.path, levels);
887 if let Some(ref mut qself) = type_path.qself {
888 recurse(qself.ty.as_mut(), levels);
889 qself.position += added;
890 }
891 },
892 Type::Paren(p) => {
893 recurse(p.elem.as_mut(), levels);
894 },
895 Type::Group(g) => {
896 recurse(g.elem.as_mut(), levels);
897 },
898 Type::Macro(_) | Type::Verbatim(_) => {
899 compile_error(t.span(),
900 "mockall_derive does not support this type in this position");
901 },
902 Type::TraitObject(tto) => {
903 for bound in tto.bounds.iter_mut() {
904 if let TypeParamBound::Trait(tb) = bound {
905 supersuperfy_path(&mut tb.path, levels);
906 }
907 }
908 },
909 Type::ImplTrait(_) => {
910 /* Should've already been flagged as a compile error */
911 },
912 Type::Infer(_) | Type::Never(_) =>
913 {
914 /* Nothing to do */
915 },
916 _ => compile_error(t.span(), "Unsupported type"),
917 }
918 }
919 recurse(&mut output, levels);
920 output
921 }
922
supersuperfy_generics(generics: &mut Generics, levels: usize)923 fn supersuperfy_generics(generics: &mut Generics, levels: usize) {
924 for param in generics.params.iter_mut() {
925 if let GenericParam::Type(tp) = param {
926 supersuperfy_bounds(&mut tp.bounds, levels);
927 if let Some(ty) = tp.default.as_mut() {
928 *ty = supersuperfy(ty, levels);
929 }
930 }
931 }
932 if let Some(wc) = generics.where_clause.as_mut() {
933 for wp in wc.predicates.iter_mut() {
934 if let WherePredicate::Type(pt) = wp {
935 pt.bounded_ty = supersuperfy(&pt.bounded_ty, levels);
936 supersuperfy_bounds(&mut pt.bounds, levels);
937 }
938 }
939 }
940 }
941
supersuperfy_bounds( bounds: &mut Punctuated<TypeParamBound, Token![+]>, levels: usize)942 fn supersuperfy_bounds(
943 bounds: &mut Punctuated<TypeParamBound, Token![+]>,
944 levels: usize)
945 {
946 for bound in bounds.iter_mut() {
947 if let TypeParamBound::Trait(tb) = bound {
948 supersuperfy_path(&mut tb.path, levels);
949 }
950 }
951 }
952
953 /// Generate a suitable mockall::Key generic paramter from any Generics
gen_keyid(g: &Generics) -> impl ToTokens954 fn gen_keyid(g: &Generics) -> impl ToTokens {
955 match g.params.len() {
956 0 => quote!(<()>),
957 1 => {
958 let (_, tg, _) = g.split_for_impl();
959 quote!(#tg)
960 },
961 _ => {
962 // Rust doesn't support variadic Generics, so mockall::Key must
963 // always have exactly one generic type. We need to add parentheses
964 // around whatever type generics the caller passes.
965 let tps = g.type_params()
966 .map(|tp| tp.ident.clone())
967 .collect::<Punctuated::<Ident, Token![,]>>();
968 quote!(<(#tps)>)
969 }
970 }
971 }
972
973 /// Generate a mock identifier from the regular one: eg "Foo" => "MockFoo"
gen_mock_ident(ident: &Ident) -> Ident974 fn gen_mock_ident(ident: &Ident) -> Ident {
975 format_ident!("Mock{}", ident)
976 }
977
978 /// Generate an identifier for the mock struct's private module: eg "Foo" =>
979 /// "__mock_Foo"
gen_mod_ident(struct_: &Ident, trait_: Option<&Ident>) -> Ident980 fn gen_mod_ident(struct_: &Ident, trait_: Option<&Ident>) -> Ident {
981 if let Some(t) = trait_ {
982 format_ident!("__mock_{struct_}_{}", t)
983 } else {
984 format_ident!("__mock_{struct_}")
985 }
986 }
987
988 /// Combine two Generics structs, producing a new one that has the union of
989 /// their parameters.
merge_generics(x: &Generics, y: &Generics) -> Generics990 fn merge_generics(x: &Generics, y: &Generics) -> Generics {
991 /// Compare only the identifiers of two GenericParams
992 fn cmp_gp_idents(x: &GenericParam, y: &GenericParam) -> bool {
993 use GenericParam::*;
994
995 match (x, y) {
996 (Type(xtp), Type(ytp)) => xtp.ident == ytp.ident,
997 (Lifetime(xld), Lifetime(yld)) => xld.lifetime == yld.lifetime,
998 (Const(xc), Const(yc)) => xc.ident == yc.ident,
999 _ => false
1000 }
1001 }
1002
1003 /// Compare only the identifiers of two WherePredicates
1004 fn cmp_wp_idents(x: &WherePredicate, y: &WherePredicate) -> bool {
1005 use WherePredicate::*;
1006
1007 match (x, y) {
1008 (Type(xpt), Type(ypt)) => xpt.bounded_ty == ypt.bounded_ty,
1009 (Lifetime(xpl), Lifetime(ypl)) => xpl.lifetime == ypl.lifetime,
1010 _ => false
1011 }
1012 }
1013
1014 let mut out = if x.lt_token.is_none() && x.where_clause.is_none() {
1015 y.clone()
1016 } else if y.lt_token.is_none() && y.where_clause.is_none() {
1017 x.clone()
1018 } else {
1019 let mut out = x.clone();
1020 // First merge the params
1021 'outer_param: for yparam in y.params.iter() {
1022 // XXX: O(n^2) loop
1023 for outparam in out.params.iter_mut() {
1024 if cmp_gp_idents(outparam, yparam) {
1025 if let (GenericParam::Type(ref mut ot),
1026 GenericParam::Type(yt)) = (outparam, yparam)
1027 {
1028 ot.attrs.extend(yt.attrs.iter().cloned());
1029 ot.colon_token = ot.colon_token.or(yt.colon_token);
1030 ot.eq_token = ot.eq_token.or(yt.eq_token);
1031 if ot.default.is_none() {
1032 ot.default = yt.default.clone();
1033 }
1034 // XXX this might result in duplicate bounds
1035 if ot.bounds != yt.bounds {
1036 ot.bounds.extend(yt.bounds.iter().cloned());
1037 }
1038 }
1039 continue 'outer_param;
1040 }
1041 }
1042 out.params.push(yparam.clone());
1043 }
1044 out
1045 };
1046 // Then merge the where clauses
1047 match (&mut out.where_clause, &y.where_clause) {
1048 (_, None) => (),
1049 (None, Some(wc)) => out.where_clause = Some(wc.clone()),
1050 (Some(out_wc), Some(y_wc)) => {
1051 'outer_wc: for ypred in y_wc.predicates.iter() {
1052 // XXX: O(n^2) loop
1053 for outpred in out_wc.predicates.iter_mut() {
1054 if cmp_wp_idents(outpred, ypred) {
1055 if let (WherePredicate::Type(ref mut ot),
1056 WherePredicate::Type(yt)) = (outpred, ypred)
1057 {
1058 match (&mut ot.lifetimes, &yt.lifetimes) {
1059 (_, None) => (),
1060 (None, Some(bl)) =>
1061 ot.lifetimes = Some(bl.clone()),
1062 (Some(obl), Some(ybl)) =>
1063 // XXX: might result in duplicates
1064 obl.lifetimes.extend(
1065 ybl.lifetimes.iter().cloned()),
1066 };
1067 // XXX: might result in duplicate bounds
1068 if ot.bounds != yt.bounds {
1069 ot.bounds.extend(yt.bounds.iter().cloned())
1070 }
1071 }
1072 continue 'outer_wc;
1073 }
1074 }
1075 out_wc.predicates.push(ypred.clone());
1076 }
1077 }
1078 }
1079 out
1080 }
1081
lifetimes_to_generic_params(lv: &Punctuated<LifetimeParam, Token![,]>) -> Punctuated<GenericParam, Token![,]>1082 fn lifetimes_to_generic_params(lv: &Punctuated<LifetimeParam, Token![,]>)
1083 -> Punctuated<GenericParam, Token![,]>
1084 {
1085 lv.iter()
1086 .map(|lt| GenericParam::Lifetime(lt.clone()))
1087 .collect()
1088 }
1089
1090 /// Transform a Vec of lifetimes into a Generics
lifetimes_to_generics(lv: &Punctuated<LifetimeParam, Token![,]>)-> Generics1091 fn lifetimes_to_generics(lv: &Punctuated<LifetimeParam, Token![,]>)-> Generics {
1092 if lv.is_empty() {
1093 Generics::default()
1094 } else {
1095 let params = lifetimes_to_generic_params(lv);
1096 Generics {
1097 lt_token: Some(Token)),
1098 gt_token: Some(Token)),
1099 params,
1100 where_clause: None
1101 }
1102 }
1103 }
1104
1105 /// Split a generics list into three: one for type generics and where predicates
1106 /// that relate to the signature, one for lifetimes that relate to the arguments
1107 /// only, and one for lifetimes that relate to the return type only.
split_lifetimes( generics: Generics, args: &[FnArg], rt: &ReturnType) -> (Generics, Punctuated<LifetimeParam, token::Comma>, Punctuated<LifetimeParam, token::Comma>)1108 fn split_lifetimes(
1109 generics: Generics,
1110 args: &[FnArg],
1111 rt: &ReturnType)
1112 -> (Generics,
1113 Punctuated<LifetimeParam, token::Comma>,
1114 Punctuated<LifetimeParam, token::Comma>)
1115 {
1116 if generics.lt_token.is_none() {
1117 return (generics, Default::default(), Default::default());
1118 }
1119
1120 // Check which types and lifetimes are referenced by the arguments
1121 let mut alts = HashSet::<Lifetime>::default();
1122 let mut rlts = HashSet::<Lifetime>::default();
1123 for arg in args {
1124 match arg {
1125 FnArg::Receiver(r) => {
1126 if let Some((_, Some(lt))) = &r.reference {
1127 alts.insert(lt.clone());
1128 }
1129 },
1130 FnArg::Typed(pt) => {
1131 alts.extend(find_lifetimes(pt.ty.as_ref()));
1132 },
1133 };
1134 };
1135
1136 if let ReturnType::Type(_, ty) = rt {
1137 rlts.extend(find_lifetimes(ty));
1138 }
1139
1140 let mut tv = Punctuated::new();
1141 let mut alv = Punctuated::new();
1142 let mut rlv = Punctuated::new();
1143 for p in generics.params.into_iter() {
1144 match p {
1145 GenericParam::Lifetime(ltd) if rlts.contains(<d.lifetime) =>
1146 rlv.push(ltd),
1147 GenericParam::Lifetime(ltd) if alts.contains(<d.lifetime) =>
1148 alv.push(ltd),
1149 GenericParam::Lifetime(_) => {
1150 // Probably a lifetime parameter from the impl block that isn't
1151 // used by this particular method
1152 },
1153 GenericParam::Type(_) => tv.push(p),
1154 _ => (),
1155 }
1156 }
1157
1158 let tg = if tv.is_empty() {
1159 Generics::default()
1160 } else {
1161 Generics {
1162 lt_token: generics.lt_token,
1163 gt_token: generics.gt_token,
1164 params: tv,
1165 where_clause: generics.where_clause
1166 }
1167 };
1168
1169 (tg, alv, rlv)
1170 }
1171
1172 /// Return the visibility that should be used for expectation!, given the
1173 /// original method's visibility.
1174 ///
1175 /// # Arguments
1176 /// - `vis`: Original visibility of the item
1177 /// - `levels`: How many modules will the mock item be nested in?
expectation_visibility(vis: &Visibility, levels: usize) -> Visibility1178 fn expectation_visibility(vis: &Visibility, levels: usize)
1179 -> Visibility
1180 {
1181 if levels == 0 {
1182 return vis.clone();
1183 }
1184
1185 let in_token = Token);
1186 let super_token = Token);
1187 match vis {
1188 Visibility::Inherited => {
1189 // Private items need pub(in super::[...]) for each level
1190 let mut path = Path::from(super_token);
1191 for _ in 1..levels {
1192 path.segments.push(super_token.into());
1193 }
1194 Visibility::Restricted(VisRestricted{
1195 pub_token: Token),
1196 paren_token: token::Paren::default(),
1197 in_token: Some(in_token),
1198 path: Box::new(path)
1199 })
1200 },
1201 Visibility::Restricted(vr) => {
1202 // crate => don't change
1203 // in crate::* => don't change
1204 // super => in super::super::super
1205 // self => in super::super
1206 // in anything_else => super::super::anything_else
1207 if vr.path.segments.first().unwrap().ident == "crate" {
1208 Visibility::Restricted(vr.clone())
1209 } else {
1210 let mut out = vr.clone();
1211 out.in_token = Some(in_token);
1212 for _ in 0..levels {
1213 out.path.segments.insert(0, super_token.into());
1214 }
1215 Visibility::Restricted(out)
1216 }
1217 },
1218 _ => vis.clone()
1219 }
1220 }
1221
staticize(generics: &Generics) -> Generics1222 fn staticize(generics: &Generics) -> Generics {
1223 let mut ret = generics.clone();
1224 for lt in ret.lifetimes_mut() {
1225 lt.lifetime = Lifetime::new("'static", Span::call_site());
1226 };
1227 ret
1228 }
1229
mock_it<M: Into<MockableItem>>(inputs: M) -> TokenStream1230 fn mock_it<M: Into<MockableItem>>(inputs: M) -> TokenStream
1231 {
1232 let mockable: MockableItem = inputs.into();
1233 let mock = MockItem::from(mockable);
1234 let ts = mock.into_token_stream();
1235 if env::var("MOCKALL_DEBUG").is_ok() {
1236 println!("{ts}");
1237 }
1238 ts
1239 }
1240
do_mock_once(input: TokenStream) -> TokenStream1241 fn do_mock_once(input: TokenStream) -> TokenStream
1242 {
1243 let item: MockableStruct = match syn::parse2(input) {
1244 Ok(mock) => mock,
1245 Err(err) => {
1246 return err.to_compile_error();
1247 }
1248 };
1249 mock_it(item)
1250 }
1251
do_mock(input: TokenStream) -> TokenStream1252 fn do_mock(input: TokenStream) -> TokenStream
1253 {
1254 cfg_if! {
1255 if #[cfg(reprocheck)] {
1256 let ts_a = do_mock_once(input.clone());
1257 let ts_b = do_mock_once(input.clone());
1258 assert_eq!(ts_a.to_string(), ts_b.to_string());
1259 }
1260 }
1261 do_mock_once(input)
1262 }
1263
1264 #[proc_macro_attribute]
concretize( _attrs: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream1265 pub fn concretize(
1266 _attrs: proc_macro::TokenStream,
1267 input: proc_macro::TokenStream) -> proc_macro::TokenStream
1268 {
1269 // Do nothing. This "attribute" is processed as text by the real proc
1270 // macros.
1271 input
1272 }
1273
1274 #[proc_macro]
mock(input: proc_macro::TokenStream) -> proc_macro::TokenStream1275 pub fn mock(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
1276 do_mock(input.into()).into()
1277 }
1278
1279 #[proc_macro_attribute]
automock(attrs: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream1280 pub fn automock(attrs: proc_macro::TokenStream, input: proc_macro::TokenStream)
1281 -> proc_macro::TokenStream
1282 {
1283 let attrs: proc_macro2::TokenStream = attrs.into();
1284 let input: proc_macro2::TokenStream = input.into();
1285 do_automock(attrs, input).into()
1286 }
1287
do_automock_once(attrs: TokenStream, input: TokenStream) -> TokenStream1288 fn do_automock_once(attrs: TokenStream, input: TokenStream) -> TokenStream {
1289 let mut output = input.clone();
1290 let attrs: Attrs = match parse2(attrs) {
1291 Ok(a) => a,
1292 Err(err) => {
1293 return err.to_compile_error();
1294 }
1295 };
1296 let item: Item = match parse2(input) {
1297 Ok(item) => item,
1298 Err(err) => {
1299 return err.to_compile_error();
1300 }
1301 };
1302 output.extend(mock_it((attrs, item)));
1303 output
1304 }
1305
do_automock(attrs: TokenStream, input: TokenStream) -> TokenStream1306 fn do_automock(attrs: TokenStream, input: TokenStream) -> TokenStream {
1307 cfg_if! {
1308 if #[cfg(reprocheck)] {
1309 let ts_a = do_automock_once(attrs.clone(), input.clone());
1310 let ts_b = do_automock_once(attrs.clone(), input.clone());
1311 assert_eq!(ts_a.to_string(), ts_b.to_string());
1312 }
1313 }
1314 do_automock_once(attrs, input)
1315 }
1316
1317 #[cfg(test)]
1318 mod t {
1319 use super::*;
1320
assert_contains(output: &str, tokens: TokenStream)1321 fn assert_contains(output: &str, tokens: TokenStream) {
1322 let s = tokens.to_string();
1323 assert!(output.contains(&s), "output does not contain {:?}", &s);
1324 }
1325
assert_not_contains(output: &str, tokens: TokenStream)1326 fn assert_not_contains(output: &str, tokens: TokenStream) {
1327 let s = tokens.to_string();
1328 assert!(!output.contains(&s), "output does not contain {:?}", &s);
1329 }
1330
1331 /// Various tests for overall code generation that are hard or impossible to
1332 /// write as integration tests
1333 mod mock {
1334 use std::str::FromStr;
1335 use super::super::*;
1336 use super::*;
1337
1338 #[test]
inherent_method_visibility()1339 fn inherent_method_visibility() {
1340 let code = "
1341 Foo {
1342 fn foo(&self);
1343 pub fn bar(&self);
1344 pub(crate) fn baz(&self);
1345 pub(super) fn bean(&self);
1346 pub(in crate::outer) fn boom(&self);
1347 }
1348 ";
1349 let ts = proc_macro2::TokenStream::from_str(code).unwrap();
1350 let output = do_mock(ts).to_string();
1351 assert_not_contains(&output, quote!(pub fn foo));
1352 assert!(!output.contains(") fn foo"));
1353 assert_contains(&output, quote!(pub fn bar));
1354 assert_contains(&output, quote!(pub(crate) fn baz));
1355 assert_contains(&output, quote!(pub(super) fn bean));
1356 assert_contains(&output, quote!(pub(in crate::outer) fn boom));
1357
1358 assert_not_contains(&output, quote!(pub fn expect_foo));
1359 assert!(!output.contains("pub fn expect_foo"));
1360 assert!(!output.contains(") fn expect_foo"));
1361 assert_contains(&output, quote!(pub fn expect_bar));
1362 assert_contains(&output, quote!(pub(crate) fn expect_baz));
1363 assert_contains(&output, quote!(pub(super) fn expect_bean));
1364 assert_contains(&output, quote!(pub(in crate::outer) fn expect_boom));
1365 }
1366
1367 #[test]
specific_impl()1368 fn specific_impl() {
1369 let code = "
1370 pub Foo<T: 'static> {}
1371 impl Bar for Foo<u32> {
1372 fn bar(&self);
1373 }
1374 impl Bar for Foo<i32> {
1375 fn bar(&self);
1376 }
1377 ";
1378 let ts = proc_macro2::TokenStream::from_str(code).unwrap();
1379 let output = do_mock(ts).to_string();
1380 assert_contains(&output, quote!(impl Bar for MockFoo<u32>));
1381 assert_contains(&output, quote!(impl Bar for MockFoo<i32>));
1382 // Ensure we don't duplicate the checkpoint function
1383 assert_not_contains(&output, quote!(
1384 self.Bar_expectations.checkpoint();
1385 self.Bar_expectations.checkpoint();
1386 ));
1387 // The expect methods should return specific types, not generic ones
1388 assert_contains(&output, quote!(
1389 pub fn expect_bar(&mut self) -> &mut __mock_MockFoo_Bar::__bar::Expectation<u32>
1390 ));
1391 assert_contains(&output, quote!(
1392 pub fn expect_bar(&mut self) -> &mut __mock_MockFoo_Bar::__bar::Expectation<i32>
1393 ));
1394 }
1395 }
1396
1397 /// Various tests for overall code generation that are hard or impossible to
1398 /// write as integration tests
1399 mod automock {
1400 use std::str::FromStr;
1401 use super::super::*;
1402 use super::*;
1403
1404 #[test]
doc_comments()1405 fn doc_comments() {
1406 let code = "
1407 mod foo {
1408 /// Function docs
1409 pub fn bar() { unimplemented!() }
1410 }
1411 ";
1412 let ts = proc_macro2::TokenStream::from_str(code).unwrap();
1413 let attrs_ts = proc_macro2::TokenStream::from_str("").unwrap();
1414 let output = do_automock(attrs_ts, ts).to_string();
1415 assert_contains(&output, quote!(#[doc=" Function docs"] pub fn bar));
1416 }
1417
1418 #[test]
method_visibility()1419 fn method_visibility() {
1420 let code = "
1421 impl Foo {
1422 fn foo(&self) {}
1423 pub fn bar(&self) {}
1424 pub(super) fn baz(&self) {}
1425 pub(crate) fn bang(&self) {}
1426 pub(in super::x) fn bean(&self) {}
1427 }";
1428 let ts = proc_macro2::TokenStream::from_str(code).unwrap();
1429 let attrs_ts = proc_macro2::TokenStream::from_str("").unwrap();
1430 let output = do_automock(attrs_ts, ts).to_string();
1431 assert_not_contains(&output, quote!(pub fn foo));
1432 assert!(!output.contains(") fn foo"));
1433 assert_not_contains(&output, quote!(pub fn expect_foo));
1434 assert!(!output.contains(") fn expect_foo"));
1435 assert_contains(&output, quote!(pub fn bar));
1436 assert_contains(&output, quote!(pub fn expect_bar));
1437 assert_contains(&output, quote!(pub(super) fn baz));
1438 assert_contains(&output, quote!(pub(super) fn expect_baz));
1439 assert_contains(&output, quote!(pub ( crate ) fn bang));
1440 assert_contains(&output, quote!(pub ( crate ) fn expect_bang));
1441 assert_contains(&output, quote!(pub ( in super :: x ) fn bean));
1442 assert_contains(&output, quote!(pub ( in super :: x ) fn expect_bean));
1443 }
1444
1445 #[test]
1446 #[should_panic(expected = "can only mock inline modules")]
external_module()1447 fn external_module() {
1448 let code = "mod foo;";
1449 let ts = proc_macro2::TokenStream::from_str(code).unwrap();
1450 let attrs_ts = proc_macro2::TokenStream::from_str("").unwrap();
1451 do_automock(attrs_ts, ts).to_string();
1452 }
1453
1454 #[test]
trait_visibility()1455 fn trait_visibility() {
1456 let code = "
1457 pub(super) trait Foo {}
1458 ";
1459 let attrs_ts = proc_macro2::TokenStream::from_str("").unwrap();
1460 let ts = proc_macro2::TokenStream::from_str(code).unwrap();
1461 let output = do_automock(attrs_ts, ts).to_string();
1462 assert_contains(&output, quote!(pub ( super ) struct MockFoo));
1463 }
1464 }
1465
1466 mod concretize_args {
1467 use super::*;
1468
check_concretize( sig: TokenStream, expected_inputs: &[TokenStream], expected_call_exprs: &[TokenStream])1469 fn check_concretize(
1470 sig: TokenStream,
1471 expected_inputs: &[TokenStream],
1472 expected_call_exprs: &[TokenStream])
1473 {
1474 let f: Signature = parse2(sig).unwrap();
1475 let (generics, inputs, call_exprs) =
1476 concretize_args(&f.generics, &f.inputs);
1477 assert!(generics.params.is_empty());
1478 assert_eq!(inputs.len(), expected_inputs.len());
1479 assert_eq!(call_exprs.len(), expected_call_exprs.len());
1480 for i in 0..inputs.len() {
1481 let actual = &inputs[i];
1482 let exp = &expected_inputs[i];
1483 assert_eq!(quote!(#actual).to_string(), quote!(#exp).to_string());
1484 }
1485 for i in 0..call_exprs.len() {
1486 let actual = &call_exprs[i];
1487 let exp = &expected_call_exprs[i];
1488 assert_eq!(quote!(#actual).to_string(), quote!(#exp).to_string());
1489 }
1490 }
1491
1492 #[test]
bystanders()1493 fn bystanders() {
1494 check_concretize(
1495 quote!(fn foo<P: AsRef<Path>>(x: i32, p: P, y: &f64)),
1496 &[quote!(x: i32), quote!(p: &(dyn AsRef<Path>)), quote!(y: &f64)],
1497 &[quote!(x), quote!(&p), quote!(y)]
1498 );
1499 }
1500
1501 #[test]
multi_bounds()1502 fn multi_bounds() {
1503 check_concretize(
1504 quote!(fn foo<P: AsRef<String> + AsMut<String>>(p: P)),
1505 &[quote!(p: &(dyn AsRef<String> + AsMut<String>))],
1506 &[quote!(&p)]
1507 );
1508 }
1509
1510 #[test]
mutable_reference_arg()1511 fn mutable_reference_arg() {
1512 check_concretize(
1513 quote!(fn foo<P: AsMut<Path>>(p: &mut P)),
1514 &[quote!(p: &mut (dyn AsMut<Path>))],
1515 &[quote!(p)]
1516 );
1517 }
1518
1519 #[test]
mutable_reference_multi_bounds()1520 fn mutable_reference_multi_bounds() {
1521 check_concretize(
1522 quote!(fn foo<P: AsRef<String> + AsMut<String>>(p: &mut P)),
1523 &[quote!(p: &mut (dyn AsRef<String> + AsMut<String>))],
1524 &[quote!(p)]
1525 );
1526 }
1527
1528 #[test]
reference_arg()1529 fn reference_arg() {
1530 check_concretize(
1531 quote!(fn foo<P: AsRef<Path>>(p: &P)),
1532 &[quote!(p: &(dyn AsRef<Path>))],
1533 &[quote!(p)]
1534 );
1535 }
1536
1537 #[test]
simple()1538 fn simple() {
1539 check_concretize(
1540 quote!(fn foo<P: AsRef<Path>>(p: P)),
1541 &[quote!(p: &(dyn AsRef<Path>))],
1542 &[quote!(&p)]
1543 );
1544 }
1545
1546 #[test]
slice()1547 fn slice() {
1548 check_concretize(
1549 quote!(fn foo<P: AsRef<Path>>(p: &[P])),
1550 &[quote!(p: &[&(dyn AsRef<Path>)])],
1551 &[quote!(&(0..p.len()).map(|__mockall_i| &p[__mockall_i] as &(dyn AsRef<Path>)).collect::<Vec<_>>())]
1552 );
1553 }
1554
1555 #[test]
slice_with_multi_bounds()1556 fn slice_with_multi_bounds() {
1557 check_concretize(
1558 quote!(fn foo<P: AsRef<Path> + AsMut<String>>(p: &[P])),
1559 &[quote!(p: &[&(dyn AsRef<Path> + AsMut<String>)])],
1560 &[quote!(&(0..p.len()).map(|__mockall_i| &p[__mockall_i] as &(dyn AsRef<Path> + AsMut<String>)).collect::<Vec<_>>())]
1561 );
1562 }
1563
1564 #[test]
where_clause()1565 fn where_clause() {
1566 check_concretize(
1567 quote!(fn foo<P>(p: P) where P: AsRef<Path>),
1568 &[quote!(p: &(dyn AsRef<Path>))],
1569 &[quote!(&p)]
1570 );
1571 }
1572 }
1573
1574 mod deimplify {
1575 use super::*;
1576
check_deimplify(orig_ts: TokenStream, expected_ts: TokenStream)1577 fn check_deimplify(orig_ts: TokenStream, expected_ts: TokenStream) {
1578 let mut orig: ReturnType = parse2(orig_ts).unwrap();
1579 let expected: ReturnType = parse2(expected_ts).unwrap();
1580 deimplify(&mut orig);
1581 assert_eq!(quote!(#orig).to_string(), quote!(#expected).to_string());
1582 }
1583
1584 // Future is a special case
1585 #[test]
impl_future()1586 fn impl_future() {
1587 check_deimplify(
1588 quote!(-> impl Future<Output=i32>),
1589 quote!(-> ::std::pin::Pin<Box<dyn Future<Output=i32>>>)
1590 );
1591 }
1592
1593 // Future is a special case, wherever it appears
1594 #[test]
impl_future_reverse()1595 fn impl_future_reverse() {
1596 check_deimplify(
1597 quote!(-> impl Send + Future<Output=i32>),
1598 quote!(-> ::std::pin::Pin<Box<dyn Send + Future<Output=i32>>>)
1599 );
1600 }
1601
1602 // Stream is a special case
1603 #[test]
impl_stream()1604 fn impl_stream() {
1605 check_deimplify(
1606 quote!(-> impl Stream<Item=i32>),
1607 quote!(-> ::std::pin::Pin<Box<dyn Stream<Item=i32>>>)
1608 );
1609 }
1610
1611 #[test]
impl_trait()1612 fn impl_trait() {
1613 check_deimplify(
1614 quote!(-> impl Foo),
1615 quote!(-> Box<dyn Foo>)
1616 );
1617 }
1618
1619 // With extra bounds
1620 #[test]
impl_trait2()1621 fn impl_trait2() {
1622 check_deimplify(
1623 quote!(-> impl Foo + Send),
1624 quote!(-> Box<dyn Foo + Send>)
1625 );
1626 }
1627 }
1628
1629 mod deselfify {
1630 use super::*;
1631
check_deselfify( orig_ts: TokenStream, actual_ts: TokenStream, generics_ts: TokenStream, expected_ts: TokenStream)1632 fn check_deselfify(
1633 orig_ts: TokenStream,
1634 actual_ts: TokenStream,
1635 generics_ts: TokenStream,
1636 expected_ts: TokenStream)
1637 {
1638 let mut ty: Type = parse2(orig_ts).unwrap();
1639 let actual: Ident = parse2(actual_ts).unwrap();
1640 let generics: Generics = parse2(generics_ts).unwrap();
1641 let expected: Type = parse2(expected_ts).unwrap();
1642 deselfify(&mut ty, &actual, &generics);
1643 assert_eq!(quote!(#ty).to_string(),
1644 quote!(#expected).to_string());
1645 }
1646
1647 #[test]
arc()1648 fn arc() {
1649 check_deselfify(
1650 quote!(Arc<Self>),
1651 quote!(Foo),
1652 quote!(),
1653 quote!(Arc<Foo>)
1654 );
1655 }
1656 #[test]
future()1657 fn future() {
1658 check_deselfify(
1659 quote!(Box<dyn Future<Output=Self>>),
1660 quote!(Foo),
1661 quote!(),
1662 quote!(Box<dyn Future<Output=Foo>>)
1663 );
1664 }
1665
1666 #[test]
qself()1667 fn qself() {
1668 check_deselfify(
1669 quote!(<Self as Self>::Self),
1670 quote!(Foo),
1671 quote!(),
1672 quote!(<Foo as Foo>::Foo)
1673 );
1674 }
1675
1676 #[test]
trait_object()1677 fn trait_object() {
1678 check_deselfify(
1679 quote!(Box<dyn Self>),
1680 quote!(Foo),
1681 quote!(),
1682 quote!(Box<dyn Foo>)
1683 );
1684 }
1685
1686 // A trait object with multiple bounds
1687 #[test]
trait_object2()1688 fn trait_object2() {
1689 check_deselfify(
1690 quote!(Box<dyn Self + Send>),
1691 quote!(Foo),
1692 quote!(),
1693 quote!(Box<dyn Foo + Send>)
1694 );
1695 }
1696 }
1697
1698 mod dewhereselfify {
1699 use super::*;
1700
1701 #[test]
lifetime()1702 fn lifetime() {
1703 let mut meth: ImplItemFn = parse2(quote!(
1704 fn foo<'a>(&self) where 'a: 'static, Self: Sized {}
1705 )).unwrap();
1706 let expected: ImplItemFn = parse2(quote!(
1707 fn foo<'a>(&self) where 'a: 'static {}
1708 )).unwrap();
1709 dewhereselfify(&mut meth.sig.generics);
1710 assert_eq!(meth, expected);
1711 }
1712
1713 #[test]
normal_method()1714 fn normal_method() {
1715 let mut meth: ImplItemFn = parse2(quote!(
1716 fn foo(&self) where Self: Sized {}
1717 )).unwrap();
1718 let expected: ImplItemFn = parse2(quote!(
1719 fn foo(&self) {}
1720 )).unwrap();
1721 dewhereselfify(&mut meth.sig.generics);
1722 assert_eq!(meth, expected);
1723 }
1724
1725 #[test]
with_real_generics()1726 fn with_real_generics() {
1727 let mut meth: ImplItemFn = parse2(quote!(
1728 fn foo<T>(&self, t: T) where Self: Sized, T: Copy {}
1729 )).unwrap();
1730 let expected: ImplItemFn = parse2(quote!(
1731 fn foo<T>(&self, t: T) where T: Copy {}
1732 )).unwrap();
1733 dewhereselfify(&mut meth.sig.generics);
1734 assert_eq!(meth, expected);
1735 }
1736 }
1737
1738 mod gen_keyid {
1739 use super::*;
1740
check_gen_keyid(orig: TokenStream, expected: TokenStream)1741 fn check_gen_keyid(orig: TokenStream, expected: TokenStream) {
1742 let g: Generics = parse2(orig).unwrap();
1743 let keyid = gen_keyid(&g);
1744 assert_eq!(quote!(#keyid).to_string(), quote!(#expected).to_string());
1745 }
1746
1747 #[test]
empty()1748 fn empty() {
1749 check_gen_keyid(quote!(), quote!(<()>));
1750 }
1751
1752 #[test]
onetype()1753 fn onetype() {
1754 check_gen_keyid(quote!(<T>), quote!(<T>));
1755 }
1756
1757 #[test]
twotypes()1758 fn twotypes() {
1759 check_gen_keyid(quote!(<T, V>), quote!(<(T, V)>));
1760 }
1761 }
1762
1763 mod merge_generics {
1764 use super::*;
1765
1766 #[test]
both()1767 fn both() {
1768 let mut g1: Generics = parse2(quote!(<T: 'static, V: Copy> )).unwrap();
1769 let wc1: WhereClause = parse2(quote!(where T: Default)).unwrap();
1770 g1.where_clause = Some(wc1);
1771
1772 let mut g2: Generics = parse2(quote!(<Q: Send, V: Clone>)).unwrap();
1773 let wc2: WhereClause = parse2(quote!(where T: Sync, Q: Debug)).unwrap();
1774 g2.where_clause = Some(wc2);
1775
1776 let gm = super::merge_generics(&g1, &g2);
1777 let gm_wc = &gm.where_clause;
1778
1779 let ge: Generics = parse2(quote!(
1780 <T: 'static, V: Copy + Clone, Q: Send>
1781 )).unwrap();
1782 let wce: WhereClause = parse2(quote!(
1783 where T: Default + Sync, Q: Debug
1784 )).unwrap();
1785
1786 assert_eq!(quote!(#ge #wce).to_string(),
1787 quote!(#gm #gm_wc).to_string());
1788 }
1789
1790 #[test]
eq()1791 fn eq() {
1792 let mut g1: Generics = parse2(quote!(<T: 'static, V: Copy> )).unwrap();
1793 let wc1: WhereClause = parse2(quote!(where T: Default)).unwrap();
1794 g1.where_clause = Some(wc1.clone());
1795
1796 let gm = super::merge_generics(&g1, &g1);
1797 let gm_wc = &gm.where_clause;
1798
1799 assert_eq!(quote!(#g1 #wc1).to_string(),
1800 quote!(#gm #gm_wc).to_string());
1801 }
1802
1803 #[test]
lhs_only()1804 fn lhs_only() {
1805 let mut g1: Generics = parse2(quote!(<T: 'static, V: Copy> )).unwrap();
1806 let wc1: WhereClause = parse2(quote!(where T: Default)).unwrap();
1807 g1.where_clause = Some(wc1.clone());
1808
1809 let g2 = Generics::default();
1810
1811 let gm = super::merge_generics(&g1, &g2);
1812 let gm_wc = &gm.where_clause;
1813
1814 assert_eq!(quote!(#g1 #wc1).to_string(),
1815 quote!(#gm #gm_wc).to_string());
1816 }
1817
1818 #[test]
lhs_wc_only()1819 fn lhs_wc_only() {
1820 let mut g1 = Generics::default();
1821 let wc1: WhereClause = parse2(quote!(where T: Default)).unwrap();
1822 g1.where_clause = Some(wc1.clone());
1823
1824 let g2 = Generics::default();
1825
1826 let gm = super::merge_generics(&g1, &g2);
1827 let gm_wc = &gm.where_clause;
1828
1829 assert_eq!(quote!(#g1 #wc1).to_string(),
1830 quote!(#gm #gm_wc).to_string());
1831 }
1832
1833 #[test]
rhs_only()1834 fn rhs_only() {
1835 let g1 = Generics::default();
1836 let mut g2: Generics = parse2(quote!(<Q: Send, V: Clone>)).unwrap();
1837 let wc2: WhereClause = parse2(quote!(where T: Sync, Q: Debug)).unwrap();
1838 g2.where_clause = Some(wc2.clone());
1839
1840 let gm = super::merge_generics(&g1, &g2);
1841 let gm_wc = &gm.where_clause;
1842
1843 assert_eq!(quote!(#g2 #wc2).to_string(),
1844 quote!(#gm #gm_wc).to_string());
1845 }
1846 }
1847
1848 mod supersuperfy {
1849 use super::*;
1850
check_supersuperfy(orig: TokenStream, expected: TokenStream)1851 fn check_supersuperfy(orig: TokenStream, expected: TokenStream) {
1852 let orig_ty: Type = parse2(orig).unwrap();
1853 let expected_ty: Type = parse2(expected).unwrap();
1854 let output = supersuperfy(&orig_ty, 1);
1855 assert_eq!(quote!(#output).to_string(),
1856 quote!(#expected_ty).to_string());
1857 }
1858
1859 #[test]
array()1860 fn array() {
1861 check_supersuperfy(
1862 quote!([super::X; n]),
1863 quote!([super::super::X; n])
1864 );
1865 }
1866
1867 #[test]
barefn()1868 fn barefn() {
1869 check_supersuperfy(
1870 quote!(fn(super::A) -> super::B),
1871 quote!(fn(super::super::A) -> super::super::B)
1872 );
1873 }
1874
1875 #[test]
group()1876 fn group() {
1877 let orig = TypeGroup {
1878 group_token: token::Group::default(),
1879 elem: Box::new(parse2(quote!(super::T)).unwrap())
1880 };
1881 let expected = TypeGroup {
1882 group_token: token::Group::default(),
1883 elem: Box::new(parse2(quote!(super::super::T)).unwrap())
1884 };
1885 let output = supersuperfy(&Type::Group(orig), 1);
1886 assert_eq!(quote!(#output).to_string(),
1887 quote!(#expected).to_string());
1888 }
1889
1890 // Just check that it doesn't panic
1891 #[test]
infer()1892 fn infer() {
1893 check_supersuperfy( quote!(_), quote!(_));
1894 }
1895
1896 // Just check that it doesn't panic
1897 #[test]
never()1898 fn never() {
1899 check_supersuperfy( quote!(!), quote!(!));
1900 }
1901
1902 #[test]
paren()1903 fn paren() {
1904 check_supersuperfy(
1905 quote!((super::X)),
1906 quote!((super::super::X))
1907 );
1908 }
1909
1910 #[test]
path()1911 fn path() {
1912 check_supersuperfy(
1913 quote!(::super::SuperT<u32>),
1914 quote!(::super::super::SuperT<u32>)
1915 );
1916 }
1917
1918 #[test]
path_with_qself()1919 fn path_with_qself() {
1920 check_supersuperfy(
1921 quote!(<super::X as super::Y>::Foo<u32>),
1922 quote!(<super::super::X as super::super::Y>::Foo<u32>),
1923 );
1924 }
1925
1926 #[test]
angle_bracketed_generic_arguments()1927 fn angle_bracketed_generic_arguments() {
1928 check_supersuperfy(
1929 quote!(mod_::T<super::X>),
1930 quote!(mod_::T<super::super::X>)
1931 );
1932 }
1933
1934 #[test]
ptr()1935 fn ptr() {
1936 check_supersuperfy(
1937 quote!(*const super::X),
1938 quote!(*const super::super::X)
1939 );
1940 }
1941
1942 #[test]
reference()1943 fn reference() {
1944 check_supersuperfy(
1945 quote!(&'a mut super::X),
1946 quote!(&'a mut super::super::X)
1947 );
1948 }
1949
1950 #[test]
slice()1951 fn slice() {
1952 check_supersuperfy(
1953 quote!([super::X]),
1954 quote!([super::super::X])
1955 );
1956 }
1957
1958 #[test]
trait_object()1959 fn trait_object() {
1960 check_supersuperfy(
1961 quote!(dyn super::X + super::Y),
1962 quote!(dyn super::super::X + super::super::Y)
1963 );
1964 }
1965
1966 #[test]
tuple()1967 fn tuple() {
1968 check_supersuperfy(
1969 quote!((super::A, super::B)),
1970 quote!((super::super::A, super::super::B))
1971 );
1972 }
1973 }
1974
1975 mod supersuperfy_generics {
1976 use super::*;
1977
check_supersuperfy_generics( orig: TokenStream, orig_wc: TokenStream, expected: TokenStream, expected_wc: TokenStream)1978 fn check_supersuperfy_generics(
1979 orig: TokenStream,
1980 orig_wc: TokenStream,
1981 expected: TokenStream,
1982 expected_wc: TokenStream)
1983 {
1984 let mut orig_g: Generics = parse2(orig).unwrap();
1985 orig_g.where_clause = parse2(orig_wc).unwrap();
1986 let mut expected_g: Generics = parse2(expected).unwrap();
1987 expected_g.where_clause = parse2(expected_wc).unwrap();
1988 let mut output: Generics = orig_g;
1989 supersuperfy_generics(&mut output, 1);
1990 let (o_ig, o_tg, o_wc) = output.split_for_impl();
1991 let (e_ig, e_tg, e_wc) = expected_g.split_for_impl();
1992 assert_eq!(quote!(#o_ig).to_string(), quote!(#e_ig).to_string());
1993 assert_eq!(quote!(#o_tg).to_string(), quote!(#e_tg).to_string());
1994 assert_eq!(quote!(#o_wc).to_string(), quote!(#e_wc).to_string());
1995 }
1996
1997 #[test]
default()1998 fn default() {
1999 check_supersuperfy_generics(
2000 quote!(<T: X = super::Y>), quote!(),
2001 quote!(<T: X = super::super::Y>), quote!(),
2002 );
2003 }
2004
2005 #[test]
empty()2006 fn empty() {
2007 check_supersuperfy_generics(quote!(), quote!(), quote!(), quote!());
2008 }
2009
2010 #[test]
everything()2011 fn everything() {
2012 check_supersuperfy_generics(
2013 quote!(<T: super::A = super::B>),
2014 quote!(where super::C: super::D),
2015 quote!(<T: super::super::A = super::super::B>),
2016 quote!(where super::super::C: super::super::D),
2017 );
2018 }
2019
2020 #[test]
bound()2021 fn bound() {
2022 check_supersuperfy_generics(
2023 quote!(<T: super::A>), quote!(),
2024 quote!(<T: super::super::A>), quote!(),
2025 );
2026 }
2027
2028 #[test]
closure()2029 fn closure() {
2030 check_supersuperfy_generics(
2031 quote!(<F: Fn(u32) -> super::SuperT>), quote!(),
2032 quote!(<F: Fn(u32) -> super::super::SuperT>), quote!(),
2033 );
2034 }
2035
2036 #[test]
wc_bounded_ty()2037 fn wc_bounded_ty() {
2038 check_supersuperfy_generics(
2039 quote!(), quote!(where super::T: X),
2040 quote!(), quote!(where super::super::T: X),
2041 );
2042 }
2043
2044 #[test]
wc_bounds()2045 fn wc_bounds() {
2046 check_supersuperfy_generics(
2047 quote!(), quote!(where T: super::X),
2048 quote!(), quote!(where T: super::super::X),
2049 );
2050 }
2051 }
2052 }
2053