]> git.lizzy.rs Git - rust.git/commitdiff
Merge branch 'pr-737'
authorManish Goregaokar <manishsmail@gmail.com>
Sat, 5 Mar 2016 18:11:34 +0000 (23:41 +0530)
committerManish Goregaokar <manishsmail@gmail.com>
Sat, 5 Mar 2016 18:11:34 +0000 (23:41 +0530)
README.md
src/lib.rs
src/misc_early.rs
tests/compile-fail/eta.rs
tests/compile-fail/redundant_closure_call.rs [new file with mode: 0644]

index 3a957a7e4c9646b06549dde8a6d6a13306cd8625..ff875085da21a5161090fe9106f96d35f6cf83c1 100644 (file)
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ A collection of lints to catch common mistakes and improve your Rust code.
 [Jump to usage instructions](#usage)
 
 ##Lints
-There are 129 lints included in this crate:
+There are 130 lints included in this crate:
 
 name                                                                                                                 | default | meaning
 ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -99,6 +99,7 @@ name
 [range_step_by_zero](https://github.com/Manishearth/rust-clippy/wiki#range_step_by_zero)                             | warn    | using Range::step_by(0), which produces an infinite iterator
 [range_zip_with_len](https://github.com/Manishearth/rust-clippy/wiki#range_zip_with_len)                             | warn    | zipping iterator with a range when enumerate() would do
 [redundant_closure](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure)                               | warn    | using redundant closures, i.e. `|a| foo(a)` (which can be written as just `foo`)
+[redundant_closure_call](https://github.com/Manishearth/rust-clippy/wiki#redundant_closure_call)                     | warn    | Closures should not be called in the expression they are defined
 [redundant_pattern](https://github.com/Manishearth/rust-clippy/wiki#redundant_pattern)                               | warn    | using `name @ _` in a pattern
 [regex_macro](https://github.com/Manishearth/rust-clippy/wiki#regex_macro)                                           | warn    | finds use of `regex!(_)`, suggests `Regex::new(_)` instead
 [result_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#result_unwrap_used)                             | allow   | using `Result.unwrap()`, which might be better handled
index 7436dada020d93b147b0bded7e538af6e4ecefeb..803a4c2345c36e94d3e98957463dd82ba692af4a 100644 (file)
@@ -272,6 +272,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
         misc::TOPLEVEL_REF_ARG,
         misc::USED_UNDERSCORE_BINDING,
         misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
+        misc_early::REDUNDANT_CLOSURE_CALL,
         misc_early::UNNEEDED_FIELD_PATTERN,
         mut_reference::UNNECESSARY_MUT_PASSED,
         mutex_atomic::MUTEX_ATOMIC,
index 604e60021037f3b8e052371a7e1f40db0dbea41b..89a0763e2e32e74a86974f6480d3a5933b65b723 100644 (file)
@@ -3,8 +3,7 @@
 use syntax::ast::*;
 use syntax::codemap::Span;
 use syntax::visit::FnKind;
-use utils::{span_lint, span_help_and_lint};
-
+use utils::{span_lint, span_help_and_lint, snippet, span_lint_and_then};
 /// **What it does:** This lint checks for structure field patterns bound to wildcards.
 ///
 /// **Why is this bad?** Using `..` instead is shorter and leaves the focus on the fields that are actually bound.
     "Function arguments having names which only differ by an underscore"
 }
 
+/// **What it does:** This lint detects closures called in the same expression where they are defined.
+///
+/// **Why is this bad?** It is unnecessarily adding to the expression's complexity.
+///
+/// **Known problems:** None.
+///
+/// **Example:** `(|| 42)()`
+declare_lint! {
+    pub REDUNDANT_CLOSURE_CALL, Warn,
+    "Closures should not be called in the expression they are defined"
+}
+
 #[derive(Copy, Clone)]
 pub struct MiscEarly;
 
 impl LintPass for MiscEarly {
     fn get_lints(&self) -> LintArray {
-        lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT)
+        lint_array!(UNNEEDED_FIELD_PATTERN, DUPLICATE_UNDERSCORE_ARGUMENT, REDUNDANT_CLOSURE_CALL)
     }
 }
 
@@ -105,7 +116,7 @@ fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, decl: &FnDecl, _: &Block, _
                                   *correspondance,
                                   &format!("`{}` already exists, having another argument having almost the same \
                                             name makes code comprehension and documentation more difficult",
-                                           arg_name[1..].to_owned()));
+                                           arg_name[1..].to_owned()));;
                     }
                 } else {
                     registered_names.insert(arg_name, arg.pat.span);
@@ -113,4 +124,43 @@ fn check_fn(&mut self, cx: &EarlyContext, _: FnKind, decl: &FnDecl, _: &Block, _
             }
         }
     }
+
+    fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
+        if let ExprKind::Call(ref paren, _) = expr.node {
+            if let ExprKind::Paren(ref closure) = paren.node {
+                if let ExprKind::Closure(_, ref decl, ref block) = closure.node {
+                    span_lint_and_then(cx,
+                                       REDUNDANT_CLOSURE_CALL,
+                                       expr.span,
+                                       "Try not to call a closure in the expression where it is declared.",
+                                       |db| {
+                                            if decl.inputs.len() == 0 {
+                                                let hint = format!("{}", snippet(cx, block.span, ".."));
+                                                db.span_suggestion(expr.span, "Try doing something like: ", hint);
+                                            }
+                                        });
+                }
+            }
+        }
+    }
+
+    fn check_block(&mut self, cx: &EarlyContext, block: &Block) {
+        for w in block.stmts.windows(2) {
+            if_let_chain! {[
+                let StmtKind::Decl(ref first, _) = w[0].node,
+                let DeclKind::Local(ref local) = first.node,
+                let Option::Some(ref t) = local.init,
+                let ExprKind::Closure(_,_,_) = t.node,
+                let PatKind::Ident(_,sp_ident,_) = local.pat.node,
+                let StmtKind::Semi(ref second,_) = w[1].node,
+                let ExprKind::Assign(_,ref call) = second.node,
+                let ExprKind::Call(ref closure,_) = call.node,
+                let ExprKind::Path(_,ref path) = closure.node
+            ], {
+                if sp_ident.node == (&path.segments[0]).identifier {
+                    span_lint(cx, REDUNDANT_CLOSURE_CALL, second.span, "Closure called just once immediately after it was declared");
+                }
+            }}
+        }
+    }
 }
index 46680f2b8d83256371e9c17657bc0e162467c1a4..0e72efe654ee33b201da51d2edae6228df6f0e41 100644 (file)
@@ -1,6 +1,6 @@
 #![feature(plugin)]
 #![plugin(clippy)]
-#![allow(unknown_lints, unused, no_effect)]
+#![allow(unknown_lints, unused, no_effect, redundant_closure_call)]
 #![deny(redundant_closure)]
 
 fn main() {
diff --git a/tests/compile-fail/redundant_closure_call.rs b/tests/compile-fail/redundant_closure_call.rs
new file mode 100644 (file)
index 0000000..73830ec
--- /dev/null
@@ -0,0 +1,25 @@
+#![feature(plugin)]
+#![plugin(clippy)]
+
+#![deny(redundant_closure_call)]
+
+fn main() {
+       let a = (|| 42)();
+       //~^ ERROR Try not to call a closure in the expression where it is declared.
+       //~| HELP Try doing something like:
+       //~| SUGGESTION let a = 42;
+
+       let mut i = 1;
+       let k = (|m| m+1)(i); //~ERROR Try not to call a closure in the expression where it is declared.
+
+       k = (|a,b| a*b)(1,5); //~ERROR Try not to call a closure in the expression where it is declared.
+
+       let closure = || 32;
+       i = closure(); //~ERROR Closure called just once immediately after it was declared
+
+       let closure = |i| i+1;
+       i = closure(3); //~ERROR Closure called just once immediately after it was declared
+
+       i = closure(4);
+}
+