Merge remote-tracking branch 'origin/upstream' am: 691813a94e am: 35933ac783 am: 0a4aa7892e

Original change: undetermined

Change-Id: Id174706c4996551e004522dbbc7ffd4eb71d1c4e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..1232443
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+  "git": {
+    "sha1": "d5351f7215c6c5bca11f704ed41d9ae768b43007"
+  },
+  "path_in_vcs": "mockall_derive"
+}
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..2220f21
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,37 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file as changes will be overridden on upgrade.
+
+rust_proc_macro {
+    name: "libmockall_derive",
+    crate_name: "mockall_derive",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.11.4",
+    srcs: ["src/lib.rs"],
+    edition: "2018",
+    rustlibs: [
+        "libcfg_if",
+        "libproc_macro2",
+        "libquote",
+        "libsyn_deprecated",
+    ],
+}
+
+rust_test_host {
+    name: "mockall_derive_test_src_lib",
+    crate_name: "mockall_derive",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.11.4",
+    srcs: ["src/lib.rs"],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    test_options: {
+        unit_test: true,
+    },
+    edition: "2018",
+    rustlibs: [
+        "libcfg_if",
+        "libproc_macro2",
+        "libquote",
+        "libsyn_deprecated",
+    ],
+}
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..89d8bc1
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,58 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "mockall_derive"
+version = "0.11.4"
+authors = ["Alan Somers <asomers@gmail.com>"]
+description = """
+Procedural macros for Mockall
+"""
+documentation = "https://docs.rs/mockall_derive"
+readme = "README.md"
+keywords = [
+    "mock",
+    "mocking",
+    "testing",
+]
+categories = ["development-tools::testing"]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/asomers/mockall"
+
+[package.metadata.release]
+push = false
+tag = false
+
+[lib]
+proc-macro = true
+
+[dependencies.cfg-if]
+version = "1.0"
+
+[dependencies.proc-macro2]
+version = "1.0"
+
+[dependencies.quote]
+version = "1.0"
+
+[dependencies.syn]
+version = "1.0.87"
+features = [
+    "extra-traits",
+    "full",
+]
+
+[dev-dependencies.pretty_assertions]
+version = "1.3"
+
+[features]
+nightly_derive = ["proc-macro2/nightly"]
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 0000000..6b579aa
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+LICENSE-APACHE
\ No newline at end of file
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..39df3da
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2019 Alan Somers
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..eaa868e
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,20 @@
+name: "mockall_derive"
+description: "()"
+third_party {
+  identifier {
+    type: "crates.io"
+    value: "https://crates.io/crates/mockall_derive"
+  }
+  identifier {
+    type: "Archive"
+    value: "https://static.crates.io/crates/mockall_derive/mockall_derive-0.11.4.crate"
+  }
+  version: "0.11.4"
+  # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
+  license_type: NOTICE
+  last_upgrade_date {
+    year: 2023
+    month: 11
+    day: 6
+  }
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..48bea6e
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 688011
+include platform/prebuilts/rust:main:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2fa2632
--- /dev/null
+++ b/README.md
@@ -0,0 +1,14 @@
+# Mockall_derive
+
+This crate should never be used directly.  You should use
+[`mockall`](https://crates.io/crates/mockall) instead.
+
+# License
+
+`mockall` is primarily distributed under the terms of both the MIT license
+and the Apache License (Version 2.0), with portions covered by various BSD-like
+licenses.
+
+See LICENSE-APACHE, and LICENSE-MIT for details
+
+
diff --git a/cargo_embargo.json b/cargo_embargo.json
new file mode 100644
index 0000000..f14bd80
--- /dev/null
+++ b/cargo_embargo.json
@@ -0,0 +1,12 @@
+{
+  "tests": true,
+  "package": {
+    "mockall_derive": {
+      "device_supported": false,
+      "dep_blocklist": [
+        "libpretty_assertions"
+      ],
+      "patch": "patches/use-deprecated-syn1-dep.patch"
+    }
+  }
+}
diff --git a/patches/remove-pretty-assertions-dep.patch b/patches/remove-pretty-assertions-dep.patch
new file mode 100644
index 0000000..8340ef6
--- /dev/null
+++ b/patches/remove-pretty-assertions-dep.patch
@@ -0,0 +1,12 @@
+Not actually needed if the tests pass...
+
+--- a/src/automock.rs	2006-07-24 03:21:28.000000000 +0200
++++ b/src/automock.rs	2023-11-06 14:54:02.079601472 +0100
+@@ -280,7 +280,6 @@
+ #[cfg(test)]
+ mod t {
+     use super::super::*;
+-    use pretty_assertions::assert_eq;
+ 
+     fn check_substitute_type(
+         attrs: TokenStream,
diff --git a/patches/use-deprecated-syn1-dep.patch b/patches/use-deprecated-syn1-dep.patch
new file mode 100644
index 0000000..5d85ecf
--- /dev/null
+++ b/patches/use-deprecated-syn1-dep.patch
@@ -0,0 +1,21 @@
+Patch Android.bp to use the old syn v1 package.
+
+--- a/Android.bp	2023-11-06 16:05:46.887866053 +0100
++++ b/Android.bp	2023-11-06 16:06:15.768058832 +0100
+@@ -14,7 +14,7 @@
+         "libcfg_if",
+         "libproc_macro2",
+         "libquote",
+-        "libsyn",
++        "libsyn_deprecated",
+     ],
+ }
+ 
+@@ -34,6 +34,6 @@
+         "libcfg_if",
+         "libproc_macro2",
+         "libquote",
+-        "libsyn",
++        "libsyn_deprecated",
+     ],
+ }
diff --git a/patches/use-explicit-extern-crate-proc-macro.patch b/patches/use-explicit-extern-crate-proc-macro.patch
new file mode 100644
index 0000000..5985b65
--- /dev/null
+++ b/patches/use-explicit-extern-crate-proc-macro.patch
@@ -0,0 +1,14 @@
+Cargo automatically imports proc_macro in Rust 2018, but Soong only
+does this for rust_proc_macro targets.
+
+--- a/src/lib.rs	2023-11-06 16:32:46.480193187 +0100
++++ b/src/lib.rs	2023-11-06 16:29:38.743132168 +0100
+@@ -34,6 +34,8 @@
+ use crate::mock_item_struct::MockItemStruct;
+ use crate::mockable_item::MockableItem;
+ 
++extern crate proc_macro;
++
+ // Define deterministic aliases for these common types.
+ type HashMap<K, V> = std::collections::HashMap<K, V, BuildHasherDefault<std::collections::hash_map::DefaultHasher>>;
+ type HashSet<K> = std::collections::HashSet<K, BuildHasherDefault<std::collections::hash_map::DefaultHasher>>;
diff --git a/src/automock.rs b/src/automock.rs
new file mode 100644
index 0000000..bba6cb1
--- /dev/null
+++ b/src/automock.rs
@@ -0,0 +1,325 @@
+// vim: tw=80
+use super::*;
+use std::collections::HashMap;
+use syn::parse::{Parse, ParseStream};
+
+/// A single automock attribute
+// This enum is very short-lived, so it's fine not to box it.
+#[allow(clippy::large_enum_variant)]
+enum Attr {
+    Mod(ItemMod),
+    Type(TraitItemType),
+}
+
+impl Parse for Attr {
+    fn parse(input: ParseStream) -> parse::Result<Self> {
+        let lookahead = input.lookahead1();
+        if lookahead.peek(Token![mod]) {
+            input.parse().map(Attr::Mod)
+        } else if lookahead.peek(Token![type]) {
+            input.parse().map(Attr::Type)
+        } else {
+            Err(lookahead.error())
+        }
+    }
+}
+
+/// automock attributes
+#[derive(Debug, Default)]
+pub(crate) struct Attrs {
+    pub attrs: HashMap<Ident, Type>,
+    pub modname: Option<Ident>,
+}
+
+impl Attrs {
+    fn get_path(&self, path: &Path) -> Option<Type> {
+        if path.leading_colon.is_none() & (path.segments.len() == 2) {
+            if path.segments.first().unwrap().ident == "Self" {
+                let ident = &path.segments.last().unwrap().ident;
+                self.attrs.get(ident).cloned()
+            } else {
+                None
+            }
+        } else {
+            None
+        }
+    }
+
+    pub(crate) fn substitute_item_impl(&self, item_impl: &mut ItemImpl) {
+        let (_, trait_path, _) = item_impl
+            .trait_
+            .as_ref()
+            .expect("Should only be called for trait item impls");
+        let trait_ident = find_ident_from_path(trait_path).0;
+        for item in item_impl.items.iter_mut() {
+            if let ImplItem::Method(method) = item {
+                let sig = &mut method.sig;
+                for fn_arg in sig.inputs.iter_mut() {
+                    if let FnArg::Typed(arg) = fn_arg {
+                        self.substitute_type(&mut arg.ty, &trait_ident);
+                    }
+                }
+                if let ReturnType::Type(_, ref mut ty) = &mut sig.output {
+                    self.substitute_type(ty, &trait_ident);
+                }
+            }
+        }
+    }
+
+    fn substitute_path_segment(&self, seg: &mut PathSegment, traitname: &Ident) {
+        match &mut seg.arguments {
+            PathArguments::None =>
+            /* nothing to do */
+            {
+                ()
+            }
+            PathArguments::Parenthesized(p) => {
+                compile_error(p.span(),
+                    "Mockall does not support mocking Fn objects.  See https://github.com/asomers/mockall/issues/139");
+            }
+            PathArguments::AngleBracketed(abga) => {
+                for arg in abga.args.iter_mut() {
+                    match arg {
+                        GenericArgument::Type(ty) => self.substitute_type(ty, traitname),
+                        GenericArgument::Binding(binding) => {
+                            self.substitute_type(&mut binding.ty, traitname);
+                        }
+                        _ => {
+                            /*
+                             * Nothing to do, as long as lifetimes can't be
+                             * associated types
+                             */
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /// Recursively substitute types in the input
+    fn substitute_type(&self, ty: &mut Type, traitname: &Ident) {
+        match ty {
+            Type::Slice(s) => self.substitute_type(s.elem.as_mut(), traitname),
+            Type::Array(a) => self.substitute_type(a.elem.as_mut(), traitname),
+            Type::Ptr(p) => self.substitute_type(p.elem.as_mut(), traitname),
+            Type::Reference(r) => self.substitute_type(r.elem.as_mut(), traitname),
+            Type::BareFn(bfn) => {
+                for fn_arg in bfn.inputs.iter_mut() {
+                    self.substitute_type(&mut fn_arg.ty, traitname);
+                }
+                if let ReturnType::Type(_, ref mut ty) = &mut bfn.output {
+                    self.substitute_type(ty, traitname);
+                }
+            }
+            Type::Tuple(tuple) => {
+                for elem in tuple.elems.iter_mut() {
+                    self.substitute_type(elem, traitname)
+                }
+            }
+            Type::Path(path) => {
+                if let Some(ref qself) = path.qself {
+                    let qp = if let Type::Path(p) = qself.ty.as_ref() {
+                        &p.path
+                    } else {
+                        panic!("QSelf's type isn't a path?")
+                    };
+                    let qident = &qp.segments.first().unwrap().ident;
+                    if qself.position != 1
+                        || qp.segments.len() != 1
+                        || path.path.segments.len() != 2
+                        || qident != "Self"
+                    {
+                        compile_error(path.span(), "QSelf is a work in progress");
+                    }
+
+                    let mut seg_iter = path.path.segments.iter().rev();
+                    let last_seg = seg_iter.next().unwrap();
+                    let to_sub = &last_seg.ident;
+                    let penultimate_seg = seg_iter.next().unwrap();
+                    let qident = &penultimate_seg.ident;
+                    drop(seg_iter);
+
+                    if qident != traitname {
+                        compile_error(qident.span(),
+                            "Mockall does not support QSelf substitutions except for the trait being mocked");
+                    }
+                    if let Some(new_type) = self.attrs.get(to_sub) {
+                        *ty = new_type.clone();
+                    } else {
+                        compile_error(to_sub.span(), "Unknown type substitution for QSelf");
+                    }
+                } else if let Some(newty) = self.get_path(&path.path) {
+                    *ty = newty;
+                } else {
+                    for seg in path.path.segments.iter_mut() {
+                        self.substitute_path_segment(seg, traitname);
+                    }
+                }
+            }
+            Type::TraitObject(to) => {
+                for bound in to.bounds.iter_mut() {
+                    self.substitute_type_param_bound(bound, traitname);
+                }
+            }
+            Type::ImplTrait(it) => {
+                for bound in it.bounds.iter_mut() {
+                    self.substitute_type_param_bound(bound, traitname);
+                }
+            }
+            Type::Paren(p) => self.substitute_type(p.elem.as_mut(), traitname),
+            Type::Group(g) => self.substitute_type(g.elem.as_mut(), traitname),
+            Type::Macro(_) | Type::Verbatim(_) => {
+                compile_error(
+                    ty.span(),
+                    "mockall_derive does not support this type when using associated types",
+                );
+            }
+            Type::Infer(_) | Type::Never(_) => { /* Nothing to do */ }
+            _ => compile_error(ty.span(), "Unsupported type"),
+        }
+    }
+
+    fn substitute_type_param_bound(&self, bound: &mut TypeParamBound, traitname: &Ident) {
+        if let TypeParamBound::Trait(t) = bound {
+            match self.get_path(&t.path) {
+                None => {
+                    for seg in t.path.segments.iter_mut() {
+                        self.substitute_path_segment(seg, traitname);
+                    }
+                }
+                Some(Type::Path(type_path)) => {
+                    t.path = type_path.path;
+                }
+                Some(_) => {
+                    compile_error(t.path.span(), "Can only substitute paths for trait bounds");
+                }
+            }
+        }
+    }
+
+    pub(crate) fn substitute_trait(&self, item: &ItemTrait) -> ItemTrait {
+        let mut output = item.clone();
+        for trait_item in output.items.iter_mut() {
+            match trait_item {
+                TraitItem::Type(tity) => {
+                    if let Some(ty) = self.attrs.get(&tity.ident) {
+                        let span = tity.span();
+                        tity.default = Some((Token![=](span), ty.clone()));
+                        // Concrete associated types aren't allowed to have
+                        // bounds
+                        tity.bounds = Punctuated::new();
+                    } else {
+                        compile_error(tity.span(), "Default value not given for associated type");
+                    }
+                }
+                TraitItem::Method(method) => {
+                    let sig = &mut method.sig;
+                    for fn_arg in sig.inputs.iter_mut() {
+                        if let FnArg::Typed(arg) = fn_arg {
+                            self.substitute_type(&mut arg.ty, &item.ident);
+                        }
+                    }
+                    if let ReturnType::Type(_, ref mut ty) = &mut sig.output {
+                        self.substitute_type(ty, &item.ident);
+                    }
+                }
+                _ => {
+                    // Nothing to do
+                }
+            }
+        }
+        output
+    }
+}
+
+impl Parse for Attrs {
+    fn parse(input: ParseStream) -> parse::Result<Self> {
+        let mut attrs = HashMap::new();
+        let mut modname = None;
+        while !input.is_empty() {
+            let attr: Attr = input.parse()?;
+            match attr {
+                Attr::Mod(item_mod) => {
+                    if let Some((br, _)) = item_mod.content {
+                        compile_error(
+                            br.span,
+                            "mod name attributes must have the form \"mod my_name;\"",
+                        );
+                    }
+                    modname = Some(item_mod.ident.clone());
+                }
+                Attr::Type(trait_item_type) => {
+                    let ident = trait_item_type.ident.clone();
+                    if let Some((_, ty)) = trait_item_type.default {
+                        attrs.insert(ident, ty.clone());
+                    } else {
+                        compile_error(
+                            trait_item_type.span(),
+                            "automock type attributes must have a default value",
+                        );
+                    }
+                }
+            }
+        }
+        Ok(Attrs { attrs, modname })
+    }
+}
+
+/// Unit tests for `Attrs`.
+#[cfg(test)]
+mod t {
+    use super::super::*;
+
+    fn check_substitute_type(
+        attrs: TokenStream,
+        input: TokenStream,
+        traitname: Ident,
+        expected: TokenStream,
+    ) {
+        let _self: super::Attrs = parse2(attrs).unwrap();
+        let mut in_ty: Type = parse2(input).unwrap();
+        let expect_ty: Type = parse2(expected).unwrap();
+        _self.substitute_type(&mut in_ty, &traitname);
+        assert_eq!(in_ty, expect_ty);
+    }
+
+    #[test]
+    fn qself() {
+        check_substitute_type(
+            quote!(
+                type T = u32;
+            ),
+            quote!(<Self as Foo>::T),
+            format_ident!("Foo"),
+            quote!(u32),
+        );
+    }
+
+    #[test]
+    #[should_panic(
+        expected = "Mockall does not support QSelf substitutions except for the trait being mocked"
+    )]
+    fn qself_other() {
+        check_substitute_type(
+            quote!(
+                type T = u32;
+            ),
+            quote!(<Self as AsRef>::T),
+            format_ident!("Foo"),
+            quote!(u32),
+        );
+    }
+
+    #[test]
+    #[should_panic(expected = "Unknown type substitution for QSelf")]
+    fn unknown_substitution() {
+        check_substitute_type(
+            quote!(
+                type T = u32;
+            ),
+            quote!(<Self as Foo>::Q),
+            format_ident!("Foo"),
+            quote!(u32),
+        );
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..6308c45
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,1761 @@
+// vim: tw=80
+//! Proc Macros for use with Mockall
+//!
+//! You probably don't want to use this crate directly.  Instead, you should use
+//! its reexports via the [`mockall`](https://docs.rs/mockall/latest/mockall)
+//! crate.
+
+#![cfg_attr(feature = "nightly_derive", feature(proc_macro_diagnostic))]
+#![cfg_attr(test, deny(warnings))]
+
+use cfg_if::cfg_if;
+use proc_macro2::{Span, TokenStream};
+use quote::{ToTokens, format_ident, quote};
+use std::{
+    env,
+    hash::BuildHasherDefault
+};
+use syn::{
+    *,
+    punctuated::Punctuated,
+    spanned::Spanned
+};
+
+mod automock;
+mod mock_function;
+mod mock_item;
+mod mock_item_struct;
+mod mock_trait;
+mod mockable_item;
+mod mockable_struct;
+use crate::automock::Attrs;
+use crate::mockable_struct::MockableStruct;
+use crate::mock_item::MockItem;
+use crate::mock_item_struct::MockItemStruct;
+use crate::mockable_item::MockableItem;
+
+extern crate proc_macro;
+
+// Define deterministic aliases for these common types.
+type HashMap<K, V> = std::collections::HashMap<K, V, BuildHasherDefault<std::collections::hash_map::DefaultHasher>>;
+type HashSet<K> = std::collections::HashSet<K, BuildHasherDefault<std::collections::hash_map::DefaultHasher>>;
+
+cfg_if! {
+    // proc-macro2's Span::unstable method requires the nightly feature, and it
+    // doesn't work in test mode.
+    // https://github.com/alexcrichton/proc-macro2/issues/159
+    if #[cfg(all(feature = "nightly_derive", not(test)))] {
+        fn compile_error(span: Span, msg: &str) {
+            span.unstable()
+                .error(msg)
+                .emit();
+        }
+    } else {
+        fn compile_error(_span: Span, msg: &str) {
+            panic!("{}.  More information may be available when mockall is built with the \"nightly\" feature.", msg);
+        }
+    }
+}
+
+fn deanonymize_lifetime(lt: &mut Lifetime) {
+    if lt.ident == "_" {
+        lt.ident = format_ident!("static");
+    }
+}
+
+fn deanonymize_path(path: &mut Path) {
+    for seg in path.segments.iter_mut() {
+        match &mut seg.arguments {
+            PathArguments::None => (),
+            PathArguments::AngleBracketed(abga) => {
+                for ga in abga.args.iter_mut() {
+                    if let GenericArgument::Lifetime(lt) = ga {
+                        deanonymize_lifetime(lt)
+                    }
+                }
+            },
+            _ => compile_error(seg.arguments.span(),
+                "Methods returning functions are TODO"),
+        }
+    }
+}
+
+/// Replace any references to the anonymous lifetime `'_` with `'static`.
+fn deanonymize(literal_type: &mut Type) {
+    match literal_type {
+        Type::Array(ta) => deanonymize(ta.elem.as_mut()),
+        Type::BareFn(tbf) => {
+            if let ReturnType::Type(_, ref mut bt) = tbf.output {
+                deanonymize(bt.as_mut());
+            }
+            for input in tbf.inputs.iter_mut() {
+                deanonymize(&mut input.ty);
+            }
+        },
+        Type::Group(tg) => deanonymize(tg.elem.as_mut()),
+        Type::Infer(_) => (),
+        Type::Never(_) => (),
+        Type::Paren(tp) => deanonymize(tp.elem.as_mut()),
+        Type::Path(tp) => {
+            if let Some(ref mut qself) = tp.qself {
+                deanonymize(qself.ty.as_mut());
+            }
+            deanonymize_path(&mut tp.path);
+        },
+        Type::Ptr(tptr) => deanonymize(tptr.elem.as_mut()),
+        Type::Reference(tr) => {
+            if let Some(lt) = tr.lifetime.as_mut() {
+                deanonymize_lifetime(lt)
+            }
+            deanonymize(tr.elem.as_mut());
+        },
+        Type::Slice(s) => deanonymize(s.elem.as_mut()),
+        Type::TraitObject(tto) => {
+            for tpb in tto.bounds.iter_mut() {
+                match tpb {
+                    TypeParamBound::Trait(tb) => deanonymize_path(&mut tb.path),
+                    TypeParamBound::Lifetime(lt) => deanonymize_lifetime(lt),
+                }
+            }
+        },
+        Type::Tuple(tt) => {
+            for ty in tt.elems.iter_mut() {
+                deanonymize(ty)
+            }
+        }
+        x => compile_error(x.span(), "Unimplemented type for deanonymize")
+    }
+}
+
+// If there are any closures in the argument list, turn them into boxed
+// functions
+fn declosurefy(gen: &Generics, args: &Punctuated<FnArg, Token![,]>) ->
+    (Generics, Vec<FnArg>, Vec<TokenStream>)
+{
+    let mut hm = HashMap::default();
+
+    let mut save_fn_types = |ident: &Ident, tpb: &TypeParamBound| {
+        if let TypeParamBound::Trait(tb) = tpb {
+            let fident = &tb.path.segments.last().unwrap().ident;
+            if ["Fn", "FnMut", "FnOnce"].iter().any(|s| fident == *s) {
+                let newty: Type = parse2(quote!(Box<dyn #tb>)).unwrap();
+                let subst_ty: Type = parse2(quote!(#ident)).unwrap();
+                assert!(hm.insert(subst_ty, newty).is_none(),
+                    "A generic parameter had two Fn bounds?");
+            }
+        }
+    };
+
+    // First, build a HashMap of all Fn generic types
+    for g in gen.params.iter() {
+        if let GenericParam::Type(tp) = g {
+            for tpb in tp.bounds.iter() {
+                save_fn_types(&tp.ident, tpb);
+            }
+        }
+    }
+    if let Some(wc) = &gen.where_clause {
+        for pred in wc.predicates.iter() {
+            if let WherePredicate::Type(pt) = pred {
+                let bounded_ty = &pt.bounded_ty;
+                if let Ok(ident) = parse2::<Ident>(quote!(#bounded_ty)) {
+                    for tpb in pt.bounds.iter() {
+                        save_fn_types(&ident, tpb);
+                    }
+                } else {
+                    // We can't yet handle where clauses this complicated
+                }
+            }
+        }
+    }
+
+    // Then remove those types from both the Generics' params and where clause
+    let should_remove = |ident: &Ident| {
+            let ty: Type = parse2(quote!(#ident)).unwrap();
+            hm.contains_key(&ty)
+    };
+    let params = gen.params.iter()
+        .filter(|g| {
+            if let GenericParam::Type(tp) = g {
+                !should_remove(&tp.ident)
+            } else {
+                true
+            }
+        }).cloned()
+        .collect::<Punctuated<_, _>>();
+    let mut wc2 = gen.where_clause.clone();
+    if let Some(wc) = &mut wc2 {
+        wc.predicates = wc.predicates.iter()
+            .filter(|wp| {
+                if let WherePredicate::Type(pt) = wp {
+                    let bounded_ty = &pt.bounded_ty;
+                    if let Ok(ident) = parse2::<Ident>(quote!(#bounded_ty)) {
+                        !should_remove(&ident)
+                    } else {
+                        // We can't yet handle where clauses this complicated
+                        true
+                    }
+                } else {
+                    true
+                }
+            }).cloned()
+            .collect::<Punctuated<_, _>>();
+        if wc.predicates.is_empty() {
+            wc2 = None;
+        }
+    }
+    let outg = Generics {
+        lt_token: if params.is_empty() { None } else { gen.lt_token },
+        gt_token: if params.is_empty() { None } else { gen.gt_token },
+        params,
+        where_clause: wc2
+    };
+
+    // Next substitute Box<Fn> into the arguments
+    let outargs = args.iter().map(|arg| {
+        if let FnArg::Typed(pt) = arg {
+            let mut immutable_pt = pt.clone();
+            demutify_arg(&mut immutable_pt);
+            if let Some(newty) = hm.get(&pt.ty) {
+                FnArg::Typed(PatType {
+                    attrs: Vec::default(),
+                    pat: immutable_pt.pat,
+                    colon_token: pt.colon_token,
+                    ty: Box::new(newty.clone())
+                })
+            } else {
+                FnArg::Typed(PatType {
+                    attrs: Vec::default(),
+                    pat: immutable_pt.pat,
+                    colon_token: pt.colon_token,
+                    ty: pt.ty.clone()
+                })
+            }
+        } else {
+            arg.clone()
+        }
+    }).collect();
+
+    // Finally, Box any closure arguments
+    // use filter_map to remove the &self argument
+    let callargs = args.iter().filter_map(|arg| {
+        match arg {
+            FnArg::Typed(pt) => {
+                let mut pt2 = pt.clone();
+                demutify_arg(&mut pt2);
+                let pat = &pt2.pat;
+                if pat_is_self(pat) {
+                    None
+                } else if hm.contains_key(&pt.ty) {
+                    Some(quote!(Box::new(#pat)))
+                } else {
+                    Some(quote!(#pat))
+                }
+            },
+            FnArg::Receiver(_) => None,
+        }
+    }).collect();
+    (outg, outargs, callargs)
+}
+
+/// Replace any "impl trait" types with "Box<dyn trait>" or equivalent.
+fn deimplify(rt: &mut ReturnType) {
+    if let ReturnType::Type(_, ty) = rt {
+        if let Type::ImplTrait(ref tit) = &**ty {
+            let needs_pin = tit.bounds
+                .iter()
+                .any(|tpb| {
+                    if let TypeParamBound::Trait(tb) = tpb {
+                        if let Some(seg) = tb.path.segments.last() {
+                            seg.ident == "Future" || seg.ident == "Stream"
+                        } else {
+                            // It might still be a Future, but we can't guess
+                            // what names it might be imported under.  Too bad.
+                            false
+                        }
+                    } else {
+                        false
+                    }
+                });
+            let bounds = &tit.bounds;
+            if needs_pin {
+                *ty = parse2(quote!(::std::pin::Pin<Box<dyn #bounds>>)).unwrap();
+            } else {
+                *ty = parse2(quote!(Box<dyn #bounds>)).unwrap();
+            }
+        }
+    }
+}
+
+/// Remove any generics that place constraints on Self.
+fn dewhereselfify(generics: &mut Generics) {
+    if let Some(ref mut wc) = &mut generics.where_clause {
+        let new_predicates = wc.predicates.iter()
+            .filter(|wp| match wp {
+                WherePredicate::Type(pt) => {
+                    pt.bounded_ty != parse2(quote!(Self)).unwrap()
+                },
+                _ => true
+            }).cloned()
+            .collect::<Punctuated<WherePredicate, Token![,]>>();
+        wc.predicates = new_predicates;
+    }
+    if generics.where_clause.as_ref()
+        .map(|wc| wc.predicates.is_empty())
+        .unwrap_or(false)
+    {
+        generics.where_clause = None;
+    }
+}
+
+/// Remove any mutability qualifiers from a method's argument list
+fn demutify(inputs: &mut Punctuated<FnArg, token::Comma>) {
+    for arg in inputs.iter_mut() {
+        match arg {
+            FnArg::Receiver(r) => if r.reference.is_none() {
+                r.mutability = None
+            },
+            FnArg::Typed(pt) => demutify_arg(pt),
+        }
+    }
+}
+
+/// Remove any "mut" from a method argument's binding.
+fn demutify_arg(arg: &mut PatType) {
+    match *arg.pat {
+        Pat::Wild(_) => {
+            compile_error(arg.span(),
+                "Mocked methods must have named arguments");
+        },
+        Pat::Ident(ref mut pat_ident) => {
+            if let Some(r) = &pat_ident.by_ref {
+                compile_error(r.span(),
+                    "Mockall does not support by-reference argument bindings");
+            }
+            if let Some((_at, subpat)) = &pat_ident.subpat {
+                compile_error(subpat.span(),
+                    "Mockall does not support subpattern bindings");
+            }
+            pat_ident.mutability = None;
+        },
+        _ => {
+            compile_error(arg.span(), "Unsupported argument type");
+        }
+    };
+}
+
+fn deselfify_path(path: &mut Path, actual: &Ident, generics: &Generics) {
+    for seg in path.segments.iter_mut() {
+        if seg.ident == "Self" {
+            seg.ident = actual.clone();
+            if let PathArguments::None = seg.arguments {
+                if !generics.params.is_empty() {
+                    let args = generics.params.iter()
+                        .map(|gp| {
+                            match gp {
+                                GenericParam::Type(tp) => {
+                                    let ident = tp.ident.clone();
+                                    GenericArgument::Type(
+                                        Type::Path(
+                                            TypePath {
+                                                qself: None,
+                                                path: Path::from(ident)
+                                            }
+                                        )
+                                    )
+                                },
+                                GenericParam::Lifetime(ld) =>{
+                                    GenericArgument::Lifetime(
+                                        ld.lifetime.clone()
+                                    )
+                                }
+                                _ => unimplemented!(),
+                            }
+                        }).collect::<Punctuated<_, _>>();
+                    seg.arguments = PathArguments::AngleBracketed(
+                        AngleBracketedGenericArguments {
+                            colon2_token: None,
+                            lt_token: generics.lt_token.unwrap(),
+                            args,
+                            gt_token: generics.gt_token.unwrap(),
+                        }
+                    );
+                }
+            } else {
+                compile_error(seg.arguments.span(),
+                    "Type arguments after Self are unexpected");
+            }
+        }
+        if let PathArguments::AngleBracketed(abga) = &mut seg.arguments
+        {
+            for arg in abga.args.iter_mut() {
+                match arg {
+                    GenericArgument::Type(ty) =>
+                        deselfify(ty, actual, generics),
+                    GenericArgument::Binding(b) =>
+                        deselfify(&mut b.ty, actual, generics),
+                    _ => /* Nothing to do */(),
+                }
+            }
+        }
+    }
+}
+
+/// Replace any references to `Self` in `literal_type` with `actual`.
+/// `generics` is the Generics field of the parent struct.  Useful for
+/// constructor methods.
+fn deselfify(literal_type: &mut Type, actual: &Ident, generics: &Generics) {
+    match literal_type {
+        Type::Slice(s) => {
+            deselfify(s.elem.as_mut(), actual, generics);
+        },
+        Type::Array(a) => {
+            deselfify(a.elem.as_mut(), actual, generics);
+        },
+        Type::Ptr(p) => {
+            deselfify(p.elem.as_mut(), actual, generics);
+        },
+        Type::Reference(r) => {
+            deselfify(r.elem.as_mut(), actual, generics);
+        },
+        Type::Tuple(tuple) => {
+            for elem in tuple.elems.iter_mut() {
+                deselfify(elem, actual, generics);
+            }
+        }
+        Type::Path(type_path) => {
+            if let Some(ref mut qself) = type_path.qself {
+                deselfify(qself.ty.as_mut(), actual, generics);
+            }
+            deselfify_path(&mut type_path.path, actual, generics);
+        },
+        Type::Paren(p) => {
+            deselfify(p.elem.as_mut(), actual, generics);
+        },
+        Type::Group(g) => {
+            deselfify(g.elem.as_mut(), actual, generics);
+        },
+        Type::Macro(_) | Type::Verbatim(_) => {
+            compile_error(literal_type.span(),
+                "mockall_derive does not support this type as a return argument");
+        },
+        Type::TraitObject(tto) => {
+            // Change types like `dyn Self` into `dyn MockXXX`.
+            for bound in tto.bounds.iter_mut() {
+                if let TypeParamBound::Trait(t) = bound {
+                    deselfify_path(&mut t.path, actual, generics);
+                }
+            }
+        },
+        Type::ImplTrait(_) => {
+            /* Should've already been flagged as a compile_error */
+        },
+        Type::BareFn(_) => {
+            /* Bare functions can't have Self arguments.  Nothing to do */
+        },
+        Type::Infer(_) | Type::Never(_) =>
+        {
+            /* Nothing to do */
+        },
+        _ => compile_error(literal_type.span(), "Unsupported type"),
+    }
+}
+
+/// Change any `Self` in a method's arguments' types with `actual`.
+/// `generics` is the Generics field of the parent struct.
+fn deselfify_args(
+    args: &mut Punctuated<FnArg, Token![,]>,
+    actual: &Ident,
+    generics: &Generics)
+{
+    for arg in args.iter_mut() {
+        if let FnArg::Typed(pt) = arg {
+            deselfify(pt.ty.as_mut(), actual, generics)
+        }
+    }
+}
+
+fn find_ident_from_path(path: &Path) -> (Ident, PathArguments) {
+    if path.segments.len() != 1 {
+        compile_error(path.span(),
+            "mockall_derive only supports structs defined in the current module");
+        return (Ident::new("", path.span()), PathArguments::None);
+    }
+    let last_seg = path.segments.last().unwrap();
+    (last_seg.ident.clone(), last_seg.arguments.clone())
+}
+
+fn find_lifetimes_in_tpb(bound: &TypeParamBound) -> HashSet<Lifetime> {
+    let mut ret = HashSet::default();
+    match bound {
+        TypeParamBound::Lifetime(lt) => {
+            ret.insert(lt.clone());
+        },
+        TypeParamBound::Trait(tb) => {
+            ret.extend(find_lifetimes_in_path(&tb.path));
+        },
+    };
+    ret
+}
+
+fn find_lifetimes_in_path(path: &Path) -> HashSet<Lifetime> {
+    let mut ret = HashSet::default();
+    for seg in path.segments.iter() {
+        if let PathArguments::AngleBracketed(abga) = &seg.arguments {
+            for arg in abga.args.iter() {
+                match arg {
+                    GenericArgument::Lifetime(lt) => {
+                        ret.insert(lt.clone());
+                    },
+                    GenericArgument::Type(ty) => {
+                        ret.extend(find_lifetimes(ty));
+                    },
+                    GenericArgument::Binding(b) => {
+                        ret.extend(find_lifetimes(&b.ty));
+                    },
+                    GenericArgument::Constraint(c) => {
+                        for bound in c.bounds.iter() {
+                            ret.extend(find_lifetimes_in_tpb(bound));
+                        }
+                    },
+                    GenericArgument::Const(_) => ()
+                }
+            }
+        }
+    }
+    ret
+}
+
+fn find_lifetimes(ty: &Type) -> HashSet<Lifetime> {
+    match ty {
+        Type::Array(ta) => find_lifetimes(ta.elem.as_ref()),
+        Type::Group(tg) => find_lifetimes(tg.elem.as_ref()),
+        Type::Infer(_ti) => HashSet::default(),
+        Type::Never(_tn) => HashSet::default(),
+        Type::Paren(tp) => find_lifetimes(tp.elem.as_ref()),
+        Type::Path(tp) => {
+            let mut ret = find_lifetimes_in_path(&tp.path);
+            if let Some(qs) = &tp.qself {
+                ret.extend(find_lifetimes(qs.ty.as_ref()));
+            }
+            ret
+        },
+        Type::Ptr(tp) => find_lifetimes(tp.elem.as_ref()),
+        Type::Reference(tr) => {
+            let mut ret = find_lifetimes(tr.elem.as_ref());
+            if let Some(lt) = &tr.lifetime {
+                ret.insert(lt.clone());
+            }
+            ret
+        },
+        Type::Slice(ts) => find_lifetimes(ts.elem.as_ref()),
+        Type::TraitObject(tto) => {
+            let mut ret = HashSet::default();
+            for bound in tto.bounds.iter() {
+                ret.extend(find_lifetimes_in_tpb(bound));
+            }
+            ret
+        }
+        Type::Tuple(tt) => {
+            let mut ret = HashSet::default();
+            for ty in tt.elems.iter() {
+                ret.extend(find_lifetimes(ty));
+            }
+            ret
+        },
+        Type::ImplTrait(tit) => {
+            let mut ret = HashSet::default();
+            for tpb in tit.bounds.iter() {
+                ret.extend(find_lifetimes_in_tpb(tpb));
+            }
+            ret
+        },
+        _ => {
+            compile_error(ty.span(), "unsupported type in this context");
+            HashSet::default()
+        }
+    }
+}
+
+
+struct AttrFormatter<'a>{
+    attrs: &'a [Attribute],
+    async_trait: bool,
+    doc: bool,
+}
+
+impl<'a> AttrFormatter<'a> {
+    fn new(attrs: &'a [Attribute]) -> AttrFormatter<'a> {
+        Self {
+            attrs,
+            async_trait: true,
+            doc: true
+        }
+    }
+
+    fn async_trait(&mut self, allowed: bool) -> &mut Self {
+        self.async_trait = allowed;
+        self
+    }
+
+    fn doc(&mut self, allowed: bool) -> &mut Self {
+        self.doc = allowed;
+        self
+    }
+
+    // XXX This logic requires that attributes are imported with their
+    // standard names.
+    #[allow(clippy::needless_bool)]
+    #[allow(clippy::if_same_then_else)]
+    fn format(&mut self) -> Vec<Attribute> {
+        self.attrs.iter()
+            .cloned()
+            .filter(|attr| {
+                let i = attr.path.get_ident();
+                if i.is_none() {
+                    false
+                } else if *i.as_ref().unwrap() == "derive" {
+                    // We can't usefully derive any traits.  Ignore them
+                    false
+                } else if *i.as_ref().unwrap() == "doc" {
+                    self.doc
+                } else if *i.as_ref().unwrap() == "async_trait" {
+                    self.async_trait
+                } else if *i.as_ref().unwrap() == "instrument" {
+                    // We can't usefully instrument the mock method, so just
+                    // ignore this attribute.
+                    // https://docs.rs/tracing/0.1.23/tracing/attr.instrument.html
+                    false
+                } else {
+                    true
+                }
+            }).collect()
+    }
+}
+
+/// Determine if this Pat is any kind of `self` binding
+fn pat_is_self(pat: &Pat) -> bool {
+    if let Pat::Ident(pi) = pat {
+        pi.ident == "self"
+    } else {
+        false
+    }
+}
+
+/// Add `levels` `super::` to the path.  Return the number of levels added.
+fn supersuperfy_path(path: &mut Path, levels: usize) -> usize {
+    if let Some(t) = path.segments.last_mut() {
+        match &mut t.arguments {
+            PathArguments::None => (),
+            PathArguments::AngleBracketed(ref mut abga) => {
+                for arg in abga.args.iter_mut() {
+                    match arg {
+                        GenericArgument::Type(ref mut ty) => {
+                            *ty = supersuperfy(ty, levels);
+                        },
+                        GenericArgument::Binding(ref mut binding) => {
+                            binding.ty = supersuperfy(&binding.ty, levels);
+                        },
+                        GenericArgument::Constraint(ref mut constraint) => {
+                            supersuperfy_bounds(&mut constraint.bounds, levels);
+                        },
+                        _ => (),
+                    }
+                }
+            },
+            PathArguments::Parenthesized(ref mut pga) => {
+                for input in pga.inputs.iter_mut() {
+                    *input = supersuperfy(input, levels);
+                }
+                if let ReturnType::Type(_, ref mut ty) = pga.output {
+                    *ty = Box::new(supersuperfy(ty, levels));
+                }
+            },
+        }
+    }
+    if let Some(t) = path.segments.first() {
+        if t.ident == "super" {
+            let mut ident = format_ident!("super");
+            ident.set_span(path.segments.span());
+            let ps = PathSegment {
+                ident,
+                arguments: PathArguments::None
+            };
+            for _ in 0..levels {
+                path.segments.insert(0, ps.clone());
+            }
+            levels
+        } else {
+            0
+        }
+    } else {
+        0
+    }
+}
+
+/// Replace any references to `super::X` in `original` with `super::super::X`.
+fn supersuperfy(original: &Type, levels: usize) -> Type {
+    let mut output = original.clone();
+    fn recurse(t: &mut Type, levels: usize) {
+        match t {
+            Type::Slice(s) => {
+                recurse(s.elem.as_mut(), levels);
+            },
+            Type::Array(a) => {
+                recurse(a.elem.as_mut(), levels);
+            },
+            Type::Ptr(p) => {
+                recurse(p.elem.as_mut(), levels);
+            },
+            Type::Reference(r) => {
+                recurse(r.elem.as_mut(), levels);
+            },
+            Type::BareFn(bfn) => {
+                if let ReturnType::Type(_, ref mut bt) = bfn.output {
+                    recurse(bt.as_mut(), levels);
+                }
+                for input in bfn.inputs.iter_mut() {
+                    recurse(&mut input.ty, levels);
+                }
+            },
+            Type::Tuple(tuple) => {
+                for elem in tuple.elems.iter_mut() {
+                    recurse(elem, levels);
+                }
+            }
+            Type::Path(type_path) => {
+                let added = supersuperfy_path(&mut type_path.path, levels);
+                if let Some(ref mut qself) = type_path.qself {
+                    recurse(qself.ty.as_mut(), levels);
+                    qself.position += added;
+                }
+            },
+            Type::Paren(p) => {
+                recurse(p.elem.as_mut(), levels);
+            },
+            Type::Group(g) => {
+                recurse(g.elem.as_mut(), levels);
+            },
+            Type::Macro(_) | Type::Verbatim(_) => {
+                compile_error(t.span(),
+                    "mockall_derive does not support this type in this position");
+            },
+            Type::TraitObject(tto) => {
+                for bound in tto.bounds.iter_mut() {
+                    if let TypeParamBound::Trait(tb) = bound {
+                        supersuperfy_path(&mut tb.path, levels);
+                    }
+                }
+            },
+            Type::ImplTrait(_) => {
+                /* Should've already been flagged as a compile error */
+            },
+            Type::Infer(_) | Type::Never(_) =>
+            {
+                /* Nothing to do */
+            },
+            _ => compile_error(t.span(), "Unsupported type"),
+        }
+    }
+    recurse(&mut output, levels);
+    output
+}
+
+fn supersuperfy_generics(generics: &mut Generics, levels: usize) {
+    for param in generics.params.iter_mut() {
+        if let GenericParam::Type(tp) = param {
+            supersuperfy_bounds(&mut tp.bounds, levels);
+            if let Some(ty) = tp.default.as_mut() {
+                *ty = supersuperfy(ty, levels);
+            }
+        }
+    }
+    if let Some(wc) = generics.where_clause.as_mut() {
+        for wp in wc.predicates.iter_mut() {
+            if let WherePredicate::Type(pt) = wp {
+                pt.bounded_ty = supersuperfy(&pt.bounded_ty, levels);
+                supersuperfy_bounds(&mut pt.bounds, levels);
+            }
+        }
+    }
+}
+
+fn supersuperfy_bounds(
+    bounds: &mut Punctuated<TypeParamBound, Token![+]>,
+    levels: usize)
+{
+    for bound in bounds.iter_mut() {
+        if let TypeParamBound::Trait(tb) = bound {
+            supersuperfy_path(&mut tb.path, levels);
+        }
+    }
+}
+
+/// Generate a suitable mockall::Key generic paramter from any Generics
+fn gen_keyid(g: &Generics) -> impl ToTokens {
+    match g.params.len() {
+        0 => quote!(<()>),
+        1 => {
+            let (_, tg, _) = g.split_for_impl();
+            quote!(#tg)
+        },
+        _ => {
+            // Rust doesn't support variadic Generics, so mockall::Key must
+            // always have exactly one generic type.  We need to add parentheses
+            // around whatever type generics the caller passes.
+            let tps = g.type_params()
+            .map(|tp| tp.ident.clone())
+            .collect::<Punctuated::<Ident, Token![,]>>();
+            quote!(<(#tps)>)
+        }
+    }
+}
+
+/// Generate a mock identifier from the regular one: eg "Foo" => "MockFoo"
+fn gen_mock_ident(ident: &Ident) -> Ident {
+    format_ident!("Mock{}", ident)
+}
+
+/// Generate an identifier for the mock struct's private module: eg "Foo" =>
+/// "__mock_Foo"
+fn gen_mod_ident(struct_: &Ident, trait_: Option<&Ident>) -> Ident {
+    if let Some(t) = trait_ {
+        format_ident!("__mock_{}_{}", struct_, t)
+    } else {
+        format_ident!("__mock_{}", struct_)
+    }
+}
+
+/// Combine two Generics structs, producing a new one that has the union of
+/// their parameters.
+fn merge_generics(x: &Generics, y: &Generics) -> Generics {
+    /// Compare only the identifiers of two GenericParams
+    fn cmp_gp_idents(x: &GenericParam, y: &GenericParam) -> bool {
+        use GenericParam::*;
+
+        match (x, y) {
+            (Type(xtp), Type(ytp)) => xtp.ident == ytp.ident,
+            (Lifetime(xld), Lifetime(yld)) => xld.lifetime == yld.lifetime,
+            (Const(xc), Const(yc)) => xc.ident == yc.ident,
+            _ => false
+        }
+    }
+
+    /// Compare only the identifiers of two WherePredicates
+    fn cmp_wp_idents(x: &WherePredicate, y: &WherePredicate) -> bool {
+        use WherePredicate::*;
+
+        match (x, y) {
+            (Type(xpt), Type(ypt)) => xpt.bounded_ty == ypt.bounded_ty,
+            (Lifetime(xpl), Lifetime(ypl)) => xpl.lifetime == ypl.lifetime,
+            (Eq(xeq), Eq(yeq)) => xeq.lhs_ty == yeq.lhs_ty,
+            _ => false
+        }
+    }
+
+    let mut out = if x.lt_token.is_none() && x.where_clause.is_none() {
+        y.clone()
+    } else if y.lt_token.is_none() && y.where_clause.is_none() {
+        x.clone()
+    } else {
+        let mut out = x.clone();
+        // First merge the params
+        'outer_param: for yparam in y.params.iter() {
+            // XXX: O(n^2) loop
+            for outparam in out.params.iter_mut() {
+                if cmp_gp_idents(outparam, yparam) {
+                    if let (GenericParam::Type(ref mut ot),
+                            GenericParam::Type(yt)) = (outparam, yparam)
+                    {
+                        ot.attrs.extend(yt.attrs.iter().cloned());
+                        ot.colon_token = ot.colon_token.or(yt.colon_token);
+                        ot.eq_token = ot.eq_token.or(yt.eq_token);
+                        if ot.default.is_none() {
+                            ot.default = yt.default.clone();
+                        }
+                        // XXX this might result in duplicate bounds
+                        if ot.bounds != yt.bounds {
+                            ot.bounds.extend(yt.bounds.iter().cloned());
+                        }
+                    }
+                    continue 'outer_param;
+                }
+            }
+            out.params.push(yparam.clone());
+        }
+        out
+    };
+    // Then merge the where clauses
+    match (&mut out.where_clause, &y.where_clause) {
+        (_, None) => (),
+        (None, Some(wc)) => out.where_clause = Some(wc.clone()),
+        (Some(out_wc), Some(y_wc)) => {
+            'outer_wc: for ypred in y_wc.predicates.iter() {
+                // XXX: O(n^2) loop
+                for outpred in out_wc.predicates.iter_mut() {
+                    if cmp_wp_idents(outpred, ypred) {
+                        if let (WherePredicate::Type(ref mut ot),
+                                WherePredicate::Type(yt)) = (outpred, ypred)
+                        {
+                            match (&mut ot.lifetimes, &yt.lifetimes) {
+                                (_, None) => (),
+                                (None, Some(bl)) =>
+                                    ot.lifetimes = Some(bl.clone()),
+                                (Some(obl), Some(ybl)) =>
+                                    // XXX: might result in duplicates
+                                    obl.lifetimes.extend(
+                                        ybl.lifetimes.iter().cloned()),
+                            };
+                            // XXX: might result in duplicate bounds
+                            if ot.bounds != yt.bounds {
+                                ot.bounds.extend(yt.bounds.iter().cloned())
+                            }
+                        }
+                        continue 'outer_wc;
+                    }
+                }
+                out_wc.predicates.push(ypred.clone());
+            }
+        }
+    }
+    out
+}
+
+/// Transform a Vec of lifetimes into a Generics
+fn lifetimes_to_generics(lv: &Punctuated<LifetimeDef, Token![,]>)-> Generics {
+    if lv.is_empty() {
+            Generics::default()
+    } else {
+        let params = lv.iter()
+            .map(|lt| GenericParam::Lifetime(lt.clone()))
+            .collect();
+        Generics {
+            lt_token: Some(Token![<](lv[0].span())),
+            gt_token: Some(Token![>](lv[0].span())),
+            params,
+            where_clause: None
+        }
+    }
+}
+
+/// Split a generics list into three: one for type generics and where predicates
+/// that relate to the signature, one for lifetimes that relate to the arguments
+/// only, and one for lifetimes that relate to the return type only.
+fn split_lifetimes(
+    generics: Generics,
+    args: &[FnArg],
+    rt: &ReturnType)
+    -> (Generics,
+        Punctuated<LifetimeDef, token::Comma>,
+        Punctuated<LifetimeDef, token::Comma>)
+{
+    if generics.lt_token.is_none() {
+        return (generics, Default::default(), Default::default());
+    }
+
+    // Check which types and lifetimes are referenced by the arguments
+    let mut alts = HashSet::<Lifetime>::default();
+    let mut rlts = HashSet::<Lifetime>::default();
+    for arg in args {
+        match arg {
+            FnArg::Receiver(r) => {
+                if let Some((_, Some(lt))) = &r.reference {
+                    alts.insert(lt.clone());
+                }
+            },
+            FnArg::Typed(pt) => {
+                alts.extend(find_lifetimes(pt.ty.as_ref()));
+            },
+        };
+    };
+
+    if let ReturnType::Type(_, ty) = rt {
+        rlts.extend(find_lifetimes(ty));
+    }
+
+    let mut tv = Punctuated::new();
+    let mut alv = Punctuated::new();
+    let mut rlv = Punctuated::new();
+    for p in generics.params.into_iter() {
+        match p {
+            GenericParam::Lifetime(ltd) if rlts.contains(&ltd.lifetime) =>
+                rlv.push(ltd),
+            GenericParam::Lifetime(ltd) if alts.contains(&ltd.lifetime) =>
+                alv.push(ltd),
+            GenericParam::Lifetime(_) => {
+                // Probably a lifetime parameter from the impl block that isn't
+                // used by this particular method
+            },
+            GenericParam::Type(_) => tv.push(p),
+            _ => (),
+        }
+    }
+
+    let tg = if tv.is_empty() {
+        Generics::default()
+    } else {
+        Generics {
+            lt_token: generics.lt_token,
+            gt_token: generics.gt_token,
+            params: tv,
+            where_clause: generics.where_clause
+        }
+    };
+
+    (tg, alv, rlv)
+}
+
+/// Return the visibility that should be used for expectation!, given the
+/// original method's visibility.
+///
+/// # Arguments
+/// - `vis`:    Original visibility of the item
+/// - `levels`: How many modules will the mock item be nested in?
+fn expectation_visibility(vis: &Visibility, levels: usize)
+    -> Visibility
+{
+    if levels == 0 {
+        return vis.clone();
+    }
+
+    let in_token = Token![in](vis.span());
+    let super_token = Token![super](vis.span());
+    match vis {
+        Visibility::Inherited => {
+            // Private items need pub(in super::[...]) for each level
+            let mut path = Path::from(super_token);
+            for _ in 1..levels {
+                path.segments.push(super_token.into());
+            }
+            Visibility::Restricted(VisRestricted{
+                pub_token: Token![pub](vis.span()),
+                paren_token: token::Paren::default(),
+                in_token: Some(in_token),
+                path: Box::new(path)
+            })
+        },
+        Visibility::Restricted(vr) => {
+            // crate => don't change
+            // in crate::* => don't change
+            // super => in super::super::super
+            // self => in super::super
+            // in anything_else => super::super::anything_else
+            if vr.path.segments.first().unwrap().ident == "crate" {
+                vr.clone().into()
+            } else {
+                let mut out = vr.clone();
+                out.in_token = Some(in_token);
+                for _ in 0..levels {
+                    out.path.segments.insert(0, super_token.into());
+                }
+                out.into()
+            }
+        },
+        _ => vis.clone()
+    }
+}
+
+fn staticize(generics: &Generics) -> Generics {
+    let mut ret = generics.clone();
+    for lt in ret.lifetimes_mut() {
+        lt.lifetime = Lifetime::new("'static", Span::call_site());
+    };
+    ret
+}
+
+fn mock_it<M: Into<MockableItem>>(inputs: M) -> TokenStream
+{
+    let mockable: MockableItem = inputs.into();
+    let mock = MockItem::from(mockable);
+    let ts = mock.into_token_stream();
+    if env::var("MOCKALL_DEBUG").is_ok() {
+        println!("{}", ts);
+    }
+    ts
+}
+
+fn do_mock_once(input: TokenStream) -> TokenStream
+{
+    let item: MockableStruct = match syn::parse2(input) {
+        Ok(mock) => mock,
+        Err(err) => {
+            return err.to_compile_error();
+        }
+    };
+    mock_it(item)
+}
+
+fn do_mock(input: TokenStream) -> TokenStream
+{
+    cfg_if! {
+        if #[cfg(reprocheck)] {
+            let ts_a = do_mock_once(input.clone());
+            let ts_b = do_mock_once(input.clone());
+            assert_eq!(ts_a.to_string(), ts_b.to_string());
+        }
+    }
+    do_mock_once(input)
+}
+
+#[proc_macro]
+pub fn mock(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    do_mock(input.into()).into()
+}
+
+#[proc_macro_attribute]
+pub fn automock(attrs: proc_macro::TokenStream, input: proc_macro::TokenStream)
+    -> proc_macro::TokenStream
+{
+    let attrs: proc_macro2::TokenStream = attrs.into();
+    let input: proc_macro2::TokenStream = input.into();
+    do_automock(attrs, input).into()
+}
+
+fn do_automock_once(attrs: TokenStream, input: TokenStream) -> TokenStream {
+    let mut output = input.clone();
+    let attrs: Attrs = match parse2(attrs) {
+        Ok(a) => a,
+        Err(err) => {
+            return err.to_compile_error();
+        }
+    };
+    let item: Item = match parse2(input) {
+        Ok(item) => item,
+        Err(err) => {
+            return err.to_compile_error();
+        }
+    };
+    output.extend(mock_it((attrs, item)));
+    output
+}
+
+fn do_automock(attrs: TokenStream, input: TokenStream) -> TokenStream {
+    cfg_if! {
+        if #[cfg(reprocheck)] {
+            let ts_a = do_automock_once(attrs.clone(), input.clone());
+            let ts_b = do_automock_once(attrs.clone(), input.clone());
+            assert_eq!(ts_a.to_string(), ts_b.to_string());
+        }
+    }
+    do_automock_once(attrs, input)
+}
+
+#[cfg(test)]
+mod t {
+    use super::*;
+
+fn assert_contains(output: &str, tokens: TokenStream) {
+    let s = tokens.to_string();
+    assert!(output.contains(&s), "output does not contain {:?}", &s);
+}
+
+fn assert_not_contains(output: &str, tokens: TokenStream) {
+    let s = tokens.to_string();
+    assert!(!output.contains(&s), "output does not contain {:?}", &s);
+}
+
+/// Various tests for overall code generation that are hard or impossible to
+/// write as integration tests
+mod mock {
+    use std::str::FromStr;
+    use super::super::*;
+    use super::*;
+
+    #[test]
+    fn inherent_method_visibility() {
+        let code = r#"
+            Foo {
+                fn foo(&self);
+                pub fn bar(&self);
+                pub(crate) fn baz(&self);
+                pub(super) fn bean(&self);
+                pub(in crate::outer) fn boom(&self);
+            }
+        "#;
+        let ts = proc_macro2::TokenStream::from_str(code).unwrap();
+        let output = do_mock(ts).to_string();
+        assert_not_contains(&output, quote!(pub fn foo));
+        assert!(!output.contains(") fn foo"));
+        assert_contains(&output, quote!(pub fn bar));
+        assert_contains(&output, quote!(pub(crate) fn baz));
+        assert_contains(&output, quote!(pub(super) fn bean));
+        assert_contains(&output, quote!(pub(in crate::outer) fn boom));
+
+        assert_not_contains(&output, quote!(pub fn expect_foo));
+        assert!(!output.contains("pub fn expect_foo"));
+        assert!(!output.contains(") fn expect_foo"));
+        assert_contains(&output, quote!(pub fn expect_bar));
+        assert_contains(&output, quote!(pub(crate) fn expect_baz));
+        assert_contains(&output, quote!(pub(super) fn expect_bean));
+        assert_contains(&output, quote!(pub(in crate::outer) fn expect_boom));
+    }
+
+    #[test]
+    fn specific_impl() {
+        let code = r#"
+            pub Foo<T: 'static> {}
+            impl Bar for Foo<u32> {
+                fn bar(&self);
+            }
+            impl Bar for Foo<i32> {
+                fn bar(&self);
+            }
+        "#;
+        let ts = proc_macro2::TokenStream::from_str(code).unwrap();
+        let output = do_mock(ts).to_string();
+        assert_contains(&output, quote!(impl Bar for MockFoo<u32>));
+        assert_contains(&output, quote!(impl Bar for MockFoo<i32>));
+        // Ensure we don't duplicate the checkpoint function
+        assert_not_contains(&output, quote!(
+            self.Bar_expectations.checkpoint();
+            self.Bar_expectations.checkpoint();
+        ));
+        // The expect methods should return specific types, not generic ones
+        assert_contains(&output, quote!(
+            pub fn expect_bar(&mut self) -> &mut __mock_MockFoo_Bar::__bar::Expectation<u32>
+        ));
+        assert_contains(&output, quote!(
+            pub fn expect_bar(&mut self) -> &mut __mock_MockFoo_Bar::__bar::Expectation<i32>
+        ));
+    }
+}
+
+/// Various tests for overall code generation that are hard or impossible to
+/// write as integration tests
+mod automock {
+    use std::str::FromStr;
+    use super::super::*;
+    use super::*;
+
+    #[test]
+    fn doc_comments() {
+        let code = r#"
+            mod foo {
+                /// Function docs
+                pub fn bar() { unimplemented!() }
+            }
+        "#;
+        let ts = proc_macro2::TokenStream::from_str(code).unwrap();
+        let attrs_ts = proc_macro2::TokenStream::from_str("").unwrap();
+        let output = do_automock(attrs_ts, ts).to_string();
+        assert_contains(&output, quote!(#[doc=" Function docs"] pub fn bar));
+    }
+
+    #[test]
+    fn method_visibility() {
+        let code = r#"
+        impl Foo {
+            fn foo(&self) {}
+            pub fn bar(&self) {}
+            pub(super) fn baz(&self) {}
+            pub(crate) fn bang(&self) {}
+            pub(in super::x) fn bean(&self) {}
+        }"#;
+        let ts = proc_macro2::TokenStream::from_str(code).unwrap();
+        let attrs_ts = proc_macro2::TokenStream::from_str("").unwrap();
+        let output = do_automock(attrs_ts, ts).to_string();
+        assert_not_contains(&output, quote!(pub fn foo));
+        assert!(!output.contains(") fn foo"));
+        assert_not_contains(&output, quote!(pub fn expect_foo));
+        assert!(!output.contains(") fn expect_foo"));
+        assert_contains(&output, quote!(pub fn bar));
+        assert_contains(&output, quote!(pub fn expect_bar));
+        assert_contains(&output, quote!(pub(super) fn baz));
+        assert_contains(&output, quote!(pub(super) fn expect_baz));
+        assert_contains(&output, quote!(pub ( crate ) fn bang));
+        assert_contains(&output, quote!(pub ( crate ) fn expect_bang));
+        assert_contains(&output, quote!(pub ( in super :: x ) fn bean));
+        assert_contains(&output, quote!(pub ( in super :: x ) fn expect_bean));
+    }
+
+    #[test]
+    #[should_panic(expected = "can only mock inline modules")]
+    fn external_module() {
+        let code = r#"mod foo;"#;
+        let ts = proc_macro2::TokenStream::from_str(code).unwrap();
+        let attrs_ts = proc_macro2::TokenStream::from_str("").unwrap();
+        do_automock(attrs_ts, ts).to_string();
+    }
+
+    #[test]
+    fn trait_visibility() {
+        let code = r#"
+        pub(super) trait Foo {}
+        "#;
+        let attrs_ts = proc_macro2::TokenStream::from_str("").unwrap();
+        let ts = proc_macro2::TokenStream::from_str(code).unwrap();
+        let output = do_automock(attrs_ts, ts).to_string();
+        assert_contains(&output, quote!(pub ( super ) struct MockFoo));
+    }
+}
+
+mod deimplify {
+    use super::*;
+
+    fn check_deimplify(orig_ts: TokenStream, expected_ts: TokenStream) {
+        let mut orig: ReturnType = parse2(orig_ts).unwrap();
+        let expected: ReturnType = parse2(expected_ts).unwrap();
+        deimplify(&mut orig);
+        assert_eq!(quote!(#orig).to_string(), quote!(#expected).to_string());
+    }
+
+    // Future is a special case
+    #[test]
+    fn impl_future() {
+        check_deimplify(
+            quote!(-> impl Future<Output=i32>),
+            quote!(-> ::std::pin::Pin<Box<dyn Future<Output=i32>>>)
+        );
+    }
+
+    // Future is a special case, wherever it appears
+    #[test]
+    fn impl_future_reverse() {
+        check_deimplify(
+            quote!(-> impl Send + Future<Output=i32>),
+            quote!(-> ::std::pin::Pin<Box<dyn Send + Future<Output=i32>>>)
+        );
+    }
+
+    // Stream is a special case
+    #[test]
+    fn impl_stream() {
+        check_deimplify(
+            quote!(-> impl Stream<Item=i32>),
+            quote!(-> ::std::pin::Pin<Box<dyn Stream<Item=i32>>>)
+        );
+    }
+
+    #[test]
+    fn impl_trait() {
+        check_deimplify(
+            quote!(-> impl Foo),
+            quote!(-> Box<dyn Foo>)
+        );
+    }
+
+    // With extra bounds
+    #[test]
+    fn impl_trait2() {
+        check_deimplify(
+            quote!(-> impl Foo + Send),
+            quote!(-> Box<dyn Foo + Send>)
+        );
+    }
+}
+
+mod deselfify {
+    use super::*;
+
+    fn check_deselfify(
+        orig_ts: TokenStream,
+        actual_ts: TokenStream,
+        generics_ts: TokenStream,
+        expected_ts: TokenStream)
+    {
+        let mut ty: Type = parse2(orig_ts).unwrap();
+        let actual: Ident = parse2(actual_ts).unwrap();
+        let generics: Generics = parse2(generics_ts).unwrap();
+        let expected: Type = parse2(expected_ts).unwrap();
+        deselfify(&mut ty, &actual, &generics);
+        assert_eq!(quote!(#ty).to_string(),
+                   quote!(#expected).to_string());
+    }
+
+    #[test]
+    fn future() {
+        check_deselfify(
+            quote!(Box<dyn Future<Output=Self>>),
+            quote!(Foo),
+            quote!(),
+            quote!(Box<dyn Future<Output=Foo>>)
+        );
+    }
+
+    #[test]
+    fn qself() {
+        check_deselfify(
+            quote!(<Self as Self>::Self),
+            quote!(Foo),
+            quote!(),
+            quote!(<Foo as Foo>::Foo)
+        );
+    }
+
+    #[test]
+    fn trait_object() {
+        check_deselfify(
+            quote!(Box<dyn Self>),
+            quote!(Foo),
+            quote!(),
+            quote!(Box<dyn Foo>)
+        );
+    }
+
+    // A trait object with multiple bounds
+    #[test]
+    fn trait_object2() {
+        check_deselfify(
+            quote!(Box<dyn Self + Send>),
+            quote!(Foo),
+            quote!(),
+            quote!(Box<dyn Foo + Send>)
+        );
+    }
+}
+
+mod dewhereselfify {
+    use super::*;
+
+    #[test]
+    fn lifetime() {
+        let mut meth: ImplItemMethod = parse2(quote!(
+                fn foo<'a>(&self) where 'a: 'static, Self: Sized;
+        )).unwrap();
+        let expected: ImplItemMethod = parse2(quote!(
+                fn foo<'a>(&self) where 'a: 'static;
+        )).unwrap();
+        dewhereselfify(&mut meth.sig.generics);
+        assert_eq!(meth, expected);
+    }
+
+    #[test]
+    fn normal_method() {
+        let mut meth: ImplItemMethod = parse2(quote!(
+                fn foo(&self) where Self: Sized;
+        )).unwrap();
+        let expected: ImplItemMethod = parse2(quote!(
+                fn foo(&self);
+        )).unwrap();
+        dewhereselfify(&mut meth.sig.generics);
+        assert_eq!(meth, expected);
+    }
+
+    #[test]
+    fn with_real_generics() {
+        let mut meth: ImplItemMethod = parse2(quote!(
+                fn foo<T>(&self, t: T) where Self: Sized, T: Copy;
+        )).unwrap();
+        let expected: ImplItemMethod = parse2(quote!(
+                fn foo<T>(&self, t: T) where T: Copy;
+        )).unwrap();
+        dewhereselfify(&mut meth.sig.generics);
+        assert_eq!(meth, expected);
+    }
+}
+
+mod gen_keyid {
+    use super::*;
+
+    fn check_gen_keyid(orig: TokenStream, expected: TokenStream) {
+        let g: Generics = parse2(orig).unwrap();
+        let keyid = gen_keyid(&g);
+        assert_eq!(quote!(#keyid).to_string(), quote!(#expected).to_string());
+    }
+
+    #[test]
+    fn empty() {
+        check_gen_keyid(quote!(), quote!(<()>));
+    }
+
+    #[test]
+    fn onetype() {
+        check_gen_keyid(quote!(<T>), quote!(<T>));
+    }
+
+    #[test]
+    fn twotypes() {
+        check_gen_keyid(quote!(<T, V>), quote!(<(T, V)>));
+    }
+}
+
+mod merge_generics {
+    use super::*;
+
+    #[test]
+    fn both() {
+        let mut g1: Generics = parse2(quote!(<T: 'static, V: Copy> )).unwrap();
+        let wc1: WhereClause = parse2(quote!(where T: Default)).unwrap();
+        g1.where_clause = Some(wc1);
+
+        let mut g2: Generics = parse2(quote!(<Q: Send, V: Clone>)).unwrap();
+        let wc2: WhereClause = parse2(quote!(where T: Sync, Q: Debug)).unwrap();
+        g2.where_clause = Some(wc2);
+
+        let gm = super::merge_generics(&g1, &g2);
+        let gm_wc = &gm.where_clause;
+
+        let ge: Generics = parse2(quote!(
+                <T: 'static, V: Copy + Clone, Q: Send>
+        )).unwrap();
+        let wce: WhereClause = parse2(quote!(
+            where T: Default + Sync, Q: Debug
+        )).unwrap();
+
+        assert_eq!(quote!(#ge #wce).to_string(),
+                   quote!(#gm #gm_wc).to_string());
+    }
+
+    #[test]
+    fn eq() {
+        let mut g1: Generics = parse2(quote!(<T: 'static, V: Copy> )).unwrap();
+        let wc1: WhereClause = parse2(quote!(where T: Default)).unwrap();
+        g1.where_clause = Some(wc1.clone());
+
+        let gm = super::merge_generics(&g1, &g1);
+        let gm_wc = &gm.where_clause;
+
+        assert_eq!(quote!(#g1 #wc1).to_string(),
+                   quote!(#gm #gm_wc).to_string());
+    }
+
+    #[test]
+    fn lhs_only() {
+        let mut g1: Generics = parse2(quote!(<T: 'static, V: Copy> )).unwrap();
+        let wc1: WhereClause = parse2(quote!(where T: Default)).unwrap();
+        g1.where_clause = Some(wc1.clone());
+
+        let g2 = Generics::default();
+
+        let gm = super::merge_generics(&g1, &g2);
+        let gm_wc = &gm.where_clause;
+
+        assert_eq!(quote!(#g1 #wc1).to_string(),
+                   quote!(#gm #gm_wc).to_string());
+    }
+
+    #[test]
+    fn lhs_wc_only() {
+        let mut g1 = Generics::default();
+        let wc1: WhereClause = parse2(quote!(where T: Default)).unwrap();
+        g1.where_clause = Some(wc1.clone());
+
+        let g2 = Generics::default();
+
+        let gm = super::merge_generics(&g1, &g2);
+        let gm_wc = &gm.where_clause;
+
+        assert_eq!(quote!(#g1 #wc1).to_string(),
+                   quote!(#gm #gm_wc).to_string());
+    }
+
+    #[test]
+    fn rhs_only() {
+        let g1 = Generics::default();
+        let mut g2: Generics = parse2(quote!(<Q: Send, V: Clone>)).unwrap();
+        let wc2: WhereClause = parse2(quote!(where T: Sync, Q: Debug)).unwrap();
+        g2.where_clause = Some(wc2.clone());
+
+        let gm = super::merge_generics(&g1, &g2);
+        let gm_wc = &gm.where_clause;
+
+        assert_eq!(quote!(#g2 #wc2).to_string(),
+                   quote!(#gm #gm_wc).to_string());
+    }
+}
+
+mod supersuperfy {
+    use super::*;
+
+    fn check_supersuperfy(orig: TokenStream, expected: TokenStream) {
+        let orig_ty: Type = parse2(orig).unwrap();
+        let expected_ty: Type = parse2(expected).unwrap();
+        let output = supersuperfy(&orig_ty, 1);
+        assert_eq!(quote!(#output).to_string(),
+                   quote!(#expected_ty).to_string());
+    }
+
+    #[test]
+    fn array() {
+        check_supersuperfy(
+            quote!([super::X; n]),
+            quote!([super::super::X; n])
+        );
+    }
+
+    #[test]
+    fn barefn() {
+        check_supersuperfy(
+            quote!(fn(super::A) -> super::B),
+            quote!(fn(super::super::A) -> super::super::B)
+        );
+    }
+
+    #[test]
+    fn group() {
+        let orig = TypeGroup {
+            group_token: token::Group::default(),
+            elem: Box::new(parse2(quote!(super::T)).unwrap())
+        };
+        let expected = TypeGroup {
+            group_token: token::Group::default(),
+            elem: Box::new(parse2(quote!(super::super::T)).unwrap())
+        };
+        let output = supersuperfy(&Type::Group(orig), 1);
+        assert_eq!(quote!(#output).to_string(),
+                   quote!(#expected).to_string());
+    }
+
+    // Just check that it doesn't panic
+    #[test]
+    fn infer() {
+        check_supersuperfy( quote!(_), quote!(_));
+    }
+
+    // Just check that it doesn't panic
+    #[test]
+    fn never() {
+        check_supersuperfy( quote!(!), quote!(!));
+    }
+
+    #[test]
+    fn paren() {
+        check_supersuperfy(
+            quote!((super::X)),
+            quote!((super::super::X))
+        );
+    }
+
+    #[test]
+    fn path() {
+        check_supersuperfy(
+            quote!(::super::SuperT<u32>),
+            quote!(::super::super::SuperT<u32>)
+        );
+    }
+
+    #[test]
+    fn path_with_qself() {
+        check_supersuperfy(
+            quote!(<super::X as super::Y>::Foo<u32>),
+            quote!(<super::super::X as super::super::Y>::Foo<u32>),
+        );
+    }
+
+    #[test]
+    fn angle_bracketed_generic_arguments() {
+        check_supersuperfy(
+            quote!(mod_::T<super::X>),
+            quote!(mod_::T<super::super::X>)
+        );
+    }
+
+    #[test]
+    fn ptr() {
+        check_supersuperfy(
+            quote!(*const super::X),
+            quote!(*const super::super::X)
+        );
+    }
+
+    #[test]
+    fn reference() {
+        check_supersuperfy(
+            quote!(&'a mut super::X),
+            quote!(&'a mut super::super::X)
+        );
+    }
+
+    #[test]
+    fn slice() {
+        check_supersuperfy(
+            quote!([super::X]),
+            quote!([super::super::X])
+        );
+    }
+
+    #[test]
+    fn trait_object() {
+        check_supersuperfy(
+            quote!(dyn super::X + super::Y),
+            quote!(dyn super::super::X + super::super::Y)
+        );
+    }
+
+    #[test]
+    fn tuple() {
+        check_supersuperfy(
+            quote!((super::A, super::B)),
+            quote!((super::super::A, super::super::B))
+        );
+    }
+}
+
+mod supersuperfy_generics {
+    use super::*;
+
+    fn check_supersuperfy_generics(
+        orig: TokenStream,
+        orig_wc: TokenStream,
+        expected: TokenStream,
+        expected_wc: TokenStream)
+    {
+        let mut orig_g: Generics = parse2(orig).unwrap();
+        orig_g.where_clause = parse2(orig_wc).unwrap();
+        let mut expected_g: Generics = parse2(expected).unwrap();
+        expected_g.where_clause = parse2(expected_wc).unwrap();
+        let mut output: Generics = orig_g;
+        supersuperfy_generics(&mut output, 1);
+        let (o_ig, o_tg, o_wc) = output.split_for_impl();
+        let (e_ig, e_tg, e_wc) = expected_g.split_for_impl();
+        assert_eq!(quote!(#o_ig).to_string(), quote!(#e_ig).to_string());
+        assert_eq!(quote!(#o_tg).to_string(), quote!(#e_tg).to_string());
+        assert_eq!(quote!(#o_wc).to_string(), quote!(#e_wc).to_string());
+    }
+
+    #[test]
+    fn default() {
+        check_supersuperfy_generics(
+            quote!(<T: X = super::Y>), quote!(),
+            quote!(<T: X = super::super::Y>), quote!(),
+        );
+    }
+
+    #[test]
+    fn empty() {
+        check_supersuperfy_generics(quote!(), quote!(), quote!(), quote!());
+    }
+
+    #[test]
+    fn everything() {
+        check_supersuperfy_generics(
+            quote!(<T: super::A = super::B>),
+            quote!(where super::C: super::D),
+            quote!(<T: super::super::A = super::super::B>),
+            quote!(where super::super::C: super::super::D),
+        );
+    }
+
+    #[test]
+    fn bound() {
+        check_supersuperfy_generics(
+            quote!(<T: super::A>), quote!(),
+            quote!(<T: super::super::A>), quote!(),
+        );
+    }
+
+    #[test]
+    fn closure() {
+        check_supersuperfy_generics(
+            quote!(<F: Fn(u32) -> super::SuperT>), quote!(),
+            quote!(<F: Fn(u32) -> super::super::SuperT>), quote!(),
+        );
+    }
+
+    #[test]
+    fn wc_bounded_ty() {
+        check_supersuperfy_generics(
+            quote!(), quote!(where super::T: X),
+            quote!(), quote!(where super::super::T: X),
+        );
+    }
+
+    #[test]
+    fn wc_bounds() {
+        check_supersuperfy_generics(
+            quote!(), quote!(where T: super::X),
+            quote!(), quote!(where T: super::super::X),
+        );
+    }
+}
+}
diff --git a/src/mock_function.rs b/src/mock_function.rs
new file mode 100644
index 0000000..86a8690
--- /dev/null
+++ b/src/mock_function.rs
@@ -0,0 +1,2436 @@
+// vim: tw=80
+use super::*;
+
+use quote::ToTokens;
+
+/// Convert a trait object reference into a reference to a Boxed trait
+///
+/// # Returns
+///
+/// Returns `true` if it was necessary to box the type.
+fn dedynify(ty: &mut Type) -> bool {
+    if let Type::Reference(ref mut tr) = ty {
+        if let Type::TraitObject(ref tto) = tr.elem.as_ref() {
+            if let Some(lt) = &tr.lifetime {
+                if lt.ident == "static" {
+                    // For methods that return 'static references, the user can
+                    // usually actually supply one, unlike nonstatic references.
+                    // dedynify is unneeded and harmful in such cases.
+                    //
+                    // But we do need to add parens to prevent parsing errors
+                    // when methods like returning add a `+ Send` to the output
+                    // type.
+                    *tr.elem = parse2(quote!((#tto))).unwrap();
+                    return false;
+                }
+            }
+
+            *tr.elem = parse2(quote!(Box<#tto>)).unwrap();
+            return true;
+        }
+    }
+    false
+}
+
+/// Convert a special reference type like "&str" into a reference to its owned
+/// type like "&String".
+fn destrify(ty: &mut Type) {
+    if let Type::Reference(ref mut tr) = ty {
+        if let Some(lt) = &tr.lifetime {
+            if lt.ident == "static" {
+                // For methods that return 'static references, the user can
+                // usually actually supply one, unlike nonstatic references.
+                // destrify is unneeded and harmful in such cases.
+                return;
+            }
+        }
+
+        let path_ty: TypePath = parse2(quote!(Path)).unwrap();
+        let pathbuf_ty: Type = parse2(quote!(::std::path::PathBuf)).unwrap();
+
+        let str_ty: TypePath = parse2(quote!(str)).unwrap();
+        let string_ty: Type = parse2(quote!(::std::string::String)).unwrap();
+
+        let cstr_ty: TypePath = parse2(quote!(CStr)).unwrap();
+        let cstring_ty: Type = parse2(quote!(::std::ffi::CString)).unwrap();
+
+        let osstr_ty: TypePath = parse2(quote!(OsStr)).unwrap();
+        let osstring_ty: Type = parse2(quote!(::std::ffi::OsString)).unwrap();
+
+        match tr.elem.as_ref() {
+            Type::Path(ref path) if *path == cstr_ty => *tr.elem = cstring_ty,
+            Type::Path(ref path) if *path == osstr_ty => *tr.elem = osstring_ty,
+            Type::Path(ref path) if *path == path_ty => *tr.elem = pathbuf_ty,
+            Type::Path(ref path) if *path == str_ty => *tr.elem = string_ty,
+            Type::Slice(ts) => {
+                let inner = (*ts.elem).clone();
+                let mut segments = Punctuated::new();
+                segments.push(format_ident!("std").into());
+                segments.push(format_ident!("vec").into());
+                let mut v: PathSegment = format_ident!("Vec").into();
+                let mut abga_args = Punctuated::new();
+                abga_args.push(GenericArgument::Type(inner));
+                v.arguments = PathArguments::AngleBracketed(AngleBracketedGenericArguments {
+                    colon2_token: None,
+                    lt_token: Token![<](Span::call_site()),
+                    args: abga_args,
+                    gt_token: Token![>](Span::call_site()),
+                });
+                segments.push(v);
+
+                *tr.elem = Type::Path(TypePath {
+                    qself: None,
+                    path: Path {
+                        leading_colon: Some(Token![::](Span::call_site())),
+                        segments,
+                    },
+                });
+            }
+            _ => (), // Nothing to do
+        };
+    }
+}
+
+/// Return the owned version of the input.
+fn ownify(ty: &Type) -> Type {
+    if let Type::Reference(ref tr) = &ty {
+        if tr
+            .lifetime
+            .as_ref()
+            .map_or(false, |lt| lt.ident == "static")
+        {
+            // Just a static expectation
+            ty.clone()
+        } else {
+            *tr.elem.clone()
+        }
+    } else {
+        ty.clone()
+    }
+}
+
+/// Add Send + Sync to a where clause
+fn send_syncify(wc: &mut Option<WhereClause>, bounded_ty: Type) {
+    let mut bounds = Punctuated::new();
+    bounds.push(TypeParamBound::Trait(TraitBound {
+        paren_token: None,
+        modifier: TraitBoundModifier::None,
+        lifetimes: None,
+        path: Path::from(format_ident!("Send")),
+    }));
+    bounds.push(TypeParamBound::Trait(TraitBound {
+        paren_token: None,
+        modifier: TraitBoundModifier::None,
+        lifetimes: None,
+        path: Path::from(format_ident!("Sync")),
+    }));
+    if wc.is_none() {
+        *wc = Some(WhereClause {
+            where_token: <Token![where]>::default(),
+            predicates: Punctuated::new(),
+        });
+    }
+    wc.as_mut()
+        .unwrap()
+        .predicates
+        .push(WherePredicate::Type(PredicateType {
+            lifetimes: None,
+            bounded_ty,
+            colon_token: Default::default(),
+            bounds,
+        }));
+}
+
+/// Build a MockFunction.
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct Builder<'a> {
+    attrs: &'a [Attribute],
+    call_levels: Option<usize>,
+    levels: usize,
+    parent: Option<&'a Ident>,
+    sig: &'a Signature,
+    struct_: Option<&'a Ident>,
+    struct_generics: Option<&'a Generics>,
+    trait_: Option<&'a Ident>,
+    vis: &'a Visibility,
+}
+
+impl<'a> Builder<'a> {
+    pub fn attrs(&mut self, attrs: &'a [Attribute]) -> &mut Self {
+        self.attrs = attrs;
+        self
+    }
+
+    pub fn build(self) -> MockFunction {
+        let mut argnames = Vec::new();
+        let mut argty = Vec::new();
+        let mut is_static = true;
+        let mut predexprs = Vec::new();
+        let mut predty = Vec::new();
+        let mut refpredty = Vec::new();
+
+        let (mut declosured_generics, declosured_inputs, call_exprs) =
+            declosurefy(&self.sig.generics, &self.sig.inputs);
+
+        for fa in declosured_inputs.iter() {
+            if let FnArg::Typed(pt) = fa {
+                let argname = (*pt.pat).clone();
+                if pat_is_self(&argname) {
+                    // A weird receiver like `Box<Self>`
+                    is_static = false;
+                    continue;
+                }
+                let aty = supersuperfy(&pt.ty, self.levels);
+                if let Type::Reference(ref tr) = aty {
+                    predexprs.push(quote!(#argname));
+                    predty.push((*tr.elem).clone());
+                    let tr2 = Type::Reference(TypeReference {
+                        and_token: tr.and_token,
+                        lifetime: None,
+                        mutability: None,
+                        elem: tr.elem.clone(),
+                    });
+                    refpredty.push(tr2);
+                } else {
+                    predexprs.push(quote!(&#argname));
+                    predty.push(aty.clone());
+                    let tr = TypeReference {
+                        and_token: Token![&](Span::call_site()),
+                        lifetime: None,
+                        mutability: None,
+                        elem: Box::new(aty.clone()),
+                    };
+                    refpredty.push(Type::Reference(tr));
+                };
+                argnames.push(argname);
+                argty.push(aty.clone());
+            } else {
+                is_static = false;
+            }
+        }
+        let (output, boxed) = match self.sig.output {
+            ReturnType::Default => (
+                Type::Tuple(TypeTuple {
+                    paren_token: token::Paren::default(),
+                    elems: Punctuated::new(),
+                }),
+                false,
+            ),
+            ReturnType::Type(_, ref ty) => {
+                let mut output_ty = supersuperfy(ty, self.levels);
+                destrify(&mut output_ty);
+                let boxed = dedynify(&mut output_ty);
+                (output_ty, boxed)
+            }
+        };
+        supersuperfy_generics(&mut declosured_generics, self.levels);
+        let owned_output = ownify(&output);
+        let mut return_ref = false;
+        let mut return_refmut = false;
+        if let Type::Reference(ref tr) = &output {
+            if tr.lifetime.as_ref().map_or(true, |lt| lt.ident != "static") {
+                if tr.mutability.is_none() {
+                    return_ref = true;
+                } else {
+                    return_refmut = true;
+                }
+            }
+        };
+        if is_static && (return_ref || return_refmut) {
+            compile_error(self.sig.span(),
+                "Mockall cannot mock static methods that return non-'static references.  It's unclear what the return value's lifetime should be.");
+        }
+        let struct_generics = self.struct_generics.cloned().unwrap_or_default();
+        let (type_generics, salifetimes, srlifetimes) = split_lifetimes(
+            struct_generics.clone(),
+            &declosured_inputs,
+            &ReturnType::Type(<Token![->]>::default(), Box::new(owned_output.clone())),
+        );
+        let srltg = lifetimes_to_generics(&srlifetimes);
+        let (call_generics, malifetimes, mrlifetimes) = split_lifetimes(
+            declosured_generics,
+            &declosured_inputs,
+            &ReturnType::Type(<Token![->]>::default(), Box::new(owned_output.clone())),
+        );
+        let mrltg = lifetimes_to_generics(&mrlifetimes);
+        let cgenerics = merge_generics(&type_generics, &call_generics);
+        let egenerics = merge_generics(&merge_generics(&cgenerics, &srltg), &mrltg);
+        let alifetimes = salifetimes
+            .into_iter()
+            .collect::<HashSet<LifetimeDef>>()
+            .union(&malifetimes.into_iter().collect::<HashSet<_>>())
+            .cloned()
+            .collect();
+
+        let fn_params = egenerics.type_params().map(|tp| tp.ident.clone()).collect();
+        let call_levels = self.call_levels.unwrap_or(self.levels);
+
+        MockFunction {
+            alifetimes,
+            argnames,
+            argty,
+            attrs: self.attrs.to_vec(),
+            call_exprs,
+            call_generics,
+            call_vis: expectation_visibility(self.vis, call_levels),
+            egenerics,
+            cgenerics,
+            fn_params,
+            is_static,
+            mod_ident: self
+                .parent
+                .unwrap_or(&Ident::new("FIXME", Span::call_site()))
+                .clone(),
+            output,
+            owned_output,
+            boxed,
+            predexprs,
+            predty,
+            refpredty,
+            return_ref,
+            return_refmut,
+            sig: self.sig.clone(),
+            struct_: self.struct_.cloned(),
+            struct_generics,
+            trait_: self.trait_.cloned(),
+            type_generics,
+            privmod_vis: expectation_visibility(self.vis, self.levels),
+        }
+    }
+
+    /// How many levels of modules beneath the original function this one is
+    /// nested.
+    pub fn call_levels(&mut self, levels: usize) -> &mut Self {
+        self.call_levels = Some(levels);
+        self
+    }
+
+    /// How many levels of modules beneath the original function this one's
+    /// private module is nested.
+    pub fn levels(&mut self, levels: usize) -> &mut Self {
+        self.levels = levels;
+        self
+    }
+
+    /// # Arguments
+    ///
+    /// * sig:      The signature of the mockable function
+    /// * v:        The visibility of the mockable function
+    pub fn new(sig: &'a Signature, vis: &'a Visibility) -> Self {
+        Builder {
+            attrs: &[],
+            levels: 0,
+            call_levels: None,
+            parent: None,
+            sig,
+            struct_: None,
+            struct_generics: None,
+            trait_: None,
+            vis,
+        }
+    }
+
+    /// Supply the name of the parent module
+    pub fn parent(&mut self, ident: &'a Ident) -> &mut Self {
+        self.parent = Some(ident);
+        self
+    }
+
+    /// Supply the name of the parent struct, if any
+    pub fn struct_(&mut self, ident: &'a Ident) -> &mut Self {
+        self.struct_ = Some(ident);
+        self
+    }
+
+    /// Supply the Generics of the parent struct, if any
+    pub fn struct_generics(&mut self, generics: &'a Generics) -> &mut Self {
+        self.struct_generics = Some(generics);
+        self
+    }
+
+    /// Supply the name of the method's trait, if any
+    pub fn trait_(&mut self, ident: &'a Ident) -> &mut Self {
+        self.trait_ = Some(ident);
+        self
+    }
+}
+
+#[derive(Clone)]
+pub(crate) struct MockFunction {
+    /// Lifetimes of the mocked method that relate to the arguments but not the
+    /// return value
+    alifetimes: Punctuated<LifetimeDef, token::Comma>,
+    /// Names of the method arguments
+    argnames: Vec<Pat>,
+    /// Types of the method arguments
+    argty: Vec<Type>,
+    /// any attributes on the original function, like #[inline]
+    pub attrs: Vec<Attribute>,
+    /// Expressions that should be used for Expectation::call's arguments
+    call_exprs: Vec<TokenStream>,
+    /// Generics used for the expectation call
+    call_generics: Generics,
+    /// Visibility of the mock function itself
+    call_vis: Visibility,
+    /// Generics of the Expectation object
+    egenerics: Generics,
+    /// Generics of the Common object
+    cgenerics: Generics,
+    /// The mock function's generic types as a list of types
+    fn_params: Vec<Ident>,
+    /// Is this for a static method or free function?
+    is_static: bool,
+    /// name of the function's parent module
+    mod_ident: Ident,
+    /// Output type of the Method, supersuperfied.
+    output: Type,
+    /// Owned version of the output type of the Method, supersuperfied.
+    ///
+    /// If the real output type is a non-'static reference, then it will differ
+    /// from this field.
+    owned_output: Type,
+    /// True if the `owned_type` is boxed by `Box<>`.
+    boxed: bool,
+    /// Expressions that create the predicate arguments from the call arguments
+    predexprs: Vec<TokenStream>,
+    /// Types used for Predicates.  Will be almost the same as args, but every
+    /// type will be a non-reference type.
+    predty: Vec<Type>,
+    /// Does the function return a non-'static reference?
+    return_ref: bool,
+    /// Does the function return a mutable reference?
+    return_refmut: bool,
+    /// References to every type in `predty`.
+    refpredty: Vec<Type>,
+    /// The signature of the mockable function
+    sig: Signature,
+    /// Name of the parent structure, if any
+    struct_: Option<Ident>,
+    /// Generics of the parent structure
+    struct_generics: Generics,
+    /// Name of this method's trait, if the method comes from a trait
+    trait_: Option<Ident>,
+    /// Type generics of the mock structure
+    type_generics: Generics,
+    /// Visibility of the expectation and its methods
+    privmod_vis: Visibility,
+}
+
+impl MockFunction {
+    /// Return the mock function itself
+    ///
+    /// # Arguments
+    ///
+    /// * `modname`:    Name of the parent struct's private module
+    // Supplying modname is an unfortunately hack.  Ideally MockFunction
+    // wouldn't need to know that.
+    pub fn call(&self, modname: Option<&Ident>) -> impl ToTokens {
+        let attrs = AttrFormatter::new(&self.attrs).format();
+        let call_exprs = &self.call_exprs;
+        let (_, tg, _) = if self.is_method_generic() || self.is_static() {
+            &self.egenerics
+        } else {
+            &self.call_generics
+        }
+        .split_for_impl();
+        let tbf = tg.as_turbofish();
+        let name = self.name();
+        let desc = self.desc();
+        let no_match_msg = quote!(std::format!(
+            "{}: No matching expectation found", #desc));
+        let sig = &self.sig;
+        let (vis, dead_code) = if self.trait_.is_some() {
+            (&Visibility::Inherited, quote!())
+        } else {
+            let dead_code = if let Visibility::Inherited = self.call_vis {
+                // This private method may be a helper only used by the struct's
+                // other methods, which we are mocking.  If so, the mock method
+                // will be dead code.  But we can't simply eliminate it, because
+                // it might also be used by other code in the same module.
+                quote!(#[allow(dead_code)])
+            } else {
+                quote!()
+            };
+            (&self.call_vis, dead_code)
+        };
+        let substruct_obj = if let Some(trait_) = &self.trait_ {
+            let ident = format_ident!("{}_expectations", trait_);
+            quote!(#ident.)
+        } else {
+            quote!()
+        };
+        let call = if self.return_refmut {
+            Ident::new("call_mut", Span::call_site())
+        } else {
+            Ident::new("call", Span::call_site())
+        };
+        let mut deref = quote!();
+        if self.boxed {
+            if self.return_ref {
+                deref = quote!(&**);
+            } else if self.return_refmut {
+                deref = quote!(&mut **);
+            }
+        }
+        if self.is_static {
+            let outer_mod_path = self.outer_mod_path(modname);
+            quote!(
+                // Don't add a doc string.  The original is included in #attrs
+                #(#attrs)*
+                #dead_code
+                #vis #sig {
+                    let no_match_msg = #no_match_msg;
+                    #deref {
+                        let __mockall_guard = #outer_mod_path::EXPECTATIONS
+                            .lock().unwrap();
+                        /*
+                         * TODO: catch panics, then gracefully release the mutex
+                         * so it won't be poisoned.  This requires bounding any
+                         * generic parameters with UnwindSafe
+                         */
+                        /* std::panic::catch_unwind(|| */
+                        __mockall_guard.#call#tbf(#(#call_exprs,)*)
+                        /*)*/
+                    }.expect(&no_match_msg)
+                }
+            )
+        } else {
+            quote!(
+                // Don't add a doc string.  The original is included in #attrs
+                #(#attrs)*
+                #dead_code
+                #vis #sig {
+                    let no_match_msg = #no_match_msg;
+                    #deref self.#substruct_obj #name.#call#tbf(#(#call_exprs,)*)
+                    .expect(&no_match_msg)
+                }
+
+            )
+        }
+    }
+
+    /// Return this method's contribution to its parent's checkpoint method
+    pub fn checkpoint(&self) -> impl ToTokens {
+        let attrs = AttrFormatter::new(&self.attrs).doc(false).format();
+        let inner_mod_ident = self.inner_mod_ident();
+        if self.is_static {
+            quote!(
+                #(#attrs)*
+                {
+                    let __mockall_timeses = #inner_mod_ident::EXPECTATIONS.lock()
+                        .unwrap()
+                        .checkpoint()
+                        .collect::<Vec<_>>();
+                }
+            )
+        } else {
+            let name = &self.name();
+            quote!(#(#attrs)* { self.#name.checkpoint(); })
+        }
+    }
+
+    /// Return a function that creates a Context object for this function
+    ///
+    /// # Arguments
+    ///
+    /// * `modname`:    Name of the parent struct's private module
+    // Supplying modname is an unfortunately hack.  Ideally MockFunction
+    // wouldn't need to know that.
+    pub fn context_fn(&self, modname: Option<&Ident>) -> impl ToTokens {
+        let attrs = AttrFormatter::new(&self.attrs).doc(false).format();
+        let context_docstr = format!(
+            "Create a [`Context`]({}{}/struct.Context.html) for mocking the `{}` method",
+            modname.map(|m| format!("{}/", m)).unwrap_or_default(),
+            self.inner_mod_ident(),
+            self.name()
+        );
+        let context_ident = format_ident!("{}_context", self.name());
+        let (_, tg, _) = self.type_generics.split_for_impl();
+        let outer_mod_path = self.outer_mod_path(modname);
+        let v = &self.call_vis;
+        quote!(
+            #(#attrs)*
+            #[doc = #context_docstr]
+            #v fn #context_ident() -> #outer_mod_path::Context #tg
+            {
+                #outer_mod_path::Context::default()
+            }
+        )
+    }
+
+    /// Generate a code fragment that will print a description of the invocation
+    fn desc(&self) -> impl ToTokens {
+        let argnames = &self.argnames;
+        let name = if let Some(s) = &self.struct_ {
+            format!("{}::{}", s, self.sig.ident)
+        } else {
+            format!("{}::{}", self.mod_ident, self.sig.ident)
+        };
+        let fields = vec!["{:?}"; argnames.len()].join(", ");
+        let fstr = format!("{}({})", name, fields);
+        quote!(std::format!(#fstr, #(::mockall::MaybeDebugger(&#argnames)),*))
+    }
+
+    /// Generate code for the expect_ method
+    ///
+    /// # Arguments
+    ///
+    /// * `modname`:    Name of the parent struct's private module
+    /// * `self_args`:  If supplied, these are the
+    ///                 AngleBracketedGenericArguments of the self type of the
+    ///                 trait impl.  e.g. The `T` in `impl Foo for Bar<T>`.
+    // Supplying modname is an unfortunately hack.  Ideally MockFunction
+    // wouldn't need to know that.
+    pub fn expect(&self, modname: &Ident, self_args: Option<&PathArguments>) -> impl ToTokens {
+        let attrs = AttrFormatter::new(&self.attrs).doc(false).format();
+        let name = self.name();
+        let expect_ident = format_ident!("expect_{}", &name);
+        let expectation_obj = self.expectation_obj(self_args);
+        let funcname = &self.sig.ident;
+        let (_, tg, _) = if self.is_method_generic() {
+            &self.egenerics
+        } else {
+            &self.call_generics
+        }
+        .split_for_impl();
+        let (ig, _, wc) = self.call_generics.split_for_impl();
+        let mut wc = wc.cloned();
+        if self.is_method_generic() && (self.return_ref || self.return_refmut) {
+            // Add Senc + Sync, required for downcast, since Expectation
+            // stores an Option<#owned_output>
+            send_syncify(&mut wc, self.owned_output.clone());
+        }
+        let tbf = tg.as_turbofish();
+        let vis = &self.call_vis;
+
+        #[cfg(not(feature = "nightly_derive"))]
+        let must_use = quote!(#[must_use =
+            "Must set return value when not using the \"nightly\" feature"
+        ]);
+        #[cfg(feature = "nightly_derive")]
+        let must_use = quote!();
+
+        let substruct_obj = if let Some(trait_) = &self.trait_ {
+            let ident = format_ident!("{}_expectations", trait_);
+            quote!(#ident.)
+        } else {
+            quote!()
+        };
+        let docstr = format!(
+            "Create an [`Expectation`]({}/{}/struct.Expectation.html) for mocking the `{}` method",
+            modname,
+            self.inner_mod_ident(),
+            funcname
+        );
+        quote!(
+            #must_use
+            #[doc = #docstr]
+            #(#attrs)*
+            #vis fn #expect_ident #ig(&mut self)
+               -> &mut #modname::#expectation_obj
+               #wc
+            {
+                self.#substruct_obj #name.expect#tbf()
+            }
+        )
+    }
+
+    /// Return the name of this function's expecation object
+    fn expectation_obj(&self, self_args: Option<&PathArguments>) -> impl ToTokens {
+        let inner_mod_ident = self.inner_mod_ident();
+        if let Some(PathArguments::AngleBracketed(abga)) = self_args {
+            // staticize any lifetimes that might be present in the Expectation
+            // object but not in the self args.  These come from the method's
+            // return type.
+            let mut abga2 = abga.clone();
+            for _ in self.egenerics.lifetimes() {
+                let lt = Lifetime::new("'static", Span::call_site());
+                let la = GenericArgument::Lifetime(lt);
+                abga2.args.insert(0, la);
+            }
+            assert!(
+                !self.is_method_generic(),
+                "specific impls with generic methods are TODO"
+            );
+            quote!(#inner_mod_ident::Expectation #abga2)
+        } else {
+            // staticize any lifetimes.  This is necessary for methods that
+            // return non-static types, because the Expectation itself must be
+            // 'static.
+            let segenerics = staticize(&self.egenerics);
+            let (_, tg, _) = segenerics.split_for_impl();
+            quote!(#inner_mod_ident::Expectation #tg)
+        }
+    }
+
+    /// Return the name of this function's expecations object
+    pub fn expectations_obj(&self) -> impl ToTokens {
+        let inner_mod_ident = self.inner_mod_ident();
+        if self.is_method_generic() {
+            quote!(#inner_mod_ident::GenericExpectations)
+        } else {
+            quote!(#inner_mod_ident::Expectations)
+        }
+    }
+
+    pub fn field_definition(&self, modname: Option<&Ident>) -> TokenStream {
+        let name = self.name();
+        let attrs = AttrFormatter::new(&self.attrs).doc(false).format();
+        let expectations_obj = &self.expectations_obj();
+        if self.is_method_generic() {
+            quote!(#(#attrs)* #name: #modname::#expectations_obj)
+        } else {
+            // staticize any lifetimes.  This is necessary for methods that
+            // return non-static types, because the Expectation itself must be
+            // 'static.
+            let segenerics = staticize(&self.egenerics);
+            let (_, tg, _) = segenerics.split_for_impl();
+            quote!(#(#attrs)* #name: #modname::#expectations_obj #tg)
+        }
+    }
+
+    /// Human-readable name of the mock function
+    fn funcname(&self) -> String {
+        if let Some(si) = &self.struct_ {
+            format!("{}::{}", si, self.name())
+        } else {
+            format!("{}", self.name())
+        }
+    }
+
+    fn hrtb(&self) -> Option<BoundLifetimes> {
+        if self.alifetimes.is_empty() {
+            None
+        } else {
+            Some(BoundLifetimes {
+                lifetimes: self.alifetimes.clone(),
+                lt_token: <Token![<]>::default(),
+                gt_token: <Token![>]>::default(),
+                ..Default::default()
+            })
+        }
+    }
+
+    fn is_expectation_generic(&self) -> bool {
+        self.egenerics
+            .params
+            .iter()
+            .any(|p| matches!(p, GenericParam::Type(_)))
+            || self.egenerics.where_clause.is_some()
+    }
+
+    /// Is the mock method generic (as opposed to a non-generic method of a
+    /// generic mock struct)?
+    pub fn is_method_generic(&self) -> bool {
+        self.call_generics
+            .params
+            .iter()
+            .any(|p| matches!(p, GenericParam::Type(_)))
+            || self.call_generics.where_clause.is_some()
+    }
+
+    fn outer_mod_path(&self, modname: Option<&Ident>) -> Path {
+        let mut path = if let Some(m) = modname {
+            Path::from(PathSegment::from(m.clone()))
+        } else {
+            Path {
+                leading_colon: None,
+                segments: Punctuated::new(),
+            }
+        };
+        path.segments
+            .push(PathSegment::from(self.inner_mod_ident()));
+        path
+    }
+
+    fn inner_mod_ident(&self) -> Ident {
+        format_ident!("__{}", &self.name())
+    }
+
+    pub fn is_static(&self) -> bool {
+        self.is_static
+    }
+
+    pub fn name(&self) -> &Ident {
+        &self.sig.ident
+    }
+
+    /// Generate code for this function's private module
+    pub fn priv_module(&self) -> impl ToTokens {
+        let attrs = AttrFormatter::new(&self.attrs).doc(false).format();
+        let common = &Common { f: self };
+        let context = &Context { f: self };
+        let expectation: Box<dyn ToTokens> = if self.return_ref {
+            Box::new(RefExpectation { f: self })
+        } else if self.return_refmut {
+            Box::new(RefMutExpectation { f: self })
+        } else {
+            Box::new(StaticExpectation { f: self })
+        };
+        let expectations: Box<dyn ToTokens> = if self.return_ref {
+            Box::new(RefExpectations { f: self })
+        } else if self.return_refmut {
+            Box::new(RefMutExpectations { f: self })
+        } else {
+            Box::new(StaticExpectations { f: self })
+        };
+        let generic_expectations = GenericExpectations { f: self };
+        let guard: Box<dyn ToTokens> = if self.is_expectation_generic() {
+            Box::new(GenericExpectationGuard { f: self })
+        } else {
+            Box::new(ConcreteExpectationGuard { f: self })
+        };
+        let matcher = &Matcher { f: self };
+        let std_mutexguard = if self.is_static {
+            quote!(
+                use std::sync::MutexGuard;
+            )
+        } else {
+            quote!()
+        };
+        let inner_mod_ident = self.inner_mod_ident();
+        let rfunc: Box<dyn ToTokens> = if self.return_ref {
+            Box::new(RefRfunc { f: self })
+        } else if self.return_refmut {
+            Box::new(RefMutRfunc { f: self })
+        } else {
+            Box::new(StaticRfunc { f: self })
+        };
+        quote!(
+            #(#attrs)*
+            #[allow(missing_docs)]
+            pub mod #inner_mod_ident {
+                use super::*;
+                use ::mockall::CaseTreeExt;
+                #std_mutexguard
+                use ::std::{
+                    boxed::Box,
+                    mem,
+                    ops::{DerefMut, Range},
+                    sync::Mutex,
+                    vec::Vec,
+                };
+                #rfunc
+                #matcher
+                #common
+                #expectation
+                #expectations
+                #generic_expectations
+                #guard
+                #context
+            }
+        )
+    }
+}
+
+/// Holds parts of the expectation that are common for all output types
+struct Common<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for Common<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let argnames = &self.f.argnames;
+        let predty = &self.f.predty;
+        let hrtb = self.f.hrtb();
+        let funcname = self.f.funcname();
+        let (ig, tg, wc) = self.f.cgenerics.split_for_impl();
+        let lg = lifetimes_to_generics(&self.f.alifetimes);
+        let refpredty = &self.f.refpredty;
+        let with_generics_idents = (0..self.f.predty.len())
+            .map(|i| format_ident!("MockallMatcher{}", i))
+            .collect::<Vec<_>>();
+        let with_generics = with_generics_idents
+            .iter()
+            .zip(self.f.predty.iter())
+            .map(|(id, mt)| quote!(#id: #hrtb ::mockall::Predicate<#mt> + Send + 'static, ))
+            .collect::<TokenStream>();
+        let with_args = self
+            .f
+            .argnames
+            .iter()
+            .zip(with_generics_idents.iter())
+            .map(|(argname, id)| quote!(#argname: #id, ))
+            .collect::<TokenStream>();
+        let boxed_withargs = argnames
+            .iter()
+            .map(|aa| quote!(Box::new(#aa), ))
+            .collect::<TokenStream>();
+        quote!(
+            /// Holds the stuff that is independent of the output type
+            struct Common #ig #wc {
+                matcher: Mutex<Matcher #tg>,
+                seq_handle: Option<::mockall::SeqHandle>,
+                times: ::mockall::Times
+            }
+
+            impl #ig std::default::Default for Common #tg #wc
+            {
+                fn default() -> Self {
+                    Common {
+                        matcher: Mutex::new(Matcher::default()),
+                        seq_handle: None,
+                        times: ::mockall::Times::default()
+                    }
+                }
+            }
+
+            impl #ig Common #tg #wc {
+                fn call(&self, desc: &str) {
+                    self.times.call()
+                        .unwrap_or_else(|m| {
+                            let desc = std::format!(
+                                "{}", self.matcher.lock().unwrap());
+                            panic!("{}: Expectation({}) {}", #funcname, desc,
+                                m);
+                        });
+                    self.verify_sequence(desc);
+                    if ::mockall::ExpectedCalls::TooFew != self.times.is_satisfied() {
+                        self.satisfy_sequence()
+                    }
+                }
+
+                fn in_sequence(&mut self, __mockall_seq: &mut ::mockall::Sequence)
+                    -> &mut Self
+                {
+                    assert!(self.times.is_exact(),
+                        "Only Expectations with an exact call count have sequences");
+                    self.seq_handle = Some(__mockall_seq.next_handle());
+                    self
+                }
+
+                fn is_done(&self) -> bool {
+                    self.times.is_done()
+                }
+
+                #[allow(clippy::ptr_arg)]
+                fn matches #lg (&self, #( #argnames: &#predty, )*) -> bool {
+                    self.matcher.lock().unwrap().matches(#(#argnames, )*)
+                }
+
+                /// Forbid this expectation from ever being called.
+                fn never(&mut self) {
+                    self.times.never();
+                }
+
+                fn satisfy_sequence(&self) {
+                    if let Some(__mockall_handle) = &self.seq_handle {
+                        __mockall_handle.satisfy()
+                    }
+                }
+
+                /// Expect this expectation to be called any number of times
+                /// contained with the given range.
+                fn times<MockallR>(&mut self, __mockall_r: MockallR)
+                    where MockallR: Into<::mockall::TimesRange>
+                {
+                    self.times.times(__mockall_r)
+                }
+
+                fn with<#with_generics>(&mut self, #with_args)
+                {
+                    let mut __mockall_guard = self.matcher.lock().unwrap();
+                    *__mockall_guard.deref_mut() =
+                        Matcher::Pred(Box::new((#boxed_withargs)));
+                }
+
+                fn withf<MockallF>(&mut self, __mockall_f: MockallF)
+                    where MockallF: #hrtb Fn(#( #refpredty, )*)
+                                    -> bool + Send + 'static
+                {
+                    let mut __mockall_guard = self.matcher.lock().unwrap();
+                    *__mockall_guard.deref_mut() =
+                         Matcher::Func(Box::new(__mockall_f));
+                }
+
+                fn withf_st<MockallF>(&mut self, __mockall_f: MockallF)
+                    where MockallF: #hrtb Fn(#( #refpredty, )*)
+                                    -> bool + 'static
+                {
+                    let mut __mockall_guard = self.matcher.lock().unwrap();
+                    *__mockall_guard.deref_mut() =
+                         Matcher::FuncSt(
+                             ::mockall::Fragile::new(Box::new(__mockall_f))
+                        );
+                }
+
+                fn verify_sequence(&self, desc: &str) {
+                    if let Some(__mockall_handle) = &self.seq_handle {
+                        __mockall_handle.verify(desc)
+                    }
+                }
+            }
+
+            impl #ig Drop for Common #tg #wc {
+                fn drop(&mut self) {
+                    if !::std::thread::panicking() {
+                        let desc = std::format!(
+                            "{}", self.matcher.lock().unwrap());
+                        match self.times.is_satisfied() {
+                            ::mockall::ExpectedCalls::TooFew => {
+                                panic!("{}: Expectation({}) called {} time(s) which is fewer than expected {}",
+                                    #funcname,
+                                    desc,
+                                    self.times.count(),
+                                    self.times.minimum());
+                            },
+                            ::mockall::ExpectedCalls::TooMany => {
+                                panic!("{}: Expectation({}) called {} time(s) which is more than expected {}",
+                                    #funcname,
+                                    desc,
+                                    self.times.count(),
+                                    self.times.maximum());
+                            },
+                            _ => ()
+                        }
+                    }
+                }
+            }
+        ).to_tokens(tokens);
+    }
+}
+
+/// Generates methods that are common for all Expectation types
+struct CommonExpectationMethods<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for CommonExpectationMethods<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let argnames = &self.f.argnames;
+        let hrtb = self.f.hrtb();
+        let lg = lifetimes_to_generics(&self.f.alifetimes);
+        let predty = &self.f.predty;
+        let with_generics_idents = (0..self.f.predty.len())
+            .map(|i| format_ident!("MockallMatcher{}", i))
+            .collect::<Vec<_>>();
+        let with_generics = with_generics_idents
+            .iter()
+            .zip(self.f.predty.iter())
+            .map(|(id, mt)| quote!(#id: #hrtb ::mockall::Predicate<#mt> + Send + 'static, ))
+            .collect::<TokenStream>();
+        let with_args = self
+            .f
+            .argnames
+            .iter()
+            .zip(with_generics_idents.iter())
+            .map(|(argname, id)| quote!(#argname: #id, ))
+            .collect::<TokenStream>();
+        let v = &self.f.privmod_vis;
+        quote!(
+            /// Add this expectation to a
+            /// [`Sequence`](../../../mockall/struct.Sequence.html).
+            #v fn in_sequence(&mut self, __mockall_seq: &mut ::mockall::Sequence)
+                -> &mut Self
+            {
+                self.common.in_sequence(__mockall_seq);
+                self
+            }
+
+            fn is_done(&self) -> bool {
+                self.common.is_done()
+            }
+
+            /// Validate this expectation's matcher.
+            #[allow(clippy::ptr_arg)]
+            fn matches #lg (&self, #(#argnames: &#predty, )*) -> bool {
+                self.common.matches(#(#argnames, )*)
+            }
+
+            /// Forbid this expectation from ever being called.
+            #v fn never(&mut self) -> &mut Self {
+                self.common.never();
+                self
+            }
+
+            /// Create a new, default, [`Expectation`](struct.Expectation.html)
+            #v fn new() -> Self {
+                Self::default()
+            }
+
+            /// Expect this expectation to be called exactly once.  Shortcut for
+            /// [`times(1)`](#method.times).
+            #v fn once(&mut self) -> &mut Self {
+                self.times(1)
+            }
+
+            /// Restrict the number of times that that this method may be called.
+            ///
+            /// The argument may be:
+            /// * A fixed number: `.times(4)`
+            /// * Various types of range:
+            ///   - `.times(5..10)`
+            ///   - `.times(..10)`
+            ///   - `.times(5..)`
+            ///   - `.times(5..=10)`
+            ///   - `.times(..=10)`
+            /// * The wildcard: `.times(..)`
+            #v fn times<MockallR>(&mut self, __mockall_r: MockallR) -> &mut Self
+                where MockallR: Into<::mockall::TimesRange>
+            {
+                self.common.times(__mockall_r);
+                self
+            }
+
+            /// Set matching crieteria for this Expectation.
+            ///
+            /// The matching predicate can be anything implemening the
+            /// [`Predicate`](../../../mockall/trait.Predicate.html) trait.  Only
+            /// one matcher can be set per `Expectation` at a time.
+            #v fn with<#with_generics>(&mut self, #with_args) -> &mut Self
+            {
+                self.common.with(#(#argnames, )*);
+                self
+            }
+
+            /// Set a matching function for this Expectation.
+            ///
+            /// This is equivalent to calling [`with`](#method.with) with a
+            /// function argument, like `with(predicate::function(f))`.
+            #v fn withf<MockallF>(&mut self, __mockall_f: MockallF) -> &mut Self
+                where MockallF: #hrtb Fn(#(&#predty, )*)
+                                -> bool + Send + 'static
+            {
+                self.common.withf(__mockall_f);
+                self
+            }
+
+            /// Single-threaded version of [`withf`](#method.withf).
+            /// Can be used when the argument type isn't `Send`.
+            #v fn withf_st<MockallF>(&mut self, __mockall_f: MockallF) -> &mut Self
+                where MockallF: #hrtb Fn(#(&#predty, )*)
+                                -> bool + 'static
+            {
+                self.common.withf_st(__mockall_f);
+                self
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+/// Holds the moethods of the Expectations object that are common for all
+/// Expectation types
+struct CommonExpectationsMethods<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for CommonExpectationsMethods<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+        let v = &self.f.privmod_vis;
+        quote!(
+            /// A collection of [`Expectation`](struct.Expectations.html)
+            /// objects.  Users will rarely if ever use this struct directly.
+            #[doc(hidden)]
+            #v struct Expectations #ig ( Vec<Expectation #tg>) #wc;
+
+            impl #ig Expectations #tg #wc {
+                /// Verify that all current expectations are satisfied and clear
+                /// them.
+                #v fn checkpoint(&mut self) -> std::vec::Drain<Expectation #tg>
+                {
+                    self.0.drain(..)
+                }
+
+                /// Create a new expectation for this method.
+                #v fn expect(&mut self) -> &mut Expectation #tg
+                {
+                    self.0.push(Expectation::default());
+                    let __mockall_l = self.0.len();
+                    &mut self.0[__mockall_l - 1]
+                }
+
+                #v fn new() -> Self {
+                    Self::default()
+                }
+            }
+            impl #ig Default for Expectations #tg #wc
+            {
+                fn default() -> Self {
+                    Expectations(Vec::new())
+                }
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+/// The ExpectationGuard structure for static methods with no generic types
+struct ExpectationGuardCommonMethods<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for ExpectationGuardCommonMethods<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        if !self.f.is_static {
+            return;
+        }
+
+        let argnames = &self.f.argnames;
+        let argty = &self.f.argty;
+        let (_, tg, _) = self.f.egenerics.split_for_impl();
+        let keyid = gen_keyid(&self.f.egenerics);
+        let expectations = if self.f.is_expectation_generic() {
+            quote!(self.guard
+                   .store
+                   .get_mut(&::mockall::Key::new::#keyid())
+                   .unwrap()
+                   .downcast_mut::<Expectations #tg>()
+                   .unwrap())
+        } else {
+            quote!(self.guard)
+        };
+        let hrtb = self.f.hrtb();
+        let output = &self.f.output;
+        let predty = &self.f.predty;
+        let with_generics_idents = (0..self.f.predty.len())
+            .map(|i| format_ident!("MockallMatcher{}", i))
+            .collect::<Vec<_>>();
+        let with_generics = with_generics_idents
+            .iter()
+            .zip(self.f.predty.iter())
+            .map(|(id, mt)| quote!(#id: #hrtb ::mockall::Predicate<#mt> + Send + 'static, ))
+            .collect::<TokenStream>();
+        let with_args = self
+            .f
+            .argnames
+            .iter()
+            .zip(with_generics_idents.iter())
+            .map(|(argname, id)| quote!(#argname: #id, ))
+            .collect::<TokenStream>();
+        let v = &self.f.privmod_vis;
+        quote!(
+            /// Just like
+            /// [`Expectation::in_sequence`](struct.Expectation.html#method.in_sequence)
+            #v fn in_sequence(&mut self,
+                __mockall_seq: &mut ::mockall::Sequence)
+                -> &mut Expectation #tg
+            {
+                #expectations.0[self.i].in_sequence(__mockall_seq)
+            }
+
+            /// Just like
+            /// [`Expectation::never`](struct.Expectation.html#method.never)
+            #v fn never(&mut self) -> &mut Expectation #tg {
+                #expectations.0[self.i].never()
+            }
+
+            /// Just like
+            /// [`Expectation::once`](struct.Expectation.html#method.once)
+            #v fn once(&mut self) -> &mut Expectation #tg {
+                #expectations.0[self.i].once()
+            }
+
+            /// Just like
+            /// [`Expectation::return_const`](struct.Expectation.html#method.return_const)
+            #v fn return_const<MockallOutput>
+            (&mut self, __mockall_c: MockallOutput)
+                -> &mut Expectation #tg
+                where MockallOutput: Clone + Into<#output> + Send + 'static
+            {
+                #expectations.0[self.i].return_const(__mockall_c)
+            }
+
+            /// Just like
+            /// [`Expectation::return_const_st`](struct.Expectation.html#method.return_const_st)
+            #v fn return_const_st<MockallOutput>
+            (&mut self, __mockall_c: MockallOutput)
+                -> &mut Expectation #tg
+                where MockallOutput: Clone + Into<#output> + 'static
+            {
+                #expectations.0[self.i].return_const_st(__mockall_c)
+            }
+
+            /// Just like
+            /// [`Expectation::returning`](struct.Expectation.html#method.returning)
+            #v fn returning<MockallF>(&mut self, __mockall_f: MockallF)
+                -> &mut Expectation #tg
+                where MockallF: #hrtb FnMut(#(#argty, )*)
+                    -> #output + Send + 'static
+            {
+                #expectations.0[self.i].returning(__mockall_f)
+            }
+
+            /// Just like
+            /// [`Expectation::return_once`](struct.Expectation.html#method.return_once)
+            #v fn return_once<MockallF>(&mut self, __mockall_f: MockallF)
+                -> &mut Expectation #tg
+                where MockallF: #hrtb FnOnce(#(#argty, )*)
+                                -> #output + Send + 'static
+            {
+                #expectations.0[self.i].return_once(__mockall_f)
+            }
+
+            /// Just like
+            /// [`Expectation::return_once_st`](struct.Expectation.html#method.return_once_st)
+            #v fn return_once_st<MockallF>(&mut self, __mockall_f: MockallF)
+                -> &mut Expectation #tg
+                where MockallF: #hrtb FnOnce(#(#argty, )*)
+                                -> #output + 'static
+            {
+                #expectations.0[self.i].return_once_st(__mockall_f)
+            }
+
+
+            /// Just like
+            /// [`Expectation::returning_st`](struct.Expectation.html#method.returning_st)
+            #v fn returning_st<MockallF>(&mut self, __mockall_f: MockallF)
+                -> &mut Expectation #tg
+                where MockallF: #hrtb FnMut(#(#argty, )*)
+                                -> #output + 'static
+            {
+                #expectations.0[self.i].returning_st(__mockall_f)
+            }
+
+            /// Just like
+            /// [`Expectation::times`](struct.Expectation.html#method.times)
+            #v fn times<MockallR>(&mut self, __mockall_r: MockallR)
+                -> &mut Expectation #tg
+                where MockallR: Into<::mockall::TimesRange>
+            {
+                #expectations.0[self.i].times(__mockall_r)
+            }
+
+            /// Just like
+            /// [`Expectation::with`](struct.Expectation.html#method.with)
+            #v fn with<#with_generics> (&mut self, #with_args)
+                -> &mut Expectation #tg
+            {
+                #expectations.0[self.i].with(#(#argnames, )*)
+            }
+
+            /// Just like
+            /// [`Expectation::withf`](struct.Expectation.html#method.withf)
+            #v fn withf<MockallF>(&mut self, __mockall_f: MockallF)
+                -> &mut Expectation #tg
+                where MockallF: #hrtb Fn(#(&#predty, )*)
+                                -> bool + Send + 'static
+            {
+                #expectations.0[self.i].withf(__mockall_f)
+            }
+
+            /// Just like
+            /// [`Expectation::withf_st`](struct.Expectation.html#method.withf_st)
+            #v fn withf_st<MockallF>(&mut self, __mockall_f: MockallF)
+                -> &mut Expectation #tg
+                where MockallF: #hrtb Fn(#(&#predty, )*)
+                                -> bool + 'static
+            {
+                #expectations.0[self.i].withf_st(__mockall_f)
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+/// The ExpectationGuard structure for static methods with no generic types
+struct ConcreteExpectationGuard<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for ConcreteExpectationGuard<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        if !self.f.is_static {
+            return;
+        }
+
+        let common_methods = ExpectationGuardCommonMethods { f: self.f };
+        let (_, tg, _) = self.f.egenerics.split_for_impl();
+        let ltdef = LifetimeDef::new(Lifetime::new("'__mockall_lt", Span::call_site()));
+        let mut e_generics = self.f.egenerics.clone();
+        e_generics.lt_token.get_or_insert(<Token![<]>::default());
+        e_generics.params.push(GenericParam::Lifetime(ltdef));
+        e_generics.gt_token.get_or_insert(<Token![>]>::default());
+        let (e_ig, e_tg, e_wc) = e_generics.split_for_impl();
+        let (ei_ig, _, _) = e_generics.split_for_impl();
+        let v = &self.f.privmod_vis;
+        quote!(
+            ::mockall::lazy_static! {
+                #[doc(hidden)]
+                #v static ref EXPECTATIONS:
+                    ::std::sync::Mutex<Expectations #tg> =
+                    ::std::sync::Mutex::new(Expectations::new());
+            }
+            /// Like an [`&Expectation`](struct.Expectation.html) but
+            /// protected by a Mutex guard.  Useful for mocking static
+            /// methods.  Forwards accesses to an `Expectation` object.
+            // We must return the MutexGuard to the caller so he can
+            // configure the expectation.  But we can't bundle both the
+            // guard and the &Expectation into the same structure; the
+            // borrow checker won't let us.  Instead we'll record the
+            // expectation's position within the Expectations vector so we
+            // can proxy its methods.
+            //
+            // ExpectationGuard is only defined for expectations that return
+            // 'static return types.
+            #v struct ExpectationGuard #e_ig #e_wc {
+                guard: MutexGuard<'__mockall_lt, Expectations #tg>,
+                i: usize
+            }
+
+            #[allow(clippy::unused_unit)]
+            impl #ei_ig ExpectationGuard #e_tg #e_wc
+            {
+                // Should only be called from the mockall_derive generated
+                // code
+                #[doc(hidden)]
+                #v fn new(mut __mockall_guard: MutexGuard<'__mockall_lt, Expectations #tg>)
+                    -> Self
+                {
+                    __mockall_guard.expect(); // Drop the &Expectation
+                    let __mockall_i = __mockall_guard.0.len() - 1;
+                    ExpectationGuard{guard: __mockall_guard, i: __mockall_i}
+                }
+
+                #common_methods
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+/// The ExpectationGuard structure for static methods with generic types
+struct GenericExpectationGuard<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for GenericExpectationGuard<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        if !self.f.is_static {
+            return;
+        }
+
+        let common_methods = ExpectationGuardCommonMethods { f: self.f };
+        let (_, tg, _) = self.f.egenerics.split_for_impl();
+        let keyid = gen_keyid(&self.f.egenerics);
+        let ltdef = LifetimeDef::new(Lifetime::new("'__mockall_lt", Span::call_site()));
+        let mut egenerics = self.f.egenerics.clone();
+        egenerics.lt_token.get_or_insert(<Token![<]>::default());
+        egenerics.params.push(GenericParam::Lifetime(ltdef));
+        egenerics.gt_token.get_or_insert(<Token![>]>::default());
+        let (e_ig, e_tg, e_wc) = egenerics.split_for_impl();
+        let fn_params = &self.f.fn_params;
+        let tbf = tg.as_turbofish();
+        let v = &self.f.privmod_vis;
+        quote!(
+            ::mockall::lazy_static! {
+                #v static ref EXPECTATIONS:
+                    ::std::sync::Mutex<GenericExpectations> =
+                    ::std::sync::Mutex::new(GenericExpectations::new());
+            }
+            /// Like an [`&Expectation`](struct.Expectation.html) but
+            /// protected by a Mutex guard.  Useful for mocking static
+            /// methods.  Forwards accesses to an `Expectation` object.
+            #v struct ExpectationGuard #e_ig #e_wc{
+                guard: MutexGuard<'__mockall_lt, GenericExpectations>,
+                i: usize,
+                _phantom: ::std::marker::PhantomData<(#(#fn_params,)*)>,
+            }
+
+            #[allow(clippy::unused_unit)]
+            impl #e_ig ExpectationGuard #e_tg #e_wc
+            {
+                // Should only be called from the mockall_derive generated
+                // code
+                #[doc(hidden)]
+                #v fn new(mut __mockall_guard: MutexGuard<'__mockall_lt, GenericExpectations>)
+                    -> Self
+                {
+                    let __mockall_ee: &mut Expectations #tg =
+                        __mockall_guard.store.entry(
+                            ::mockall::Key::new::#keyid()
+                        ).or_insert_with(||
+                            Box::new(Expectations #tbf ::new()))
+                        .downcast_mut()
+                        .unwrap();
+                    __mockall_ee.expect();    // Drop the &Expectation
+                    let __mockall_i = __mockall_ee.0.len() - 1;
+                    ExpectationGuard{guard: __mockall_guard, i: __mockall_i,
+                        _phantom: ::std::marker::PhantomData}
+                }
+
+                #common_methods
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+/// Generates Context, which manages the context for expectations of static
+/// methods.
+struct Context<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for Context<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        if !self.f.is_static {
+            return;
+        }
+
+        let ltdef = LifetimeDef::new(Lifetime::new("'__mockall_lt", Span::call_site()));
+        let mut egenerics = self.f.egenerics.clone();
+        egenerics.lt_token.get_or_insert(<Token![<]>::default());
+        egenerics.params.push(GenericParam::Lifetime(ltdef));
+        egenerics.gt_token.get_or_insert(<Token![>]>::default());
+        let (_, e_tg, _) = egenerics.split_for_impl();
+        let (ty_ig, ty_tg, ty_wc) = self.f.type_generics.split_for_impl();
+        let mut meth_generics = self.f.call_generics.clone();
+        let ltdef = LifetimeDef::new(Lifetime::new("'__mockall_lt", Span::call_site()));
+        meth_generics.params.push(GenericParam::Lifetime(ltdef));
+        let (meth_ig, _meth_tg, meth_wc) = meth_generics.split_for_impl();
+        let ctx_fn_params = self
+            .f
+            .struct_generics
+            .type_params()
+            .map(|tp| tp.ident.clone())
+            .collect::<Punctuated<Ident, Token![,]>>();
+        let v = &self.f.privmod_vis;
+
+        #[cfg(not(feature = "nightly_derive"))]
+        let must_use = quote!(#[must_use =
+            "Must set return value when not using the \"nightly\" feature"
+        ]);
+        #[cfg(feature = "nightly_derive")]
+        let must_use = quote!();
+
+        quote!(
+            /// Manages the context for expectations of static methods.
+            ///
+            /// Expectations on this method will be validated and cleared when
+            /// the `Context` object drops.  The `Context` object does *not*
+            /// provide any form of synchronization, so multiple tests that set
+            /// expectations on the same static method must provide their own.
+            #[must_use = "Context only serves to create expectations" ]
+            #v struct Context #ty_ig #ty_wc {
+                // Prevent "unused type parameter" errors
+                // Surprisingly, PhantomData<Fn(generics)> is Send even if
+                // generics are not, unlike PhantomData<generics>
+                _phantom: ::std::marker::PhantomData<
+                    Box<dyn Fn(#ctx_fn_params) + Send>
+                >
+            }
+            impl #ty_ig Context #ty_tg #ty_wc {
+                /// Verify that all current expectations for this method are
+                /// satisfied and clear them.
+                #v fn checkpoint(&self) {
+                    Self::do_checkpoint()
+                }
+                #[doc(hidden)]
+                #v fn do_checkpoint() {
+                    let __mockall_timeses = EXPECTATIONS
+                        .lock()
+                        .unwrap()
+                        .checkpoint()
+                        .collect::<Vec<_>>();
+                }
+
+                /// Create a new expectation for this method.
+                #must_use
+                #v fn expect #meth_ig ( &self,) -> ExpectationGuard #e_tg
+                    #meth_wc
+                {
+                    ExpectationGuard::new(EXPECTATIONS.lock().unwrap())
+                }
+            }
+            impl #ty_ig Default for Context #ty_tg #ty_wc {
+                fn default() -> Self {
+                    Context {_phantom: std::marker::PhantomData}
+                }
+            }
+            impl #ty_ig Drop for Context #ty_tg #ty_wc {
+                fn drop(&mut self) {
+                    Self::do_checkpoint()
+                }
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+struct Matcher<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for Matcher<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let (ig, tg, wc) = self.f.cgenerics.split_for_impl();
+        let argnames = &self.f.argnames;
+        let braces = argnames.iter().fold(String::new(), |mut acc, _argname| {
+            if acc.is_empty() {
+                acc.push_str("{}");
+            } else {
+                acc.push_str(", {}");
+            }
+            acc
+        });
+        let fn_params = &self.f.fn_params;
+        let hrtb = self.f.hrtb();
+        let indices = (0..argnames.len())
+            .map(|i| syn::Index::from(i))
+            .collect::<Vec<_>>();
+        let lg = lifetimes_to_generics(&self.f.alifetimes);
+        let pred_matches = argnames
+            .iter()
+            .enumerate()
+            .map(|(i, argname)| {
+                let idx = syn::Index::from(i);
+                quote!(__mockall_pred.#idx.eval(#argname),)
+            })
+            .collect::<TokenStream>();
+        let preds = self
+            .f
+            .predty
+            .iter()
+            .map(|t| quote!(Box<dyn #hrtb ::mockall::Predicate<#t> + Send>,))
+            .collect::<TokenStream>();
+        let predty = &self.f.predty;
+        let refpredty = &self.f.refpredty;
+        quote!(
+            enum Matcher #ig #wc {
+                Always,
+                Func(Box<dyn #hrtb Fn(#( #refpredty, )*) -> bool + Send>),
+                // Version of Matcher::Func for closures that aren't Send
+                FuncSt(::mockall::Fragile<Box<dyn #hrtb Fn(#( #refpredty, )*) -> bool>>),
+                Pred(Box<(#preds)>),
+                // Prevent "unused type parameter" errors
+                // Surprisingly, PhantomData<Fn(generics)> is Send even if
+                // generics are not, unlike PhantomData<generics>
+                _Phantom(Box<dyn Fn(#(#fn_params,)*) + Send>)
+            }
+            impl #ig Matcher #tg #wc {
+                #[allow(clippy::ptr_arg)]
+                fn matches #lg (&self, #( #argnames: &#predty, )*) -> bool {
+                    match self {
+                        Matcher::Always => true,
+                        Matcher::Func(__mockall_f) =>
+                            __mockall_f(#(#argnames, )*),
+                        Matcher::FuncSt(__mockall_f) =>
+                            (__mockall_f.get())(#(#argnames, )*),
+                        Matcher::Pred(__mockall_pred) =>
+                            [#pred_matches]
+                            .iter()
+                            .all(|__mockall_x| *__mockall_x),
+                        _ => unreachable!()
+                    }
+                }
+            }
+
+            impl #ig Default for Matcher #tg #wc {
+                #[allow(unused_variables)]
+                fn default() -> Self {
+                    Matcher::Always
+                }
+            }
+
+            impl #ig ::std::fmt::Display for Matcher #tg #wc {
+                fn fmt(&self, __mockall_fmt: &mut ::std::fmt::Formatter<'_>)
+                    -> ::std::fmt::Result
+                {
+                    match self {
+                        Matcher::Always => write!(__mockall_fmt, "<anything>"),
+                        Matcher::Func(_) => write!(__mockall_fmt, "<function>"),
+                        Matcher::FuncSt(_) => write!(__mockall_fmt, "<single threaded function>"),
+                        Matcher::Pred(__mockall_p) => {
+                            write!(__mockall_fmt, #braces,
+                                #(__mockall_p.#indices,)*)
+                        }
+                        _ => unreachable!(),
+                    }
+                }
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+struct RefRfunc<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for RefRfunc<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let fn_params = &self.f.fn_params;
+        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+        let lg = lifetimes_to_generics(&self.f.alifetimes);
+        let owned_output = &self.f.owned_output;
+
+        #[cfg(not(feature = "nightly_derive"))]
+        let default_err_msg = "Returning default values requires the \"nightly\" feature";
+        #[cfg(feature = "nightly_derive")]
+        let default_err_msg = "Can only return default values for types that impl std::Default";
+
+        quote!(
+            enum Rfunc #ig #wc {
+                Default(Option<#owned_output>),
+                Const(#owned_output),
+                // Prevent "unused type parameter" errors Surprisingly,
+                // PhantomData<Fn(generics)> is Send even if generics are not,
+                // unlike PhantomData<generics>
+                _Phantom(Mutex<Box<dyn Fn(#(#fn_params,)*) + Send>>)
+            }
+
+            impl #ig  Rfunc #tg #wc {
+                fn call #lg (&self)
+                    -> std::result::Result<&#owned_output, &'static str>
+                {
+                    match self {
+                        Rfunc::Default(Some(ref __mockall_o)) => {
+                            ::std::result::Result::Ok(__mockall_o)
+                        },
+                        Rfunc::Default(None) => {
+                            Err(#default_err_msg)
+                        },
+                        Rfunc::Const(ref __mockall_o) => {
+                            ::std::result::Result::Ok(__mockall_o)
+                        },
+                        Rfunc::_Phantom(_) => unreachable!()
+                    }
+                }
+            }
+
+            impl #ig std::default::Default for Rfunc #tg #wc
+            {
+                fn default() -> Self {
+                    use ::mockall::ReturnDefault;
+                    Rfunc::Default(::mockall::DefaultReturner::<#owned_output>
+                                ::maybe_return_default())
+                }
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+struct RefMutRfunc<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for RefMutRfunc<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let argnames = &self.f.argnames;
+        let argty = &self.f.argty;
+        let fn_params = &self.f.fn_params;
+        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+        let lg = lifetimes_to_generics(&self.f.alifetimes);
+        let owned_output = &self.f.owned_output;
+        let output = &self.f.output;
+
+        #[cfg(not(feature = "nightly_derive"))]
+        let default_err_msg = "Returning default values requires the \"nightly\" feature";
+        #[cfg(feature = "nightly_derive")]
+        let default_err_msg = "Can only return default values for types that impl std::Default";
+
+        quote!(
+            #[allow(clippy::unused_unit)]
+            enum Rfunc #ig #wc {
+                Default(Option<#owned_output>),
+                Mut((Box<dyn FnMut(#(#argty, )*) -> #owned_output + Send + Sync>),
+                    Option<#owned_output>),
+                // Version of Rfunc::Mut for closures that aren't Send
+                MutSt((::mockall::Fragile<
+                           Box<dyn FnMut(#(#argty, )*) -> #owned_output >>
+                       ), Option<#owned_output>
+                ),
+                Var(#owned_output),
+                // Prevent "unused type parameter" errors Surprisingly,
+                // PhantomData<Fn(generics)> is Send even if generics are not,
+                // unlike PhantomData<generics>
+                _Phantom(Mutex<Box<dyn Fn(#(#fn_params,)*) + Send>>)
+            }
+
+            impl #ig  Rfunc #tg #wc {
+                fn call_mut #lg (&mut self, #(#argnames: #argty, )*)
+                    -> std::result::Result<#output, &'static str>
+                {
+                    match self {
+                        Rfunc::Default(Some(ref mut __mockall_o)) => {
+                            ::std::result::Result::Ok(__mockall_o)
+                        },
+                        Rfunc::Default(None) => {
+                            Err(#default_err_msg)
+                        },
+                        Rfunc::Mut(ref mut __mockall_f, ref mut __mockall_o) =>
+                        {
+                            *__mockall_o = Some(__mockall_f(#(#argnames, )*));
+                            if let Some(ref mut __mockall_o2) = __mockall_o {
+                                ::std::result::Result::Ok(__mockall_o2)
+                            } else {
+                                unreachable!()
+                            }
+                        },
+                        Rfunc::MutSt(ref mut __mockall_f, ref mut __mockall_o)=>
+                        {
+                            *__mockall_o = Some((__mockall_f.get_mut())(
+                                    #(#argnames, )*)
+                            );
+                            if let Some(ref mut __mockall_o2) = __mockall_o {
+                                ::std::result::Result::Ok(__mockall_o2)
+                            } else {
+                                unreachable!()
+                            }
+                        },
+                        Rfunc::Var(ref mut __mockall_o) => {
+                            ::std::result::Result::Ok(__mockall_o)
+                        },
+                        Rfunc::_Phantom(_) => unreachable!()
+                    }
+                }
+            }
+
+            impl #ig std::default::Default for Rfunc #tg #wc
+            {
+                fn default() -> Self {
+                    use ::mockall::ReturnDefault;
+                    Rfunc::Default(::mockall::DefaultReturner::<#owned_output>
+                                ::maybe_return_default())
+                }
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+struct StaticRfunc<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for StaticRfunc<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let argnames = &self.f.argnames;
+        let argty = &self.f.argty;
+        let fn_params = &self.f.fn_params;
+        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+        let hrtb = self.f.hrtb();
+        let lg = lifetimes_to_generics(&self.f.alifetimes);
+        let output = &self.f.output;
+        quote!(
+            #[allow(clippy::unused_unit)]
+            enum Rfunc #ig #wc {
+                Default,
+                // Indicates that a `return_once` expectation has already
+                // returned
+                Expired,
+                Mut(Box<dyn #hrtb FnMut(#(#argty, )*) -> #output + Send>),
+                // Version of Rfunc::Mut for closures that aren't Send
+                MutSt(::mockall::Fragile<
+                    Box<dyn #hrtb FnMut(#(#argty, )*) -> #output >>
+                ),
+                Once(Box<dyn #hrtb FnOnce(#(#argty, )*) -> #output + Send>),
+                // Version of Rfunc::Once for closure that aren't Send
+                OnceSt(::mockall::Fragile<
+                    Box<dyn #hrtb FnOnce(#(#argty, )*) -> #output>>
+                ),
+                // Prevent "unused type parameter" errors Surprisingly,
+                // PhantomData<Fn(generics)> is Send even if generics are not,
+                // unlike PhantomData<generics>
+                _Phantom(Box<dyn Fn(#(#fn_params,)*) + Send>)
+            }
+
+            impl #ig  Rfunc #tg #wc {
+                fn call_mut #lg (&mut self, #( #argnames: #argty, )* )
+                    -> std::result::Result<#output, &'static str>
+                {
+                    match self {
+                        Rfunc::Default => {
+                            use ::mockall::ReturnDefault;
+                            ::mockall::DefaultReturner::<#output>
+                                ::return_default()
+                        },
+                        Rfunc::Expired => {
+                            Err("called twice, but it returns by move")
+                        },
+                        Rfunc::Mut(__mockall_f) => {
+                            ::std::result::Result::Ok(__mockall_f( #(#argnames, )* ))
+                        },
+                        Rfunc::MutSt(__mockall_f) => {
+                            ::std::result::Result::Ok((__mockall_f.get_mut())(#(#argnames,)*))
+                        },
+                        Rfunc::Once(_) => {
+                            if let Rfunc::Once(mut __mockall_f) =
+                                mem::replace(self, Rfunc::Expired) {
+                                ::std::result::Result::Ok(__mockall_f( #(#argnames, )* ))
+                            } else {
+                                unreachable!()
+                            }
+                        },
+                        Rfunc::OnceSt(_) => {
+                            if let Rfunc::OnceSt(mut __mockall_f) =
+                                mem::replace(self, Rfunc::Expired) {
+                                ::std::result::Result::Ok((__mockall_f.into_inner())(#(#argnames,)*))
+                            } else {
+                                unreachable!()
+                            }
+                        },
+                        Rfunc::_Phantom(_) => unreachable!()
+                    }
+                }
+            }
+
+            impl #ig std::default::Default for Rfunc #tg #wc
+            {
+                fn default() -> Self {
+                    Rfunc::Default
+                }
+            }
+        ).to_tokens(tokens);
+    }
+}
+
+/// An expectation type for functions that take a &self and return a reference
+struct RefExpectation<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for RefExpectation<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let argnames = &self.f.argnames;
+        let argty = &self.f.argty;
+        let common_methods = CommonExpectationMethods { f: self.f };
+        let desc = self.f.desc();
+        let funcname = self.f.funcname();
+        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+
+        let (_, common_tg, _) = self.f.cgenerics.split_for_impl();
+        let lg = lifetimes_to_generics(&self.f.alifetimes);
+        let output = &self.f.output;
+        let owned_output = &self.f.owned_output;
+        let v = &self.f.privmod_vis;
+        quote!(
+            /// Expectation type for methods taking a `&self` argument and
+            /// returning immutable references.  This is the type returned by
+            /// the `expect_*` methods.
+            #v struct Expectation #ig #wc {
+                common: Common #common_tg,
+                rfunc: Rfunc #tg,
+            }
+
+            #[allow(clippy::unused_unit)]
+            impl #ig Expectation #tg #wc {
+                /// Call this [`Expectation`] as if it were the real method.
+                #v fn call #lg (&self, #(#argnames: #argty, )*) -> #output
+                {
+                    self.common.call(&#desc);
+                    self.rfunc.call().unwrap_or_else(|m| {
+                        let desc = std::format!(
+                            "{}", self.common.matcher.lock().unwrap());
+                        panic!("{}: Expectation({}) {}", #funcname, desc,
+                            m);
+                    })
+                }
+
+                /// Return a reference to a constant value from the `Expectation`
+                #v fn return_const(&mut self, __mockall_o: #owned_output)
+                    -> &mut Self
+                {
+                    self.rfunc = Rfunc::Const(__mockall_o);
+                    self
+                }
+
+                #common_methods
+            }
+            impl #ig Default for Expectation #tg #wc
+            {
+                fn default() -> Self {
+                    Expectation {
+                        common: Common::default(),
+                        rfunc: Rfunc::default()
+                    }
+                }
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+/// For methods that take &mut self and return a reference
+struct RefMutExpectation<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for RefMutExpectation<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let common_methods = CommonExpectationMethods { f: self.f };
+        let argnames = &self.f.argnames;
+        let argty = &self.f.argty;
+        let desc = self.f.desc();
+        let funcname = self.f.funcname();
+        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+        let (_, common_tg, _) = self.f.cgenerics.split_for_impl();
+        let lg = lifetimes_to_generics(&self.f.alifetimes);
+        let owned_output = &self.f.owned_output;
+        let v = &self.f.privmod_vis;
+        quote!(
+            /// Expectation type for methods taking a `&mut self` argument and
+            /// returning references.  This is the type returned by the
+            /// `expect_*` methods.
+            #v struct Expectation #ig #wc {
+                common: Common #common_tg,
+                rfunc: Rfunc #tg
+            }
+
+            #[allow(clippy::unused_unit)]
+            impl #ig Expectation #tg #wc {
+                /// Simulating calling the real method for this expectation
+                #v fn call_mut #lg (&mut self, #(#argnames: #argty, )*)
+                    -> &mut #owned_output
+                {
+                    self.common.call(&#desc);
+                    let desc = std::format!(
+                        "{}", self.common.matcher.lock().unwrap());
+                    self.rfunc.call_mut(#(#argnames, )*).unwrap_or_else(|m| {
+                            panic!("{}: Expectation({}) {}", #funcname, desc,
+                                   m);
+                    })
+                }
+
+                /// Convenience method that can be used to supply a return value
+                /// for a `Expectation`.  The value will be returned by mutable
+                /// reference.
+                #v fn return_var(&mut self, __mockall_o: #owned_output) -> &mut Self
+                {
+                    self.rfunc = Rfunc::Var(__mockall_o);
+                    self
+                }
+
+                /// Supply a closure that the `Expectation` will use to create its
+                /// return value.  The return value will be returned by mutable
+                /// reference.
+                #v fn returning<MockallF>(&mut self, __mockall_f: MockallF)
+                    -> &mut Self
+                    where MockallF: FnMut(#(#argty, )*) -> #owned_output + Send + Sync + 'static
+                {
+                    self.rfunc = Rfunc::Mut(Box::new(__mockall_f), None);
+                    self
+                }
+
+                /// Single-threaded version of [`returning`](#method.returning).
+                /// Can be used when the argument or return type isn't `Send`.
+                #v fn returning_st<MockallF>(&mut self, __mockall_f: MockallF)
+                    -> &mut Self
+                    where MockallF: FnMut(#(#argty, )*) -> #owned_output + 'static
+                {
+                    self.rfunc = Rfunc::MutSt(
+                        ::mockall::Fragile::new(Box::new(__mockall_f)), None);
+                    self
+                }
+
+                #common_methods
+            }
+            impl #ig Default for Expectation #tg #wc
+            {
+                fn default() -> Self {
+                    Expectation {
+                        common: Common::default(),
+                        rfunc: Rfunc::default()
+                    }
+                }
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+/// An expectation type for functions return a `'static` value
+struct StaticExpectation<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for StaticExpectation<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let common_methods = CommonExpectationMethods { f: self.f };
+        let argnames = &self.f.argnames;
+        let argty = &self.f.argty;
+        let desc = self.f.desc();
+        let hrtb = self.f.hrtb();
+        let funcname = self.f.funcname();
+        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+        let (_, common_tg, _) = self.f.cgenerics.split_for_impl();
+        let lg = lifetimes_to_generics(&self.f.alifetimes);
+        let output = &self.f.output;
+        let v = &self.f.privmod_vis;
+
+        quote!(
+            /// Expectation type for methods that return a `'static` type.
+            /// This is the type returned by the `expect_*` methods.
+            #v struct Expectation #ig #wc {
+                common: Common #common_tg,
+                rfunc: Mutex<Rfunc #tg>,
+            }
+
+            #[allow(clippy::unused_unit)]
+            impl #ig Expectation #tg #wc {
+                /// Call this [`Expectation`] as if it were the real method.
+                #[doc(hidden)]
+                #v fn call #lg (&self, #(#argnames: #argty, )* ) -> #output
+                {
+                    self.common.call(&#desc);
+                    self.rfunc.lock().unwrap().call_mut(#(#argnames, )*)
+                        .unwrap_or_else(|message| {
+                            let desc = std::format!(
+                                "{}", self.common.matcher.lock().unwrap());
+                            panic!("{}: Expectation({}) {}", #funcname, desc,
+                                   message);
+                        })
+                }
+
+                /// Return a constant value from the `Expectation`
+                ///
+                /// The output type must be `Clone`.  The compiler can't always
+                /// infer the proper type to use with this method; you will
+                /// usually need to specify it explicitly.  i.e.
+                /// `return_const(42i32)` instead of `return_const(42)`.
+                // We must use Into<#output> instead of #output because where
+                // clauses don't accept equality constraints.
+                // https://github.com/rust-lang/rust/issues/20041
+                #[allow(unused_variables)]
+                #v fn return_const<MockallOutput>(&mut self,
+                    __mockall_c: MockallOutput)
+                    -> &mut Self
+                    where MockallOutput: Clone + Into<#output> + Send + 'static
+                {
+                    self.returning(move |#(#argnames, )*| __mockall_c.clone().into())
+                }
+
+                /// Single-threaded version of
+                /// [`return_const`](#method.return_const).  This is useful for
+                /// return types that are not `Send`.
+                ///
+                /// The output type must be `Clone`.  The compiler can't always
+                /// infer the proper type to use with this method; you will
+                /// usually need to specify it explicitly.  i.e.
+                /// `return_const(42i32)` instead of `return_const(42)`.
+                ///
+                /// It is a runtime error to call the mock method from a
+                /// different thread than the one that originally called this
+                /// method.
+                // We must use Into<#output> instead of #output because where
+                // clauses don't accept equality constraints.
+                // https://github.com/rust-lang/rust/issues/20041
+                #[allow(unused_variables)]
+                #v fn return_const_st<MockallOutput>(&mut self,
+                    __mockall_c: MockallOutput)
+                    -> &mut Self
+                    where MockallOutput: Clone + Into<#output> + 'static
+                {
+                    self.returning_st(move |#(#argnames, )*| __mockall_c.clone().into())
+                }
+
+                /// Supply an `FnOnce` closure that will provide the return
+                /// value for this Expectation.  This is useful for return types
+                /// that aren't `Clone`.  It will be an error to call this
+                /// method multiple times.
+                #v fn return_once<MockallF>(&mut self, __mockall_f: MockallF)
+                    -> &mut Self
+                    where MockallF: #hrtb FnOnce(#(#argty, )*)
+                                    -> #output + Send + 'static
+                {
+                    {
+                        let mut __mockall_guard = self.rfunc.lock().unwrap();
+                        *__mockall_guard.deref_mut() =
+                            Rfunc::Once(Box::new(__mockall_f));
+                    }
+                    self
+                }
+
+                /// Single-threaded version of
+                /// [`return_once`](#method.return_once).  This is useful for
+                /// return types that are neither `Send` nor `Clone`.
+                ///
+                /// It is a runtime error to call the mock method from a
+                /// different thread than the one that originally called this
+                /// method.  It is also a runtime error to call the method more
+                /// than once.
+                #v fn return_once_st<MockallF>(&mut self, __mockall_f:
+                                                  MockallF) -> &mut Self
+                    where MockallF: #hrtb FnOnce(#(#argty, )*)
+                                    -> #output + 'static
+                {
+                    {
+                        let mut __mockall_guard = self.rfunc.lock().unwrap();
+                        *__mockall_guard.deref_mut() = Rfunc::OnceSt(
+                            ::mockall::Fragile::new(Box::new(__mockall_f)));
+                    }
+                    self
+                }
+
+                /// Supply a closure that will provide the return value for this
+                /// `Expectation`.  The method's arguments are passed to the
+                /// closure by value.
+                #v fn returning<MockallF>(&mut self, __mockall_f: MockallF)
+                    -> &mut Self
+                    where MockallF: #hrtb FnMut(#(#argty, )*)
+                                    -> #output + Send + 'static
+                {
+                    {
+                        let mut __mockall_guard = self.rfunc.lock().unwrap();
+                        *__mockall_guard.deref_mut() =
+                            Rfunc::Mut(Box::new(__mockall_f));
+                    }
+                    self
+                }
+
+                /// Single-threaded version of [`returning`](#method.returning).
+                /// Can be used when the argument or return type isn't `Send`.
+                ///
+                /// It is a runtime error to call the mock method from a
+                /// different thread than the one that originally called this
+                /// method.
+                #v fn returning_st<MockallF>(&mut self, __mockall_f: MockallF)
+                    -> &mut Self
+                    where MockallF: #hrtb FnMut(#(#argty, )*)
+                                    -> #output + 'static
+                {
+                    {
+                        let mut __mockall_guard = self.rfunc.lock().unwrap();
+                        *__mockall_guard.deref_mut() = Rfunc::MutSt(
+                            ::mockall::Fragile::new(Box::new(__mockall_f)));
+                    }
+                    self
+                }
+
+                #common_methods
+            }
+            impl #ig Default for Expectation #tg #wc
+            {
+                fn default() -> Self {
+                    Expectation {
+                        common: Common::default(),
+                        rfunc: Mutex::new(Rfunc::default())
+                    }
+                }
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+/// An collection of RefExpectation's
+struct RefExpectations<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for RefExpectations<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let common_methods = CommonExpectationsMethods { f: self.f };
+        let argnames = &self.f.argnames;
+        let argty = &self.f.argty;
+        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+        let lg = lifetimes_to_generics(&self.f.alifetimes);
+        let output = &self.f.output;
+        let predexprs = &self.f.predexprs;
+        let v = &self.f.privmod_vis;
+        quote!(
+            #common_methods
+            impl #ig Expectations #tg #wc {
+                /// Simulate calling the real method.  Every current expectation
+                /// will be checked in FIFO order and the first one with
+                /// matching arguments will be used.
+                #v fn call #lg (&self, #(#argnames: #argty, )* )
+                    -> Option<#output>
+                {
+                    self.0.iter()
+                        .find(|__mockall_e|
+                              __mockall_e.matches(#(#predexprs, )*) &&
+                              (!__mockall_e.is_done() || self.0.len() == 1))
+                        .map(move |__mockall_e|
+                             __mockall_e.call(#(#argnames),*)
+                        )
+                }
+
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+/// An collection of RefMutExpectation's
+struct RefMutExpectations<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for RefMutExpectations<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let common_methods = CommonExpectationsMethods { f: self.f };
+        let argnames = &self.f.argnames;
+        let argty = &self.f.argty;
+        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+        let lg = lifetimes_to_generics(&self.f.alifetimes);
+        let output = &self.f.output;
+        let predexprs = &self.f.predexprs;
+        let v = &self.f.privmod_vis;
+        quote!(
+            #common_methods
+            impl #ig Expectations #tg #wc {
+                /// Simulate calling the real method.  Every current expectation
+                /// will be checked in FIFO order and the first one with
+                /// matching arguments will be used.
+                #v fn call_mut #lg (&mut self, #(#argnames: #argty, )* )
+                    -> Option<#output>
+                {
+                    let __mockall_n = self.0.len();
+                    self.0.iter_mut()
+                        .find(|__mockall_e|
+                              __mockall_e.matches(#(#predexprs, )*) &&
+                              (!__mockall_e.is_done() || __mockall_n == 1))
+                        .map(move |__mockall_e|
+                             __mockall_e.call_mut(#(#argnames, )*)
+                        )
+                }
+
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+/// An collection of Expectation's for methods returning static values
+struct StaticExpectations<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for StaticExpectations<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let common_methods = CommonExpectationsMethods { f: self.f };
+        let argnames = &self.f.argnames;
+        let argty = &self.f.argty;
+        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+        let lg = lifetimes_to_generics(&self.f.alifetimes);
+        let output = &self.f.output;
+        let predexprs = &self.f.predexprs;
+        let v = &self.f.privmod_vis;
+        quote!(
+            #common_methods
+            impl #ig Expectations #tg #wc {
+                /// Simulate calling the real method.  Every current expectation
+                /// will be checked in FIFO order and the first one with
+                /// matching arguments will be used.
+                #v fn call #lg (&self, #(#argnames: #argty, )* )
+                    -> Option<#output>
+                {
+                    self.0.iter()
+                        .find(|__mockall_e|
+                              __mockall_e.matches(#(#predexprs, )*) &&
+                              (!__mockall_e.is_done() || self.0.len() == 1))
+                        .map(move |__mockall_e|
+                             __mockall_e.call(#(#argnames, )*)
+                        )
+                }
+
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
+
+struct GenericExpectations<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for GenericExpectations<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        if !self.f.is_expectation_generic() {
+            return;
+        }
+        if !self.f.is_static() && !self.f.is_method_generic() {
+            return;
+        }
+
+        let ge = StaticGenericExpectations { f: self.f };
+        let v = &self.f.privmod_vis;
+        quote!(
+            /// A collection of [`Expectation`](struct.Expectations.html)
+            /// objects for a generic method.  Users will rarely if ever use
+            /// this struct directly.
+            #[doc(hidden)]
+            #[derive(Default)]
+            #v struct GenericExpectations{
+                store: std::collections::hash_map::HashMap<::mockall::Key,
+                               Box<dyn ::mockall::AnyExpectations>>
+            }
+            impl GenericExpectations {
+                /// Verify that all current expectations are satisfied and clear
+                /// them.  This applies to all sets of generic parameters!
+                #v fn checkpoint(&mut self) ->
+                    std::collections::hash_map::Drain<::mockall::Key,
+                               Box<dyn ::mockall::AnyExpectations>>
+                {
+                    self.store.drain()
+                }
+
+                #v fn new() -> Self {
+                    Self::default()
+                }
+            }
+            #ge
+        )
+        .to_tokens(tokens);
+    }
+}
+
+/// Generates methods for GenericExpectations for methods returning static
+/// values
+struct StaticGenericExpectations<'a> {
+    f: &'a MockFunction,
+}
+
+impl<'a> ToTokens for StaticGenericExpectations<'a> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let argnames = &self.f.argnames;
+        let argty = &self.f.argty;
+        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
+        let keyid = gen_keyid(&self.f.egenerics);
+        let mut any_wc = wc.cloned();
+        if self.f.return_ref || self.f.return_refmut {
+            // Add Senc + Sync, required for downcast, since Expectation
+            // stores an Option<#owned_output>
+            send_syncify(&mut any_wc, self.f.owned_output.clone());
+        }
+        let tbf = tg.as_turbofish();
+        let output = &self.f.output;
+        let v = &self.f.privmod_vis;
+        let (call, get, self_, downcast) = if self.f.return_refmut {
+            (
+                format_ident!("call_mut"),
+                format_ident!("get_mut"),
+                quote!(&mut self),
+                format_ident!("downcast_mut"),
+            )
+        } else {
+            (
+                format_ident!("call"),
+                format_ident!("get"),
+                quote!(&self),
+                format_ident!("downcast_ref"),
+            )
+        };
+        quote!(
+            impl #ig ::mockall::AnyExpectations for Expectations #tg #any_wc {}
+            impl GenericExpectations {
+                /// Simulating calling the real method.
+                #v fn #call #ig (#self_, #(#argnames: #argty, )* )
+                    -> Option<#output> #wc
+                {
+                    self.store.#get(&::mockall::Key::new::#keyid())
+                        .map(|__mockall_e| {
+                            __mockall_e.#downcast::<Expectations #tg>()
+                            .unwrap()
+                            .#call(#(#argnames, )*)
+                        }).flatten()
+                }
+
+                /// Create a new Expectation.
+                #v fn expect #ig (&mut self) -> &mut Expectation #tg #any_wc
+                {
+                    self.store.entry(::mockall::Key::new::#keyid())
+                        .or_insert_with(|| Box::new(Expectations #tbf::new()))
+                        .downcast_mut::<Expectations #tg>()
+                        .unwrap()
+                        .expect()
+                }
+            }
+        )
+        .to_tokens(tokens)
+    }
+}
diff --git a/src/mock_item.rs b/src/mock_item.rs
new file mode 100644
index 0000000..109d9c2
--- /dev/null
+++ b/src/mock_item.rs
@@ -0,0 +1,172 @@
+// vim: tw=80
+use super::*;
+
+use crate::{
+    mock_function::MockFunction,
+    mockable_item::{MockableItem, MockableModule},
+};
+
+/// A Mock item
+pub(crate) enum MockItem {
+    Module(MockItemModule),
+    Struct(MockItemStruct),
+}
+
+impl From<MockableItem> for MockItem {
+    fn from(mockable: MockableItem) -> MockItem {
+        match mockable {
+            MockableItem::Struct(s) => MockItem::Struct(MockItemStruct::from(s)),
+            MockableItem::Module(mod_) => MockItem::Module(MockItemModule::from(mod_)),
+        }
+    }
+}
+
+impl ToTokens for MockItem {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        match self {
+            MockItem::Module(mod_) => mod_.to_tokens(tokens),
+            MockItem::Struct(s) => s.to_tokens(tokens),
+        }
+    }
+}
+
+enum MockItemContent {
+    Fn(Box<MockFunction>),
+    Tokens(TokenStream),
+}
+
+pub(crate) struct MockItemModule {
+    attrs: TokenStream,
+    vis: Visibility,
+    mock_ident: Ident,
+    orig_ident: Option<Ident>,
+    content: Vec<MockItemContent>,
+}
+
+impl From<MockableModule> for MockItemModule {
+    fn from(mod_: MockableModule) -> MockItemModule {
+        let mock_ident = mod_.mock_ident.clone();
+        let orig_ident = mod_.orig_ident;
+        let mut content = Vec::new();
+        for item in mod_.content.into_iter() {
+            let span = item.span();
+            match item {
+                Item::ExternCrate(_) | Item::Impl(_) => {
+                    // Ignore
+                }
+                Item::Static(is) => {
+                    content.push(MockItemContent::Tokens(is.into_token_stream()));
+                }
+                Item::Const(ic) => {
+                    content.push(MockItemContent::Tokens(ic.into_token_stream()));
+                }
+                Item::Fn(f) => {
+                    let mf = mock_function::Builder::new(&f.sig, &f.vis)
+                        .attrs(&f.attrs)
+                        .parent(&mock_ident)
+                        .levels(1)
+                        .call_levels(0)
+                        .build();
+                    content.push(MockItemContent::Fn(Box::new(mf)));
+                }
+                Item::ForeignMod(ifm) => {
+                    for item in ifm.items {
+                        if let ForeignItem::Fn(mut f) = item {
+                            // Foreign functions are always unsafe.  Mock
+                            // foreign functions should be unsafe too, to
+                            // prevent "warning: unused unsafe" messages.
+                            f.sig.unsafety = Some(Token![unsafe](f.span()));
+                            let mf = mock_function::Builder::new(&f.sig, &f.vis)
+                                .attrs(&f.attrs)
+                                .parent(&mock_ident)
+                                .levels(1)
+                                .call_levels(0)
+                                .build();
+                            content.push(MockItemContent::Fn(Box::new(mf)));
+                        } else {
+                            compile_error(item.span(),
+                                "Mockall does not yet support  this type in this position.  Please open an issue with your use case at https://github.com/asomers/mockall");
+                        }
+                    }
+                }
+                Item::Mod(_)
+                | Item::Struct(_)
+                | Item::Enum(_)
+                | Item::Union(_)
+                | Item::Trait(_) => {
+                    compile_error(span, "Mockall does not yet support deriving nested mocks");
+                }
+                Item::Type(ty) => {
+                    content.push(MockItemContent::Tokens(ty.into_token_stream()));
+                }
+                Item::TraitAlias(ta) => {
+                    content.push(MockItemContent::Tokens(ta.into_token_stream()));
+                }
+                Item::Use(u) => {
+                    content.push(MockItemContent::Tokens(u.into_token_stream()));
+                }
+                _ => compile_error(span, "Unsupported item"),
+            }
+        }
+        MockItemModule {
+            attrs: mod_.attrs,
+            vis: mod_.vis,
+            mock_ident: mod_.mock_ident,
+            orig_ident,
+            content,
+        }
+    }
+}
+
+impl ToTokens for MockItemModule {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let mut body = TokenStream::new();
+        let mut cp_body = TokenStream::new();
+        let attrs = &self.attrs;
+        let modname = &self.mock_ident;
+        let vis = &self.vis;
+
+        for item in self.content.iter() {
+            match item {
+                MockItemContent::Tokens(ts) => ts.to_tokens(&mut body),
+                MockItemContent::Fn(f) => {
+                    let call = f.call(None);
+                    let ctx_fn = f.context_fn(None);
+                    let priv_mod = f.priv_module();
+                    quote!(
+                        #priv_mod
+                        #call
+                        #ctx_fn
+                    )
+                    .to_tokens(&mut body);
+                    f.checkpoint().to_tokens(&mut cp_body);
+                }
+            }
+        }
+
+        quote!(
+            /// Verify that all current expectations for every function in
+            /// this module are satisfied and clear them.
+            pub fn checkpoint() { #cp_body }
+        )
+        .to_tokens(&mut body);
+        let docstr = {
+            if let Some(ident) = &self.orig_ident {
+                let inner = format!("Mock version of the `{}` module", ident);
+                quote!( #[doc = #inner])
+            } else {
+                // Typically an extern FFI block.  Not really anything good we
+                // can put in the doc string.
+                quote!(#[allow(missing_docs)])
+            }
+        };
+        quote!(
+            #[allow(unused_imports)]
+            #attrs
+            #docstr
+            #vis mod #modname {
+                #body
+        })
+        .to_tokens(tokens);
+    }
+}
diff --git a/src/mock_item_struct.rs b/src/mock_item_struct.rs
new file mode 100644
index 0000000..9bf5c13
--- /dev/null
+++ b/src/mock_item_struct.rs
@@ -0,0 +1,456 @@
+// vim: tw=80
+use super::*;
+
+use quote::ToTokens;
+use std::collections::HashSet;
+
+use crate::{mock_function::MockFunction, mock_trait::MockTrait};
+
+fn phantom_default_inits(generics: &Generics) -> Vec<TokenStream> {
+    generics
+        .params
+        .iter()
+        .enumerate()
+        .map(|(count, _param)| {
+            let phident = format_ident!("_t{}", count);
+            quote!(#phident: ::std::marker::PhantomData)
+        })
+        .collect()
+}
+
+/// Generate any PhantomData field definitions
+fn phantom_fields(generics: &Generics) -> Vec<TokenStream> {
+    generics
+        .params
+        .iter()
+        .enumerate()
+        .filter_map(|(count, param)| {
+            let phident = format_ident!("_t{}", count);
+            match param {
+                syn::GenericParam::Lifetime(l) => {
+                    if !l.bounds.is_empty() {
+                        compile_error(
+                            l.bounds.span(),
+                            "#automock does not yet support lifetime bounds on structs",
+                        );
+                    }
+                    let lifetime = &l.lifetime;
+                    Some(quote!(#phident: ::std::marker::PhantomData<&#lifetime ()>))
+                }
+                syn::GenericParam::Type(tp) => {
+                    let ty = &tp.ident;
+                    Some(quote!(#phident: ::std::marker::PhantomData<#ty>))
+                }
+                syn::GenericParam::Const(_) => {
+                    compile_error(
+                        param.span(),
+                        "#automock does not yet support generic constants",
+                    );
+                    None
+                }
+            }
+        })
+        .collect()
+}
+
+/// Filter out multiple copies of the same trait, even if they're implemented on
+/// different types.  But allow them if they have different attributes, which
+/// probably indicates that they aren't meant to be compiled together.
+fn unique_trait_iter<'a, I: Iterator<Item = &'a MockTrait>>(
+    i: I,
+) -> impl Iterator<Item = &'a MockTrait> {
+    let mut hs = HashSet::<(Path, Vec<Attribute>)>::default();
+    i.filter(move |mt| {
+        let impl_attrs = AttrFormatter::new(&mt.attrs)
+            .async_trait(false)
+            .doc(false)
+            .format();
+        let key = (mt.trait_path.clone(), impl_attrs);
+        if hs.contains(&key) {
+            false
+        } else {
+            hs.insert(key);
+            true
+        }
+    })
+}
+
+/// A collection of methods defined in one spot
+struct Methods(Vec<MockFunction>);
+
+impl Methods {
+    /// Are all of these methods static?
+    fn all_static(&self) -> bool {
+        self.0.iter().all(|meth| meth.is_static())
+    }
+
+    fn checkpoints(&self) -> Vec<impl ToTokens> {
+        self.0
+            .iter()
+            .filter(|meth| !meth.is_static())
+            .map(|meth| meth.checkpoint())
+            .collect::<Vec<_>>()
+    }
+
+    /// Return a fragment of code to initialize struct fields during default()
+    fn default_inits(&self) -> Vec<TokenStream> {
+        self.0
+            .iter()
+            .filter(|meth| !meth.is_static())
+            .map(|meth| {
+                let name = meth.name();
+                let attrs = AttrFormatter::new(&meth.attrs).doc(false).format();
+                quote!(#(#attrs)* #name: Default::default())
+            })
+            .collect::<Vec<_>>()
+    }
+
+    fn field_definitions(&self, modname: &Ident) -> Vec<TokenStream> {
+        self.0
+            .iter()
+            .filter(|meth| !meth.is_static())
+            .map(|meth| meth.field_definition(Some(modname)))
+            .collect::<Vec<_>>()
+    }
+
+    fn priv_mods(&self) -> Vec<impl ToTokens> {
+        self.0
+            .iter()
+            .map(|meth| meth.priv_module())
+            .collect::<Vec<_>>()
+    }
+}
+
+pub(crate) struct MockItemStruct {
+    attrs: Vec<Attribute>,
+    consts: Vec<ImplItemConst>,
+    generics: Generics,
+    /// Should Mockall generate a Debug implementation?
+    auto_debug: bool,
+    /// Does the original struct have a `new` method?
+    has_new: bool,
+    /// Inherent methods of the mock struct
+    methods: Methods,
+    /// Name of the overall module that holds all of the mock stuff
+    modname: Ident,
+    name: Ident,
+    /// Is this a whole MockStruct or just a substructure for a trait impl?
+    traits: Vec<MockTrait>,
+    vis: Visibility,
+}
+
+impl MockItemStruct {
+    fn debug_impl(&self) -> impl ToTokens {
+        if self.auto_debug {
+            let (ig, tg, wc) = self.generics.split_for_impl();
+            let struct_name = &self.name;
+            let struct_name_str = format!("{}", self.name);
+            quote!(
+                impl #ig ::std::fmt::Debug for #struct_name #tg #wc {
+                    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>)
+                        -> ::std::result::Result<(), std::fmt::Error>
+                    {
+                        f.debug_struct(#struct_name_str).finish()
+                    }
+                }
+            )
+        } else {
+            quote!()
+        }
+    }
+
+    fn new_method(&self) -> impl ToTokens {
+        if self.has_new {
+            TokenStream::new()
+        } else {
+            quote!(
+                /// Create a new mock object with no expectations.
+                ///
+                /// This method will not be generated if the real struct
+                /// already has a `new` method.  However, it *will* be
+                /// generated if the struct implements a trait with a `new`
+                /// method.  The trait's `new` method can still be called
+                /// like `<MockX as TraitY>::new`
+                pub fn new() -> Self {
+                    Self::default()
+                }
+            )
+        }
+    }
+
+    fn phantom_default_inits(&self) -> Vec<TokenStream> {
+        phantom_default_inits(&self.generics)
+    }
+
+    fn phantom_fields(&self) -> Vec<TokenStream> {
+        phantom_fields(&self.generics)
+    }
+}
+
+impl From<MockableStruct> for MockItemStruct {
+    fn from(mockable: MockableStruct) -> MockItemStruct {
+        let auto_debug = mockable.derives_debug();
+        let modname = gen_mod_ident(&mockable.name, None);
+        let generics = mockable.generics.clone();
+        let struct_name = &mockable.name;
+        let vis = mockable.vis;
+        let has_new = mockable.methods.iter().any(|meth| meth.sig.ident == "new")
+            || mockable.impls.iter().any(|impl_| {
+                impl_.items.iter().any(|ii| {
+                    if let ImplItem::Method(iim) = ii {
+                        iim.sig.ident == "new"
+                    } else {
+                        false
+                    }
+                })
+            });
+        let methods = Methods(
+            mockable
+                .methods
+                .into_iter()
+                .map(|meth| {
+                    mock_function::Builder::new(&meth.sig, &meth.vis)
+                        .attrs(&meth.attrs)
+                        .struct_(struct_name)
+                        .struct_generics(&generics)
+                        .levels(2)
+                        .call_levels(0)
+                        .build()
+                })
+                .collect::<Vec<_>>(),
+        );
+        let structname = &mockable.name;
+        let traits = mockable
+            .impls
+            .into_iter()
+            .map(|i| MockTrait::new(structname, &generics, i, &vis))
+            .collect();
+
+        MockItemStruct {
+            attrs: mockable.attrs,
+            auto_debug,
+            consts: mockable.consts,
+            generics,
+            has_new,
+            methods,
+            modname,
+            name: mockable.name,
+            traits,
+            vis,
+        }
+    }
+}
+
+impl ToTokens for MockItemStruct {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let attrs = AttrFormatter::new(&self.attrs).async_trait(false).format();
+        let consts = &self.consts;
+        let debug_impl = self.debug_impl();
+        let struct_name = &self.name;
+        let (ig, tg, wc) = self.generics.split_for_impl();
+        let modname = &self.modname;
+        let calls = self
+            .methods
+            .0
+            .iter()
+            .map(|meth| meth.call(Some(modname)))
+            .collect::<Vec<_>>();
+        let contexts = self
+            .methods
+            .0
+            .iter()
+            .filter(|meth| meth.is_static())
+            .map(|meth| meth.context_fn(Some(modname)))
+            .collect::<Vec<_>>();
+        let expects = self
+            .methods
+            .0
+            .iter()
+            .filter(|meth| !meth.is_static())
+            .map(|meth| meth.expect(modname, None))
+            .collect::<Vec<_>>();
+        let method_checkpoints = self.methods.checkpoints();
+        let new_method = self.new_method();
+        let priv_mods = self.methods.priv_mods();
+        let substructs = unique_trait_iter(self.traits.iter())
+            .map(|trait_| MockItemTraitImpl {
+                attrs: trait_.attrs.clone(),
+                generics: self.generics.clone(),
+                fieldname: format_ident!("{}_expectations", trait_.ss_name()),
+                methods: Methods(trait_.methods.clone()),
+                modname: format_ident!("{}_{}", &self.modname, trait_.ss_name()),
+                name: format_ident!("{}_{}", &self.name, trait_.ss_name()),
+            })
+            .collect::<Vec<_>>();
+        let substruct_expectations = substructs
+            .iter()
+            .filter(|ss| !ss.all_static())
+            .map(|ss| {
+                let attrs = AttrFormatter::new(&ss.attrs)
+                    .async_trait(false)
+                    .doc(false)
+                    .format();
+                let fieldname = &ss.fieldname;
+                quote!(#(#attrs)* self.#fieldname.checkpoint();)
+            })
+            .collect::<Vec<_>>();
+        let mut field_definitions = substructs
+            .iter()
+            .filter(|ss| !ss.all_static())
+            .map(|ss| {
+                let attrs = AttrFormatter::new(&ss.attrs)
+                    .async_trait(false)
+                    .doc(false)
+                    .format();
+                let fieldname = &ss.fieldname;
+                let tyname = &ss.name;
+                quote!(#(#attrs)* #fieldname: #tyname #tg)
+            })
+            .collect::<Vec<_>>();
+        field_definitions.extend(self.methods.field_definitions(modname));
+        field_definitions.extend(self.phantom_fields());
+        let mut default_inits = substructs
+            .iter()
+            .filter(|ss| !ss.all_static())
+            .map(|ss| {
+                let attrs = AttrFormatter::new(&ss.attrs)
+                    .async_trait(false)
+                    .doc(false)
+                    .format();
+                let fieldname = &ss.fieldname;
+                quote!(#(#attrs)* #fieldname: Default::default())
+            })
+            .collect::<Vec<_>>();
+        default_inits.extend(self.methods.default_inits());
+        default_inits.extend(self.phantom_default_inits());
+        let trait_impls = self
+            .traits
+            .iter()
+            .map(|trait_| {
+                let modname = format_ident!("{}_{}", &self.modname, trait_.ss_name());
+                trait_.trait_impl(&modname)
+            })
+            .collect::<Vec<_>>();
+        let vis = &self.vis;
+        quote!(
+            #[allow(non_snake_case)]
+            #[allow(missing_docs)]
+            pub mod #modname {
+                use super::*;
+                #(#priv_mods)*
+            }
+            #[allow(non_camel_case_types)]
+            #[allow(non_snake_case)]
+            #[allow(missing_docs)]
+            #(#attrs)*
+            #vis struct #struct_name #ig #wc
+            {
+                #(#field_definitions),*
+            }
+            #debug_impl
+            impl #ig ::std::default::Default for #struct_name #tg #wc {
+                #[allow(clippy::default_trait_access)]
+                fn default() -> Self {
+                    Self {
+                        #(#default_inits),*
+                    }
+                }
+            }
+            #(#substructs)*
+            impl #ig #struct_name #tg #wc {
+                #(#consts)*
+                #(#calls)*
+                #(#contexts)*
+                #(#expects)*
+                /// Validate that all current expectations for all methods have
+                /// been satisfied, and discard them.
+                pub fn checkpoint(&mut self) {
+                    #(#substruct_expectations)*
+                    #(#method_checkpoints)*
+                }
+                #new_method
+            }
+            #(#trait_impls)*
+        )
+        .to_tokens(tokens);
+    }
+}
+
+pub(crate) struct MockItemTraitImpl {
+    attrs: Vec<Attribute>,
+    generics: Generics,
+    /// Inherent methods of the mock struct
+    methods: Methods,
+    /// Name of the overall module that holds all of the mock stuff
+    modname: Ident,
+    name: Ident,
+    /// Name of the field of this type in the parent's structure
+    fieldname: Ident,
+}
+
+impl MockItemTraitImpl {
+    /// Are all of this traits's methods static?
+    fn all_static(&self) -> bool {
+        self.methods.all_static()
+    }
+
+    fn phantom_default_inits(&self) -> Vec<TokenStream> {
+        phantom_default_inits(&self.generics)
+    }
+
+    fn phantom_fields(&self) -> Vec<TokenStream> {
+        phantom_fields(&self.generics)
+    }
+}
+
+impl ToTokens for MockItemTraitImpl {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let attrs = AttrFormatter::new(&self.attrs)
+            .async_trait(false)
+            .doc(false)
+            .format();
+        let struct_name = &self.name;
+        let (ig, tg, wc) = self.generics.split_for_impl();
+        let modname = &self.modname;
+        let method_checkpoints = self.methods.checkpoints();
+        let mut default_inits = self.methods.default_inits();
+        default_inits.extend(self.phantom_default_inits());
+        let mut field_definitions = self.methods.field_definitions(modname);
+        field_definitions.extend(self.phantom_fields());
+        let priv_mods = self.methods.priv_mods();
+        quote!(
+            #[allow(non_snake_case)]
+            #[allow(missing_docs)]
+            #(#attrs)*
+            pub mod #modname {
+                use super::*;
+                #(#priv_mods)*
+            }
+            #[allow(non_camel_case_types)]
+            #[allow(non_snake_case)]
+            #[allow(missing_docs)]
+            #(#attrs)*
+            struct #struct_name #ig #wc
+            {
+                #(#field_definitions),*
+            }
+            #(#attrs)*
+            impl #ig ::std::default::Default for #struct_name #tg #wc {
+                fn default() -> Self {
+                    Self {
+                        #(#default_inits),*
+                    }
+                }
+            }
+            #(#attrs)*
+            impl #ig #struct_name #tg #wc {
+                /// Validate that all current expectations for all methods have
+                /// been satisfied, and discard them.
+                pub fn checkpoint(&mut self) {
+                    #(#method_checkpoints)*
+                }
+            }
+        )
+        .to_tokens(tokens);
+    }
+}
diff --git a/src/mock_trait.rs b/src/mock_trait.rs
new file mode 100644
index 0000000..eba29b6
--- /dev/null
+++ b/src/mock_trait.rs
@@ -0,0 +1,184 @@
+// vim: tw=80
+use proc_macro2::Span;
+use quote::{format_ident, quote, ToTokens};
+use std::{
+    collections::hash_map::DefaultHasher,
+    hash::{Hash, Hasher},
+};
+use syn::{spanned::Spanned, *};
+
+use crate::{
+    compile_error,
+    mock_function::{self, MockFunction},
+    AttrFormatter,
+};
+
+pub(crate) struct MockTrait {
+    pub attrs: Vec<Attribute>,
+    pub consts: Vec<ImplItemConst>,
+    pub generics: Generics,
+    pub methods: Vec<MockFunction>,
+    /// Internally-used name of the trait used.
+    pub ss_name: Ident,
+    /// Fully-qualified name of the trait
+    pub trait_path: Path,
+    /// Path on which the trait is implemented.  Usually will be the same as
+    /// structname, but might include concrete generic parameters.
+    self_path: PathSegment,
+    pub types: Vec<ImplItemType>,
+    pub unsafety: Option<Token![unsafe]>,
+}
+
+impl MockTrait {
+    fn ss_name_priv(trait_path: &Path) -> Ident {
+        let path_args = &trait_path.segments.last().unwrap().arguments;
+        if path_args.is_empty() {
+            // Skip the hashing step for easie debugging of generated code
+            format_ident!("{}", trait_path.segments.last().unwrap().ident)
+        } else {
+            // Hash the path args to permit mocking structs that implement
+            // multiple traits distinguished only by their path args
+            let mut hasher = DefaultHasher::new();
+            path_args.hash(&mut hasher);
+            format_ident!(
+                "{}_{}",
+                trait_path.segments.last().unwrap().ident,
+                hasher.finish()
+            )
+        }
+    }
+
+    pub fn ss_name(&self) -> &Ident {
+        &self.ss_name
+    }
+
+    /// Create a new MockTrait
+    ///
+    /// # Arguments
+    /// * `structname` - name of the struct that implements this trait
+    /// * `struct_generics` - Generics of the parent structure
+    /// * `impl_`  -    Mockable ItemImpl for a trait
+    /// * `vis`     -   Visibility of the struct
+    pub fn new(
+        structname: &Ident,
+        struct_generics: &Generics,
+        impl_: ItemImpl,
+        vis: &Visibility,
+    ) -> Self {
+        let mut consts = Vec::new();
+        let mut methods = Vec::new();
+        let mut types = Vec::new();
+        let trait_path = if let Some((_, path, _)) = impl_.trait_ {
+            path
+        } else {
+            compile_error(impl_.span(), "impl block must implement a trait");
+            Path::from(format_ident!("__mockall_invalid"))
+        };
+        let ss_name = MockTrait::ss_name_priv(&trait_path);
+        let self_path = match *impl_.self_ty {
+            Type::Path(mut type_path) => type_path.path.segments.pop().unwrap().into_value(),
+            x => {
+                compile_error(
+                    x.span(),
+                    "mockall_derive only supports mocking traits and structs",
+                );
+                PathSegment::from(Ident::new("", Span::call_site()))
+            }
+        };
+
+        for ii in impl_.items.into_iter() {
+            match ii {
+                ImplItem::Const(iic) => {
+                    consts.push(iic);
+                }
+                ImplItem::Method(iim) => {
+                    let mf = mock_function::Builder::new(&iim.sig, vis)
+                        .attrs(&iim.attrs)
+                        .levels(2)
+                        .call_levels(0)
+                        .struct_(structname)
+                        .struct_generics(struct_generics)
+                        .trait_(&ss_name)
+                        .build();
+                    methods.push(mf);
+                }
+                ImplItem::Type(iit) => {
+                    types.push(iit);
+                }
+                _ => {
+                    compile_error(ii.span(), "This impl item is not yet supported by MockAll");
+                }
+            }
+        }
+        MockTrait {
+            attrs: impl_.attrs,
+            consts,
+            generics: impl_.generics,
+            methods,
+            ss_name,
+            trait_path,
+            self_path,
+            types,
+            unsafety: impl_.unsafety,
+        }
+    }
+
+    /// Generate code for the trait implementation on the mock struct
+    ///
+    /// # Arguments
+    ///
+    /// * `modname`:    Name of the parent struct's private module
+    // Supplying modname is an unfortunately hack.  Ideally MockTrait
+    // wouldn't need to know that.
+    pub fn trait_impl(&self, modname: &Ident) -> impl ToTokens {
+        let trait_impl_attrs = &self.attrs;
+        let impl_attrs = AttrFormatter::new(&self.attrs)
+            .async_trait(false)
+            .doc(false)
+            .format();
+        let (ig, _tg, wc) = self.generics.split_for_impl();
+        let consts = &self.consts;
+        let path_args = &self.self_path.arguments;
+        let calls = self
+            .methods
+            .iter()
+            .map(|meth| meth.call(Some(modname)))
+            .collect::<Vec<_>>();
+        let contexts = self
+            .methods
+            .iter()
+            .filter(|meth| meth.is_static())
+            .map(|meth| meth.context_fn(Some(modname)))
+            .collect::<Vec<_>>();
+        let expects = self
+            .methods
+            .iter()
+            .filter(|meth| !meth.is_static())
+            .map(|meth| {
+                if meth.is_method_generic() {
+                    // Specific impls with generic methods are TODO.
+                    meth.expect(modname, None)
+                } else {
+                    meth.expect(modname, Some(path_args))
+                }
+            })
+            .collect::<Vec<_>>();
+        let trait_path = &self.trait_path;
+        let self_path = &self.self_path;
+        let types = &self.types;
+        let unsafety = &self.unsafety;
+        quote!(
+            #(#trait_impl_attrs)*
+            #unsafety impl #ig #trait_path for #self_path #wc {
+                #(#consts)*
+                #(#types)*
+                #(#calls)*
+            }
+            #(#impl_attrs)*
+            impl #ig #self_path #wc {
+                #(#expects)*
+                #(#contexts)*
+            }
+        )
+    }
+}
diff --git a/src/mockable_item.rs b/src/mockable_item.rs
new file mode 100644
index 0000000..03c894d
--- /dev/null
+++ b/src/mockable_item.rs
@@ -0,0 +1,164 @@
+// vim: tw=80
+use super::*;
+
+/// Performs transformations on a function to make it mockable
+fn mockable_fn(mut item_fn: ItemFn) -> ItemFn {
+    demutify(&mut item_fn.sig.inputs);
+    deimplify(&mut item_fn.sig.output);
+    item_fn
+}
+
+/// Performs transformations on an Item to make it mockable
+fn mockable_item(item: Item) -> Item {
+    match item {
+        Item::Fn(item_fn) => Item::Fn(mockable_fn(item_fn)),
+        x => x,
+    }
+}
+
+/// An item that's ready to be mocked.
+///
+/// It should be functionally identical or near-identical to the original item,
+/// but with minor alterations that make it suitable for mocking, such as
+/// altered lifetimes.
+pub(crate) enum MockableItem {
+    Module(MockableModule),
+    Struct(MockableStruct),
+}
+
+impl From<(Attrs, Item)> for MockableItem {
+    fn from((attrs, item): (Attrs, Item)) -> MockableItem {
+        match item {
+            Item::Impl(item_impl) => MockableItem::Struct(MockableStruct::from(item_impl)),
+            Item::ForeignMod(item_foreign_mod) => {
+                MockableItem::Module(MockableModule::from((attrs, item_foreign_mod)))
+            }
+            Item::Mod(item_mod) => MockableItem::Module(MockableModule::from(item_mod)),
+            Item::Trait(trait_) => MockableItem::Struct(MockableStruct::from((attrs, trait_))),
+            _ => panic!("automock does not support this item type"),
+        }
+    }
+}
+
+impl From<MockableStruct> for MockableItem {
+    fn from(mock: MockableStruct) -> MockableItem {
+        MockableItem::Struct(mock)
+    }
+}
+
+pub(crate) struct MockableModule {
+    pub attrs: TokenStream,
+    pub vis: Visibility,
+    pub mock_ident: Ident,
+    /// Ident of the original module, if any
+    pub orig_ident: Option<Ident>,
+    pub content: Vec<Item>,
+}
+
+impl From<(Attrs, ItemForeignMod)> for MockableModule {
+    fn from((attrs, foreign): (Attrs, ItemForeignMod)) -> MockableModule {
+        let orig_ident = None;
+        let mock_ident = attrs.modname.expect(concat!(
+            "module name is required when mocking foreign functions,",
+            " like `#[automock(mod mock_ffi)]`"
+        ));
+        let vis = Visibility::Public(VisPublic {
+            pub_token: <Token![pub]>::default(),
+        });
+        let attrs = quote!(
+            #[deprecated(since = "0.9.0", note = "Using automock directly on an extern block is deprecated.  Instead, wrap the extern block in a module, and automock that, like #[automock] mod ffi { extern \"C\" { fn foo ... } }")]
+        );
+        let mut content = vec![
+            // When mocking extern blocks, we pretend that they're modules, so
+            // we need a "use super::*;" to ensure that types can resolve
+            Item::Use(ItemUse {
+                attrs: Vec::new(),
+                vis: Visibility::Inherited,
+                use_token: token::Use::default(),
+                leading_colon: None,
+                tree: UseTree::Path(UsePath {
+                    ident: Ident::new("super", Span::call_site()),
+                    colon2_token: token::Colon2::default(),
+                    tree: Box::new(UseTree::Glob(UseGlob {
+                        star_token: token::Star::default(),
+                    })),
+                }),
+                semi_token: token::Semi::default(),
+            }),
+        ];
+        content.extend(foreign.items.into_iter().map(|foreign_item| {
+            match foreign_item {
+                ForeignItem::Fn(f) => {
+                    let span = f.sig.span();
+                    let mut sig = f.sig;
+
+                    // When mocking extern blocks, we pretend that they're
+                    // modules.  So we must supersuperfy everything by one
+                    // level.
+                    let vis = expectation_visibility(&f.vis, 1);
+
+                    for arg in sig.inputs.iter_mut() {
+                        if let FnArg::Typed(pt) = arg {
+                            *pt.ty = supersuperfy(pt.ty.as_ref(), 1);
+                        }
+                    }
+                    if let ReturnType::Type(_, ty) = &mut sig.output {
+                        **ty = supersuperfy(&*ty, 1);
+                    }
+
+                    // Foreign functions are always unsafe.  Mock foreign
+                    // functions should be unsafe too, to prevent "warning:
+                    // unused unsafe" messages.
+                    sig.unsafety = Some(Token![unsafe](span));
+                    let block = Box::new(Block {
+                        brace_token: token::Brace::default(),
+                        stmts: Vec::new(),
+                    });
+
+                    Item::Fn(ItemFn {
+                        attrs: f.attrs,
+                        vis,
+                        sig,
+                        block,
+                    })
+                }
+                _ => {
+                    compile_error(foreign_item.span(), "Unsupported foreign item type");
+                    Item::Verbatim(TokenStream::default())
+                }
+            }
+        }));
+        MockableModule {
+            attrs,
+            vis,
+            mock_ident,
+            orig_ident,
+            content,
+        }
+    }
+}
+
+impl From<ItemMod> for MockableModule {
+    fn from(mod_: ItemMod) -> MockableModule {
+        let span = mod_.span();
+        let vis = mod_.vis;
+        let mock_ident = format_ident!("mock_{}", mod_.ident);
+        let orig_ident = Some(mod_.ident);
+        let content = if let Some((_, content)) = mod_.content {
+            content.into_iter().map(mockable_item).collect()
+        } else {
+            compile_error(
+                span,
+                "automock can only mock inline modules, not modules from another file",
+            );
+            Vec::new()
+        };
+        MockableModule {
+            attrs: TokenStream::new(),
+            vis,
+            mock_ident,
+            orig_ident,
+            content,
+        }
+    }
+}
diff --git a/src/mockable_struct.rs b/src/mockable_struct.rs
new file mode 100644
index 0000000..fe28199
--- /dev/null
+++ b/src/mockable_struct.rs
@@ -0,0 +1,642 @@
+// vim: tw=80
+use super::*;
+use syn::parse::{Parse, ParseStream};
+
+/// Make any implicit lifetime parameters explicit
+fn add_lifetime_parameters(sig: &mut Signature) {
+    fn add_to_trait_object(generics: &mut Generics, var: &Pat, to: &mut TypeTraitObject) {
+        let mut has_lifetime = false;
+        for bound in to.bounds.iter() {
+            if let TypeParamBound::Lifetime(_) = bound {
+                has_lifetime = true;
+            }
+        }
+        if !has_lifetime {
+            let arg_ident = match *var {
+                Pat::Wild(_) => {
+                    compile_error(var.span(), "Mocked methods must have named arguments");
+                    format_ident!("dont_care")
+                }
+                Pat::Ident(ref pat_ident) => {
+                    if let Some(r) = &pat_ident.by_ref {
+                        compile_error(
+                            r.span(),
+                            "Mockall does not support by-reference argument bindings",
+                        );
+                    }
+                    if let Some((_at, subpat)) = &pat_ident.subpat {
+                        compile_error(
+                            subpat.span(),
+                            "Mockall does not support subpattern bindings",
+                        );
+                    }
+                    pat_ident.ident.clone()
+                }
+                _ => {
+                    compile_error(var.span(), "Unsupported argument type");
+                    format_ident!("dont_care")
+                }
+            };
+            let s = format!("'__mockall_{}", arg_ident);
+            let span = Span::call_site();
+            let lt = Lifetime::new(&s, span);
+            to.bounds.push(TypeParamBound::Lifetime(lt.clone()));
+            generics.lt_token.get_or_insert(Token![<](span));
+            generics.gt_token.get_or_insert(Token![>](span));
+            let gpl = GenericParam::Lifetime(LifetimeDef::new(lt));
+            generics.params.push(gpl);
+        }
+    }
+
+    fn add_to_type(generics: &mut Generics, var: &Pat, ty: &mut Type) {
+        match ty {
+            Type::Array(ta) => add_to_type(generics, var, ta.elem.as_mut()),
+            Type::BareFn(_) => (),
+            Type::ImplTrait(_) => (),
+            Type::Path(_) => (),
+            Type::Ptr(_) => (),
+            Type::Reference(tr) => {
+                match tr.elem.as_mut() {
+                    Type::Paren(tp) => {
+                        if let Type::TraitObject(to) = tp.elem.as_mut() {
+                            add_to_trait_object(generics, var, to);
+                        } else {
+                            add_to_type(generics, var, tr.elem.as_mut());
+                        }
+                    }
+                    Type::TraitObject(to) => {
+                        add_to_trait_object(generics, var, to);
+                        // We need to wrap it in a Paren.  Otherwise it won't be
+                        // syntactically valid after we add a lifetime bound,
+                        // due to a "ambiguous `+` in a type" error
+                        *tr.elem = Type::Paren(TypeParen {
+                            paren_token: token::Paren::default(),
+                            elem: Box::new(Type::TraitObject(to.clone())),
+                        });
+                    }
+                    _ => add_to_type(generics, var, tr.elem.as_mut()),
+                }
+            }
+            Type::Slice(ts) => add_to_type(generics, var, ts.elem.as_mut()),
+            Type::Tuple(tt) => {
+                for ty in tt.elems.iter_mut() {
+                    add_to_type(generics, var, ty)
+                }
+            }
+            _ => compile_error(ty.span(), "unsupported type in this position"),
+        }
+    }
+
+    for arg in sig.inputs.iter_mut() {
+        if let FnArg::Typed(pt) = arg {
+            add_to_type(&mut sig.generics, &pt.pat, &mut pt.ty)
+        }
+    }
+}
+
+/// Generate a #[derive(Debug)] Attribute
+fn derive_debug() -> Attribute {
+    Attribute {
+        pound_token: <Token![#]>::default(),
+        style: AttrStyle::Outer,
+        bracket_token: token::Bracket::default(),
+        path: Path::from(format_ident!("derive")),
+        tokens: quote!((Debug)),
+    }
+}
+
+/// Add "Mock" to the front of the named type
+fn mock_ident_in_type(ty: &mut Type) {
+    match ty {
+        Type::Path(type_path) => {
+            if type_path.path.segments.len() != 1 {
+                compile_error(
+                    type_path.path.span(),
+                    "mockall_derive only supports structs defined in the current module",
+                );
+                return;
+            }
+            let ident = &mut type_path.path.segments.last_mut().unwrap().ident;
+            *ident = gen_mock_ident(ident)
+        }
+        x => {
+            compile_error(
+                x.span(),
+                "mockall_derive only supports mocking traits and structs",
+            );
+        }
+    };
+}
+
+/// Performs transformations on the ItemImpl to make it mockable
+fn mockable_item_impl(mut impl_: ItemImpl, name: &Ident, generics: &Generics) -> ItemImpl {
+    mock_ident_in_type(&mut impl_.self_ty);
+    for item in impl_.items.iter_mut() {
+        if let ImplItem::Method(ref mut iim) = item {
+            mockable_method(iim, name, generics);
+        }
+    }
+    impl_
+}
+
+/// Performs transformations on the method to make it mockable
+fn mockable_method(meth: &mut ImplItemMethod, name: &Ident, generics: &Generics) {
+    demutify(&mut meth.sig.inputs);
+    deselfify_args(&mut meth.sig.inputs, name, generics);
+    add_lifetime_parameters(&mut meth.sig);
+    deimplify(&mut meth.sig.output);
+    dewhereselfify(&mut meth.sig.generics);
+    if let ReturnType::Type(_, ty) = &mut meth.sig.output {
+        deselfify(ty, name, generics);
+        deanonymize(ty);
+    }
+    sanity_check_sig(&meth.sig);
+}
+
+/// Performs transformations on the method to make it mockable
+fn mockable_trait_method(meth: &mut TraitItemMethod, name: &Ident, generics: &Generics) {
+    demutify(&mut meth.sig.inputs);
+    deselfify_args(&mut meth.sig.inputs, name, generics);
+    add_lifetime_parameters(&mut meth.sig);
+    deimplify(&mut meth.sig.output);
+    dewhereselfify(&mut meth.sig.generics);
+    if let ReturnType::Type(_, ty) = &mut meth.sig.output {
+        deselfify(ty, name, generics);
+        deanonymize(ty);
+    }
+    sanity_check_sig(&meth.sig);
+}
+
+/// Generates a mockable item impl from a trait method definition
+fn mockable_trait(trait_: ItemTrait, name: &Ident, generics: &Generics) -> ItemImpl {
+    let items = trait_
+        .items
+        .into_iter()
+        .map(|ti| match ti {
+            TraitItem::Method(mut tim) => {
+                mockable_trait_method(&mut tim, name, generics);
+                ImplItem::Method(tim2iim(tim, &Visibility::Inherited))
+            }
+            TraitItem::Const(tic) => ImplItem::Const(tic2iic(tic, &Visibility::Inherited)),
+            TraitItem::Type(tit) => ImplItem::Type(tit2iit(tit, &Visibility::Inherited)),
+            _ => {
+                compile_error(ti.span(), "Unsupported in this context");
+                ImplItem::Verbatim(TokenStream::new())
+            }
+        })
+        .collect::<Vec<_>>();
+    let mut trait_path = Path::from(trait_.ident);
+    let mut struct_path = Path::from(name.clone());
+    let (_, stg, _) = generics.split_for_impl();
+    let (_, ttg, _) = trait_.generics.split_for_impl();
+    if let Ok(abga) = parse2::<AngleBracketedGenericArguments>(quote!(#stg)) {
+        struct_path.segments.last_mut().unwrap().arguments = PathArguments::AngleBracketed(abga);
+    }
+    if let Ok(abga) = parse2::<AngleBracketedGenericArguments>(quote!(#ttg)) {
+        trait_path.segments.last_mut().unwrap().arguments = PathArguments::AngleBracketed(abga);
+    }
+    let self_ty = Box::new(Type::Path(TypePath {
+        qself: None,
+        path: struct_path,
+    }));
+    ItemImpl {
+        attrs: trait_.attrs,
+        defaultness: None,
+        unsafety: trait_.unsafety,
+        impl_token: <Token![impl]>::default(),
+        generics: generics.clone(),
+        trait_: Some((None, trait_path, <Token![for]>::default())),
+        self_ty,
+        brace_token: trait_.brace_token,
+        items,
+    }
+}
+
+fn sanity_check_sig(sig: &Signature) {
+    for arg in sig.inputs.iter() {
+        if let FnArg::Typed(pt) = arg {
+            if let Type::ImplTrait(it) = pt.ty.as_ref() {
+                let bounds = &it.bounds;
+                let s = format!(
+                    "Mockall does not support \"impl trait\" in argument position.  Use \"T: {}\" instead",
+                    quote!(#bounds)
+                );
+                compile_error(it.span(), &s);
+            }
+        }
+    }
+}
+
+/// Converts a TraitItemConst into an ImplItemConst
+fn tic2iic(tic: TraitItemConst, vis: &syn::Visibility) -> ImplItemConst {
+    let span = tic.span();
+    let (eq_token, expr) = tic.default.unwrap_or_else(|| {
+        compile_error(
+            span,
+            "Mocked associated consts must have a default implementation",
+        );
+        (<Token![=]>::default(), Expr::Verbatim(TokenStream::new()))
+    });
+    ImplItemConst {
+        attrs: tic.attrs,
+        vis: vis.clone(),
+        defaultness: None,
+        const_token: tic.const_token,
+        ident: tic.ident,
+        colon_token: tic.colon_token,
+        ty: tic.ty,
+        eq_token,
+        expr,
+        semi_token: tic.semi_token,
+    }
+}
+
+/// Converts a TraitItemMethod into an ImplItemMethod
+fn tim2iim(m: syn::TraitItemMethod, vis: &syn::Visibility) -> syn::ImplItemMethod {
+    let empty_block = Block {
+        brace_token: token::Brace::default(),
+        stmts: Vec::new(),
+    };
+    syn::ImplItemMethod {
+        attrs: m.attrs,
+        vis: vis.clone(),
+        defaultness: None,
+        sig: m.sig,
+        block: empty_block,
+    }
+}
+
+/// Converts a TraitItemType into an ImplItemType
+fn tit2iit(tit: TraitItemType, vis: &Visibility) -> ImplItemType {
+    let span = tit.span();
+    let (eq_token, ty) = tit.default.unwrap_or_else(|| {
+        compile_error(span, "associated types in mock! must be fully specified");
+        (token::Eq::default(), Type::Verbatim(TokenStream::new()))
+    });
+    ImplItemType {
+        attrs: tit.attrs,
+        vis: vis.clone(),
+        defaultness: None,
+        type_token: tit.type_token,
+        ident: tit.ident,
+        generics: tit.generics,
+        eq_token,
+        ty,
+        semi_token: tit.semi_token,
+    }
+}
+
+pub(crate) struct MockableStruct {
+    pub attrs: Vec<Attribute>,
+    pub consts: Vec<ImplItemConst>,
+    pub generics: Generics,
+    /// Inherent methods of the mockable struct
+    pub methods: Vec<ImplItemMethod>,
+    pub name: Ident,
+    pub vis: Visibility,
+    pub impls: Vec<ItemImpl>,
+}
+
+impl MockableStruct {
+    /// Does this struct derive Debug?
+    pub fn derives_debug(&self) -> bool {
+        self.attrs.iter().any(|attr| {
+            if let Ok(Meta::List(ml)) = attr.parse_meta() {
+                let i = ml.path.get_ident();
+                if i.map_or(false, |i| *i == "derive") {
+                    ml.nested.iter().any(|nm| {
+                        if let NestedMeta::Meta(m) = nm {
+                            let i = m.path().get_ident();
+                            i.map_or(false, |i| *i == "Debug")
+                        } else {
+                            false
+                        }
+                    })
+                } else {
+                    false
+                }
+            } else {
+                false
+            }
+        })
+    }
+}
+
+impl From<(Attrs, ItemTrait)> for MockableStruct {
+    fn from((attrs, item_trait): (Attrs, ItemTrait)) -> MockableStruct {
+        let trait_ = attrs.substitute_trait(&item_trait);
+        let mut attrs = trait_.attrs.clone();
+        attrs.push(derive_debug());
+        let vis = trait_.vis.clone();
+        let name = gen_mock_ident(&trait_.ident);
+        let generics = trait_.generics.clone();
+        let impls = vec![mockable_trait(trait_, &name, &generics)];
+        MockableStruct {
+            attrs,
+            consts: Vec::new(),
+            vis,
+            name,
+            generics,
+            methods: Vec::new(),
+            impls,
+        }
+    }
+}
+
+impl From<ItemImpl> for MockableStruct {
+    fn from(mut item_impl: ItemImpl) -> MockableStruct {
+        let name = match &*item_impl.self_ty {
+            Type::Path(type_path) => {
+                let n = find_ident_from_path(&type_path.path).0;
+                gen_mock_ident(&n)
+            }
+            x => {
+                compile_error(
+                    x.span(),
+                    "mockall_derive only supports mocking traits and structs",
+                );
+                Ident::new("", Span::call_site())
+            }
+        };
+        let mut attrs = item_impl.attrs.clone();
+        attrs.push(derive_debug());
+        let mut consts = Vec::new();
+        let generics = item_impl.generics.clone();
+        let mut methods = Vec::new();
+        let pub_token = Token![pub](Span::call_site());
+        let vis = Visibility::Public(VisPublic { pub_token });
+        let mut impls = Vec::new();
+        if let Some((bang, _path, _)) = &item_impl.trait_ {
+            if bang.is_some() {
+                compile_error(bang.span(), "Unsupported by automock");
+            }
+
+            // Substitute any associated types in this ItemImpl.
+            // NB: this would not be necessary if the user always fully
+            // qualified them, e.g. `<Self as MyTrait>::MyType`
+            let mut attrs = Attrs::default();
+            for item in item_impl.items.iter() {
+                match item {
+                    ImplItem::Const(_iic) => (),
+                    ImplItem::Method(_meth) => (),
+                    ImplItem::Type(ty) => {
+                        attrs.attrs.insert(ty.ident.clone(), ty.ty.clone());
+                    }
+                    x => compile_error(x.span(), "Unsupported by automock"),
+                }
+            }
+            attrs.substitute_item_impl(&mut item_impl);
+            impls.push(mockable_item_impl(item_impl, &name, &generics));
+        } else {
+            for item in item_impl.items.into_iter() {
+                match item {
+                    ImplItem::Method(mut meth) => {
+                        mockable_method(&mut meth, &name, &item_impl.generics);
+                        methods.push(meth)
+                    }
+                    ImplItem::Const(iic) => consts.push(iic),
+                    // Rust doesn't allow types in an inherent impl
+                    x => compile_error(x.span(), "Unsupported by Mockall in this context"),
+                }
+            }
+        };
+        MockableStruct {
+            attrs,
+            consts,
+            generics,
+            methods,
+            name,
+            vis,
+            impls,
+        }
+    }
+}
+
+impl Parse for MockableStruct {
+    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
+        let attrs = input.call(syn::Attribute::parse_outer)?;
+        let vis: syn::Visibility = input.parse()?;
+        let original_name: syn::Ident = input.parse()?;
+        let mut generics: syn::Generics = input.parse()?;
+        let wc: Option<syn::WhereClause> = input.parse()?;
+        generics.where_clause = wc;
+        let name = gen_mock_ident(&original_name);
+        let impl_content;
+        let _brace_token = braced!(impl_content in input);
+        let mut consts = Vec::new();
+        let mut methods = Vec::new();
+        while !impl_content.is_empty() {
+            let item: ImplItem = impl_content.parse()?;
+            match item {
+                ImplItem::Method(mut iim) => {
+                    mockable_method(&mut iim, &name, &generics);
+                    methods.push(iim);
+                }
+                ImplItem::Const(iic) => consts.push(iic),
+                _ => {
+                    return Err(input.error("Unsupported in this context"));
+                }
+            }
+        }
+
+        let mut impls = Vec::new();
+        while !input.is_empty() {
+            let item: Item = input.parse()?;
+            match item {
+                Item::Trait(it) => {
+                    let note = "Deprecated mock! syntax.  Instead of \"trait X\", write \"impl X for Y\".  See PR #205";
+                    let mut impl_ = mockable_trait(it, &name, &generics);
+                    impl_.attrs.push(Attribute {
+                        pound_token: <token::Pound>::default(),
+                        style: AttrStyle::Outer,
+                        bracket_token: token::Bracket::default(),
+                        path: Path::from(format_ident!("deprecated")),
+                        tokens: quote!((since = "0.9.0", note = #note)),
+                    });
+                    impls.push(impl_)
+                }
+                Item::Impl(ii) => impls.push(mockable_item_impl(ii, &name, &generics)),
+                _ => return Err(input.error("Unsupported in this context")),
+            }
+        }
+
+        Ok(MockableStruct {
+            attrs,
+            consts,
+            generics,
+            methods,
+            name,
+            vis,
+            impls,
+        })
+    }
+}
+
+#[cfg(test)]
+mod t {
+    use super::*;
+
+    mod add_lifetime_parameters {
+        use super::*;
+
+        #[test]
+        fn array() {
+            let mut meth: TraitItemMethod = parse2(quote!(
+                fn foo(&self, x: [&dyn T; 1]);
+            ))
+            .unwrap();
+            add_lifetime_parameters(&mut meth.sig);
+            assert_eq!(
+                quote!(
+                    fn foo<'__mockall_x>(&self, x: [&(dyn T + '__mockall_x); 1]);
+                )
+                .to_string(),
+                quote!(#meth).to_string()
+            );
+        }
+
+        #[test]
+        fn bare_fn_with_named_args() {
+            let mut meth: TraitItemMethod = parse2(quote!(
+                fn foo(&self, x: fn(&dyn T));
+            ))
+            .unwrap();
+            add_lifetime_parameters(&mut meth.sig);
+            assert_eq!(
+                quote!(
+                    fn foo(&self, x: fn(&dyn T));
+                )
+                .to_string(),
+                quote!(#meth).to_string()
+            );
+        }
+
+        #[test]
+        fn plain() {
+            let mut meth: TraitItemMethod = parse2(quote!(
+                fn foo(&self, x: &dyn T);
+            ))
+            .unwrap();
+            add_lifetime_parameters(&mut meth.sig);
+            assert_eq!(
+                quote!(
+                    fn foo<'__mockall_x>(&self, x: &(dyn T + '__mockall_x));
+                )
+                .to_string(),
+                quote!(#meth).to_string()
+            );
+        }
+
+        #[test]
+        fn slice() {
+            let mut meth: TraitItemMethod = parse2(quote!(
+                fn foo(&self, x: &[&dyn T]);
+            ))
+            .unwrap();
+            add_lifetime_parameters(&mut meth.sig);
+            assert_eq!(
+                quote!(
+                    fn foo<'__mockall_x>(&self, x: &[&(dyn T + '__mockall_x)]);
+                )
+                .to_string(),
+                quote!(#meth).to_string()
+            );
+        }
+
+        #[test]
+        fn tuple() {
+            let mut meth: TraitItemMethod = parse2(quote!(
+                fn foo(&self, x: (&dyn T, u32));
+            ))
+            .unwrap();
+            add_lifetime_parameters(&mut meth.sig);
+            assert_eq!(
+                quote!(
+                    fn foo<'__mockall_x>(&self, x: (&(dyn T + '__mockall_x), u32));
+                )
+                .to_string(),
+                quote!(#meth).to_string()
+            );
+        }
+
+        #[test]
+        fn with_anonymous_lifetime() {
+            let mut meth: TraitItemMethod = parse2(quote!(
+                fn foo(&self, x: &(dyn T + '_));
+            ))
+            .unwrap();
+            add_lifetime_parameters(&mut meth.sig);
+            assert_eq!(
+                quote!(
+                    fn foo(&self, x: &(dyn T + '_));
+                )
+                .to_string(),
+                quote!(#meth).to_string()
+            );
+        }
+
+        #[test]
+        fn with_parens() {
+            let mut meth: TraitItemMethod = parse2(quote!(
+                fn foo(&self, x: &(dyn T));
+            ))
+            .unwrap();
+            add_lifetime_parameters(&mut meth.sig);
+            assert_eq!(
+                quote!(
+                    fn foo<'__mockall_x>(&self, x: &(dyn T + '__mockall_x));
+                )
+                .to_string(),
+                quote!(#meth).to_string()
+            );
+        }
+
+        #[test]
+        fn with_lifetime_parameter() {
+            let mut meth: TraitItemMethod = parse2(quote!(
+                fn foo<'a>(&self, x: &(dyn T + 'a));
+            ))
+            .unwrap();
+            add_lifetime_parameters(&mut meth.sig);
+            assert_eq!(
+                quote!(
+                    fn foo<'a>(&self, x: &(dyn T + 'a));
+                )
+                .to_string(),
+                quote!(#meth).to_string()
+            );
+        }
+
+        #[test]
+        fn with_static_lifetime() {
+            let mut meth: TraitItemMethod = parse2(quote!(
+                fn foo(&self, x: &(dyn T + 'static));
+            ))
+            .unwrap();
+            add_lifetime_parameters(&mut meth.sig);
+            assert_eq!(
+                quote!(
+                    fn foo(&self, x: &(dyn T + 'static));
+                )
+                .to_string(),
+                quote!(#meth).to_string()
+            );
+        }
+    }
+
+    mod sanity_check_sig {
+        use super::*;
+
+        #[test]
+        #[should_panic(
+            expected = "Mockall does not support \"impl trait\" in argument position.  Use \"T: SomeTrait\" instead."
+        )]
+        fn impl_trait() {
+            let meth: ImplItemMethod = parse2(quote!(
+                fn foo(&self, x: impl SomeTrait);
+            ))
+            .unwrap();
+            sanity_check_sig(&meth.sig);
+        }
+    }
+}