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