about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Wright <mikerite@lavabit.com>2020-08-23 07:50:59 +0200
committerMichael Wright <mikerite@lavabit.com>2020-08-23 07:50:59 +0200
commite8d33d73dc3f9d0daf9b3affe65a2431f5a3e13a (patch)
treeb0bc083d86082b8bf05ee732574c15839736e443
parentdd07860b839a46782e3750a8924ecf380486c460 (diff)
downloadrust-e8d33d73dc3f9d0daf9b3affe65a2431f5a3e13a.tar.gz
rust-e8d33d73dc3f9d0daf9b3affe65a2431f5a3e13a.zip
Fix `let_and_return` bad suggestion
Add a cast to the suggestion when the return expression has adjustments.
These adjustments are lost when the suggestion is applied.

This is similar to the problem in issue #4437.

Closes #5729
-rw-r--r--clippy_lints/src/returns.rs5
-rw-r--r--tests/ui/let_and_return.rs21
-rw-r--r--tests/ui/let_and_return.stderr16
3 files changed, 40 insertions, 2 deletions
diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs
index 3c5541e64b4..a6e4252a0c8 100644
--- a/clippy_lints/src/returns.rs
+++ b/clippy_lints/src/returns.rs
@@ -99,7 +99,10 @@ impl<'tcx> LateLintPass<'tcx> for Return {
                     |err| {
                         err.span_label(local.span, "unnecessary `let` binding");
 
-                        if let Some(snippet) = snippet_opt(cx, initexpr.span) {
+                        if let Some(mut snippet) = snippet_opt(cx, initexpr.span) {
+                            if !cx.typeck_results().expr_adjustments(&retexpr).is_empty() {
+                                snippet.push_str(" as _");
+                            }
                             err.multipart_suggestion(
                                 "return the expression directly",
                                 vec![
diff --git a/tests/ui/let_and_return.rs b/tests/ui/let_and_return.rs
index 09614b8c1ad..73e550b3df8 100644
--- a/tests/ui/let_and_return.rs
+++ b/tests/ui/let_and_return.rs
@@ -135,4 +135,25 @@ mod no_lint_if_stmt_borrows {
     }
 }
 
+mod issue_5729 {
+    use std::sync::Arc;
+
+    trait Foo {}
+
+    trait FooStorage {
+        fn foo_cloned(&self) -> Arc<dyn Foo>;
+    }
+
+    struct FooStorageImpl<T: Foo> {
+        foo: Arc<T>,
+    }
+
+    impl<T: Foo + 'static> FooStorage for FooStorageImpl<T> {
+        fn foo_cloned(&self) -> Arc<dyn Foo> {
+            let clone = Arc::clone(&self.foo);
+            clone
+        }
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/let_and_return.stderr b/tests/ui/let_and_return.stderr
index eacf948b392..fe878e5f206 100644
--- a/tests/ui/let_and_return.stderr
+++ b/tests/ui/let_and_return.stderr
@@ -27,5 +27,19 @@ LL |
 LL |         5
    |
 
-error: aborting due to 2 previous errors
+error: returning the result of a `let` binding from a block
+  --> $DIR/let_and_return.rs:154:13
+   |
+LL |             let clone = Arc::clone(&self.foo);
+   |             ---------------------------------- unnecessary `let` binding
+LL |             clone
+   |             ^^^^^
+   |
+help: return the expression directly
+   |
+LL |             
+LL |             Arc::clone(&self.foo) as _
+   |
+
+error: aborting due to 3 previous errors