diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index fd6ed36cb19..6ee9e2e9754 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -798,57 +798,55 @@ fn walk_parents<'tcx>( }), ExprKind::MethodCall(_, receiver, args, _) => { let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); - std::iter::once(receiver) - .chain(args.iter()) + if receiver.hir_id == child_id { + // Check for calls to trait methods where the trait is implemented on a reference. + // Two cases need to be handled: + // * `self` methods on `&T` will never have auto-borrow + // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take + // priority. + if e.hir_id != child_id { + return Some(Position::ReborrowStable(precedence)) + } else if let Some(trait_id) = cx.tcx.trait_of_item(id) + && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e)) + && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() + && let subs = match cx + .typeck_results() + .node_substs_opt(parent.hir_id) + .and_then(|subs| subs.get(1..)) + { + Some(subs) => cx.tcx.mk_substs(subs.iter().copied()), + None => cx.tcx.mk_substs(std::iter::empty::>()), + } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() { + // Trait methods taking `&self` + sub_ty + } else { + // Trait methods taking `self` + arg_ty + } && impl_ty.is_ref() + && cx.tcx.infer_ctxt().enter(|infcx| + infcx + .type_implements_trait(trait_id, impl_ty, subs, cx.param_env) + .must_apply_modulo_regions() + ) + { + return Some(Position::MethodReceiverRefImpl) + } else { + return Some(Position::MethodReceiver) + } + } + args.iter() .position(|arg| arg.hir_id == child_id) .map(|i| { - if i == 0 { - // Check for calls to trait methods where the trait is implemented on a reference. - // Two cases need to be handled: - // * `self` methods on `&T` will never have auto-borrow - // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take - // priority. - if e.hir_id != child_id { - Position::ReborrowStable(precedence) - } else if let Some(trait_id) = cx.tcx.trait_of_item(id) - && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e)) - && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() - && let subs = match cx - .typeck_results() - .node_substs_opt(parent.hir_id) - .and_then(|subs| subs.get(1..)) - { - Some(subs) => cx.tcx.mk_substs(subs.iter().copied()), - None => cx.tcx.mk_substs(std::iter::empty::>()), - } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() { - // Trait methods taking `&self` - sub_ty - } else { - // Trait methods taking `self` - arg_ty - } && impl_ty.is_ref() - && cx.tcx.infer_ctxt().enter(|infcx| - infcx - .type_implements_trait(trait_id, impl_ty, subs, cx.param_env) - .must_apply_modulo_regions() + let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1]; + if let ty::Param(param_ty) = ty.kind() { + needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv) + } else { + ty_auto_deref_stability( + cx, + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)), + precedence, ) - { - Position::MethodReceiverRefImpl - } else { - Position::MethodReceiver - } - } else { - let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; - if let ty::Param(param_ty) = ty.kind() { - needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) - } else { - ty_auto_deref_stability( - cx, - cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), - precedence, - ) - .position_for_arg() - } + .position_for_arg() } }) }, diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index fca3cb46a2e..d55a8e1ead1 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter { MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"), Finite => { return; - }, + } }; span_lint(cx, lint, expr.span, msg); } @@ -229,11 +229,9 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { return MaybeInfinite.and(is_infinite(cx, receiver)); } } - if method.ident.name == sym!(last) { - let not_double_ended = cx - .tcx - .get_diagnostic_item(sym::DoubleEndedIterator) - .map_or(false, |id| { + if method.ident.name == sym!(last) && args.is_empty() { + let not_double_ended = + cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator).map_or(false, |id| { !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[]) }); if not_double_ended { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 25f366bfe6a..3cbdaff407b 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -370,7 +370,7 @@ fn check_for_is_empty<'tcx>( } fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) { - if let (&ExprKind::MethodCall(method_path, receiver, ..), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { + if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, method) { if name.as_str() == "is_empty" { @@ -378,7 +378,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } } - check_len(cx, span, method_path.ident.name, receiver, &lit.node, op, compare_to); + check_len(cx, span, method_path.ident.name, receiver, args, &lit.node, op, compare_to); } else { check_empty_expr(cx, span, method, lit, op); } @@ -389,6 +389,7 @@ fn check_len( span: Span, method_name: Symbol, receiver: &Expr<'_>, + args: &[Expr<'_>], lit: &LitKind, op: &str, compare_to: u32, @@ -399,7 +400,7 @@ fn check_len( return; } - if method_name == sym::len && has_is_empty(cx, receiver) { + if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 9ae6297ec2f..25a9e6dafea 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -21,10 +21,7 @@ pub(super) fn check( receiver: &Expr<'_>, args: &[Expr<'_>], ) { - let arg = match args { - [] if method_name == sym::clone => receiver, - _ => return, - }; + let arg = if method_name == sym::clone && args.is_empty() { receiver } else { return }; if cx .typeck_results() .type_dependent_def_id(expr.hir_id) diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index 7098d564cfc..f82ca891200 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -20,8 +20,7 @@ pub(super) fn check( if !(args.is_empty() && method_name == sym::clone) { return; } - let arg = receiver; - let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs(); + let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); if let ty::Adt(_, subst) = obj_ty.kind() { let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { @@ -34,7 +33,7 @@ pub(super) fn check( return; }; - let snippet = snippet_with_macro_callsite(cx, arg.span, ".."); + let snippet = snippet_with_macro_callsite(cx, receiver.span, ".."); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 16fdd36c026..fc9ba15d82a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3381,7 +3381,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { impl Methods { #[allow(clippy::too_many_lines)] fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some((name, recv, [args @ ..], span)) = method_call(expr) { + if let Some((name, recv, args, span)) = method_call(expr) { match (name, args) { ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { zst_offset::check(cx, expr, recv); @@ -3485,7 +3485,7 @@ impl Methods { } }, ("last", []) | ("skip", [_]) => { - if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) { + if let Some((name2, recv2, args2, _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } @@ -3500,7 +3500,7 @@ impl Methods { } else { map_err_ignore::check(cx, expr, m_arg); } - if let Some((name, recv2, [args @ ..], span2)) = method_call(recv) { + if let Some((name, recv2, args, span2)) = method_call(recv) { match (name, args) { ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv), @@ -3520,7 +3520,7 @@ impl Methods { manual_ok_or::check(cx, expr, recv, def, map); }, ("next", []) => { - if let Some((name2, recv2, [args2 @ ..], _)) = method_call(recv) { + if let Some((name2, recv2, args2, _)) = method_call(recv) { match (name2, args2) { ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false), ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), @@ -3593,7 +3593,7 @@ impl Methods { }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("take", [_arg]) => { - if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) { + if let Some((name2, recv2, args2, _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index c618f6b5d92..44b21e7b080 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -109,14 +109,12 @@ fn fetch_const<'a>( args: &'a [Expr<'a>], m: MinMax, ) -> Option<(MinMax, Constant, &'a Expr<'a>)> { - if (receiver.is_some() && args.len() != 1) || (receiver.is_none() && args.len() != 2) { + let mut args = receiver.into_iter().chain(args.into_iter()); + let arg0 = args.next()?; + let arg1 = args.next()?; + if args.next().is_some() { return None; } - let (arg0, arg1) = if let Some(receiver) = receiver { - (receiver, &args[0]) - } else { - (&args[0], &args[1]) - }; constant_simple(cx, cx.typeck_results(), arg0).map_or_else( || constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)), |c| { diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 7fbfecf96ec..cfc181e435b 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -150,7 +150,7 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> { .. }, self_arg, - [remaining_args @ ..], + remaining_args, _, ) => { let method_name = method_name_ident.name.as_str();