Auto merge of #13540 - GnomedDev:create-dir-single-arg, r=y21

Check MethodCall/Call arg count earlier or at all

This gets rid of a bunch of possible panic spots, as well as bailing out earlier for optimisation reasons.

I started doing this because I saw that a significant amount of time was being spent in the `create_dir` restriction lint when running clippy with `perf`, but this also helps with robustness.

changelog: none
This commit is contained in:
bors 2024-10-13 13:34:48 +00:00
commit 236751d093
59 changed files with 127 additions and 149 deletions

View File

@ -47,7 +47,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
// And the call is that of a `Box` method
&& path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box())
// And the single argument to the call is another function call
// This is the `T::default()` of `Box::new(T::default())`
// This is the `T::default()` (or default equivalent) of `Box::new(T::default())`
&& let ExprKind::Call(arg_path, _) = arg.kind
// And we are not in a foreign crate's macro
&& !in_external_macro(cx.sess(), expr.span)

View File

@ -19,7 +19,7 @@ pub(super) fn check(
if msrv.meets(msrvs::UNSIGNED_ABS)
&& let ty::Int(from) = cast_from.kind()
&& let ty::Uint(to) = cast_to.kind()
&& let ExprKind::MethodCall(method_path, receiver, ..) = 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() {

View File

@ -19,7 +19,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

View File

@ -34,7 +34,7 @@
impl LateLintPass<'_> for CreateDir {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::Call(func, [arg, ..]) = expr.kind
if let ExprKind::Call(func, [arg]) = expr.kind
&& let ExprKind::Path(ref path) = func.kind
&& let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
&& cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id)

View File

@ -83,7 +83,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !expr.span.from_expansion()
// Avoid cases already linted by `field_reassign_with_default`
&& !self.reassigned_linted.contains(&expr.span)
&& let ExprKind::Call(path, ..) = expr.kind
&& let ExprKind::Call(path, []) = expr.kind
&& !in_automatically_derived(cx.tcx, expr.hir_id)
&& let ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
@ -253,7 +253,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
/// Checks if the given expression is the `default` method belonging to the `Default` trait.
fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool {
if let ExprKind::Call(fn_expr, _) = &expr.kind
if let ExprKind::Call(fn_expr, []) = &expr.kind
&& let ExprKind::Path(qpath) = &fn_expr.kind
&& let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id)
{

View File

@ -43,7 +43,7 @@
impl<'tcx> LateLintPass<'tcx> for Exit {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if let ExprKind::Call(path_expr, _args) = e.kind
if let ExprKind::Call(path_expr, [_]) = e.kind
&& let ExprKind::Path(ref path) = path_expr.kind
&& let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id()
&& cx.tcx.is_diagnostic_item(sym::process_exit, def_id)

View File

@ -57,7 +57,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
&& unwrap_fun.ident.name == sym::unwrap
// match call to write_fmt
&& let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind)
&& let ExprKind::Call(write_recv_path, _) = write_recv.kind
&& let ExprKind::Call(write_recv_path, []) = write_recv.kind
&& write_fun.ident.name == sym!(write_fmt)
&& let Some(def_id) = path_def_id(cx, write_recv_path)
{

View File

@ -436,12 +436,12 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
lhs,
rhs,
) = expr.kind
&& let ExprKind::MethodCall(path, self_arg, [], _) = &lhs.kind
&& path.ident.name.as_str() == "exp"
&& cx.typeck_results().expr_ty(lhs).is_floating_point()
&& let Some(value) = ConstEvalCtxt::new(cx).eval(rhs)
&& (F32(1.0) == value || F64(1.0) == value)
&& let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind
&& cx.typeck_results().expr_ty(self_arg).is_floating_point()
&& path.ident.name.as_str() == "exp"
{
span_lint_and_sugg(
cx,

View File

@ -151,7 +151,7 @@ struct FormatImplExpr<'a, 'tcx> {
impl FormatImplExpr<'_, '_> {
fn check_to_string_in_display(&self) {
if self.format_trait_impl.name == sym::Display
&& let ExprKind::MethodCall(path, self_arg, ..) = self.expr.kind
&& let ExprKind::MethodCall(path, self_arg, [], _) = self.expr.kind
// Get the hir_id of the object we are calling the method on
// Is the method to_string() ?
&& path.ident.name == sym::to_string

View File

@ -82,7 +82,7 @@ fn mutex_lock_call<'tcx>(
expr: &'tcx Expr<'_>,
op_mutex: Option<&'tcx Expr<'_>>,
) -> ControlFlow<&'tcx Expr<'tcx>> {
if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
if let ExprKind::MethodCall(path, self_arg, [], _) = &expr.kind
&& path.ident.as_str() == "lock"
&& let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
&& is_type_diagnostic_item(cx, ty, sym::Mutex)

View File

@ -57,7 +57,7 @@ pub fn new(conf: &'static Conf) -> Self {
impl<'tcx> LateLintPass<'tcx> for LargeFuture {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if let ExprKind::Match(scrutinee, _, MatchSource::AwaitDesugar) = expr.kind
&& let ExprKind::Call(func, [arg, ..]) = scrutinee.kind
&& let ExprKind::Call(func, [arg]) = scrutinee.kind
&& let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind
&& !expr.span.from_expansion()
&& let ty = cx.typeck_results().expr_ty(arg)

View File

@ -517,7 +517,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
return;
}
if let (&ExprKind::MethodCall(method_path, receiver, args, _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) {
if let (&ExprKind::MethodCall(method_path, receiver, [], _), ExprKind::Lit(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" {
@ -525,29 +525,17 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
}
}
check_len(
cx,
span,
method_path.ident.name,
receiver,
args,
&lit.node,
op,
compare_to,
);
check_len(cx, span, method_path.ident.name, receiver, &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,
compare_to: u32,
@ -558,7 +546,7 @@ fn check_len(
return;
}
if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) {
if method_name == sym::len && has_is_empty(cx, receiver) {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,

View File

@ -47,8 +47,9 @@ fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>,
);
}
fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: Symbol) -> bool {
if let ExprKind::MethodCall(..) = expr.kind
fn match_method_call<const ARGS_COUNT: usize>(cx: &LateContext<'_>, expr: &Expr<'_>, method: Symbol) -> bool {
if let ExprKind::MethodCall(_, _, args, _) = expr.kind
&& args.len() == ARGS_COUNT
&& let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
{
cx.tcx.is_diagnostic_item(method, id)
@ -58,9 +59,9 @@ fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: Symbol) -> b
}
fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, is_empty_recv: &Expr<'_>) -> bool {
if (match_method_call(cx, expr, sym::option_unwrap) || match_method_call(cx, expr, sym::option_expect))
if (match_method_call::<0>(cx, expr, sym::option_unwrap) || match_method_call::<1>(cx, expr, sym::option_expect))
&& let ExprKind::MethodCall(_, unwrap_recv, ..) = expr.kind
&& match_method_call(cx, unwrap_recv, sym::vec_pop)
&& match_method_call::<0>(cx, unwrap_recv, sym::vec_pop)
&& let ExprKind::MethodCall(_, pop_recv, ..) = unwrap_recv.kind
{
// make sure they're the same `Vec`
@ -96,7 +97,7 @@ fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &E
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, full_cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>, loop_span: Span) {
if let ExprKind::Unary(UnOp::Not, cond) = full_cond.kind
&& let ExprKind::MethodCall(_, is_empty_recv, _, _) = cond.kind
&& match_method_call(cx, cond, sym::vec_is_empty)
&& match_method_call::<0>(cx, cond, sym::vec_is_empty)
&& let ExprKind::Block(body, _) = body.kind
&& let Some(stmt) = body.stmts.first()
{

View File

@ -172,10 +172,8 @@ fn get_vec_push<'tcx>(
stmt: &'tcx Stmt<'_>,
) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, SyntaxContext)> {
if let StmtKind::Semi(semi_stmt) = &stmt.kind
// Extract method being called
&& let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind
// Figure out the parameters for the method call
&& let Some(pushed_item) = args.first()
// Extract method being called and figure out the parameters for the method call
&& let ExprKind::MethodCall(path, self_expr, [pushed_item], _) = &semi_stmt.kind
// Check that the method being called is push() on a Vec
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec)
&& path.ident.name.as_str() == "push"

View File

@ -42,7 +42,7 @@ fn check_expr_post(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
return;
}
if let ExprKind::Call(func, _) = &expr.kind
if let ExprKind::Call(func, []) = &expr.kind
&& let ExprKind::Path(QPath::Resolved(_, path)) = &func.kind
&& let Some(def_id) = path.res.opt_def_id()
&& is_entrypoint_fn(cx, def_id)

View File

@ -95,7 +95,7 @@ fn get_one_size_of_ty<'tcx>(
}
fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>)> {
if let ExprKind::Call(count_func, _func_args) = expr.kind
if let ExprKind::Call(count_func, []) = expr.kind
&& let ExprKind::Path(ref count_func_qpath) = count_func.kind
&& let QPath::Resolved(_, count_func_path) = count_func_qpath
&& let Some(segment_zero) = count_func_path.segments.first()

View File

@ -41,7 +41,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
&& bin_op.node == BinOpKind::Eq
{
// a.count_ones() == 1
if let ExprKind::MethodCall(method_name, reciever, _, _) = left.kind
if let ExprKind::MethodCall(method_name, reciever, [], _) = left.kind
&& method_name.ident.as_str() == "count_ones"
&& let &Uint(_) = cx.typeck_results().expr_ty(reciever).kind()
&& check_lit(right, 1)
@ -50,7 +50,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
}
// 1 == a.count_ones()
if let ExprKind::MethodCall(method_name, reciever, _, _) = right.kind
if let ExprKind::MethodCall(method_name, reciever, [], _) = right.kind
&& method_name.ident.as_str() == "count_ones"
&& let &Uint(_) = cx.typeck_results().expr_ty(reciever).kind()
&& check_lit(left, 1)

View File

@ -83,12 +83,12 @@ fn simplify_half<'tcx>(
) -> Option<&'tcx Expr<'tcx>> {
if !expr1.span.from_expansion()
// expr1 is `[T1].len()`?
&& let ExprKind::MethodCall(method_path, receiver, _, _) = expr1.kind
&& let ExprKind::MethodCall(method_path, receiver, [], _) = expr1.kind
&& method_path.ident.name == sym::len
&& let receiver_ty = cx.typeck_results().expr_ty(receiver)
&& let ty::Slice(ty1) = receiver_ty.peel_refs().kind()
// expr2 is `size_of::<T2>()`?
&& let ExprKind::Call(func, _) = expr2.kind
&& let ExprKind::Call(func, []) = expr2.kind
&& let ExprKind::Path(ref func_qpath) = func.kind
&& let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id()
&& cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id)

View File

@ -52,8 +52,8 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
}
match expr.kind {
ExprKind::Call(func, args) => {
parse_call(cx, expr.span, func, args);
ExprKind::Call(func, [arg]) => {
parse_call(cx, expr.span, func, arg);
},
ExprKind::MethodCall(path_segment, receiver, ..) => {
parse_method_call(cx, expr.span, path_segment, receiver);
@ -93,20 +93,15 @@ fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegmen
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 {
} else if let ExprKind::Call(func, [arg]) = method_arg_kind {
// If our first argument is a function call itself, it could be an `unwrap`-like function.
// E.g. String::try_from("hello").unwrap(), TryFrom::try_from("").expect("hello"), etc.
parse_call(cx, span, func, args);
parse_call(cx, span, func, arg);
}
}
/// Tries to parse an expression as a function call, emitting the warning if necessary.
fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_>]) {
if args.len() != 1 {
return;
}
let arg_kind = &args[0].kind;
fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, arg: &Expr<'_>) {
if let ExprKind::Path(qpath) = &func.kind {
// String::from(...) or String::try_from(...)
if let QPath::TypeRelative(ty, path_seg) = qpath
@ -115,13 +110,13 @@ fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_
&& let QPath::Resolved(_, path) = qpath
&& let [path_seg] = path.segments
&& path_seg.ident.name == sym::String
&& is_expr_kind_empty_str(arg_kind)
&& is_expr_kind_empty_str(&arg.kind)
{
warn_then_suggest(cx, span);
} else if let QPath::Resolved(_, path) = qpath {
// From::from(...) or TryFrom::try_from(...)
if let [path_seg1, path_seg2] = path.segments
&& is_expr_kind_empty_str(arg_kind)
&& is_expr_kind_empty_str(&arg.kind)
&& ((path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from)
|| (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from))
{

View File

@ -210,7 +210,7 @@ fn find_method_sugg_for_if_let<'tcx>(
// check that `while_let_on_iterator` lint does not trigger
if keyword == "while"
&& let ExprKind::MethodCall(method_path, ..) = let_expr.kind
&& let ExprKind::MethodCall(method_path, _, [], _) = let_expr.kind
&& method_path.ident.name == sym::next
&& is_trait_method(cx, let_expr, sym::Iterator)
{

View File

@ -21,10 +21,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
// #[allow(unreachable_code)]
// val,
// };
if let ExprKind::Call(match_fun, [try_arg, ..]) = scrutinee.kind
if let ExprKind::Call(match_fun, [try_arg]) = scrutinee.kind
&& let ExprKind::Path(ref match_fun_path) = match_fun.kind
&& matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..))
&& let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind
&& let ExprKind::Call(err_fun, [err_arg]) = try_arg.kind
&& is_res_lang_ctor(cx, path_res(cx, err_fun), ResultErr)
&& let Some(return_ty) = find_return_type(cx, &expr.kind)
{

View File

@ -58,7 +58,7 @@ pub(super) fn check(
return;
},
// ? is a Call, makes sure not to rec *x?, but rather (*x)?
ExprKind::Call(hir_callee, _) => matches!(
ExprKind::Call(hir_callee, [_]) => matches!(
hir_callee.kind,
ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, ..))
),

View File

@ -106,9 +106,9 @@ fn pat_is_recv(ident: Ident, param: &hir::Pat<'_>) -> bool {
fn parent_is_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
if let Some(expr) = get_parent_expr(cx, expr)
&& is_trait_method(cx, expr, sym::Iterator)
&& let ExprKind::MethodCall(path, _, _, _) = expr.kind
&& let ExprKind::MethodCall(path, _, [_], _) = expr.kind
&& path.ident.name == sym::map
&& is_trait_method(cx, expr, sym::Iterator)
{
return true;
}

View File

@ -87,7 +87,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args
/// Checks `CStr::from_ptr(b"foo\0".as_ptr().cast())`
fn check_from_ptr(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>) {
if let ExprKind::MethodCall(method, lit, ..) = peel_ptr_cast(arg).kind
if let ExprKind::MethodCall(method, lit, [], _) = peel_ptr_cast(arg).kind
&& method.ident.name == sym::as_ptr
&& !lit.span.from_expansion()
&& let ExprKind::Lit(lit) = lit.kind

View File

@ -68,8 +68,7 @@ enum MinMax {
fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
// `T::max_value()` `T::min_value()` inherent methods
if let hir::ExprKind::Call(func, args) = &expr.kind
&& args.is_empty()
if let hir::ExprKind::Call(func, []) = &expr.kind
&& let hir::ExprKind::Path(hir::QPath::TypeRelative(_, segment)) = &func.kind
{
match segment.ident.as_str() {

View File

@ -86,9 +86,8 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
}
}
},
hir::ExprKind::Call(call, args) => {
hir::ExprKind::Call(call, [arg]) => {
if let hir::ExprKind::Path(qpath) = call.kind
&& let [arg] = args
&& ident_eq(name, arg)
{
handle_path(cx, call, &qpath, e, recv);

View File

@ -321,7 +321,10 @@ fn visit_block(&mut self, block: &'tcx Block<'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 method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
if args.is_empty()
&& 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);
return;

View File

@ -259,7 +259,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.name == sym::to_string
&& let hir::Expr { kind, .. } = self_arg
&& let hir::ExprKind::Lit(lit) = kind

View File

@ -43,7 +43,8 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
for_each_local_use_after_expr(cx, local_id, call.hir_id, |expr| {
if let Some(parent) = get_parent_expr(cx, expr) {
let data = if let ExprKind::MethodCall(segment, recv, args, span) = parent.kind {
if segment.ident.name == sym!(parse)
if args.is_empty()
&& segment.ident.name == sym!(parse)
&& let parse_result_ty = cx.typeck_results().expr_ty(parent)
&& is_type_diagnostic_item(cx, parse_result_ty, sym::Result)
&& let ty::Adt(_, substs) = parse_result_ty.kind()

View File

@ -10,7 +10,7 @@
use rustc_span::sym;
fn is_unwrap_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if let ExprKind::MethodCall(path, receiver, ..) = expr.kind
if let ExprKind::MethodCall(path, receiver, [], _) = expr.kind
&& path.ident.name == sym::unwrap
{
is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::Result)

View File

@ -34,14 +34,13 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
}
fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
if let ExprKind::Call(f, args) = expr.kind
if let ExprKind::Call(f, [arg]) = expr.kind
&& let ExprKind::Path(ref path) = f.kind
&& let Some(ctor_call_id) = cx.qpath_res(path, f.hir_id).opt_def_id()
&& is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Current), ctor_call_id)
{
// check if argument of `SeekFrom::Current` is `0`
if args.len() == 1
&& let ExprKind::Lit(lit) = args[0].kind
if let ExprKind::Lit(lit) = arg.kind
&& let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node
{
return true;

View File

@ -26,12 +26,11 @@ pub(super) fn check<'tcx>(
if let Some(seek_trait_id) = cx.tcx.get_diagnostic_item(sym::IoSeek)
&& implements_trait(cx, ty, seek_trait_id, &[])
&& let ExprKind::Call(func, args1) = arg.kind
&& let ExprKind::Call(func, [arg]) = arg.kind
&& let ExprKind::Path(ref path) = func.kind
&& let Some(ctor_call_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
&& is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Start), ctor_call_id)
&& args1.len() == 1
&& let ExprKind::Lit(lit) = args1[0].kind
&& let ExprKind::Lit(lit) = arg.kind
&& let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node
{
let method_call_span = expr.span.with_lo(name_span.lo());

View File

@ -27,7 +27,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::
}
if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[1].kind
&& let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind
&& let ExprKind::MethodCall(path_segment, method_arg, [], _) = &arg.kind
&& path_segment.ident.name == rustc_span::sym::to_string
&& (is_ref_char(cx, method_arg) || is_char(cx, method_arg))
{

View File

@ -26,7 +26,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::
}
if let ExprKind::AddrOf(BorrowKind::Ref, _, arg) = &args[0].kind
&& let ExprKind::MethodCall(path_segment, method_arg, _, _) = &arg.kind
&& let ExprKind::MethodCall(path_segment, method_arg, [], _) = &arg.kind
&& path_segment.ident.name == rustc_span::sym::to_string
&& (is_ref_char(cx, method_arg) || is_char(cx, method_arg))
{

View File

@ -333,7 +333,7 @@ fn parse_iter_usage<'tcx>(
kind: ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)),
..
},
_,
[_],
) => {
let parent_span = e.span.parent_callsite().unwrap();
if parent_span.ctxt() == ctxt {

View File

@ -9,8 +9,7 @@
/// lint for `MaybeUninit::uninit().assume_init()` (we already have the latter)
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
if let hir::ExprKind::Call(callee, args) = recv.kind
&& args.is_empty()
if let hir::ExprKind::Call(callee, []) = recv.kind
&& is_path_diagnostic_item(cx, callee, sym::maybe_uninit_uninit)
&& !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr))
{

View File

@ -86,12 +86,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
// changing the type, then we can move forward.
&& rcv_ty.peel_refs() == res_ty.peel_refs()
&& let Some(parent) = get_parent_expr(cx, expr)
&& let hir::ExprKind::MethodCall(segment, _, args, _) = parent.kind
// Check that it only has one argument.
&& let hir::ExprKind::MethodCall(segment, _, [arg], _) = parent.kind
&& segment.ident.span != expr.span
// We check that the called method name is `map`.
&& segment.ident.name == sym::map
// And that it only has one argument.
&& let [arg] = args
&& is_calling_clone(cx, arg)
// And that we are not recommending recv.clone() over Arc::clone() or similar
&& !should_call_clone_as_function(cx, rcv_ty)

View File

@ -139,7 +139,7 @@ fn assert_len_expr<'hir>(
&& let ExprKind::Binary(bin_op, left, right) = &condition.kind
&& let Some((cmp, asserted_len, slice_len)) = len_comparison(*bin_op, left, right)
&& let ExprKind::MethodCall(method, recv, ..) = &slice_len.kind
&& let ExprKind::MethodCall(method, recv, [], _) = &slice_len.kind
&& cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice()
&& method.ident.name == sym::len

View File

@ -47,7 +47,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if let ExprKind::Path(ref path) = fn_expr.kind {
check_arguments(
cx,
arguments.iter().collect(),
&mut arguments.iter(),
cx.typeck_results().expr_ty(fn_expr),
&rustc_hir_pretty::qpath_to_string(&cx.tcx, path),
"function",
@ -60,7 +60,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
let method_type = cx.tcx.type_of(def_id).instantiate(cx.tcx, args);
check_arguments(
cx,
iter::once(receiver).chain(arguments.iter()).collect(),
&mut iter::once(receiver).chain(arguments.iter()),
method_type,
path.ident.as_str(),
"method",
@ -73,7 +73,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
fn check_arguments<'tcx>(
cx: &LateContext<'tcx>,
arguments: Vec<&Expr<'_>>,
arguments: &mut dyn Iterator<Item = &'tcx Expr<'tcx>>,
type_definition: Ty<'tcx>,
name: &str,
fn_kind: &str,

View File

@ -281,7 +281,7 @@ fn self_cmp_call<'tcx>(
needs_fully_qualified: &mut bool,
) -> bool {
match cmp_expr.kind {
ExprKind::Call(path, [_self, _other]) => path_res(cx, path)
ExprKind::Call(path, [_, _]) => path_res(cx, path)
.opt_def_id()
.is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)),
ExprKind::MethodCall(_, _, [_other], ..) => {

View File

@ -71,7 +71,7 @@ fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicabilit
if let ExprKind::Call(func, [arg]) = expr.kind
&& let ExprKind::Path(qpath) = &func.kind
&& let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id()
&& let ExprKind::MethodCall(rcv_path, receiver, _, _) = &arg.kind
&& let ExprKind::MethodCall(rcv_path, receiver, [], _) = &arg.kind
&& rcv_path.ident.name.as_str() == "get"
{
let fn_name = cx.tcx.item_name(def_id);

View File

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

View File

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

View File

@ -206,12 +206,11 @@ fn expr_return_none_or_err(
sym::Result => path_to_local(expr).is_some() && path_to_local(expr) == path_to_local(cond_expr),
_ => false,
},
ExprKind::Call(call_expr, args_expr) => {
ExprKind::Call(call_expr, [arg]) => {
if smbl == sym::Result
&& let ExprKind::Path(QPath::Resolved(_, path)) = &call_expr.kind
&& let Some(segment) = path.segments.first()
&& let Some(err_sym) = err_sym
&& let Some(arg) = args_expr.first()
&& let ExprKind::Path(QPath::Resolved(_, arg_path)) = &arg.kind
&& let Some(PathSegment { ident, .. }) = arg_path.segments.first()
{
@ -241,7 +240,7 @@ fn expr_return_none_or_err(
fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr)
&& !is_else_clause(cx.tcx, expr)
&& let ExprKind::MethodCall(segment, caller, ..) = &cond.kind
&& let ExprKind::MethodCall(segment, caller, [], _) = &cond.kind
&& let caller_ty = cx.typeck_results().expr_ty(caller)
&& let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then)
&& (is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block))
@ -332,7 +331,7 @@ fn inside_try_block(&self) -> bool {
fn is_try_block(cx: &LateContext<'_>, bl: &Block<'_>) -> bool {
if let Some(expr) = bl.expr
&& let ExprKind::Call(callee, _) = expr.kind
&& let ExprKind::Call(callee, [_]) = expr.kind
{
is_path_lang_item(cx, callee, LangItem::TryTraitFromOutput)
} else {

View File

@ -357,7 +357,7 @@ fn check_final_expr<'tcx>(
let replacement = if let Some(inner_expr) = inner {
// if desugar of `do yeet`, don't lint
if let ExprKind::Call(path_expr, _) = inner_expr.kind
if let ExprKind::Call(path_expr, [_]) = inner_expr.kind
&& let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, ..)) = path_expr.kind
{
return;

View File

@ -421,11 +421,10 @@ fn dummy_stmt_expr<'any>(expr: &'any hir::Expr<'any>) -> hir::Stmt<'any> {
}
fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_>) -> bool {
if let hir::ExprKind::Call(fun, args) = expr.kind
if let hir::ExprKind::Call(fun, [first_arg]) = expr.kind
&& let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind
&& let Res::Def(DefKind::Fn, did) = fun_path.res
&& lcx.tcx.is_diagnostic_item(sym::mem_drop, did)
&& let [first_arg, ..] = args
{
let has_ident = |local_expr: &hir::Expr<'_>| {
if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind

View File

@ -34,7 +34,7 @@
fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option<Ty<'tcx>> {
match expr.kind {
ExprKind::Call(count_func, _func_args) => {
ExprKind::Call(count_func, _) => {
if !inverted
&& let ExprKind::Path(ref count_func_qpath) = count_func.kind
&& let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id()

View File

@ -152,7 +152,7 @@ fn as_vec_initializer<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Opt
&& is_path_diagnostic_item(cx, func, sym::vec_with_capacity)
{
Some(InitializedSize::Initialized(len_expr))
} else if matches!(expr.kind, ExprKind::Call(func, _) if is_path_diagnostic_item(cx, func, sym::vec_new)) {
} else if matches!(expr.kind, ExprKind::Call(func, []) if is_path_diagnostic_item(cx, func, sym::vec_new)) {
Some(InitializedSize::Uninitialized)
} else {
None
@ -268,7 +268,7 @@ fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'tcx>) {
/// Returns `true` if give expression is `repeat(0).take(...)`
fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool {
if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind
if let ExprKind::MethodCall(take_path, recv, [len_arg], _) = expr.kind
&& take_path.ident.name == sym!(take)
// Check that take is applied to `repeat(0)`
&& self.is_repeat_zero(recv)

View File

@ -253,18 +253,17 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
use rustc_ast::LitKind;
if let ExprKind::Call(fun, args) = e.kind
if let ExprKind::Call(fun, [bytes_arg]) = e.kind
// Find std::str::converts::from_utf8
&& is_path_diagnostic_item(cx, fun, sym::str_from_utf8)
// Find string::as_bytes
&& let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args[0].kind
&& let ExprKind::AddrOf(BorrowKind::Ref, _, args) = bytes_arg.kind
&& let ExprKind::Index(left, right, _) = args.kind
&& let (method_names, expressions, _) = method_calls(left, 1)
&& method_names.len() == 1
&& method_names == [sym!(as_bytes)]
&& expressions.len() == 1
&& expressions[0].1.is_empty()
&& method_names[0] == sym!(as_bytes)
// Check for slicer
&& let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), _, _) = right.kind
@ -393,7 +392,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
return;
}
if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
if let ExprKind::MethodCall(path, self_arg, [], _) = &expr.kind
&& path.ident.name == sym::to_string
&& let ty = cx.typeck_results().expr_ty(self_arg)
&& let ty::Ref(_, ty, ..) = ty.kind()
@ -449,7 +448,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
return;
}
if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
if let ExprKind::MethodCall(path, self_arg, [], _) = &expr.kind
&& path.ident.name == sym::to_string
&& let ty = cx.typeck_results().expr_ty(self_arg)
&& is_type_lang_item(cx, ty, LangItem::String)

View File

@ -51,9 +51,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
None
}
},
hir::ExprKind::Call(to_digits_call, to_digit_args) => {
if let [char_arg, radix_arg] = *to_digit_args
&& let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind
hir::ExprKind::Call(to_digits_call, [char_arg, radix_arg]) => {
if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind
&& let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id)
&& let Some(to_digits_def_id) = to_digits_call_res.opt_def_id()
&& match_def_path(cx, to_digits_def_id, &[

View File

@ -25,14 +25,15 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
return;
}
let args: Vec<_> = match expr.kind {
ExprKind::Call(_, args) => args.iter().collect(),
ExprKind::MethodCall(_, receiver, args, _) => std::iter::once(receiver).chain(args.iter()).collect(),
let (reciever, args) = match expr.kind {
ExprKind::Call(_, args) => (None, args),
ExprKind::MethodCall(_, receiver, args, _) => (Some(receiver), args),
_ => return,
};
let args_to_recover = args
let args_to_recover = reciever
.into_iter()
.chain(args)
.filter(|arg| {
if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) {
!matches!(

View File

@ -38,13 +38,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
if expr.span.from_expansion() {
return;
}
if let hir::ExprKind::MethodCall(path, recv, args, ..) = expr.kind
if let hir::ExprKind::MethodCall(path, recv, [map_arg], ..) = expr.kind
&& let Some(sym::Option | sym::Result) = get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(recv))
{
let (constructor_path, constructor_item) = if let hir::ExprKind::Call(constructor, constructor_args) =
recv.kind
let (constructor_path, constructor_item) = if let hir::ExprKind::Call(constructor, [arg, ..]) = recv.kind
&& let hir::ExprKind::Path(constructor_path) = constructor.kind
&& let Some(arg) = constructor_args.first()
{
if constructor.span.from_expansion() || arg.span.from_expansion() {
return;
@ -70,9 +68,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tc
_ => return,
}
if let Some(map_arg) = args.first()
&& let hir::ExprKind::Path(fun) = map_arg.kind
{
if let hir::ExprKind::Path(fun) = map_arg.kind {
if map_arg.span.from_expansion() {
return;
}

View File

@ -52,8 +52,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
Applicability::MachineApplicable,
);
} else if cx.tcx.is_diagnostic_item(sym::from_fn, fun_def_id)
&& let [.., last_arg] = args
&& let ExprKind::Lit(spanned) = &last_arg.kind
&& let [arg] = args
&& let ExprKind::Lit(spanned) = &arg.kind
&& let LitKind::Str(symbol, _) = spanned.node
&& symbol.is_empty()
&& let inner_expr_type = cx.typeck_results().expr_ty(inner_expr)

View File

@ -222,7 +222,7 @@ fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
}
fn unpack_try<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
while let ExprKind::Call(func, [ref arg_0, ..]) = expr.kind
while let ExprKind::Call(func, [ref arg_0]) = expr.kind
&& matches!(
func.kind,
ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..))
@ -244,7 +244,7 @@ fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
/// waited on. Otherwise return None.
fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
if let ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind {
if let ExprKind::Call(func, [ref arg_0, ..]) = expr.kind {
if let ExprKind::Call(func, [ref arg_0]) = expr.kind {
if matches!(
func.kind,
ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..))

View File

@ -153,13 +153,12 @@ fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str)
}
} else if let ExprKind::Unary(UnOp::Not, expr) = &expr.kind {
return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false);
} else if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind
} else if let ExprKind::MethodCall(method_name, receiver, [], _) = &expr.kind
&& let Some(local_id) = path_to_local(receiver)
&& let ty = cx.typeck_results().expr_ty(receiver)
&& let name = method_name.ident.as_str()
&& (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name))
{
assert!(args.is_empty());
let unwrappable = match name {
"is_some" | "is_ok" => true,
"is_err" | "is_none" => false,
@ -208,7 +207,7 @@ struct MutationVisitor<'tcx> {
/// expression: that will be where the actual method call is.
fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool {
if let Node::Expr(mutating_expr) = tcx.parent_hir_node(expr_id)
&& let ExprKind::MethodCall(path, ..) = mutating_expr.kind
&& let ExprKind::MethodCall(path, _, [], _) = mutating_expr.kind
{
path.ident.name.as_str() == "as_mut"
} else {
@ -275,7 +274,7 @@ enum AsRefKind {
/// Checks if the expression is a method call to `as_{ref,mut}` and returns the receiver of it.
/// If it isn't, the expression itself is returned.
fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Option<AsRefKind>) {
if let ExprKind::MethodCall(path, recv, ..) = expr.kind {
if let ExprKind::MethodCall(path, recv, [], _) = expr.kind {
if path.ident.name == sym::as_ref {
(recv, Some(AsRefKind::AsRef))
} else if path.ident.name.as_str() == "as_mut" {
@ -303,7 +302,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
self.visit_branch(expr, cond, else_inner, true);
}
} else {
// find `unwrap[_err]()` calls:
// find `unwrap[_err]()` or `expect("...")` calls:
if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind
&& let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg)
&& let Some(id) = path_to_local(self_arg)

View File

@ -129,7 +129,7 @@ fn into_iter_bound<'tcx>(
/// Extracts the receiver of a `.into_iter()` method call.
fn into_iter_call<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>) -> Option<&'hir Expr<'hir>> {
if let ExprKind::MethodCall(name, recv, _, _) = expr.kind
if let ExprKind::MethodCall(name, recv, [], _) = expr.kind
&& is_trait_method(cx, expr, sym::IntoIterator)
&& name.ident.name == sym::into_iter
{
@ -173,7 +173,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
}
},
ExprKind::MethodCall(name, recv, ..) => {
ExprKind::MethodCall(name, recv, [], _) => {
if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" {
let a = cx.typeck_results().expr_ty(e);
let b = cx.typeck_results().expr_ty(recv);

View File

@ -5,6 +5,7 @@
use rustc_hir::{Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::Span;
use std::borrow::{Borrow, Cow};
@ -76,19 +77,19 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
return;
}
if let ExprKind::Call(func, and_then_args) = expr.kind
if let ExprKind::Call(func, [call_cx, call_lint, call_sp, call_msg, call_f]) = expr.kind
&& is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"])
&& and_then_args.len() == 5
&& let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind
&& let ExprKind::Closure(&Closure { body, .. }) = &call_f.kind
&& let body = cx.tcx.hir().body(body)
&& let only_expr = peel_blocks_with_stmt(body.value)
&& let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind
&& let ExprKind::Path(..) = recv.kind
{
let and_then_snippets = get_and_then_snippets(cx, and_then_args);
let and_then_snippets =
get_and_then_snippets(cx, call_cx.span, call_lint.span, call_sp.span, call_msg.span);
let mut sle = SpanlessEq::new(cx).deny_side_effects();
match ps.ident.as_str() {
"span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
"span_suggestion" if sle.eq_expr(call_sp, &span_call_args[0]) => {
suggest_suggestion(
cx,
expr,
@ -96,11 +97,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
&span_suggestion_snippets(cx, span_call_args),
);
},
"span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
"span_help" if sle.eq_expr(call_sp, &span_call_args[0]) => {
let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
},
"span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
"span_note" if sle.eq_expr(call_sp, &span_call_args[0]) => {
let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
},
@ -125,11 +126,17 @@ struct AndThenSnippets<'a> {
msg: Cow<'a, str>,
}
fn get_and_then_snippets<'a, 'hir>(cx: &LateContext<'_>, and_then_snippets: &'hir [Expr<'hir>]) -> AndThenSnippets<'a> {
let cx_snippet = snippet(cx, and_then_snippets[0].span, "cx");
let lint_snippet = snippet(cx, and_then_snippets[1].span, "..");
let span_snippet = snippet(cx, and_then_snippets[2].span, "span");
let msg_snippet = snippet(cx, and_then_snippets[3].span, r#""...""#);
fn get_and_then_snippets(
cx: &LateContext<'_>,
cx_span: Span,
lint_span: Span,
span_span: Span,
msg_span: Span,
) -> AndThenSnippets<'static> {
let cx_snippet = snippet(cx, cx_span, "cx");
let lint_snippet = snippet(cx, lint_span, "..");
let span_snippet = snippet(cx, span_span, "span");
let msg_snippet = snippet(cx, msg_span, r#""...""#);
AndThenSnippets {
cx: cx_snippet,

View File

@ -243,7 +243,7 @@ fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
pub fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
const ALLOWED_METHOD_NAMES: &[&str] = &["len", "as_ptr", "is_empty"];
if let ExprKind::MethodCall(path, ..) = e.kind {
if let ExprKind::MethodCall(path, _, [], _) = e.kind {
ALLOWED_METHOD_NAMES.contains(&path.ident.name.as_str())
} else {
is_trait_method(cx, e, sym::IntoIterator)

View File

@ -484,10 +484,9 @@ fn expr(&self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
}),
ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
ExprKind::Binary(op, left, right) => self.binop(op, left, right),
ExprKind::Call(callee, args) => {
ExprKind::Call(callee, []) => {
// We only handle a few const functions for now.
if args.is_empty()
&& let ExprKind::Path(qpath) = &callee.kind
if let ExprKind::Path(qpath) = &callee.kind
&& let Some(did) = self.typeck.qpath_res(qpath, callee.hir_id).opt_def_id()
{
match self.tcx.get_diagnostic_name(did) {