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