if let hir::ExprKind::Closure(hir::Closure {
capture_clause: hir::CaptureBy::Ref,
..
- }) = arg.kind {
+ }) = arg.kind
+ {
closure_span = Some(arg.span.shrink_to_lo());
break;
}
///
/// The `PathSegment` represents the method name and its generic arguments
/// (within the angle brackets).
- /// The first element of the `&[Expr]` is the expression that evaluates
+ /// The `&Expr` is the expression that evaluates
/// to the object on which the method is being called on (the receiver),
- /// and the remaining elements are the rest of the arguments.
+ /// and the `&[Expr]` is the rest of the arguments.
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
- /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d], span)`.
+ /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d], span)`.
/// The final `Span` represents the span of the function and arguments
/// (e.g. `foo::<Bar, Baz>(a, b, c, d)` in `x.foo::<Bar, Baz>(a, b, c, d)`
///
}
// We only care about method call expressions.
- if let hir::ExprKind::MethodCall(call, receiver, ..) = &expr.kind {
+ if let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind {
if call.ident.name != sym::into_iter {
return;
}
};
// As this is a method call expression, we have at least one argument.
- let receiver_arg = receiver;
let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
}
match first_method_call(expr) {
- Some((path, receiver)) if path.ident.name == sym::as_ptr => {
- let unwrap_arg = receiver;
+ Some((path, unwrap_arg)) if path.ident.name == sym::as_ptr => {
let as_ptr_span = path.ident.span;
match first_method_call(unwrap_arg) {
Some((path, receiver))
if path.ident.name == sym::unwrap || path.ident.name == sym::expect =>
{
- let source_arg = receiver;
- lint_cstring_as_ptr(cx, as_ptr_span, source_arg, unwrap_arg);
+ lint_cstring_as_ptr(cx, as_ptr_span, receiver, unwrap_arg);
}
_ => return,
}
// When we apply adjustments to the receiver, use the span of
// the overall method call for better diagnostics. args[0]
// is guaranteed to exist, since a method call always has a receiver.
- let old_adjustment_span = self.adjustment_span.replace((receiver.hir_id, expr_span));
+ let old_adjustment_span =
+ self.adjustment_span.replace((receiver.hir_id, expr_span));
info!("Using method span: {:?}", expr.span);
let args = std::iter::once(receiver)
.chain(args.iter())
hir::ExprKind::MethodCall(.., receiver, ref args, _) => {
let succ = self.check_is_ty_uninhabited(expr, succ);
- std::iter::once(receiver)
- .chain(args.iter())
+ let succ = args
+ .iter()
.rev()
- .fold(succ, |succ, expr| self.propagate_through_expr(expr, succ))
+ .fold(succ, |succ, expr| self.propagate_through_expr(expr, succ));
+ self.propagate_through_expr(receiver, succ)
}
hir::ExprKind::Tup(ref exprs) => self.propagate_through_exprs(exprs, succ),
if let hir::ExprKind::MethodCall(ref segment, receiver, args, _) = expr.kind {
let clone_trait =
self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span));
- if let (true, Some(true), sym::clone) = (
- args.is_empty(),
- self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
+ if args.is_empty()
+ && self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
|did| {
let ai = self.tcx.associated_item(did);
ai.trait_container(self.tcx) == Some(clone_trait)
},
- ),
- segment.ident.name,
- ) {
+ ) == Some(true)
+ && segment.ident.name == sym::clone
+ {
// If this expression had a clone call when suggesting borrowing
// we want to suggest removing it because it'd now be unnecessary.
sugg_sp = receiver.span;
&self,
expr: &'tcx hir::Expr<'tcx>,
segment: &hir::PathSegment<'_>,
- receiver: &'tcx hir::Expr<'tcx>,
+ rcvr: &'tcx hir::Expr<'tcx>,
args: &'tcx [hir::Expr<'tcx>],
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
- let rcvr = &receiver;
let rcvr_t = self.check_expr(&rcvr);
// no need to check for bot/err -- callee does that
- let rcvr_t = self.structurally_resolved_type(receiver.span, rcvr_t);
+ let rcvr_t = self.structurally_resolved_type(rcvr.span, rcvr_t);
let span = segment.ident.span;
let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) {
span,
rcvr_t,
segment.ident,
- SelfSource::MethodCall(receiver),
+ SelfSource::MethodCall(rcvr),
error,
- Some((receiver, args)),
+ Some((rcvr, args)),
) {
err.emit();
}
.enumerate()
.filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at))
.collect();
- let args: Vec<&'tcx hir::Expr<'tcx>> = if let Some(receiver) = receiver {
- std::iter::once(receiver).chain(args.iter()).collect()
- } else {
- args.iter().collect()
- };
-
// If there's one field that references the given generic, great!
- if let [(idx, _)] = args_referencing_param.as_slice() && let Some(arg) = args.get(*idx) {
+ if let [(idx, _)] = args_referencing_param.as_slice()
+ && let Some(arg) = receiver
+ .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) {
error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span);
error.obligation.cause.map_code(|parent_code| {
ObligationCauseCode::FunctionArgumentObligation {
}),
ExprKind::MethodCall(_, receiver, args, _) => {
let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
- std::iter::once(receiver)
- .chain(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::<ty::subst::GenericArg<'_>>()),
- } && 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()
- )
+ 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..))
{
- Position::MethodReceiverRefImpl
+ Some(subs) => cx.tcx.mk_substs(subs.iter().copied()),
+ None => cx.tcx.mk_substs(std::iter::empty::<ty::subst::GenericArg<'_>>()),
+ } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
+ // Trait methods taking `&self`
+ sub_ty
} else {
- Position::MethodReceiver
- }
+ // 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| {
+ 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 {
- 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()
- }
+ ty_auto_deref_stability(
+ cx,
+ cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
+ precedence,
+ )
+ .position_for_arg()
}
})
},
MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"),
Finite => {
return;
- },
+ }
};
span_lint(cx, lint, expr.span, msg);
}
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 {
}
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" {
}
}
- 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);
}
span: Span,
method_name: Symbol,
receiver: &Expr<'_>,
+ args: &[Expr<'_>],
lit: &LitKind,
op: &str,
compare_to: u32,
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,
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)
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) {
return;
};
- let snippet = snippet_with_macro_callsite(cx, arg.span, "..");
+ let snippet = snippet_with_macro_callsite(cx, receiver.span, "..");
span_lint_and_sugg(
cx,
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);
}
},
("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);
}
} 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),
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),
},
("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);
}
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| {
..
},
self_arg,
- [remaining_args @ ..],
+ remaining_args,
_,
) => {
let method_name = method_name_ident.name.as_str();