use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::higher::VecArgs;
use clippy_utils::source::snippet_opt;
-use clippy_utils::usage::UsedAfterExprVisitor;
-use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local_id};
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::usage::local_used_after_expr;
+use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local, path_to_local_id};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, ClosureKind, Ty, TypeFoldable};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::sym;
declare_clippy_lint! {
/// ### What it does
/// ```
/// where `foo(_)` is a plain function that takes the exact argument type of
/// `x`.
+ #[clippy::version = "pre 1.29.0"]
pub REDUNDANT_CLOSURE,
style,
"redundant closures, i.e., `|a| foo(a)` (which can be written as just `foo`)"
/// ```rust,ignore
/// Some('a').map(char::to_uppercase);
/// ```
+ #[clippy::version = "1.35.0"]
pub REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
pedantic,
"redundant closures for method calls"
// A type param function ref like `T::f` is not 'static, however
// it is if cast like `T::f as fn()`. This seems like a rustc bug.
if !substs.types().any(|t| matches!(t.kind(), ty::Param(_)));
+ let callee_ty_unadjusted = cx.typeck_results().expr_ty(callee).peel_refs();
+ if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Arc);
+ if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Rc);
then {
span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
if let Some(mut snippet) = snippet_opt(cx, callee.span) {
if_chain! {
if let ty::Closure(_, substs) = callee_ty.peel_refs().kind();
- if let ClosureKind::FnMut = substs.as_closure().kind();
+ if substs.as_closure().kind() == ClosureKind::FnMut;
if get_enclosing_loop_or_closure(cx.tcx, expr).is_some()
- || UsedAfterExprVisitor::is_found(cx, callee);
+ || path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, callee));
then {
// Mutable closure is used after current expr; we cannot consume it.
);
if_chain!(
- if let ExprKind::MethodCall(path, _, args, _) = body.value.kind;
+ if let ExprKind::MethodCall(path, args, _) = body.value.kind;
if check_inputs(cx, body.params, 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);
}
match *cx.typeck_results().expr_adjustments(arg) {
[] => true,
- [Adjustment {
- kind: Adjust::Deref(None),
- ..
- }, Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
- ..
- }] => {
+ [
+ Adjustment {
+ kind: Adjust::Deref(None),
+ ..
+ },
+ Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
+ ..
+ },
+ ] => {
// re-borrow with the same mutability is allowed
let ty = cx.typeck_results().expr_ty(arg);
matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())