mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-10 07:04:18 +00:00
Warn about calling a closure in the same expression where it's defined.
This commit is contained in:
parent
bdda6a2d3e
commit
e421a0f8a3
5 changed files with 83 additions and 6 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -3,8 +3,7 @@ use std::collections::HashMap;
|
|||
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.
|
||||
|
@ -29,12 +28,24 @@ declare_lint! {
|
|||
"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 @@ impl EarlyLintPass for MiscEarly {
|
|||
*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 @@ impl EarlyLintPass for MiscEarly {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
25
tests/compile-fail/redundant_closure_call.rs
Normal file
25
tests/compile-fail/redundant_closure_call.rs
Normal file
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in a new issue