]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/redundant_closure_call.rs
Auto merge of #9539 - Jarcho:ice_9445, r=flip1995
[rust.git] / clippy_lints / src / redundant_closure_call.rs
index 9477e79f567ad3c70ad6118e8d60a8278ef4bf5b..74eea6de4bbeff43d30c92d83a8553c73d6cfab9 100644 (file)
@@ -1,4 +1,5 @@
-use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_ast::visit as ast_visit;
@@ -8,27 +9,29 @@
 use rustc_hir::intravisit as hir_visit;
 use rustc_hir::intravisit::Visitor as HirVisitor;
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
-    /// **What it does:** Detects closures called in the same expression where they
+    /// ### What it does
+    /// Detects closures called in the same expression where they
     /// are defined.
     ///
-    /// **Why is this bad?** It is unnecessarily adding to the expression's
+    /// ### Why is this bad?
+    /// It is unnecessarily adding to the expression's
     /// complexity.
     ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust,ignore
-    /// // Bad
-    /// let a = (|| 42)()
+    /// ### Example
+    /// ```rust
+    /// let a = (|| 42)();
+    /// ```
     ///
-    /// // Good
-    /// let a = 42
+    /// Use instead:
+    /// ```rust
+    /// let a = 42;
     /// ```
+    #[clippy::version = "pre 1.29.0"]
     pub REDUNDANT_CLOSURE_CALL,
     complexity,
     "throwaway closures called in the expression they are defined"
@@ -50,13 +53,11 @@ fn new() -> Self {
 
 impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor {
     fn visit_expr(&mut self, ex: &'ast ast::Expr) {
-        if let ast::ExprKind::Ret(_) = ex.kind {
-            self.found_return = true;
-        } else if let ast::ExprKind::Try(_) = ex.kind {
+        if let ast::ExprKind::Ret(_) | ast::ExprKind::Try(_) = ex.kind {
             self.found_return = true;
         }
 
-        ast_visit::walk_expr(self, ex)
+        ast_visit::walk_expr(self, ex);
     }
 }
 
@@ -68,7 +69,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
         if_chain! {
             if let ast::ExprKind::Call(ref paren, _) = expr.kind;
             if let ast::ExprKind::Paren(ref closure) = paren.kind;
-            if let ast::ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.kind;
+            if let ast::ExprKind::Closure(_, _, ref r#async, _, ref decl, ref block, _) = closure.kind;
             then {
                 let mut visitor = ReturnVisitor::new();
                 visitor.visit_expr(block);
@@ -77,13 +78,22 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
                         cx,
                         REDUNDANT_CLOSURE_CALL,
                         expr.span,
-                        "Try not to call a closure in the expression where it is declared.",
+                        "try not to call a closure in the expression where it is declared",
                         |diag| {
                             if decl.inputs.is_empty() {
-                                let mut app = Applicability::MachineApplicable;
-                                let hint =
-                                    snippet_with_applicability(cx, block.span, "..", &mut app).into_owned();
-                                diag.span_suggestion(expr.span, "Try doing something like: ", hint, app);
+                                let app = Applicability::MachineApplicable;
+                                let mut hint = Sugg::ast(cx, block, "..");
+
+                                if r#async.is_async() {
+                                    // `async x` is a syntax error, so it becomes `async { x }`
+                                    if !matches!(block.kind, ast::ExprKind::Block(_, _)) {
+                                        hint = hint.blockify();
+                                    }
+
+                                    hint = hint.asyncify();
+                                }
+
+                                diag.span_suggestion(expr.span, "try doing something like", hint.to_string(), app);
                             }
                         },
                     );
@@ -95,20 +105,25 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
 
 impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
-        fn count_closure_usage<'tcx>(block: &'tcx hir::Block<'_>, path: &'tcx hir::Path<'tcx>) -> usize {
-            struct ClosureUsageCount<'tcx> {
+        fn count_closure_usage<'a, 'tcx>(
+            cx: &'a LateContext<'tcx>,
+            block: &'tcx hir::Block<'_>,
+            path: &'tcx hir::Path<'tcx>,
+        ) -> usize {
+            struct ClosureUsageCount<'a, 'tcx> {
+                cx: &'a LateContext<'tcx>,
                 path: &'tcx hir::Path<'tcx>,
                 count: usize,
-            };
-            impl<'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'tcx> {
-                type Map = Map<'tcx>;
+            }
+            impl<'a, 'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> {
+                type NestedFilter = nested_filter::OnlyBodies;
 
                 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                     if_chain! {
-                        if let hir::ExprKind::Call(ref closure, _) = expr.kind;
-                        if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind;
-                        if self.path.segments[0].ident == path.segments[0].ident
-                            && self.path.res == path.res;
+                        if let hir::ExprKind::Call(closure, _) = expr.kind;
+                        if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind;
+                        if self.path.segments[0].ident == path.segments[0].ident;
+                        if self.path.res == path.res;
                         then {
                             self.count += 1;
                         }
@@ -116,33 +131,33 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                     hir_visit::walk_expr(self, expr);
                 }
 
-                fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
-                    hir_visit::NestedVisitorMap::None
+                fn nested_visit_map(&mut self) -> Self::Map {
+                    self.cx.tcx.hir()
                 }
-            };
-            let mut closure_usage_count = ClosureUsageCount { path, count: 0 };
+            }
+            let mut closure_usage_count = ClosureUsageCount { cx, path, count: 0 };
             closure_usage_count.visit_block(block);
             closure_usage_count.count
         }
 
         for w in block.stmts.windows(2) {
             if_chain! {
-                if let hir::StmtKind::Local(ref local) = w[0].kind;
-                if let Option::Some(ref t) = local.init;
-                if let hir::ExprKind::Closure(..) = t.kind;
+                if let hir::StmtKind::Local(local) = w[0].kind;
+                if let Option::Some(t) = local.init;
+                if let hir::ExprKind::Closure { .. } = t.kind;
                 if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind;
-                if let hir::StmtKind::Semi(ref second) = w[1].kind;
-                if let hir::ExprKind::Assign(_, ref call, _) = second.kind;
-                if let hir::ExprKind::Call(ref closure, _) = call.kind;
-                if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind;
+                if let hir::StmtKind::Semi(second) = w[1].kind;
+                if let hir::ExprKind::Assign(_, call, _) = second.kind;
+                if let hir::ExprKind::Call(closure, _) = call.kind;
+                if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = closure.kind;
                 if ident == path.segments[0].ident;
-                if  count_closure_usage(block, path) == 1;
+                if count_closure_usage(cx, block, path) == 1;
                 then {
                     span_lint(
                         cx,
                         REDUNDANT_CLOSURE_CALL,
                         second.span,
-                        "Closure called just once immediately after it was declared",
+                        "closure called just once immediately after it was declared",
                     );
                 }
             }