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;
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",
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 {
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(),
}
},
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);
+}
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());
+}
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