Repository: asomers/mockall (Rust)

Issue:
Doesn't support `self: Arc<Self>`
Doesn't seem to work with self types other than `self`, `&self` and `&mut self`.
Can't use "self: Box<Self>" when mocking trait.
I can't mock traits with functions that take "self: Box\<Self\>".

This fails to compile:
```
#[automock]
trait Foo {
    fn do_work(self: Box<Self>);
}
```
As does this:

```
mock! {
    pub Bar {
        fn do_work(self: Box<Self>);
    }
}
```

The second snippet is more important to me personally as I'm using the workaround for [THIS ](https://github.com/asomers/mockall/issues/75) issue.


Discussion:
Could you provide an example, please?
@asomers Sure:
```
#[automock]
trait Foo {
    fn arc_self(self: Arc<Self>) {}
}
```






Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0621d98c..a7fec30c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,8 +5,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 
 ## [Unreleased] - ReleaseDate
 ### Added
+- Support mocking methods with arbitrary receivers like `self: Box<Self`
+  ([#176](https://github.com/asomers/mockall/pull/176))
+
 - Support mocking methods with trait object arguments that use implicit
-  lifetimes
+  lifetimes.
   ([#174](https://github.com/asomers/mockall/pull/174))
 
 ### Changed
diff --git a/mockall_derive/src/lib.rs b/mockall_derive/src/lib.rs
index fde5b15b..9ec212ae 100644
--- a/mockall_derive/src/lib.rs
+++ b/mockall_derive/src/lib.rs
@@ -163,7 +163,9 @@ fn declosurefy(gen: &Generics, args: &Punctuated<FnArg, Token![,]>) ->
                 let mut pt2 = pt.clone();
                 demutify_arg(&mut pt2);
                 let pat = &pt2.pat;
-                if hm.contains_key(&pt.ty) {
+                if pat_is_self(pat) {
+                    None
+                } else if hm.contains_key(&pt.ty) {
                     Some(quote!(Box::new(#pat)))
                 } else {
                     Some(quote!(#pat))
@@ -452,6 +454,15 @@ fn format_attrs(attrs: &[syn::Attribute], include_docs: bool) -> TokenStream {
     out
 }
 
+/// 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
+    }
+}
+
 fn supersuperfy_path(path: &mut Path, levels: i32) {
     if let Some(t) = path.segments.first() {
         if t.ident == "super" {
diff --git a/mockall_derive/src/mock_function.rs b/mockall_derive/src/mock_function.rs
index 145223fa..fd1610d1 100644
--- a/mockall_derive/src/mock_function.rs
+++ b/mockall_derive/src/mock_function.rs
@@ -139,6 +139,11 @@ impl<'a> Builder<'a> {
         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));


Test patch:
diff --git a/mockall/tests/mock_box_self.rs b/mockall/tests/mock_box_self.rs
new file mode 100644
index 00000000..354ca461
--- /dev/null
+++ b/mockall/tests/mock_box_self.rs
@@ -0,0 +1,67 @@
+// vim: tw=80
+//! Methods that take receivers like Box<Self> instead of &self
+#![deny(warnings)]
+
+use mockall::*;
+use std::sync::Arc;
+use std::pin::Pin;
+use std::rc::Rc;
+
+mock! {
+    Foo {
+        fn foo(self: &Box<Self>);
+        fn baz(mut self: Box<Self>);
+        fn bar(self: Box<Self>);
+        fn bean(self: Arc<Self>);
+        fn booz(self: Pin<Box<Self>>);
+        fn blez(self: Rc<Self>);
+    }
+}
+
+#[test]
+fn arc() {
+    let mut mock = MockFoo::new();
+    mock.expect_bean()
+        .returning(|| ());
+    Arc::new(mock).bean();
+}
+
+#[test]
+fn pin() {
+    let mut mock = MockFoo::new();
+    mock.expect_booz()
+        .returning(|| ());
+    Pin::new(Box::new(mock)).booz();
+}
+
+#[test]
+fn rc() {
+    let mut mock = MockFoo::new();
+    mock.expect_blez()
+        .returning(|| ());
+    Rc::new(mock).blez();
+}
+
+#[test]
+fn ref_box() {
+    let mut mock = Box::new(MockFoo::new());
+    mock.expect_foo()
+        .returning(|| ());
+    mock.foo();
+}
+
+#[test]
+fn mutable() {
+    let mut mock = Box::new(MockFoo::new());
+    mock.expect_baz()
+        .returning(|| ());
+    mock.baz();
+}
+
+#[test]
+fn owned() {
+    let mut mock = Box::new(MockFoo::new());
+    mock.expect_bar()
+        .returning(|| ());
+    mock.bar();
+}