use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::higher;
use clippy_utils::higher::VecArgs;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{implements_trait, type_is_unsafe_function};
+use clippy_utils::usage::UsedAfterExprVisitor;
+use clippy_utils::{get_enclosing_loop_or_closure, higher};
use clippy_utils::{is_adjusted, iter_input_pats};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{def_id, Expr, ExprKind, Param, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, ClosureKind, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
for arg in args {
// skip `foo(macro!())`
if arg.span.ctxt() == expr.span.ctxt() {
- check_closure(cx, arg)
+ check_closure(cx, arg);
}
}
},
}
}
-fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) {
+fn check_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Closure(_, decl, eid, _, _) = expr.kind {
let body = cx.tcx.hir().body(eid);
let ex = &body.value;
if ex.span.ctxt() != expr.span.ctxt() {
- if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
- // replace `|| vec![]` with `Vec::new`
- span_lint_and_sugg(
- cx,
- REDUNDANT_CLOSURE,
- expr.span,
- "redundant closure",
- "replace the closure with `Vec::new`",
- "std::vec::Vec::new".into(),
- Applicability::MachineApplicable,
- );
+ if decl.inputs.is_empty() {
+ if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
+ // replace `|| vec![]` with `Vec::new`
+ span_lint_and_sugg(
+ cx,
+ REDUNDANT_CLOSURE,
+ expr.span,
+ "redundant closure",
+ "replace the closure with `Vec::new`",
+ "std::vec::Vec::new".into(),
+ Applicability::MachineApplicable,
+ );
+ }
}
// skip `foo(|| macro!())`
return;
then {
span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
- if let Some(snippet) = snippet_opt(cx, caller.span) {
+ if let Some(mut snippet) = snippet_opt(cx, caller.span) {
+ if_chain! {
+ if let ty::Closure(_, substs) = fn_ty.kind();
+ if let ClosureKind::FnMut = substs.as_closure().kind();
+ if UsedAfterExprVisitor::is_found(cx, caller)
+ || get_enclosing_loop_or_closure(cx.tcx, expr).is_some();
+
+ then {
+ // Mutable closure is used after current expr; we cannot consume it.
+ snippet = format!("&mut {}", snippet);
+ }
+ }
diag.span_suggestion(
expr.span,
"replace the closure with the function itself",
cx.tcx.impl_of_method(method_def_id).and_then(|_| {
//a type may implicitly implement other type's methods (e.g. Deref)
if match_types(expected_type_of_self, actual_type_of_self) {
- return Some(get_type_name(cx, actual_type_of_self));
+ Some(get_type_name(cx, actual_type_of_self))
+ } else {
+ None
}
- None
})
}