Auto merge of #101261 - TaKO8Ki:separate-receiver-from-arguments-in-hir, r=cjgillot

Separate the receiver from arguments in HIR

Related to #100232

cc `@cjgillot`
This commit is contained in:
bors 2022-09-05 16:21:40 +00:00
commit 2ccf843471
111 changed files with 677 additions and 586 deletions

View file

@ -66,7 +66,7 @@ Starting with an `expr`, you can check whether it is calling a specific method
impl<'tcx> LateLintPass<'tcx> for MyStructLint {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
// Check our expr is calling a method
if let hir::ExprKind::MethodCall(path, _, [_self_arg, ..]) = &expr.kind
if let hir::ExprKind::MethodCall(path, _, _self_arg, ..) = &expr.kind
// Check the name of this method is `some_method`
&& path.ident.name == sym!(some_method)
// Optionally, check the type of the self argument.

View file

@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
&& matches!(cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::assert_macro))
&& let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn)
&& matches!(panic_expn, PanicExpn::Empty)
&& let ExprKind::MethodCall(method_segment, [recv], _) = condition.kind
&& let ExprKind::MethodCall(method_segment, recv, [], _) = condition.kind
&& let result_type_with_refs = cx.typeck_results().expr_ty(recv)
&& let result_type = result_type_with_refs.peel_refs()
&& is_type_diagnostic_item(cx, result_type, sym::Result)

View file

@ -55,7 +55,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
// do not lint if the closure is called using an iterator (see #1141)
if_chain! {
if let Some(parent) = get_parent_expr(self.cx, expr);
if let ExprKind::MethodCall(_, [self_arg, ..], _) = &parent.kind;
if let ExprKind::MethodCall(_, self_arg, ..) = &parent.kind;
let caller = self.cx.typeck_results().expr_ty(self_arg);
if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator);
if implements_trait(self.cx, caller, iter_id, &[]);
@ -117,7 +117,8 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
);
}
} else {
let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
let span =
block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
if span.from_expansion() || expr.span.from_expansion() {
return;
}

View file

@ -270,8 +270,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
))
})
},
ExprKind::MethodCall(path, args, _) if args.len() == 1 => {
let type_of_receiver = cx.typeck_results().expr_ty(&args[0]);
ExprKind::MethodCall(path, receiver, [], _) => {
let type_of_receiver = cx.typeck_results().expr_ty(receiver);
if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option)
&& !is_type_diagnostic_item(cx, type_of_receiver, sym::Result)
{
@ -285,7 +285,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
let path: &str = path.ident.name.as_str();
a == path
})
.and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, args[0].span)?, neg_method)))
.and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, receiver.span)?, neg_method)))
},
_ => None,
}

View file

@ -20,7 +20,7 @@ pub(super) fn check(
if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
&& let ty::Int(from) = cast_from.kind()
&& let ty::Uint(to) = cast_to.kind()
&& let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind
&& let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind
&& method_path.ident.name.as_str() == "abs"
{
let span = if from.bit_width() == to.bit_width() {
@ -37,7 +37,7 @@ pub(super) fn check(
span,
&format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
"replace with",
format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()),
format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()),
Applicability::MachineApplicable,
);
}

View file

@ -44,7 +44,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
.saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))),
_ => nbits,
},
ExprKind::MethodCall(method, [left, right], _) => {
ExprKind::MethodCall(method, left, [right], _) => {
if signed {
return nbits;
}
@ -55,7 +55,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
};
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
},
ExprKind::MethodCall(method, [_, lo, hi], _) => {
ExprKind::MethodCall(method, _, [lo, hi], _) => {
if method.ident.as_str() == "clamp" {
//FIXME: make this a diagnostic item
if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
}
nbits
},
ExprKind::MethodCall(method, [_value], _) => {
ExprKind::MethodCall(method, _value, [], _) => {
if method.ident.name.as_str() == "signum" {
0 // do not lint if cast comes from a `signum` function
} else {

View file

@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
cx.typeck_results().expr_ty(expr),
);
lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
} else if let ExprKind::MethodCall(method_path, [self_arg, ..], _) = &expr.kind {
} else if let ExprKind::MethodCall(method_path, self_arg, ..) = &expr.kind {
if method_path.ident.name == sym!(cast)
&& let Some(generic_args) = method_path.args
&& let [GenericArg::Type(cast_to)] = generic_args.args
@ -64,7 +64,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
return false;
};
match parent.kind {
ExprKind::MethodCall(name, [self_arg, ..], _) if self_arg.hir_id == e.hir_id => {
ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => {
if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
&& let Some(def_id) = cx.tcx.impl_of_method(def_id)

View file

@ -41,14 +41,14 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
}
// Don't lint for the result of methods that always return non-negative values.
if let ExprKind::MethodCall(path, _, _) = cast_op.kind {
if let ExprKind::MethodCall(path, ..) = cast_op.kind {
let mut method_name = path.ident.name.as_str();
let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
if_chain! {
if method_name == "unwrap";
if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]);
if let ExprKind::MethodCall(inner_path, _, _) = &arglist[0][0].kind;
if let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind;
then {
method_name = inner_path.ident.name.as_str();
}

View file

@ -69,10 +69,7 @@ struct NumericFallbackVisitor<'a, 'tcx> {
impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
fn new(cx: &'a LateContext<'tcx>) -> Self {
Self {
ty_bounds: vec![TyBound::Nothing],
cx,
}
Self { ty_bounds: vec![TyBound::Nothing], cx }
}
/// Check whether a passed literal has potential to cause fallback or not.
@ -129,19 +126,21 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
}
return;
}
},
}
ExprKind::MethodCall(_, args, _) => {
ExprKind::MethodCall(_, receiver, args, _) => {
if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
for (expr, bound) in iter::zip(*args, fn_sig.inputs()) {
for (expr, bound) in
iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs())
{
self.ty_bounds.push(TyBound::Ty(*bound));
self.visit_expr(expr);
self.ty_bounds.pop();
}
return;
}
},
}
ExprKind::Struct(_, fields, base) => {
let ty = self.cx.typeck_results().expr_ty(expr);
@ -176,15 +175,15 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
return;
}
}
},
}
ExprKind::Lit(lit) => {
let ty = self.cx.typeck_results().expr_ty(expr);
self.check_lit(lit, ty, expr.hir_id);
return;
},
}
_ => {},
_ => {}
}
walk_expr(self, expr);
@ -198,7 +197,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
} else {
self.ty_bounds.push(TyBound::Nothing);
}
},
}
_ => self.ty_bounds.push(TyBound::Nothing),
}

View file

@ -581,7 +581,7 @@ fn try_parse_ref_op<'tcx>(
expr: &'tcx Expr<'_>,
) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
let (def_id, arg) = match expr.kind {
ExprKind::MethodCall(_, [arg], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
ExprKind::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
ExprKind::Call(
Expr {
kind: ExprKind::Path(path),
@ -796,58 +796,59 @@ fn walk_parents<'tcx>(
},
})
}),
ExprKind::MethodCall(_, args, _) => {
ExprKind::MethodCall(_, receiver, args, _) => {
let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
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 {
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
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, *param_ty, e, precedence, msrv)
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)),
cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
precedence,
)
.position_for_arg()
}
}
})
})
},
ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),

View file

@ -828,7 +828,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
{

View file

@ -245,8 +245,8 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio
match expr.kind {
ExprKind::MethodCall(
_,
map,
[
map,
Expr {
kind: ExprKind::AddrOf(_, _, key),
span: key_span,
@ -280,7 +280,7 @@ struct InsertExpr<'tcx> {
value: &'tcx Expr<'tcx>,
}
fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
if let ExprKind::MethodCall(_, [map, key, value], _) = expr.kind {
if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind {
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) {
Some(InsertExpr { map, key, value })

View file

@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
if !is_adjusted(cx, &body.value);
if let ExprKind::Call(callee, args) = body.value.kind;
if let ExprKind::Path(_) = callee.kind;
if check_inputs(cx, body.params, args);
if check_inputs(cx, body.params, None, args);
let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
.map_or(callee_ty, |id| cx.tcx.type_of(id));
@ -146,8 +146,8 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
if_chain!(
if !is_adjusted(cx, &body.value);
if let ExprKind::MethodCall(path, args, _) = body.value.kind;
if check_inputs(cx, body.params, args);
if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind;
if check_inputs(cx, body.params, Some(receiver), args);
let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
let substs = cx.typeck_results().node_substs(body.value.hir_id);
let call_ty = cx.tcx.bound_type_of(method_def_id).subst(cx.tcx, substs);
@ -167,12 +167,17 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
}
}
fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_>]) -> bool {
if params.len() != call_args.len() {
fn check_inputs(
cx: &LateContext<'_>,
params: &[Param<'_>],
receiver: Option<&Expr<'_>>,
call_args: &[Expr<'_>],
) -> bool {
if receiver.map_or(params.len() != call_args.len(), |_| params.len() != call_args.len() + 1) {
return false;
}
let binding_modes = cx.typeck_results().pat_binding_modes();
std::iter::zip(params, call_args).all(|(param, arg)| {
let check_inputs = |param: &Param<'_>, arg| {
match param.pat.kind {
PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
_ => return false,
@ -200,7 +205,9 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_
},
_ => false,
}
})
};
std::iter::zip(params, receiver.into_iter().chain(call_args.iter()))
.all(|(param, arg)| check_inputs(param, arg))
}
fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {

View file

@ -45,10 +45,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if_chain! {
// match call to unwrap
if let ExprKind::MethodCall(unwrap_fun, [write_call], _) = expr.kind;
if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind;
if unwrap_fun.ident.name == sym::unwrap;
// match call to write_fmt
if let ExprKind::MethodCall(write_fun, [write_recv, write_arg], _) = look_in_block(cx, &write_call.kind);
if let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind);
if write_fun.ident.name == sym!(write_fmt);
// match calls to std::io::stdout() / std::io::stderr ()
if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {

View file

@ -84,7 +84,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
{

View file

@ -164,15 +164,15 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
suggestion.maybe_par()
}
fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
if let Some(method) = get_specialized_log_method(cx, &args[1]) {
fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
if let Some(method) = get_specialized_log_method(cx, &args[0]) {
span_lint_and_sugg(
cx,
SUBOPTIMAL_FLOPS,
expr.span,
"logarithm for bases 2, 10 and e can be computed more accurately",
"consider using",
format!("{}.{}()", Sugg::hir(cx, &args[0], "..").maybe_par(), method),
format!("{}.{}()", Sugg::hir(cx, receiver, "..").maybe_par(), method),
Applicability::MachineApplicable,
);
}
@ -180,14 +180,14 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
// TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and
// suggest usage of `(x + (y - 1)).ln_1p()` instead
fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
},
lhs,
rhs,
) = &args[0].kind
) = receiver.kind
{
let recv = match (
constant(cx, cx.typeck_results(), lhs),
@ -235,9 +235,9 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
}
}
fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
// Check receiver
if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) {
let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
"exp"
} else if F32(2.0) == value || F64(2.0) == value {
@ -252,24 +252,24 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
expr.span,
"exponent for bases 2 and e can be computed more accurately",
"consider using",
format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method),
format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method),
Applicability::MachineApplicable,
);
}
// Check argument
if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
(
SUBOPTIMAL_FLOPS,
"square-root of a number can be computed more efficiently and accurately",
format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
)
} else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
(
IMPRECISE_FLOPS,
"cube-root of a number can be computed more accurately",
format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
)
} else if let Some(exponent) = get_integer_from_float_constant(&value) {
(
@ -277,7 +277,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
"exponentiation with integer powers can be computed more efficiently",
format!(
"{}.powi({})",
Sugg::hir(cx, &args[0], "..").maybe_par(),
Sugg::hir(cx, receiver, "..").maybe_par(),
numeric_literal::format(&exponent.to_string(), None, false)
),
)
@ -297,13 +297,14 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
}
}
fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
if value == Int(2) {
if let Some(parent) = get_parent_expr(cx, expr) {
if let Some(grandparent) = get_parent_expr(cx, parent) {
if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = grandparent.kind {
if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind
{
if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
return;
}
}
@ -327,8 +328,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
"consider using",
format!(
"{}.mul_add({}, {})",
Sugg::hir(cx, &args[0], "..").maybe_par(),
Sugg::hir(cx, &args[0], ".."),
Sugg::hir(cx, receiver, "..").maybe_par(),
Sugg::hir(cx, receiver, ".."),
Sugg::hir(cx, other_addend, ".."),
),
Applicability::MachineApplicable,
@ -339,14 +340,14 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
}
}
fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
if let ExprKind::Binary(
Spanned {
node: BinOpKind::Add, ..
},
add_lhs,
add_rhs,
) = args[0].kind
) = receiver.kind
{
// check if expression of the form x * x + y * y
if_chain! {
@ -363,12 +364,12 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
if_chain! {
if let ExprKind::MethodCall(
PathSegment { ident: lmethod_name, .. },
[largs_0, largs_1, ..],
largs_0, [largs_1, ..],
_
) = &add_lhs.kind;
if let ExprKind::MethodCall(
PathSegment { ident: rmethod_name, .. },
[rargs_0, rargs_1, ..],
rargs_0, [rargs_1, ..],
_
) = &add_rhs.kind;
if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
@ -384,8 +385,8 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
None
}
fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
if let Some(message) = detect_hypot(cx, args) {
fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
if let Some(message) = detect_hypot(cx, receiver) {
span_lint_and_sugg(
cx,
IMPRECISE_FLOPS,
@ -406,7 +407,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
if cx.typeck_results().expr_ty(lhs).is_floating_point();
if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs);
if F32(1.0) == value || F64(1.0) == value;
if let ExprKind::MethodCall(path, [self_arg, ..], _) = &lhs.kind;
if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind;
if cx.typeck_results().expr_ty(self_arg).is_floating_point();
if path.ident.name.as_str() == "exp";
then {
@ -450,8 +451,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
) = &expr.kind
{
if let Some(parent) = get_parent_expr(cx, expr) {
if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = parent.kind {
if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind {
if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
return;
}
}
@ -586,14 +587,14 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
if_chain! {
if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, args_a, _) = expr_a.kind;
if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, args_b, _) = expr_b.kind;
if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind;
if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind;
then {
return method_name_a.as_str() == method_name_b.as_str() &&
args_a.len() == args_b.len() &&
(
["ln", "log2", "log10"].contains(&method_name_a.as_str()) ||
method_name_a.as_str() == "log" && args_a.len() == 2 && eq_expr_value(cx, &args_a[1], &args_b[1])
method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])
);
}
}
@ -612,8 +613,8 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
rhs,
) = &expr.kind;
if are_same_base_logs(cx, lhs, rhs);
if let ExprKind::MethodCall(_, [largs_self, ..], _) = &lhs.kind;
if let ExprKind::MethodCall(_, [rargs_self, ..], _) = &rhs.kind;
if let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind;
if let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind;
then {
span_lint_and_sugg(
cx,
@ -711,16 +712,16 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
return;
}
if let ExprKind::MethodCall(path, args, _) = &expr.kind {
let recv_ty = cx.typeck_results().expr_ty(&args[0]);
if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
let recv_ty = cx.typeck_results().expr_ty(receiver);
if recv_ty.is_floating_point() {
match path.ident.name.as_str() {
"ln" => check_ln1p(cx, expr, args),
"log" => check_log_base(cx, expr, args),
"powf" => check_powf(cx, expr, args),
"powi" => check_powi(cx, expr, args),
"sqrt" => check_hypot(cx, expr, args),
"ln" => check_ln1p(cx, expr, receiver),
"log" => check_log_base(cx, expr, receiver, args),
"powf" => check_powf(cx, expr, receiver, args),
"powi" => check_powi(cx, expr, receiver, args),
"sqrt" => check_hypot(cx, expr, receiver),
_ => {},
}
}

View file

@ -99,7 +99,12 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
}
}
fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) {
fn check_format_in_format_args(
cx: &LateContext<'_>,
call_site: Span,
name: Symbol,
arg: &Expr<'_>,
) {
let expn_data = arg.span.ctxt().outer_expn_data();
if expn_data.call_site.from_expansion() {
return;
@ -126,7 +131,7 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb
fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
if_chain! {
if !value.span.from_expansion();
if let ExprKind::MethodCall(_, [receiver], _) = value.kind;
if let ExprKind::MethodCall(_, receiver, [], _) = value.kind;
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
if is_diag_trait_item(cx, method_def_id, sym::ToString);
let receiver_ty = cx.typeck_results().expr_ty(receiver);
@ -177,10 +182,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex
// Returns true if `hir_id` is referred to by multiple format params
fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool {
args.params()
.filter(|param| param.value.hir_id == hir_id)
.at_most_one()
.is_err()
args.params().filter(|param| param.value.hir_id == hir_id).at_most_one().is_err()
}
fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
@ -190,11 +192,7 @@ where
let mut n_total = 0;
let mut n_needed = 0;
loop {
if let Some(Adjustment {
kind: Adjust::Deref(overloaded_deref),
target,
}) = iter.next()
{
if let Some(Adjustment { kind: Adjust::Deref(overloaded_deref), target }) = iter.next() {
n_total += 1;
if overloaded_deref.is_some() {
n_needed = n_total;

View file

@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl {
fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
// Get the hir_id of the object we are calling the method on
if let ExprKind::MethodCall(path, [ref self_arg, ..], _) = expr.kind;
if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind;
// Is the method to_string() ?
if path.ident.name == sym::to_string;
// Is the method a part of the ToString trait? (i.e. not to_string() implemented

View file

@ -54,7 +54,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
impl<'tcx> LateLintPass<'tcx> for FormatPushString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let arg = match expr.kind {
ExprKind::MethodCall(_, [_, arg], _) => {
ExprKind::MethodCall(_, _, [arg], _) => {
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) &&
match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
arg

View file

@ -212,7 +212,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
return;
}
match expr.kind {
Call(_, args) | MethodCall(_, args, _) => {
Call(_, args) => {
let mut tys = DefIdSet::default();
for arg in args {
if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
@ -230,6 +230,24 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
tys.clear();
}
},
MethodCall(_, receiver, args, _) => {
let mut tys = DefIdSet::default();
for arg in std::iter::once(receiver).chain(args.iter()) {
if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
&& is_mutable_ty(
self.cx,
self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg),
arg.span,
&mut tys,
)
&& is_mutated_static(arg)
{
self.mutates_static = true;
return;
}
tys.clear();
}
},
Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
self.mutates_static |= is_mutated_static(target);
},

View file

@ -88,11 +88,12 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
}
}
},
hir::ExprKind::MethodCall(_, args, _) => {
hir::ExprKind::MethodCall(_, receiver, args, _) => {
let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap();
let base_type = self.cx.tcx.type_of(def_id);
if type_is_unsafe_function(self.cx, base_type) {
self.check_arg(receiver);
for arg in args {
self.check_arg(arg);
}

View file

@ -129,7 +129,7 @@ impl<'tcx, 'l> ArmVisitor<'tcx, 'l> {
fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
if_chain! {
if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
if path.ident.as_str() == "lock";
let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
if is_type_diagnostic_item(cx, ty, sym::Mutex);

View file

@ -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);
}
@ -123,43 +123,43 @@ use self::Heuristic::{All, Always, Any, First};
/// is an upper bound, e.g., some methods can return a possibly
/// infinite iterator at worst, e.g., `take_while`.
const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [
("zip", 2, All, Infinite),
("chain", 2, Any, Infinite),
("cycle", 1, Always, Infinite),
("map", 2, First, Infinite),
("by_ref", 1, First, Infinite),
("cloned", 1, First, Infinite),
("rev", 1, First, Infinite),
("inspect", 1, First, Infinite),
("enumerate", 1, First, Infinite),
("peekable", 2, First, Infinite),
("fuse", 1, First, Infinite),
("skip", 2, First, Infinite),
("skip_while", 1, First, Infinite),
("filter", 2, First, Infinite),
("filter_map", 2, First, Infinite),
("flat_map", 2, First, Infinite),
("unzip", 1, First, Infinite),
("take_while", 2, First, MaybeInfinite),
("scan", 3, First, MaybeInfinite),
("zip", 1, All, Infinite),
("chain", 1, Any, Infinite),
("cycle", 0, Always, Infinite),
("map", 1, First, Infinite),
("by_ref", 0, First, Infinite),
("cloned", 0, First, Infinite),
("rev", 0, First, Infinite),
("inspect", 0, First, Infinite),
("enumerate", 0, First, Infinite),
("peekable", 1, First, Infinite),
("fuse", 0, First, Infinite),
("skip", 1, First, Infinite),
("skip_while", 0, First, Infinite),
("filter", 1, First, Infinite),
("filter_map", 1, First, Infinite),
("flat_map", 1, First, Infinite),
("unzip", 0, First, Infinite),
("take_while", 1, First, MaybeInfinite),
("scan", 2, First, MaybeInfinite),
];
fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
match expr.kind {
ExprKind::MethodCall(method, args, _) => {
ExprKind::MethodCall(method, receiver, args, _) => {
for &(name, len, heuristic, cap) in &HEURISTICS {
if method.ident.name.as_str() == name && args.len() == len {
return (match heuristic {
Always => Infinite,
First => is_infinite(cx, &args[0]),
Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])),
All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])),
First => is_infinite(cx, receiver),
Any => is_infinite(cx, receiver).or(is_infinite(cx, &args[0])),
All => is_infinite(cx, receiver).and(is_infinite(cx, &args[0])),
})
.and(cap);
}
}
if method.ident.name == sym!(flat_map) && args.len() == 2 {
if let ExprKind::Closure(&Closure { body, .. }) = args[1].kind {
if method.ident.name == sym!(flat_map) && args.len() == 1 {
if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind {
let body = cx.tcx.hir().body(body);
return is_infinite(cx, &body.value);
}
@ -179,29 +179,29 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
/// the names and argument lengths of methods that *may* exhaust their
/// iterators
const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [
("find", 2),
("rfind", 2),
("position", 2),
("rposition", 2),
("any", 2),
("all", 2),
("find", 1),
("rfind", 1),
("position", 1),
("rposition", 1),
("any", 1),
("all", 1),
];
/// the names and argument lengths of methods that *always* exhaust
/// their iterators
const COMPLETING_METHODS: [(&str, usize); 12] = [
("count", 1),
("fold", 3),
("for_each", 2),
("partition", 2),
("max", 1),
("max_by", 2),
("max_by_key", 2),
("min", 1),
("min_by", 2),
("min_by_key", 2),
("sum", 1),
("product", 1),
("count", 0),
("fold", 2),
("for_each", 1),
("partition", 1),
("max", 0),
("max_by", 1),
("max_by_key", 1),
("min", 0),
("min_by", 1),
("min_by_key", 1),
("sum", 0),
("product", 0),
];
/// the paths of types that are known to be infinitely allocating
@ -218,26 +218,24 @@ const INFINITE_COLLECTORS: &[Symbol] = &[
fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
match expr.kind {
ExprKind::MethodCall(method, args, _) => {
ExprKind::MethodCall(method, receiver, args, _) => {
for &(name, len) in &COMPLETING_METHODS {
if method.ident.name.as_str() == name && args.len() == len {
return is_infinite(cx, &args[0]);
return is_infinite(cx, receiver);
}
}
for &(name, len) in &POSSIBLY_COMPLETING_METHODS {
if method.ident.name.as_str() == name && args.len() == len {
return MaybeInfinite.and(is_infinite(cx, &args[0]));
return MaybeInfinite.and(is_infinite(cx, receiver));
}
}
if method.ident.name == sym!(last) && args.len() == 1 {
let not_double_ended = cx
.tcx
.get_diagnostic_item(sym::DoubleEndedIterator)
.map_or(false, |id| {
!implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), 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 {
return is_infinite(cx, &args[0]);
return is_infinite(cx, receiver);
}
} else if method.ident.name == sym!(collect) {
let ty = cx.typeck_results().expr_ty(expr);
@ -245,7 +243,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
.iter()
.any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item))
{
return is_infinite(cx, &args[0]);
return is_infinite(cx, receiver);
}
}
},

View file

@ -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, args, _), &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, args, &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);
}
@ -388,6 +388,7 @@ fn check_len(
cx: &LateContext<'_>,
span: Span,
method_name: Symbol,
receiver: &Expr<'_>,
args: &[Expr<'_>],
lit: &LitKind,
op: &str,
@ -399,7 +400,7 @@ fn check_len(
return;
}
if method_name == sym::len && args.len() == 1 && has_is_empty(cx, &args[0]) {
if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
@ -410,7 +411,7 @@ fn check_len(
format!(
"{}{}.is_empty()",
op,
snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
snippet_with_applicability(cx, receiver.span, "_", &mut applicability)
),
applicability,
);

View file

@ -119,7 +119,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
if_chain! {
if let ExprKind::MethodCall(method, [recv], _) = end.kind;
if let ExprKind::MethodCall(method, recv, [], _) = end.kind;
if method.ident.name == sym::len;
if path_to_local(recv) == path_to_local(base);
then {
@ -341,7 +341,7 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti
fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
if_chain! {
if let ExprKind::MethodCall(method, [arg], _) = expr.kind;
if let ExprKind::MethodCall(method, arg, [], _) = expr.kind;
if method.ident.name == sym::clone;
then { arg } else { expr }
}

View file

@ -33,7 +33,7 @@ fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
if_chain! {
if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind;
if let ExprKind::MethodCall(method, [callee, ..], _) = unpack_cond(cond).kind;
if let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind;
if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name);
if let ty::Adt(def, _substs) = cx.typeck_results().expr_ty(callee).kind();
if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did());

View file

@ -742,7 +742,7 @@ fn check_for_loop<'tcx>(
fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
if let ExprKind::MethodCall(method, [self_arg], _) = arg.kind {
if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
let method_name = method.ident.as_str();
// check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
match method_name {

View file

@ -25,11 +25,11 @@ pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
}
fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
if_chain! {
if let ExprKind::MethodCall(method, args, _) = expr.kind;
if let ExprKind::MethodCall(chain_method, _, _) = args[0].kind;
if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind;
if let ExprKind::MethodCall(chain_method, ..) = receiver.kind;
if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator);
then {
let ty = cx.typeck_results().expr_ty(&args[0]);
let ty = cx.typeck_results().expr_ty(receiver);
let mut applicability = Applicability::MaybeIncorrect;
let is_empty_sugg = "next().is_none()".to_string();
let method_name = method.ident.name.as_str();
@ -41,7 +41,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
"len" => "count()".to_string(),
"is_empty" => is_empty_sugg,
"contains" => {
let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability);
let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability);
let (arg, pred) = contains_arg
.strip_prefix('&')
.map_or(("&x", &*contains_arg), |s| ("x", s));
@ -80,7 +80,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
if let StmtKind::Local(local) = stmt.kind;
if let PatKind::Binding(_, id, ..) = local.pat.kind;
if let Some(init_expr) = local.init;
if let ExprKind::MethodCall(method_name, &[ref iter_source], ..) = init_expr.kind;
if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind;
if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
let ty = cx.typeck_results().expr_ty(init_expr);
if is_type_diagnostic_item(cx, ty, sym::Vec) ||
@ -203,7 +203,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
// Check function calls on our collection
if let ExprKind::MethodCall(method_name, [recv, args @ ..], _) = &expr.kind {
if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind {
if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
self.visit_expr(recv);

View file

@ -188,7 +188,7 @@ pub(super) fn check<'tcx>(
fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
if_chain! {
if let ExprKind::MethodCall(method, [recv], _) = expr.kind;
if let ExprKind::MethodCall(method, recv, [], _) = expr.kind;
if method.ident.name == sym::len;
if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind;
if path.segments.len() == 1;
@ -301,7 +301,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
if_chain! {
// a range index op
if let ExprKind::MethodCall(meth, [args_0, args_1, ..], _) = &expr.kind;
if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind;
if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX))
|| (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT));
if !self.check(args_1, args_0, expr);
@ -356,9 +356,12 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
self.visit_expr(expr);
}
},
ExprKind::MethodCall(_, args, _) => {
ExprKind::MethodCall(_, receiver, args, _) => {
let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) {
for (ty, expr) in iter::zip(
self.cx.tcx.fn_sig(def_id).inputs().skip_binder(),
std::iter::once(receiver).chain(args.iter()),
) {
self.prefer_mutable = false;
if let ty::Ref(_, _, mutbl) = *ty.kind() {
if mutbl == Mutability::Mut {

View file

@ -120,8 +120,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
| ExprKind::Repeat(e, _)
| ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
ExprKind::Array(es) | ExprKind::MethodCall(_, es, _) | ExprKind::Tup(es) => {
never_loop_expr_all(&mut es.iter(), main_loop_id)
ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), main_loop_id),
ExprKind::MethodCall(_, receiver, es, _) => {
never_loop_expr_all(&mut std::iter::once(receiver).chain(es.iter()), main_loop_id)
},
ExprKind::Struct(_, fields, base) => {
let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id);

View file

@ -180,10 +180,9 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&
if_chain! {
// Extract method being called
if let StmtKind::Semi(semi_stmt) = &stmt.kind;
if let ExprKind::MethodCall(path, args, _) = &semi_stmt.kind;
if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind;
// Figure out the parameters for the method call
if let Some(self_expr) = args.get(0);
if let Some(pushed_item) = args.get(1);
if let Some(pushed_item) = args.get(0);
// Check that the method being called is push() on a Vec
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
if path.ident.name.as_str() == "push";

View file

@ -35,32 +35,29 @@ pub(super) fn check<'tcx>(
) => (arg, "&mut "),
ExprKind::MethodCall(
method,
[
Expr {
kind: ExprKind::Array([arg]),
..
},
],
Expr {
kind: ExprKind::Array([arg]),
..
},
[],
_,
) if method.ident.name == rustc_span::sym::iter => (arg, "&"),
ExprKind::MethodCall(
method,
[
Expr {
kind: ExprKind::Array([arg]),
..
},
],
Expr {
kind: ExprKind::Array([arg]),
..
},
[],
_,
) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "),
ExprKind::MethodCall(
method,
[
Expr {
kind: ExprKind::Array([arg]),
..
},
],
Expr {
kind: ExprKind::Array([arg]),
..
},
[],
_,
) if method.ident.name == rustc_span::sym::into_iter => (arg, ""),
// Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise.

View file

@ -11,7 +11,14 @@ use rustc_lint::LateContext;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) {
([stmt, stmts @ ..], expr) => {
if let StmtKind::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind {
if let StmtKind::Local(&Local {
init: Some(e),
els: None,
..
})
| StmtKind::Semi(e)
| StmtKind::Expr(e) = stmt.kind
{
(e, !stmts.is_empty() || expr.is_some())
} else {
return;

View file

@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let Res::Def(_, pat_did) = pat_path.res;
if match_def_path(cx, pat_did, &paths::OPTION_SOME);
// check for call to `Iterator::next`
if let ExprKind::MethodCall(method_name, [iter_expr], _) = let_expr.kind;
if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind;
if method_name.ident.name == sym::next;
if is_trait_method(cx, let_expr, sym::Iterator);
if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr);

View file

@ -134,7 +134,7 @@ fn create_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, base_sugg: String) -> Stri
fn is_ty_conversion(expr: &Expr<'_>) -> bool {
if let ExprKind::Cast(..) = expr.kind {
true
} else if let ExprKind::MethodCall(path, [_], _) = expr.kind
} else if let ExprKind::MethodCall(path, _, [], _) = expr.kind
&& path.ident.name == rustc_span::sym::try_into
{
// This is only called for `usize` which implements `TryInto`. Therefore,

View file

@ -66,9 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if let Some(parent_expr) = get_parent_expr(cx, expr)
&& let Assign(left_expr, collect_expr, _) = &parent_expr.kind
&& let hir::ExprKind::MethodCall(seg, _, _) = &collect_expr.kind
&& let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind
&& seg.args.is_none()
&& let hir::ExprKind::MethodCall(_, [target_expr], _) = &collect_expr.kind
&& let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
&& let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
&& match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv);
@ -87,10 +87,10 @@ fn check_into_iter(
target_expr: &hir::Expr<'_>,
msrv: Option<RustcVersion>,
) {
if let hir::ExprKind::MethodCall(_, [into_iter_expr, _], _) = &target_expr.kind
if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
&& let hir::ExprKind::MethodCall(_, [struct_expr], _) = &into_iter_expr.kind
&& let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind
&& let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
&& match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER)
&& match_acceptable_type(cx, left_expr, msrv)
@ -106,14 +106,14 @@ fn check_iter(
target_expr: &hir::Expr<'_>,
msrv: Option<RustcVersion>,
) {
if let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind
if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED)
|| match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED))
&& let hir::ExprKind::MethodCall(_, [iter_expr, _], _) = &filter_expr.kind
&& let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
&& let hir::ExprKind::MethodCall(_, [struct_expr], _) = &iter_expr.kind
&& let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &iter_expr.kind
&& let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id)
&& match_acceptable_def_path(cx, iter_expr_def_id)
&& match_acceptable_type(cx, left_expr, msrv)
@ -130,13 +130,13 @@ fn check_to_owned(
msrv: Option<RustcVersion>,
) {
if meets_msrv(msrv, msrvs::STRING_RETAIN)
&& let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind
&& let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
&& match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
&& let hir::ExprKind::MethodCall(_, [chars_expr, _], _) = &filter_expr.kind
&& let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
&& let hir::ExprKind::MethodCall(_, [str_expr], _) = &chars_expr.kind
&& let hir::ExprKind::MethodCall(_, str_expr, [], _) = &chars_expr.kind
&& let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
&& match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS)
&& let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
@ -147,7 +147,7 @@ fn check_to_owned(
}
fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) {
if let hir::ExprKind::MethodCall(_, [_, closure], _) = filter_expr.kind
if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind
&& let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind
&& let filter_body = cx.tcx.hir().body(body)
&& let [filter_params] = filter_body.params

View file

@ -55,8 +55,8 @@ impl LateLintPass<'_> for ManualStringNew {
ExprKind::Call(func, args) => {
parse_call(cx, expr.span, func, args);
},
ExprKind::MethodCall(path_segment, args, _) => {
parse_method_call(cx, expr.span, path_segment, args);
ExprKind::MethodCall(path_segment, receiver, ..) => {
parse_method_call(cx, expr.span, path_segment, receiver);
},
_ => (),
}
@ -88,14 +88,9 @@ fn warn_then_suggest(cx: &LateContext<'_>, span: Span) {
}
/// Tries to parse an expression as a method call, emitting the warning if necessary.
fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, args: &[Expr<'_>]) {
if args.is_empty() {
// When parsing TryFrom::try_from(...).expect(...), we will have more than 1 arg.
return;
}
fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, receiver: &Expr<'_>) {
let ident = path_segment.ident.as_str();
let method_arg_kind = &args[0].kind;
let method_arg_kind = &receiver.kind;
if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) {
warn_then_suggest(cx, span);
} else if let ExprKind::Call(func, args) = method_arg_kind {

View file

@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
if_chain! {
if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
if let ExprKind::MethodCall(_, [target_arg, pattern], _) = cond.kind;
if let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind;
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id);
if let ExprKind::Path(target_path) = &target_arg.kind;
then {
@ -132,7 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
// Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
if_chain! {
if let ExprKind::MethodCall(_, [arg], _) = expr.kind;
if let ExprKind::MethodCall(_, arg, [], _) = expr.kind;
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if match_def_path(cx, method_def_id, &paths::STR_LEN);
then {

View file

@ -200,8 +200,13 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String {
)
}
fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) {
let var_arg = &map_args[0];
fn lint_map_unit_fn(
cx: &LateContext<'_>,
stmt: &hir::Stmt<'_>,
expr: &hir::Expr<'_>,
map_args: (&hir::Expr<'_>, &[hir::Expr<'_>]),
) {
let var_arg = &map_args.0;
let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) {
("Option", "Some", OPTION_MAP_UNIT_FN)
@ -210,7 +215,7 @@ fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr
} else {
return;
};
let fn_arg = &map_args[1];
let fn_arg = &map_args.1[0];
if is_unit_function(cx, fn_arg) {
let mut applicability = Applicability::MachineApplicable;

View file

@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
};
if_chain! {
if let ExprKind::MethodCall(ok_path, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
if let ExprKind::MethodCall(ok_path, result_types_0, ..) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation
if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized;
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);

View file

@ -48,7 +48,7 @@ struct MatchExprVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
match ex.kind {
ExprKind::MethodCall(segment, [receiver], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
_ => walk_expr(self, ex),
}
}

View file

@ -120,7 +120,7 @@ fn find_sugg_for_if_let<'tcx>(
// check that `while_let_on_iterator` lint does not trigger
if_chain! {
if keyword == "while";
if let ExprKind::MethodCall(method_path, _, _) = let_expr.kind;
if let ExprKind::MethodCall(method_path, ..) = let_expr.kind;
if method_path.ident.name == sym::next;
if is_trait_method(cx, let_expr, sym::Iterator);
then {

View file

@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
self.is_chain_end = false;
match ex.kind {
ExprKind::MethodCall(_, [ref expr, ..], _) => {
ExprKind::MethodCall(_, expr, ..) => {
self.visit_expr(expr);
}
ExprKind::Binary(_, left, right) => {
@ -331,8 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
ExprKind::Index(..) |
ExprKind::Ret(..) |
ExprKind::Repeat(..) |
ExprKind::Yield(..) |
ExprKind::MethodCall(..) => walk_expr(self, ex),
ExprKind::Yield(..) => walk_expr(self, ex),
ExprKind::AddrOf(_, _, _) |
ExprKind::Block(_, _) |
ExprKind::Break(_, _) |

View file

@ -42,11 +42,11 @@ pub(super) fn check<'tcx>(
if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
if !is_local_used(cx, needle, arg_id);
then {
let haystack = if let ExprKind::MethodCall(path, args, _) =
let haystack = if let ExprKind::MethodCall(path, receiver, [], _) =
filter_recv.kind {
let p = path.ident.name;
if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
&args[0]
if p == sym::iter || p == sym!(iter_mut) {
receiver
} else {
filter_recv
}

View file

@ -23,7 +23,7 @@ pub(super) fn check(
if Some(id) == cx.tcx.lang_items().option_some_variant();
then {
let mut applicability = Applicability::MachineApplicable;
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0].0).peel_refs();
if *self_ty.kind() != ty::Str {
return false;
@ -37,7 +37,7 @@ pub(super) fn check(
"like this",
format!("{}{}.{}({})",
if info.eq { "" } else { "!" },
snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
suggest,
snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)),
applicability,

View file

@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
"like this",
format!("{}{}.{}('{}')",
if info.eq { "" } else { "!" },
snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
suggest,
c.escape_default()),
applicability,

View file

@ -14,11 +14,14 @@ use super::CLONE_ON_COPY;
/// Checks for the `CLONE_ON_COPY` lint.
#[allow(clippy::too_many_lines)]
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, args: &[Expr<'_>]) {
let arg = match args {
[arg] if method_name == sym::clone => arg,
_ => return,
};
pub(super) fn check(
cx: &LateContext<'_>,
expr: &Expr<'_>,
method_name: Symbol,
receiver: &Expr<'_>,
args: &[Expr<'_>],
) {
let arg = if method_name == sym::clone && args.is_empty() { receiver } else { return };
if cx
.typeck_results()
.type_dependent_def_id(expr.hir_id)
@ -81,7 +84,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
// &*x is a nop, &x.clone() is not
ExprKind::AddrOf(..) => return,
// (*x).func() is useless, x.clone().func() can work in case func borrows self
ExprKind::MethodCall(_, [self_arg, ..], _)
ExprKind::MethodCall(_, self_arg, ..)
if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
{
return;
@ -91,7 +94,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
hir_callee.kind,
ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _))
),
ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id => true,
ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
| ExprKind::Field(..)
| ExprKind::Index(..) => true,

View file

@ -10,12 +10,17 @@ use rustc_span::symbol::{sym, Symbol};
use super::CLONE_ON_REF_PTR;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
if !(args.len() == 1 && method_name == sym::clone) {
pub(super) fn check(
cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
method_name: Symbol,
receiver: &hir::Expr<'_>,
args: &[hir::Expr<'_>],
) {
if !(args.is_empty() && method_name == sym::clone) {
return;
}
let arg = &args[0];
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) {
@ -28,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Sym
return;
};
let snippet = snippet_with_macro_callsite(cx, arg.span, "..");
let snippet = snippet_with_macro_callsite(cx, receiver.span, "..");
span_lint_and_sugg(
cx,

View file

@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
// If the parent node's `to` argument is the same as the `to` argument
// of the last replace call in the current chain, don't lint as it was already linted
if let Some(parent) = get_parent_expr(cx, expr)
&& let Some(("replace", [_, current_from, current_to], _)) = method_call(parent)
&& let Some(("replace", _, [current_from, current_to], _)) = method_call(parent)
&& eq_expr_value(cx, to, current_to)
&& from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
{
@ -48,7 +48,7 @@ fn collect_replace_calls<'tcx>(
let mut from_args = VecDeque::new();
let _: Option<()> = for_each_expr(expr, |e| {
if let Some(("replace", [_, from, to], _)) = method_call(e) {
if let Some(("replace", _, [from, to], _)) = method_call(e) {
if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
methods.push_front(e);
from_args.push_front(from);
@ -78,7 +78,7 @@ fn check_consecutive_replace_calls<'tcx>(
.collect();
let app = Applicability::MachineApplicable;
let earliest_replace_call = replace_methods.methods.front().unwrap();
if let Some((_, [..], span_lo)) = method_call(earliest_replace_call) {
if let Some((_, _, [..], span_lo)) = method_call(earliest_replace_call) {
span_lint_and_sugg(
cx,
COLLAPSIBLE_STR_REPLACE,

View file

@ -19,6 +19,7 @@ pub(super) fn check<'tcx>(
expr: &hir::Expr<'_>,
method_span: Span,
name: &str,
receiver: &'tcx hir::Expr<'tcx>,
args: &'tcx [hir::Expr<'tcx>],
) {
// Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
@ -28,16 +29,13 @@ pub(super) fn check<'tcx>(
loop {
arg_root = match &arg_root.kind {
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
hir::ExprKind::MethodCall(method_name, call_args, _) => {
if call_args.len() == 1
&& (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref)
&& {
let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
let base_type = arg_type.peel_refs();
*base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
}
{
&call_args[0]
hir::ExprKind::MethodCall(method_name, receiver, [], ..) => {
if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && {
let arg_type = cx.typeck_results().expr_ty(receiver);
let base_type = arg_type.peel_refs();
*base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
} {
receiver
} else {
break;
}
@ -114,11 +112,11 @@ pub(super) fn check<'tcx>(
}
}
if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) {
if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) {
return;
}
let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]);
let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver);
let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) {
"||"
} else if is_type_diagnostic_item(cx, receiver_type, sym::Result) {
@ -127,7 +125,7 @@ pub(super) fn check<'tcx>(
return;
};
let arg_root = get_arg_root(cx, &args[1]);
let arg_root = get_arg_root(cx, &args[0]);
let span_replace_word = method_span.with_hi(expr.span.hi());

View file

@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
if_chain! {
if is_type_diagnostic_item(cx, ty, sym::Vec);
//check source object
if let ExprKind::MethodCall(src_method, [drain_vec, drain_arg], _) = &arg.kind;
if let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind;
if src_method.ident.as_str() == "drain";
let src_ty = cx.typeck_results().expr_ty(drain_vec);
//check if actual src type is mutable for code suggestion

View file

@ -28,11 +28,11 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
let closure_expr = peel_blocks(&body.value);
let arg_id = body.params[0].pat.hir_id;
match closure_expr.kind {
hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, args, _) => {
hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
if_chain! {
if ident.name == method_name;
if let hir::ExprKind::Path(path) = &args[0].kind;
if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id);
if let hir::ExprKind::Path(path) = &receiver.kind;
if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
then {
return arg_id == *local
}
@ -106,7 +106,7 @@ pub(super) fn check<'tcx>(
};
// closure ends with is_some() or is_ok()
if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
if let ExprKind::MethodCall(path, [filter_arg], _) = filter_body.value.kind;
if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
Some(false)
@ -123,13 +123,13 @@ pub(super) fn check<'tcx>(
if let [map_param] = map_body.params;
if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
// closure ends with expect() or unwrap()
if let ExprKind::MethodCall(seg, [map_arg, ..], _) = map_body.value.kind;
if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
// .filter(..).map(|y| f(y).copied().unwrap())
// ~~~~
let map_arg_peeled = match map_arg.kind {
ExprKind::MethodCall(method, [original_arg], _) if acceptable_methods(method) => {
ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
original_arg
},
_ => map_arg,

View file

@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
) = arg.kind
// LHS of subtraction is "x.len()"
&& let ExprKind::MethodCall(lhs_path, [lhs_recv], _) = &lhs.kind
&& let ExprKind::MethodCall(lhs_path, lhs_recv, [], _) = &lhs.kind
&& lhs_path.ident.name == sym::len
// RHS of subtraction is 1

View file

@ -12,13 +12,19 @@ use rustc_span::symbol::{sym, Symbol};
use super::INEFFICIENT_TO_STRING;
/// Checks for the `INEFFICIENT_TO_STRING` lint
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
pub fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &hir::Expr<'_>,
method_name: Symbol,
receiver: &hir::Expr<'_>,
args: &[hir::Expr<'_>],
) {
if_chain! {
if args.len() == 1 && method_name == sym::to_string;
if args.is_empty() && method_name == sym::to_string;
if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id);
let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver);
let self_ty = substs.type_at(0);
let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
if deref_count >= 1;
@ -35,7 +41,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
self_ty, deref_self_ty
));
let mut applicability = Applicability::MachineApplicable;
let arg_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability);
diag.span_suggestion(
expr.span,
"try dereferencing the receiver",

View file

@ -16,9 +16,9 @@ pub(super) fn check(
expr: &hir::Expr<'_>,
method_span: Span,
method_name: Symbol,
args: &[hir::Expr<'_>],
receiver: &hir::Expr<'_>,
) {
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
let self_ty = cx.typeck_results().expr_ty_adjusted(receiver);
if_chain! {
if let ty::Ref(..) = self_ty.kind();
if method_name == sym::into_iter;

View file

@ -35,7 +35,7 @@ fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -
&& range.end.map_or(true, |e| {
if range.limits == RangeLimits::HalfOpen
&& let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind
&& let ExprKind::MethodCall(name, [self_arg], _) = e.kind
&& let ExprKind::MethodCall(name, self_arg, [], _) = e.kind
&& name.ident.name == sym::len
&& let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
{

View file

@ -48,7 +48,7 @@ pub(super) fn check<'tcx>(
}
}
},
hir::ExprKind::MethodCall(method, [obj], _) => if_chain! {
hir::ExprKind::MethodCall(method, obj, [], _) => if_chain! {
if ident_eq(name, obj) && method.ident.name == sym::clone;
if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);

View file

@ -3161,11 +3161,13 @@ impl_lint_pass!(Methods => [
]);
/// Extracts a method call name, args, and `Span` of the method name.
fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> {
if let ExprKind::MethodCall(path, args, _) = recv.kind {
if !args.iter().any(|e| e.span.from_expansion()) {
fn method_call<'tcx>(
recv: &'tcx hir::Expr<'tcx>,
) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span)> {
if let ExprKind::MethodCall(path, receiver, args, _) = recv.kind {
if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
let name = path.ident.name.as_str();
return Some((name, args, path.ident.span));
return Some((name, receiver, args, path.ident.span));
}
}
None
@ -3183,17 +3185,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
hir::ExprKind::Call(func, args) => {
from_iter_instead_of_collect::check(cx, expr, args, func);
},
hir::ExprKind::MethodCall(method_call, args, _) => {
hir::ExprKind::MethodCall(method_call, receiver, args, _) => {
let method_span = method_call.ident.span;
or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
clone_on_copy::check(cx, expr, method_call.ident.name, args);
clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args);
inefficient_to_string::check(cx, expr, method_call.ident.name, args);
single_char_add_str::check(cx, expr, args);
into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args);
single_char_pattern::check(cx, expr, method_call.ident.name, args);
unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv);
or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args);
clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args);
inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args);
single_char_add_str::check(cx, expr, receiver, args);
into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);
},
hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
let mut info = BinaryExprInfo {
@ -3379,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);
@ -3399,13 +3401,13 @@ impl Methods {
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
("collect", []) => match method_call(recv) {
Some((name @ ("cloned" | "copied"), [recv2], _)) => {
Some((name @ ("cloned" | "copied"), recv2, [], _)) => {
iter_cloned_collect::check(cx, name, expr, recv2);
},
Some(("map", [m_recv, m_arg], _)) => {
Some(("map", m_recv, [m_arg], _)) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
},
Some(("take", [take_self_arg, take_arg], _)) => {
Some(("take", take_self_arg, [take_arg], _)) => {
if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
}
@ -3413,26 +3415,26 @@ impl Methods {
_ => {},
},
("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _)) => {
iter_count::check(cx, expr, recv2, name2);
},
Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg),
Some(("bytes", [recv2], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
Some(("map", _, [arg], _)) => suspicious_map::check(cx, expr, recv, arg),
Some(("filter", recv2, [arg], _)) => bytecount::check(cx, expr, recv2, arg),
Some(("bytes", recv2, [], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
_ => {},
},
("drain", [arg]) => {
iter_with_drain::check(cx, expr, recv, span, arg);
},
("ends_with", [arg]) => {
if let ExprKind::MethodCall(_, _, span) = expr.kind {
if let ExprKind::MethodCall(.., span) = expr.kind {
case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
}
},
("expect", [_]) => match method_call(recv) {
Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
Some(("ok", recv, [], _)) => ok_expect::check(cx, expr, recv),
Some(("err", recv, [], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
},
("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
@ -3452,13 +3454,13 @@ impl Methods {
flat_map_option::check(cx, expr, arg, span);
},
("flatten", []) => match method_call(recv) {
Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
Some(("map", recv, [map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
_ => {},
},
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
("for_each", [_]) => {
if let Some(("inspect", [_, _], span2)) = method_call(recv) {
if let Some(("inspect", _, [_], span2)) = method_call(recv) {
inspect_for_each::check(cx, expr, span2);
}
},
@ -3478,12 +3480,12 @@ impl Methods {
iter_on_single_or_empty_collections::check(cx, expr, name, recv);
},
("join", [join_arg]) => {
if let Some(("collect", _, span)) = method_call(recv) {
if let Some(("collect", _, _, span)) = method_call(recv) {
unnecessary_join::check(cx, expr, recv, join_arg, span);
}
},
("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);
}
@ -3498,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),
@ -3518,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),
@ -3531,10 +3533,10 @@ impl Methods {
}
},
("nth", [n_arg]) => match method_call(recv) {
Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
Some(("bytes", recv2, [], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
Some(("iter", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
Some(("iter_mut", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
},
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
@ -3591,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);
}
@ -3614,13 +3616,13 @@ impl Methods {
},
("unwrap", []) => {
match method_call(recv) {
Some(("get", [recv, get_arg], _)) => {
Some(("get", recv, [get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, false);
},
Some(("get_mut", [recv, get_arg], _)) => {
Some(("get_mut", recv, [get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, true);
},
Some(("or", [recv, or_arg], or_span)) => {
Some(("or", recv, [or_arg], or_span)) => {
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
},
_ => {},
@ -3629,19 +3631,19 @@ impl Methods {
},
("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
("unwrap_or", [u_arg]) => match method_call(recv) {
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _)) => {
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
},
Some(("map", [m_recv, m_arg], span)) => {
Some(("map", m_recv, [m_arg], span)) => {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
},
Some(("then_some", [t_recv, t_arg], _)) => {
Some(("then_some", t_recv, [t_arg], _)) => {
obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
},
_ => {},
},
("unwrap_or_else", [u_arg]) => match method_call(recv) {
Some(("map", [recv, map_arg], _))
Some(("map", recv, [map_arg], _))
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
_ => {
unwrap_or_else_default::check(cx, expr, recv, u_arg);
@ -3649,7 +3651,7 @@ impl Methods {
},
},
("zip", [arg]) => {
if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind
if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
&& name.ident.name == sym::iter
{
range_zip_with_len::check(cx, expr, iter_recv, arg);
@ -3662,7 +3664,7 @@ impl Methods {
}
fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call(recv) {
if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span)) = method_call(recv) {
search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
}
}

View file

@ -36,12 +36,12 @@ enum OpenOption {
}
fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
if let ExprKind::MethodCall(path, arguments, _) = argument.kind {
let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs();
if let ExprKind::MethodCall(path, receiver, arguments, _) = argument.kind {
let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
// Only proceed if this is a call on some object of type std::fs::OpenOptions
if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 {
let argument_option = match arguments[1].kind {
if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 1 {
let argument_option = match arguments[0].kind {
ExprKind::Lit(ref span) => {
if let Spanned {
node: LitKind::Bool(lit),
@ -77,7 +77,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
_ => (),
}
get_open_options(cx, &arguments[0], options);
get_open_options(cx, receiver, options);
}
}
}

View file

@ -56,13 +56,12 @@ pub(super) fn check<'tcx>(
let closure_expr = peel_blocks(&closure_body.value);
match &closure_expr.kind {
hir::ExprKind::MethodCall(_, args, _) => {
hir::ExprKind::MethodCall(_, receiver, [], _) => {
if_chain! {
if args.len() == 1;
if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id);
if path_to_local_id(receiver, closure_body.params[0].pat.hir_id);
let adj = cx
.typeck_results()
.expr_adjustments(&args[0])
.expr_adjustments(receiver)
.iter()
.map(|x| &x.kind)
.collect::<Box<[_]>>();

View file

@ -20,6 +20,7 @@ pub(super) fn check<'tcx>(
expr: &hir::Expr<'_>,
method_span: Span,
name: &str,
receiver: &'tcx hir::Expr<'_>,
args: &'tcx [hir::Expr<'_>],
) {
/// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
@ -144,7 +145,7 @@ pub(super) fn check<'tcx>(
}
}
if let [self_arg, arg] = args {
if let [arg] = args {
let inner_arg = if let hir::ExprKind::Block(
hir::Block {
stmts: [],
@ -163,11 +164,11 @@ pub(super) fn check<'tcx>(
let or_has_args = !or_args.is_empty();
if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
let fun_span = if or_has_args { None } else { Some(fun.span) };
check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span);
check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span);
}
},
hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
check_general_case(cx, name, method_span, self_arg, arg, expr.span, None);
check_general_case(cx, name, method_span, receiver, arg, expr.span, None);
},
_ => (),
}

View file

@ -16,7 +16,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
if is_integer_const(cx, start, 0);
// `.len()` call
if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind;
if let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind;
if len_path.ident.name == sym::len;
// `.iter()` and `.len()` called on same `Path`
if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind;

View file

@ -3,12 +3,12 @@ use clippy_utils::{match_def_path, paths};
use rustc_hir as hir;
use rustc_lint::LateContext;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
single_char_push_string::check(cx, expr, args);
single_char_push_string::check(cx, expr, receiver, args);
} else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
single_char_insert_string::check(cx, expr, args);
single_char_insert_string::check(cx, expr, receiver, args);
}
}
}

View file

@ -8,12 +8,12 @@ use rustc_lint::LateContext;
use super::SINGLE_CHAR_ADD_STR;
/// lint for length-1 `str`s as argument for `insert_str`
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
let mut applicability = Applicability::MachineApplicable;
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) {
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
let base_string_snippet =
snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability);
let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability);
snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability);
let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string);
span_lint_and_sugg(
cx,

View file

@ -10,37 +10,43 @@ use rustc_span::symbol::Symbol;
use super::SINGLE_CHAR_PATTERN;
const PATTERN_METHODS: [(&str, usize); 24] = [
("contains", 1),
("starts_with", 1),
("ends_with", 1),
("find", 1),
("rfind", 1),
("split", 1),
("split_inclusive", 1),
("rsplit", 1),
("split_terminator", 1),
("rsplit_terminator", 1),
("splitn", 2),
("rsplitn", 2),
("split_once", 1),
("rsplit_once", 1),
("matches", 1),
("rmatches", 1),
("match_indices", 1),
("rmatch_indices", 1),
("strip_prefix", 1),
("strip_suffix", 1),
("trim_start_matches", 1),
("trim_end_matches", 1),
("replace", 1),
("replacen", 1),
("contains", 0),
("starts_with", 0),
("ends_with", 0),
("find", 0),
("rfind", 0),
("split", 0),
("split_inclusive", 0),
("rsplit", 0),
("split_terminator", 0),
("rsplit_terminator", 0),
("splitn", 1),
("rsplitn", 1),
("split_once", 0),
("rsplit_once", 0),
("matches", 0),
("rmatches", 0),
("match_indices", 0),
("rmatch_indices", 0),
("strip_prefix", 0),
("strip_suffix", 0),
("trim_start_matches", 0),
("trim_end_matches", 0),
("replace", 0),
("replacen", 0),
];
/// lint for length-1 `str`s for methods in `PATTERN_METHODS`
pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
pub(super) fn check(
cx: &LateContext<'_>,
_expr: &hir::Expr<'_>,
method_name: Symbol,
receiver: &hir::Expr<'_>,
args: &[hir::Expr<'_>],
) {
for &(method, pos) in &PATTERN_METHODS {
if_chain! {
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(&args[0]).kind();
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind();
if *ty.kind() == ty::Str;
if method_name.as_str() == method && args.len() > pos;
let arg = &args[pos];

View file

@ -8,11 +8,11 @@ use rustc_lint::LateContext;
use super::SINGLE_CHAR_ADD_STR;
/// lint for length-1 `str`s as argument for `push_str`
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
let mut applicability = Applicability::MachineApplicable;
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) {
let base_string_snippet =
snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability);
snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
let sugg = format!("{}.push({})", base_string_snippet, extension_string);
span_lint_and_sugg(
cx,

View file

@ -292,7 +292,7 @@ fn parse_iter_usage<'tcx>(
) -> Option<IterUsage> {
let (kind, span) = match iter.next() {
Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
let (name, args) = if let ExprKind::MethodCall(name, [_, args @ ..], _) = e.kind {
let (name, args) = if let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind {
(name, args)
} else {
return None;
@ -327,7 +327,7 @@ fn parse_iter_usage<'tcx>(
} else {
if_chain! {
if let Some((_, Node::Expr(next_expr))) = iter.next();
if let ExprKind::MethodCall(next_name, [_], _) = next_expr.kind;
if let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind;
if next_name.ident.name == sym::next;
if next_expr.span.ctxt() == ctxt;
if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id);
@ -367,7 +367,7 @@ fn parse_iter_usage<'tcx>(
}
},
_ if e.span.ctxt() != ctxt => (None, span),
ExprKind::MethodCall(name, [_], _)
ExprKind::MethodCall(name, _, [], _)
if name.ident.name == sym::unwrap
&& cx
.typeck_results()

View file

@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
return;
}
if let Some(arglists) = method_chain_args(arg, &["chars"]) {
let target = &arglists[0][0];
let target = &arglists[0].0;
let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
let ref_str = if *self_ty.kind() == ty::Str {
""

View file

@ -43,7 +43,7 @@ pub fn check_for_loop_iter(
if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
then {
let snippet = if_chain! {
if let ExprKind::MethodCall(maybe_iter_method_name, [collection], _) = receiver.kind;
if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind;
if maybe_iter_method_name.ident.name == sym::iter;
if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);

View file

@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(
// This is a duplicate of what's happening in clippy_lints::methods::method_call,
// which isn't ideal, We want to get the method call span,
// but prefer to avoid changing the signature of the function itself.
if let hir::ExprKind::MethodCall(_, _, span) = expr.kind {
if let hir::ExprKind::MethodCall(.., span) = expr.kind {
span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
diag.span_suggestion(
span,

View file

@ -50,9 +50,13 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident
// The two exprs are method calls.
// Check to see that the function is the same and the arguments are mirrored
// This is enough because the receiver of the method is listed in the arguments
(ExprKind::MethodCall(left_segment, left_args, _), ExprKind::MethodCall(right_segment, right_args, _)) => {
(
ExprKind::MethodCall(left_segment, left_receiver, left_args, _),
ExprKind::MethodCall(right_segment, right_receiver, right_args, _),
) => {
left_segment.ident == right_segment.ident
&& iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
&& mirrored_exprs(left_receiver, a_ident, right_receiver, b_ident)
},
// Two tuples with mirrored contents
(ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => {
@ -125,7 +129,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
] = &closure_body.params;
if let ExprKind::MethodCall(method_path, [left_expr, right_expr], _) = closure_body.value.kind;
if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind;
if method_path.ident.name == sym::cmp;
if is_trait_method(cx, &closure_body.value, sym::Ord);
then {

View file

@ -24,12 +24,13 @@ pub fn check<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'tcx>,
method_name: Symbol,
args: &'tcx [Expr<'tcx>],
receiver: &'tcx Expr<'_>,
args: &'tcx [Expr<'_>],
msrv: Option<RustcVersion>,
) {
if_chain! {
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if let [receiver] = args;
if args.is_empty();
then {
if is_cloned_or_copied(cx, method_name, method_def_id) {
unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
@ -245,9 +246,14 @@ fn check_other_call_arg<'tcx>(
) -> bool {
if_chain! {
if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call);
if let Some((callee_def_id, call_substs, call_receiver, call_args)) = get_callee_substs_and_args(cx, maybe_call);
let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id);
let index = if let Some(call_receiver) = call_receiver {
std::iter::once(call_receiver).chain(call_args.iter()).position(|arg| arg.hir_id == maybe_arg.hir_id)
} else {
call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id)
};
if let Some(i) = index;
if let Some(input) = fn_sig.inputs().get(i);
let (input, n_refs) = peel_mid_ty_refs(*input);
if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input);
@ -342,22 +348,22 @@ fn skip_addr_of_ancestors<'tcx>(
fn get_callee_substs_and_args<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'tcx>,
) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> {
) -> Option<(DefId, SubstsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> {
if_chain! {
if let ExprKind::Call(callee, args) = expr.kind;
let callee_ty = cx.typeck_results().expr_ty(callee);
if let ty::FnDef(callee_def_id, _) = callee_ty.kind();
then {
let substs = cx.typeck_results().node_substs(callee.hir_id);
return Some((*callee_def_id, substs, args));
return Some((*callee_def_id, substs, None, args));
}
}
if_chain! {
if let ExprKind::MethodCall(_, args, _) = expr.kind;
if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind;
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
then {
let substs = cx.typeck_results().node_substs(expr.hir_id);
return Some((method_def_id, substs, args));
return Some((method_def_id, substs, Some(receiver), args));
}
}
None

View file

@ -28,7 +28,7 @@ pub(super) fn derefs_to_slice<'tcx>(
}
}
if let hir::ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind {
if let hir::ExprKind::MethodCall(path, self_arg, ..) = &expr.kind {
if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) {
Some(self_arg)
} else {
@ -139,9 +139,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
self.addr_of_exprs.push(parent);
return;
},
ExprKind::MethodCall(_, args, _) => {
ExprKind::MethodCall(.., args, _) => {
if_chain! {
if args.iter().skip(1).all(|arg| !self.is_binding(arg));
if args.iter().all(|arg| !self.is_binding(arg));
if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id);
let method_ty = self.cx.tcx.type_of(method_def_id);
let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder();

View file

@ -75,23 +75,22 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
.qpath_res(qpath, path.hir_id)
.opt_def_id()
.and_then(|def_id| match cx.tcx.get_diagnostic_name(def_id) {
Some(sym::cmp_min) => fetch_const(cx, args, MinMax::Min),
Some(sym::cmp_max) => fetch_const(cx, args, MinMax::Max),
Some(sym::cmp_min) => fetch_const(cx, None, args, MinMax::Min),
Some(sym::cmp_max) => fetch_const(cx, None, args, MinMax::Max),
_ => None,
})
} else {
None
}
},
ExprKind::MethodCall(path, args, _) => {
ExprKind::MethodCall(path, receiver, args @ [_], _) => {
if_chain! {
if let [obj, _] = args;
if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
then {
if path.ident.name == sym!(max) {
fetch_const(cx, args, MinMax::Max)
fetch_const(cx, Some(receiver), args, MinMax::Max)
} else if path.ident.name == sym!(min) {
fetch_const(cx, args, MinMax::Min)
fetch_const(cx, Some(receiver), args, MinMax::Min)
} else {
None
}
@ -104,16 +103,24 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
}
}
fn fetch_const<'a>(cx: &LateContext<'_>, args: &'a [Expr<'a>], m: MinMax) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
if args.len() != 2 {
fn fetch_const<'a>(
cx: &LateContext<'_>,
receiver: Option<&'a Expr<'a>>,
args: &'a [Expr<'a>],
m: MinMax,
) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
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;
}
constant_simple(cx, cx.typeck_results(), &args[0]).map_or_else(
|| constant_simple(cx, cx.typeck_results(), &args[1]).map(|c| (m, c, &args[0])),
constant_simple(cx, cx.typeck_results(), arg0).map_or_else(
|| constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)),
|c| {
if constant_simple(cx, cx.typeck_results(), &args[1]).is_none() {
if constant_simple(cx, cx.typeck_results(), arg1).is_none() {
// otherwise ignore
Some((m, c, &args[1]))
Some((m, c, arg1))
} else {
None
}

View file

@ -43,18 +43,24 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
if let ExprKind::Path(ref path) = fn_expr.kind {
check_arguments(
cx,
arguments,
arguments.iter().collect(),
cx.typeck_results().expr_ty(fn_expr),
&rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
"function",
);
}
},
ExprKind::MethodCall(path, arguments, _) => {
ExprKind::MethodCall(path, receiver, arguments, _) => {
let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
let substs = cx.typeck_results().node_substs(e.hir_id);
let method_type = cx.tcx.bound_type_of(def_id).subst(cx.tcx, substs);
check_arguments(cx, arguments, method_type, path.ident.as_str(), "method");
check_arguments(
cx,
std::iter::once(receiver).chain(arguments.iter()).collect(),
method_type,
path.ident.as_str(),
"method",
);
},
_ => (),
}
@ -63,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
fn check_arguments<'tcx>(
cx: &LateContext<'tcx>,
arguments: &[Expr<'_>],
arguments: Vec<&Expr<'_>>,
type_definition: Ty<'tcx>,
name: &str,
fn_kind: &str,

View file

@ -56,12 +56,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
if_chain! {
// Check the method name is `for_each`.
if let ExprKind::MethodCall(method_name, [for_each_recv, for_each_arg], _) = expr.kind;
if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind;
if method_name.ident.name == Symbol::intern("for_each");
// Check `for_each` is an associated function of `Iterator`.
if is_trait_method(cx, expr, sym::Iterator);
// Checks the receiver of `for_each` is also a method call.
if let ExprKind::MethodCall(_, [iter_recv], _) = for_each_recv.kind;
if let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind;
// Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or
// `v.foo().iter().for_each()` must be skipped.
if matches!(

View file

@ -43,7 +43,7 @@ declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]);
impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
match &expr.kind {
ExprKind::MethodCall(path, [func, param], _) => {
ExprKind::MethodCall(path, func, [param], _) => {
let obj_ty = cx.typeck_results().expr_ty(func).peel_refs();
if_chain! {

View file

@ -304,13 +304,13 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
}
return;
},
ExprKind::MethodCall(_, args, _)
ExprKind::MethodCall(_, receiver, args, _)
if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| {
id == param.fn_id
&& has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id))
}) =>
{
if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) {
if let Some(idx) = std::iter::once(receiver).chain(args.iter()).position(|arg| arg.hir_id == child_id) {
param.uses.push(Usage::new(span, idx));
}
return;

View file

@ -38,7 +38,7 @@ fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'t
fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
let typeck = cx.typeck_results();
let (arg, arg_span) = match expr.kind {
ExprKind::MethodCall(.., [arg], _)
ExprKind::MethodCall(_, arg, [], _)
if typeck
.type_dependent_def_id(expr.hir_id)
.and_then(|id| cx.tcx.trait_of_item(id))

View file

@ -17,7 +17,7 @@ pub(crate) fn check<'tcx>(
right: &'tcx Expr<'_>,
) {
if op == BinOpKind::Div
&& let ExprKind::MethodCall(method_path, [self_arg], _) = left.kind
&& let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
&& let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right)
{

View file

@ -113,7 +113,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
}
if_chain! {
if let ExprKind::MethodCall(method_name, [ref self_arg, ..], _) = expr.kind;
if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
if sym!(signum) == method_name.ident.name;
// Check that the receiver of the signum() is a float (expressions[0] is the receiver of
// the method call)

View file

@ -591,8 +591,11 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
set_skip_flag();
}
},
ExprKind::MethodCall(name, expr_args @ [self_arg, ..], _) => {
let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
ExprKind::MethodCall(name, self_arg, expr_args, _) => {
let i = std::iter::once(self_arg)
.chain(expr_args.iter())
.position(|arg| arg.hir_id == child_id)
.unwrap_or(0);
if i == 0 {
// Check if the method can be renamed.
let name = name.ident.as_str();

View file

@ -93,7 +93,7 @@ fn expr_as_ptr_offset_call<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> {
if let ExprKind::MethodCall(path_segment, [arg_0, arg_1, ..], _) = &expr.kind {
if let ExprKind::MethodCall(path_segment, arg_0, [arg_1, ..], _) = &expr.kind {
if is_expr_ty_raw_ptr(cx, arg_0) {
if path_segment.ident.name == sym::offset {
return Some((arg_0, arg_1, Method::Offset));

View file

@ -86,7 +86,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex
if_chain! {
if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
if !is_else_clause(cx.tcx, expr);
if let ExprKind::MethodCall(segment, [caller, ..], _) = &cond.kind;
if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind;
let caller_ty = cx.typeck_results().expr_ty(caller);
let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else);
if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block);

View file

@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
// finds use of `_.read(&mut v)`
let mut read_found = false;
let mut visitor = expr_visitor_no_bodies(|expr| {
if let ExprKind::MethodCall(path, [_self, arg], _) = expr.kind
if let ExprKind::MethodCall(path, _self, [arg], _) = expr.kind
&& let PathSegment { ident: read_or_read_exact, .. } = *path
&& matches!(read_or_read_exact.as_str(), "read" | "read_exact")
&& let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind

View file

@ -108,7 +108,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
};
if_chain! {
// Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods
if let ExprKind::MethodCall(method_path, [ptr_self, .., count], _) = expr.kind;
if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind;
let method_ident = method_path.ident.as_str();
if METHODS.iter().any(|m| *m == method_ident);

View file

@ -201,7 +201,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
if_chain! {
if self.initialization_found;
if let ExprKind::MethodCall(path, [self_arg, extend_arg], _) = expr.kind;
if let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind;
if path_to_local_id(self_arg, self.vec_alloc.local_id);
if path.ident.name == sym!(extend);
if self.is_repeat_take(extend_arg);
@ -215,7 +215,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
/// Checks if the given expression is resizing a vector with 0
fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
if self.initialization_found
&& let ExprKind::MethodCall(path, [self_arg, len_arg, fill_arg], _) = expr.kind
&& let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
&& path_to_local_id(self_arg, self.vec_alloc.local_id)
&& path.ident.name == sym!(resize)
// Check that is filled with 0
@ -224,7 +224,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
// Check that len expression is equals to `with_capacity` expression
if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
self.slow_expression = Some(InitializationType::Resize(expr));
} else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" {
} else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
self.slow_expression = Some(InitializationType::Resize(expr));
}
}
@ -233,7 +233,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
/// Returns `true` if give expression is `repeat(0).take(...)`
fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
if_chain! {
if let ExprKind::MethodCall(take_path, [recv, len_arg, ..], _) = expr.kind;
if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind;
if take_path.ident.name == sym!(take);
// Check that take is applied to `repeat(0)`
if self.is_repeat_zero(recv);
@ -241,7 +241,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
// Check that len expression is equals to `with_capacity` expression
if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
return true;
} else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" {
} else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
return true;
}
}

View file

@ -262,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
let (method_names, expressions, _) = method_calls(left, 1);
if method_names.len() == 1;
if expressions.len() == 1;
if expressions[0].len() == 1;
if expressions[0].1.is_empty();
if method_names[0] == sym!(as_bytes);
// Check for slicer
@ -270,7 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
then {
let mut applicability = Applicability::MachineApplicable;
let string_expression = &expressions[0][0];
let string_expression = &expressions[0].0;
let snippet_app = snippet_with_applicability(
cx,
@ -291,12 +291,12 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
}
if_chain! {
if let ExprKind::MethodCall(path, args, _) = &e.kind;
if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
if path.ident.name == sym!(as_bytes);
if let ExprKind::Lit(lit) = &args[0].kind;
if let ExprKind::Lit(lit) = &receiver.kind;
if let LitKind::Str(lit_content, _) = &lit.node;
then {
let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
let callsite = snippet(cx, receiver.span.source_callsite(), r#""foo""#);
let mut applicability = Applicability::MachineApplicable;
if callsite.starts_with("include_str!") {
span_lint_and_sugg(
@ -305,7 +305,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
e.span,
"calling `as_bytes()` on `include_str!(..)`",
"consider using `include_bytes!(..)` instead",
snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen(
snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen(
"include_str",
"include_bytes",
1,
@ -314,7 +314,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
);
} else if lit_content.as_str().is_ascii()
&& lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
&& !args[0].span.from_expansion()
&& !receiver.span.from_expansion()
{
span_lint_and_sugg(
cx,
@ -324,7 +324,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
"consider using a byte string literal instead",
format!(
"b{}",
snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
),
applicability,
);
@ -333,9 +333,9 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
}
if_chain! {
if let ExprKind::MethodCall(path, [recv], _) = &e.kind;
if let ExprKind::MethodCall(path, recv, [], _) = &e.kind;
if path.ident.name == sym!(into_bytes);
if let ExprKind::MethodCall(path, [recv], _) = &recv.kind;
if let ExprKind::MethodCall(path, recv, [], _) = &recv.kind;
if matches!(path.ident.name.as_str(), "to_owned" | "to_string");
if let ExprKind::Lit(lit) = &recv.kind;
if let LitKind::Str(lit_content, _) = &lit.node;
@ -393,7 +393,7 @@ declare_lint_pass!(StrToString => [STR_TO_STRING]);
impl<'tcx> LateLintPass<'tcx> for StrToString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
if_chain! {
if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
if path.ident.name == sym::to_string;
let ty = cx.typeck_results().expr_ty(self_arg);
if let ty::Ref(_, ty, ..) = ty.kind();
@ -443,7 +443,7 @@ declare_lint_pass!(StringToString => [STRING_TO_STRING]);
impl<'tcx> LateLintPass<'tcx> for StringToString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
if_chain! {
if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
if path.ident.name == sym::to_string;
let ty = cx.typeck_results().expr_ty(self_arg);
if is_type_diagnostic_item(cx, ty, sym::String);
@ -487,11 +487,11 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
let tyckres = cx.typeck_results();
if_chain! {
if let ExprKind::MethodCall(path, [split_recv], split_ws_span) = expr.kind;
if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind;
if path.ident.name == sym!(split_whitespace);
if let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id);
if cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id);
if let ExprKind::MethodCall(path, [_trim_recv], trim_span) = split_recv.kind;
if let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind;
if let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str();
if let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id);
if is_one_of_trim_diagnostic_items(cx, trim_def_id);

View file

@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
if let ExprKind::Path(path) = &func.kind;
if let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id();
if match_libc_symbol(cx, did, "strlen");
if let ExprKind::MethodCall(path, [self_arg], _) = recv.kind;
if let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind;
if !recv.span.from_expansion();
if path.ident.name == sym::as_ptr;
then {

View file

@ -39,19 +39,17 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]);
impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if_chain! {
if let hir::ExprKind::MethodCall(is_some_path, is_some_args, _) = &expr.kind;
if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind;
if is_some_path.ident.name.as_str() == "is_some";
if let [to_digit_expr] = &**is_some_args;
then {
let match_result = match &to_digit_expr.kind {
hir::ExprKind::MethodCall(to_digits_path, to_digit_args, _) => {
hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => {
if_chain! {
if let [char_arg, radix_arg] = &**to_digit_args;
if to_digits_path.ident.name.as_str() == "to_digit";
let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg);
if *char_arg_ty.kind() == ty::Char;
then {
Some((true, char_arg, radix_arg))
Some((true, *char_arg, radix_arg))
} else {
None
}
@ -59,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
}
hir::ExprKind::Call(to_digits_call, to_digit_args) => {
if_chain! {
if let [char_arg, radix_arg] = &**to_digit_args;
if let [char_arg, radix_arg] = *to_digit_args;
if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind;
if let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id);
if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id();

View file

@ -177,7 +177,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt
});
}
},
ExprKind::MethodCall(path, [self_expr, _], _) if is_reserve(cx, path, self_expr) => {
ExprKind::MethodCall(path, self_expr, [_], _) if is_reserve(cx, path, self_expr) => {
return Some(TargetVec {
location: VecLocation::Expr(self_expr),
init_kind: None,
@ -211,7 +211,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
}
});
match expr.kind {
ExprKind::MethodCall(path, [self_expr, _], _) => {
ExprKind::MethodCall(path, self_expr, [_], _) => {
let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" {
Some((self_expr, expr.span))

View file

@ -144,8 +144,9 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa
impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if let ExprKind::MethodCall(_, args, _) = expr.kind {
if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind {
let arg_indices = get_args_to_check(cx, expr);
let args = std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>();
for (i, trait_name) in arg_indices {
if i < args.len() {
match check_arg(cx, &args[i]) {

View file

@ -128,7 +128,7 @@ fn needs_inferred_result_ty(
locals_to_check: &mut Vec<HirId>,
seen_locals: &mut HirIdSet,
) -> bool {
let (id, args) = match e.kind {
let (id, receiver, args) = match e.kind {
ExprKind::Call(
Expr {
kind: ExprKind::Path(ref path),
@ -137,11 +137,11 @@ fn needs_inferred_result_ty(
},
args,
) => match cx.qpath_res(path, *hir_id) {
Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, args),
Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, None, args),
_ => return false,
},
ExprKind::MethodCall(_, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) {
Some(id) => (id, args),
ExprKind::MethodCall(_, receiver, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) {
Some(id) => (id, Some(receiver), args),
None => return false,
},
ExprKind::Path(QPath::Resolved(None, path)) => {
@ -156,6 +156,11 @@ fn needs_inferred_result_ty(
};
let sig = cx.tcx.fn_sig(id).skip_binder();
if let ty::Param(output_ty) = *sig.output().kind() {
let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver {
std::iter::once(receiver).chain(args.iter()).collect()
} else {
args.iter().collect()
};
sig.inputs().iter().zip(args).all(|(&ty, arg)| {
!ty.is_param(output_ty.index) || each_value_source_needs_inference(cx, arg, locals_to_check, seen_locals)
})

View file

@ -30,26 +30,27 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
}
}
match expr.kind {
ExprKind::Call(_, args) | ExprKind::MethodCall(_, args, _) => {
let args_to_recover = args
.iter()
.filter(|arg| {
if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) {
!matches!(
&arg.kind,
ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
)
} else {
false
}
})
.collect::<Vec<_>>();
if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
lint_unit_args(cx, expr, &args_to_recover);
let args: Vec<_> = match expr.kind {
ExprKind::Call(_, args) => args.iter().collect(),
ExprKind::MethodCall(_, receiver, args, _) => std::iter::once(receiver).chain(args.iter()).collect(),
_ => return,
};
let args_to_recover = args
.into_iter()
.filter(|arg| {
if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) {
!matches!(
&arg.kind,
ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
)
} else {
false
}
},
_ => (),
})
.collect::<Vec<_>>();
if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
lint_unit_args(cx, expr, &args_to_recover.as_slice());
}
}

View file

@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
check_map_error(cx, res, expr);
}
},
hir::ExprKind::MethodCall(path, [ref arg_0, ..], _) => match path.ident.as_str() {
hir::ExprKind::MethodCall(path, arg_0, ..) => match path.ident.as_str() {
"expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => {
check_map_error(cx, arg_0, expr);
},
@ -94,9 +94,9 @@ fn try_remove_await<'a>(expr: &'a hir::Expr<'a>) -> Option<&hir::Expr<'a>> {
fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
let mut call = call;
while let hir::ExprKind::MethodCall(path, args, _) = call.kind {
while let hir::ExprKind::MethodCall(path, receiver, ..) = call.kind {
if matches!(path.ident.as_str(), "or" | "or_else" | "ok") {
call = &args[0];
call = receiver;
} else {
break;
}
@ -110,7 +110,7 @@ fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<
}
fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>, is_await: bool) {
if let hir::ExprKind::MethodCall(path, _, _) = call.kind {
if let hir::ExprKind::MethodCall(path, ..) = call.kind {
let symbol = path.ident.as_str();
let read_trait = if is_await {
match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT)

View file

@ -149,7 +149,8 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
ident: method_name_ident,
..
},
[self_arg, remaining_args @ ..],
self_arg,
remaining_args,
_,
) => {
let method_name = method_name_ident.name.as_str();

View file

@ -154,13 +154,13 @@ fn collect_unwrap_info<'tcx>(
return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false);
} else {
if_chain! {
if let ExprKind::MethodCall(method_name, args, _) = &expr.kind;
if let Some(local_id) = path_to_local(&args[0]);
let ty = cx.typeck_results().expr_ty(&args[0]);
if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind;
if let Some(local_id) = path_to_local(receiver);
let ty = cx.typeck_results().expr_ty(receiver);
let name = method_name.ident.as_str();
if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name);
then {
assert!(args.len() == 1);
assert!(args.len() == 0);
let unwrappable = match name {
"is_some" | "is_ok" => true,
"is_err" | "is_none" => false,
@ -231,7 +231,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
} else {
// find `unwrap[_err]()` calls:
if_chain! {
if let ExprKind::MethodCall(method_name, [self_arg, ..], _) = expr.kind;
if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
if let Some(id) = path_to_local(self_arg);
if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name);
let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name);

View file

@ -83,7 +83,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
// check for `expect`
if let Some(arglists) = method_chain_args(expr, &["expect"]) {
let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
{
@ -93,7 +93,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
|| is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
{

View file

@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
}
},
ExprKind::MethodCall(name, .., [recv, ..], _) => {
ExprKind::MethodCall(name, recv, ..) => {
if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" {
let a = cx.typeck_results().expr_ty(e);
let b = cx.typeck_results().expr_ty(recv);

View file

@ -402,10 +402,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
self.expr(func);
self.slice(args, |e| self.expr(e));
},
ExprKind::MethodCall(method_name, args, _) => {
bind!(self, method_name, args);
kind!("MethodCall({method_name}, {args}, _)");
ExprKind::MethodCall(method_name, receiver, args, _) => {
bind!(self, method_name, receiver, args);
kind!("MethodCall({method_name}, {receiver}, {args}, _)");
self.ident(field!(method_name.ident));
self.expr(receiver);
self.slice(args, |e| self.expr(e));
},
ExprKind::Tup(elements) => {

Some files were not shown because too many files have changed in this diff Show more