]> git.lizzy.rs Git - rust.git/commitdiff
Fix `redundant_closure_for_method_calls` suggestion
authorMatthew Ingwersen <matttpt@gmail.com>
Fri, 28 Oct 2022 19:48:04 +0000 (15:48 -0400)
committerMatthew Ingwersen <matttpt@gmail.com>
Fri, 28 Oct 2022 20:25:51 +0000 (16:25 -0400)
Certain types must be enclosed in angle brackets and must have generic
arguments substituted to create a working suggestion. For example, if
`s` has type `&[u8]`, then `|s| s.len()` may be replaced with
`<[u8]>::len`. Previously, Clippy erroneously suggested `[T]::len`.

clippy_lints/src/eta_reduction.rs
tests/ui/eta.fixed
tests/ui/eta.rs
tests/ui/eta.stderr

index 7b9786d7e570f91b398f2d7ea9e4fa46cb098fdf..9588be7364d82a57a32bb91d8874703d0738dd6b 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::{self, Ty, TypeVisitable};
+use rustc_middle::ty::{self, EarlyBinder, SubstsRef, Ty, TypeVisitable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
 
@@ -150,7 +150,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             if check_sig(cx, closure_ty, call_ty);
             then {
                 span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| {
-                    let name = get_ufcs_type_name(cx, method_def_id);
+                    let name = get_ufcs_type_name(cx, method_def_id, substs);
                     diag.span_suggestion(
                         expr.span,
                         "replace the closure with the method itself",
@@ -220,7 +220,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tc
     cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig)
 }
 
-fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
+fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, substs: SubstsRef<'tcx>) -> String {
     let assoc_item = cx.tcx.associated_item(method_def_id);
     let def_id = assoc_item.container_id(cx.tcx);
     match assoc_item.container {
@@ -229,6 +229,15 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
             let ty = cx.tcx.type_of(def_id);
             match ty.kind() {
                 ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
+                ty::Array(..)
+                | ty::Dynamic(..)
+                | ty::Never
+                | ty::RawPtr(_)
+                | ty::Ref(..)
+                | ty::Slice(_)
+                | ty::Tuple(_) => {
+                    format!("<{}>", EarlyBinder(ty).subst(cx.tcx, substs))
+                },
                 _ => ty.to_string(),
             }
         },
index a9cc80aaaf623c81f85c79be05c1c8b93b6b6ecf..dc129591eac4eb7e4f9e96f9dc64f739acfad0b6 100644 (file)
@@ -316,3 +316,25 @@ pub fn mutable_impl_fn_mut(mut f: impl FnMut(), mut f_used_once: impl FnMut()) -
 
     move || takes_fn_mut(&mut f_used_once)
 }
+
+impl dyn TestTrait + '_ {
+    fn method_on_dyn(&self) -> bool {
+        false
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/7746
+fn angle_brackets_and_substs() {
+    let array_opt: Option<&[u8; 3]> = Some(&[4, 8, 7]);
+    array_opt.map(<[u8; 3]>::as_slice);
+
+    let slice_opt: Option<&[u8]> = Some(b"slice");
+    slice_opt.map(<[u8]>::len);
+
+    let ptr_opt: Option<*const usize> = Some(&487);
+    ptr_opt.map(<*const usize>::is_null);
+
+    let test_struct = TestStruct { some_ref: &487 };
+    let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct);
+    dyn_opt.map(<dyn TestTrait>::method_on_dyn);
+}
index cc99906ccd6677e29488c732a9a5998842c7b542..025fd6a0b7afdf1f5995c0a9d38f314d28efbb3c 100644 (file)
@@ -316,3 +316,25 @@ fn takes_fn_once(_: impl FnOnce()) {}
 
     move || takes_fn_mut(|| f_used_once())
 }
+
+impl dyn TestTrait + '_ {
+    fn method_on_dyn(&self) -> bool {
+        false
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/7746
+fn angle_brackets_and_substs() {
+    let array_opt: Option<&[u8; 3]> = Some(&[4, 8, 7]);
+    array_opt.map(|a| a.as_slice());
+
+    let slice_opt: Option<&[u8]> = Some(b"slice");
+    slice_opt.map(|s| s.len());
+
+    let ptr_opt: Option<*const usize> = Some(&487);
+    ptr_opt.map(|p| p.is_null());
+
+    let test_struct = TestStruct { some_ref: &487 };
+    let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct);
+    dyn_opt.map(|d| d.method_on_dyn());
+}
index 434706b7e258f07d70cd75e9523b4807c06a739c..a521fb868607ad8de2aafb9e3085a6b6bfd12f1e 100644 (file)
@@ -134,5 +134,29 @@ error: redundant closure
 LL |     move || takes_fn_mut(|| f_used_once())
    |                          ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once`
 
-error: aborting due to 22 previous errors
+error: redundant closure
+  --> $DIR/eta.rs:329:19
+   |
+LL |     array_opt.map(|a| a.as_slice());
+   |                   ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice`
+
+error: redundant closure
+  --> $DIR/eta.rs:332:19
+   |
+LL |     slice_opt.map(|s| s.len());
+   |                   ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len`
+
+error: redundant closure
+  --> $DIR/eta.rs:335:17
+   |
+LL |     ptr_opt.map(|p| p.is_null());
+   |                 ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null`
+
+error: redundant closure
+  --> $DIR/eta.rs:339:17
+   |
+LL |     dyn_opt.map(|d| d.method_on_dyn());
+   |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
+
+error: aborting due to 26 previous errors