Auto merge of #9447 - flip1995:rustup, r=flip1995

Rustup

r? `@ghost`

changelog: none
This commit is contained in:
bors 2022-09-08 19:42:33 +00:00
commit 32fa80dda5
162 changed files with 897 additions and 791 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

@ -1,3 +1,4 @@
#![feature(let_chains)]
#![feature(let_else)]
#![feature(once_cell)]
#![feature(rustc_private)]

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

@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
hir_id: body.value.hir_id,
};
let typeck_results = cx.tcx.typeck_body(body_id);
let expr_ty = typeck_results.expr_ty(&body.value);
let expr_ty = typeck_results.expr_ty(body.value);
if implements_trait(cx, expr_ty, future_trait_def_id, &[]) {
let return_expr_span = match &body.value.kind {

View File

@ -475,7 +475,7 @@ fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem
fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
if let ItemKind::Fn(_, _, eid) = item.kind {
is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value)
} else {
true
}
@ -483,7 +483,7 @@ fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
fn is_relevant_impl(cx: &LateContext<'_>, item: &ImplItem<'_>) -> bool {
match item.kind {
ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value),
ImplItemKind::Fn(_, eid) => is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value),
_ => false,
}
}
@ -492,7 +492,7 @@ fn is_relevant_trait(cx: &LateContext<'_>, item: &TraitItem<'_>) -> bool {
match item.kind {
TraitItemKind::Fn(_, TraitFn::Required(_)) => true,
TraitItemKind::Fn(_, TraitFn::Provided(eid)) => {
is_relevant_expr(cx, cx.tcx.typeck_body(eid), &cx.tcx.hir().body(eid).value)
is_relevant_expr(cx, cx.tcx.typeck_body(eid), cx.tcx.hir().body(eid).value)
},
_ => false,
}

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, &[]);

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

@ -131,10 +131,10 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
}
},
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();

View File

@ -503,7 +503,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
}
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
if let PatKind::Binding(BindingAnnotation::REF, id, name, _) = pat.kind {
if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
// This binding id has been seen before. Add this pattern to the list of changes.
if let Some(prev_pat) = opt_prev_pat {
@ -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,56 +796,54 @@ 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)
}
return Some(Position::MethodReceiver);
}
args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
if let ty::Param(param_ty) = ty.kind() {
needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv)
} else {
let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
if let ty::Param(param_ty) = ty.kind() {
needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv)
} else {
ty_auto_deref_stability(
cx,
cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
precedence,
)
.position_for_arg()
}
ty_auto_deref_stability(
cx,
cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
precedence,
)
.position_for_arg()
}
})
},
@ -1174,7 +1172,7 @@ fn replace_types<'tcx>(
if replaced.insert(param_ty.index) {
for projection_predicate in projection_predicates {
if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx)
&& let ty::Term::Ty(term_ty) = projection_predicate.term
&& let Some(term_ty) = projection_predicate.term.ty()
&& let ty::Param(term_param_ty) = term_ty.kind()
{
let item_def_id = projection_predicate.projection_ty.item_def_id;

View File

@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
typeck_results: cx.tcx.typeck(item.def_id),
panic_span: None,
};
fpu.visit_expr(&body.value);
fpu.visit_expr(body.value);
lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
}
},
@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for DocMarkdown {
typeck_results: cx.tcx.typeck(item.def_id),
panic_span: None,
};
fpu.visit_expr(&body.value);
fpu.visit_expr(body.value);
lint_for_missing_headers(cx, item.def_id, item.span, sig, headers, Some(body_id), fpu.panic_span);
}
}
@ -348,7 +348,7 @@ fn lint_for_missing_headers<'tcx>(
if let Some(future) = cx.tcx.lang_items().future_trait();
let typeck = cx.tcx.typeck_body(body_id);
let body = cx.tcx.hir().body(body_id);
let ret_ty = typeck.expr_ty(&body.value);
let ret_ty = typeck.expr_ty(body.value);
if implements_trait(cx, ret_ty, future, &[]);
if let ty::Opaque(_, subs) = ret_ty.kind();
if let Some(gen) = subs.types().next();
@ -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

@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
};
if body.value.span.from_expansion() {
if body.params.is_empty() {
if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, &body.value) {
if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) {
// replace `|| vec![]` with `Vec::new`
span_lint_and_sugg(
cx,
@ -103,10 +103,10 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
let closure_ty = cx.typeck_results().expr_ty(expr);
if_chain!(
if !is_adjusted(cx, &body.value);
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));
@ -145,9 +145,9 @@ 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 !is_adjusted(cx, body.value);
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,8 @@ 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() {
@ -128,7 +128,7 @@ fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>)
if let Some(Node::Pat(res_pat)) = cx.tcx.hir().find(expr_res);
// Find id of the local we found in the block
if let PatKind::Binding(BindingAnnotation::Unannotated, local_hir_id, _ident, None) = local.pat.kind;
if let PatKind::Binding(BindingAnnotation::NONE, local_hir_id, _ident, None) = local.pat.kind;
// If those two are the same hir id
if res_pat.hir_id == local_hir_id;

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)
{
@ -110,7 +110,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
typeck_results: cx.tcx.typeck(impl_item.id.def_id),
result: Vec::new(),
};
fpu.visit_expr(&body.value);
fpu.visit_expr(body.value);
// if we've found one, lint
if !fpu.result.is_empty() {

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) {
if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
Some("exp")
} else if F32(2.0) == value || F64(2.0) == value {
@ -251,25 +251,25 @@ 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

@ -126,7 +126,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);

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);
},
@ -254,6 +272,6 @@ fn mutates_static<'tcx>(cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) -> bo
cx,
mutates_static: false,
};
intravisit::walk_expr(&mut v, &body.value);
intravisit::walk_expr(&mut v, body.value);
v.mutates_static
}

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

@ -232,7 +232,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
return;
}
let res_ty = cx.typeck_results().expr_ty(&body.value);
let res_ty = cx.typeck_results().expr_ty(body.value);
if res_ty.is_unit() || res_ty.is_never() {
return;
}
@ -243,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
None => return,
}
} else {
&body.value
body.value
};
lint_implicit_returns(cx, expr, expr.span.ctxt(), None);
}

View File

@ -95,12 +95,14 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
let mut removed_pat: FxHashSet<hir::HirId> = FxHashSet::default();
let mut slices: FxIndexMap<hir::HirId, SliceLintInformation> = FxIndexMap::default();
pat.walk_always(|pat| {
if let hir::PatKind::Binding(binding, value_hir_id, ident, sub_pat) = pat.kind {
// We'll just ignore mut and ref mut for simplicity sake right now
if let hir::BindingAnnotation::Mutable | hir::BindingAnnotation::RefMut = binding {
return;
}
// We'll just ignore mut and ref mut for simplicity sake right now
if let hir::PatKind::Binding(
hir::BindingAnnotation(by_ref, hir::Mutability::Not),
value_hir_id,
ident,
sub_pat,
) = pat.kind
{
// This block catches bindings with sub patterns. It would be hard to build a correct suggestion
// for them and it's likely that the user knows what they are doing in such a case.
if removed_pat.contains(&value_hir_id) {
@ -116,7 +118,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
if let ty::Slice(inner_ty) | ty::Array(inner_ty, _) = bound_ty.peel_refs().kind() {
// The values need to use the `ref` keyword if they can't be copied.
// This will need to be adjusted if the lint want to support mutable access in the future
let src_is_ref = bound_ty.is_ref() && binding != hir::BindingAnnotation::Ref;
let src_is_ref = bound_ty.is_ref() && by_ref != hir::ByRef::Yes;
let needs_ref = !(src_is_ref || is_copy(cx, *inner_ty));
let slice_info = slices

View File

@ -123,45 +123,45 @@ 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);
return is_infinite(cx, body.value);
}
}
Finite
@ -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,26 @@ 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 {
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(&args[0]), 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 +245,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,8 @@ 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,16 +379,28 @@ 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);
}
}
// FIXME(flip1995): Figure out how to reduce the number of arguments
#[allow(clippy::too_many_arguments)]
fn check_len(
cx: &LateContext<'_>,
span: Span,
method_name: Symbol,
receiver: &Expr<'_>,
args: &[Expr<'_>],
lit: &LitKind,
op: &str,
@ -399,7 +412,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 +423,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

@ -4,7 +4,7 @@ use clippy_utils::{path_to_local_id, visitors::is_local_used};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::BindingAnnotation;
use rustc_hir::{BindingAnnotation, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
};
let mutability = match mode {
BindingAnnotation::RefMut | BindingAnnotation::Mutable => "<mut> ",
BindingAnnotation(_, Mutability::Mut) => "<mut> ",
_ => "",
};

View File

@ -4,6 +4,7 @@
#![feature(control_flow_enum)]
#![feature(drain_filter)]
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(let_else)]
#![feature(lint_reasons)]
#![feature(never_type)]

View File

@ -276,7 +276,7 @@ fn could_use_elision<'tcx>(
let mut checker = BodyLifetimeChecker {
lifetimes_used_in_body: false,
};
checker.visit_expr(&body.value);
checker.visit_expr(body.value);
if checker.lifetimes_used_in_body {
return false;
}

View File

@ -106,7 +106,7 @@ fn get_binding(pat: &Pat<'_>) -> Option<HirId> {
hir_id = None;
return;
}
if let BindingAnnotation::Unannotated = annotation {
if let BindingAnnotation::NONE = annotation {
hir_id = Some(id);
}
});

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

@ -44,7 +44,7 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId>
if_chain! {
if let Some(hir_id) = path_to_local(bound);
if let Node::Pat(pat) = cx.tcx.hir().get(hir_id);
if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind;
if let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind;
then {
return Some(hir_id);
}

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 {
@ -370,7 +373,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
},
ExprKind::Closure(&Closure { body, .. }) => {
let body = self.cx.tcx.hir().body(body);
self.visit_expr(&body.value);
self.visit_expr(body.value);
},
_ => walk_expr(self, expr),
}

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);
@ -178,9 +179,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
never_loop_expr(expr, main_loop_id)
},
InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter(), main_loop_id),
InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter().copied(), main_loop_id),
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
never_loop_expr_all(&mut once(in_expr).chain(out_expr.iter()), main_loop_id)
never_loop_expr_all(&mut once(*in_expr).chain(out_expr.iter().copied()), main_loop_id)
},
InlineAsmOperand::Const { .. }
| InlineAsmOperand::SymFn { .. }

View File

@ -7,7 +7,7 @@ use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;
use std::iter::Iterator;
@ -65,7 +65,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if let Node::Pat(pat) = node;
if let PatKind::Binding(bind_ann, ..) = pat.kind;
if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut));
let parent_node = cx.tcx.hir().get_parent_node(hir_id);
if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node);
if let Some(init) = parent_let_expr.init;
@ -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), .. }) | 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);
@ -356,7 +356,7 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
after_loop: false,
used_iter: false,
};
v.visit_expr(&cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
v.visit_expr(cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
v.used_iter
}
}

View File

@ -105,7 +105,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id);
then {
cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (real_ty, resolved_ty))
cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (*real_ty, resolved_ty))
} else {
None
}
@ -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

@ -165,7 +165,7 @@ fn check<'tcx>(
}
// `ref` and `ref mut` annotations were handled earlier.
let annotation = if matches!(annotation, BindingAnnotation::Mutable) {
let annotation = if matches!(annotation, BindingAnnotation::MUT) {
"mut "
} else {
""

View File

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{is_lang_ctor, peel_blocks};
use rustc_errors::Applicability;
use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, LangItem, PatKind, QPath};
use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty;
@ -10,18 +10,17 @@ use super::MATCH_AS_REF;
pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
let arm_ref: Option<BindingAnnotation> = if is_none_arm(cx, &arms[0]) {
let arm_ref_mut = if is_none_arm(cx, &arms[0]) {
is_ref_some_arm(cx, &arms[1])
} else if is_none_arm(cx, &arms[1]) {
is_ref_some_arm(cx, &arms[0])
} else {
None
};
if let Some(rb) = arm_ref {
let suggestion = if rb == BindingAnnotation::Ref {
"as_ref"
} else {
"as_mut"
if let Some(rb) = arm_ref_mut {
let suggestion = match rb {
Mutability::Not => "as_ref",
Mutability::Mut => "as_mut",
};
let output_ty = cx.typeck_results().expr_ty(expr);
@ -66,19 +65,18 @@ fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
}
// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotation> {
fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
if_chain! {
if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
if is_lang_ctor(cx, qpath, LangItem::OptionSome);
if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind;
if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind;
if let ExprKind::Path(ref some_path) = e.kind;
if is_lang_ctor(cx, some_path, LangItem::OptionSome);
if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind;
if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
then {
return Some(rb)
return Some(mutabl)
}
}
None

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

@ -8,7 +8,7 @@ use clippy_utils::{
};
use rustc_errors::Applicability;
use rustc_hir::LangItem::OptionNone;
use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath};
use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath};
use rustc_lint::LateContext;
use rustc_span::sym;
use rustc_typeck::hir_ty_to_ty;
@ -189,8 +189,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
},
)),
) => {
return !matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut)
&& pat_ident.name == first_seg.ident.name;
return !matches!(annot, BindingAnnotation(ByRef::Yes, _)) && pat_ident.name == first_seg.ident.name;
},
// Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
(PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {

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

@ -175,7 +175,7 @@ fn collect_pat_paths<'a>(acc: &mut Vec<Ty<'a>>, cx: &LateContext<'a>, pat: &Pat<
let p_ty = cx.typeck_results().pat_ty(p);
collect_pat_paths(acc, cx, p, p_ty);
}),
PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::Unannotated, .., None) | PatKind::Path(_) => {
PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::NONE, .., None) | PatKind::Path(_) => {
acc.push(ty);
},
_ => {},

View File

@ -152,7 +152,7 @@ pub(crate) trait BindInsteadOfMap {
match arg.kind {
hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) => {
let closure_body = cx.tcx.hir().body(body);
let closure_expr = peel_blocks(&closure_body.value);
let closure_expr = peel_blocks(closure_body.value);
if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, fn_decl_span) {
true

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

@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg;
use clippy_utils::ty::is_copy;
use rustc_errors::Applicability;
use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, adjustment::Adjust};
use rustc_span::symbol::{sym, Symbol};
@ -14,10 +14,17 @@ 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()
@ -81,7 +88,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,19 +98,14 @@ 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,
_ => false,
},
// local binding capturing a reference
Some(Node::Local(l))
if matches!(
l.pat.kind,
PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..)
) =>
{
Some(Node::Local(l)) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => {
return;
},
_ => false,

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

@ -25,14 +25,14 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
},
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
let body = cx.tcx.hir().body(body);
let closure_expr = peel_blocks(&body.value);
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

@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
if let Some(id) = path_to_local(recv);
if let Node::Pat(pat) = cx.tcx.hir().get(id);
if let PatKind::Binding(ann, _, _, _) = pat.kind;
if ann != BindingAnnotation::Mutable;
if ann != BindingAnnotation::MUT;
then {
application = Applicability::Unspecified;
diag.span_help(

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

@ -30,16 +30,16 @@ pub(super) fn check<'tcx>(
if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind;
then {
let closure_body = cx.tcx.hir().body(body);
let closure_expr = peel_blocks(&closure_body.value);
let closure_expr = peel_blocks(closure_body.value);
match closure_body.params[0].pat.kind {
hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
hir::BindingAnnotation::Unannotated, .., name, None
hir::BindingAnnotation::NONE, .., name, None
) = inner.kind {
if ident_eq(name, closure_expr) {
lint_explicit_closure(cx, e.span, recv.span, true, msrv);
}
},
hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => {
match closure_expr.kind {
hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
if ident_eq(name, inner) {
@ -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

@ -3162,11 +3162,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
@ -3184,17 +3186,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 {
@ -3303,9 +3305,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
// one of the associated types must be Self
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
let assoc_ty = match projection_predicate.term {
ty::Term::Ty(ty) => ty,
ty::Term::Const(_c) => continue,
let assoc_ty = match projection_predicate.term.unpack() {
ty::TermKind::Ty(ty) => ty,
ty::TermKind::Const(_c) => continue,
};
// walk the associated type and check for Self
if let Some(self_adt) = self_ty.ty_adt_def() {
@ -3380,7 +3382,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);
@ -3400,13 +3402,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);
}
@ -3414,26 +3416,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),
@ -3453,13 +3455,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);
}
},
@ -3479,12 +3481,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);
}
@ -3499,7 +3501,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),
@ -3519,7 +3521,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),
@ -3532,10 +3534,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"),
@ -3592,7 +3594,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);
}
@ -3615,13 +3617,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);
},
_ => {},
@ -3630,19 +3632,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);
@ -3650,7 +3652,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);
@ -3663,7 +3665,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.is_empty() {
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

@ -53,16 +53,15 @@ pub(super) fn check<'tcx>(
}),
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
let closure_body = cx.tcx.hir().body(body);
let closure_expr = peel_blocks(&closure_body.value);
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

@ -74,7 +74,7 @@ pub(super) fn check<'tcx>(
if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = map_arg.kind;
let arg_snippet = snippet(cx, fn_decl_span, "..");
let body = cx.tcx.hir().body(body);
if let Some((func, [arg_char])) = reduce_unit_expression(&body.value);
if let Some((func, [arg_char])) = reduce_unit_expression(body.value);
if let Some(id) = path_def_id(cx, func).map(|ctor_id| cx.tcx.parent(ctor_id));
if Some(id) == cx.tcx.lang_items().option_some_variant();
then {

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())`, `unwrap_or(T::default())`,
@ -149,7 +150,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: [],
@ -168,11 +169,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

@ -130,7 +130,7 @@ fn check_manual_split_once_indirect(
let ctxt = expr.span.ctxt();
let mut parents = cx.tcx.hir().parent_iter(expr.hir_id);
if let (_, Node::Local(local)) = parents.next()?
&& let PatKind::Binding(BindingAnnotation::Mutable, iter_binding_id, iter_ident, None) = local.pat.kind
&& let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind
&& let (iter_stmt_id, Node::Stmt(_)) = parents.next()?
&& let (_, Node::Block(enclosing_block)) = parents.next()?
@ -212,11 +212,10 @@ fn indirect_usage<'tcx>(
ctxt: SyntaxContext,
) -> Option<IndirectUsage<'tcx>> {
if let StmtKind::Local(Local {
pat:
Pat {
kind: PatKind::Binding(BindingAnnotation::Unannotated, _, ident, None),
..
},
pat: Pat {
kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None),
..
},
init: Some(init_expr),
hir_id: local_hir_id,
..
@ -292,7 +291,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 +326,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 +366,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

@ -15,9 +15,9 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, count_recv: &hi
if let Some(def_id) = cx.tcx.hir().opt_local_def_id(closure.hir_id);
if let Some(body_id) = cx.tcx.hir().maybe_body_owned_by(def_id);
let closure_body = cx.tcx.hir().body(body_id);
if !cx.typeck_results().expr_ty(&closure_body.value).is_unit();
if !cx.typeck_results().expr_ty(closure_body.value).is_unit();
then {
if let Some(map_mutated_vars) = mutated_variables(&closure_body.value, cx) {
if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) {
// A variable is used mutably inside of the closure. Suppress the lint.
if !map_mutated_vars.is_empty() {
return;

View File

@ -21,14 +21,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
let body = cx.tcx.hir().body(body);
let arg_id = body.params[0].pat.hir_id;
let mutates_arg =
mutated_variables(&body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id));
let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, &body.value);
let mutates_arg = mutated_variables(body.value, cx).map_or(true, |used_mutably| used_mutably.contains(&arg_id));
let (clone_or_copy_needed, _) = clone_or_copy_needed(cx, body.params[0].pat, body.value);
let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, &body.value);
let (mut found_mapping, mut found_filtering) = check_expression(cx, arg_id, body.value);
let mut return_visitor = ReturnVisitor::new(cx, arg_id);
return_visitor.visit_expr(&body.value);
return_visitor.visit_expr(body.value);
found_mapping |= return_visitor.found_mapping;
found_filtering |= return_visitor.found_filtering;
@ -36,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
let sugg = if !found_filtering {
if name == "filter_map" { "map" } else { "map(..).next()" }
} else if !found_mapping && !mutates_arg && (!clone_or_copy_needed || is_copy(cx, in_ty)) {
match cx.typeck_results().expr_ty(&body.value).kind() {
match cx.typeck_results().expr_ty(body.value).kind() {
ty::Adt(adt, subst)
if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) =>
{

View File

@ -31,7 +31,7 @@ pub(super) fn check(
// Extract the body of the closure passed to fold
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind;
let closure_body = cx.tcx.hir().body(body);
let closure_expr = peel_blocks(&closure_body.value);
let closure_expr = peel_blocks(closure_body.value);
// Check if the closure body is of the form `acc <op> some_expr(x)`
if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind;

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,9 +129,9 @@ 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);
if is_trait_method(cx, closure_body.value, sym::Ord);
then {
let (closure_body, closure_arg, reverse) = if mirrored_exprs(
left_expr,

View File

@ -28,12 +28,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);
@ -249,9 +250,9 @@ 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_args)) = get_callee_substs_and_args(cx, maybe_call);
if let Some((callee_def_id, _, recv, 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);
if let Some(i) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == maybe_arg.hir_id);
if let Some(input) = fn_sig.inputs().get(i);
let (input, n_refs) = peel_mid_ty_refs(*input);
if let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input);
@ -307,22 +308,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(_, recv, 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(recv), args));
}
}
None
@ -377,9 +378,10 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
}
}
Node::Expr(parent_expr) => {
if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, parent_expr) {
if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
{
let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
if let Some(arg_index) = call_args.iter().position(|arg| arg.hir_id == expr.hir_id)
if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
&& let Some(param_ty) = fn_sig.inputs().get(arg_index)
&& let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
{

View File

@ -52,7 +52,7 @@ fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>)
if body.params.is_empty()
&& let hir::Expr{ kind, .. } = &body.value
&& let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, [self_arg], _) = kind
&& let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
&& ident == &symbol::Ident::from_str("to_string")
&& let hir::Expr{ kind, .. } = self_arg
&& let hir::ExprKind::Lit(lit) = kind

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

@ -1,7 +1,6 @@
use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{match_trait_method, paths};
use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -75,45 +74,49 @@ 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, _) => {
if_chain! {
if let [obj, _] = args;
if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
then {
if path.ident.name == sym!(max) {
fetch_const(cx, args, MinMax::Max)
} else if path.ident.name == sym!(min) {
fetch_const(cx, args, MinMax::Min)
} else {
None
}
ExprKind::MethodCall(path, receiver, args @ [_], _) => {
if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD) {
if path.ident.name == sym!(max) {
fetch_const(cx, Some(receiver), args, MinMax::Max)
} else if path.ident.name == sym!(min) {
fetch_const(cx, Some(receiver), args, MinMax::Min)
} else {
None
}
} else {
None
}
},
_ => None,
}
}
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);
let first_arg = args.next()?;
let second_arg = 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(), first_arg).map_or_else(
|| constant_simple(cx, cx.typeck_results(), second_arg).map(|c| (m, c, first_arg)),
|c| {
if constant_simple(cx, cx.typeck_results(), &args[1]).is_none() {
if constant_simple(cx, cx.typeck_results(), second_arg).is_none() {
// otherwise ignore
Some((m, c, &args[1]))
Some((m, c, second_arg))
} else {
None
}

View File

@ -5,8 +5,8 @@ use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt,
StmtKind, TyKind,
self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind,
Stmt, StmtKind, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
return;
}
for arg in iter_input_pats(decl, body) {
if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind {
if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind {
span_lint(
cx,
TOPLEVEL_REF_ARG,
@ -162,9 +162,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
if_chain! {
if !in_external_macro(cx.tcx.sess, stmt.span);
if let StmtKind::Local(local) = stmt.kind;
if let PatKind::Binding(an, .., name, None) = local.pat.kind;
if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind;
if let Some(init) = local.init;
if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut;
then {
// use the macro callsite when the init span (but not the whole local span)
// comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];`
@ -173,7 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
} else {
Sugg::hir(cx, init, "..")
};
let (mutopt, initref) = if an == BindingAnnotation::RefMut {
let (mutopt, initref) = if mutabl == Mutability::Mut {
("mut ", sugg_init.mut_addr())
} else {
("", sugg_init.addr())

View File

@ -1,18 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_ast::ast::{BindingMode, Mutability, Pat, PatKind};
use rustc_ast::ast::{Pat, PatKind};
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;
use super::REDUNDANT_PATTERN;
pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
if let PatKind::Ident(left, ident, Some(ref right)) = pat.kind {
let left_binding = match left {
BindingMode::ByRef(Mutability::Mut) => "ref mut ",
BindingMode::ByRef(Mutability::Not) => "ref ",
BindingMode::ByValue(..) => "",
};
if let PatKind::Ident(ann, ident, Some(ref right)) = pat.kind {
if let PatKind::Wild = right.kind {
span_lint_and_sugg(
cx,
@ -23,7 +17,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
ident.name, ident.name,
),
"try",
format!("{}{}", left_binding, ident.name),
format!("{}{}", ann.prefix_str(), ident.name),
Applicability::MachineApplicable,
);
}

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

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use if_chain::if_chain;
use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -120,14 +120,14 @@ impl EarlyLintPass for NeedlessArbitrarySelfType {
match &p.ty.kind {
TyKind::Path(None, path) => {
if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), _, _) = p.pat.kind {
check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
}
},
TyKind::Rptr(lifetime, mut_ty) => {
if_chain! {
if let TyKind::Path(None, path) = &mut_ty.ty.kind;
if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind;
then {
check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
}

View File

@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
if let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind;
// Check sub_pat got a `ref` keyword (excluding `ref mut`).
if let PatKind::Binding(BindingAnnotation::Ref, .., spanned_name, _) = sub_pat.kind;
if let PatKind::Binding(BindingAnnotation::REF, .., spanned_name, _) = sub_pat.kind;
let parent_id = cx.tcx.hir().get_parent_node(pat.hir_id);
if let Some(parent_node) = cx.tcx.hir().find(parent_id);
then {

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