diff --git a/src/lib.rs b/src/lib.rs index 4009aa1cf8d..c5469c19858 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ pub mod unicode; pub mod utils; pub mod strings; pub mod methods; +pub mod returns; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { @@ -55,7 +56,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_lint_pass(box misc::ModuloOne as LintPassObject); reg.register_lint_pass(box unicode::Unicode as LintPassObject); reg.register_lint_pass(box strings::StringAdd as LintPassObject); - reg.register_lint_pass(box misc::NeedlessReturn as LintPassObject); + reg.register_lint_pass(box returns::ReturnPass as LintPassObject); reg.register_lint_pass(box methods::MethodsPass as LintPassObject); reg.register_lint_group("clippy", vec![types::BOX_VEC, types::LINKEDLIST, @@ -77,7 +78,7 @@ pub fn plugin_registrar(reg: &mut Registry) { collapsible_if::COLLAPSIBLE_IF, unicode::ZERO_WIDTH_SPACE, strings::STRING_ADD_ASSIGN, - misc::NEEDLESS_RETURN, + returns::NEEDLESS_RETURN, misc::MODULO_ONE, methods::OPTION_UNWRAP_USED, methods::RESULT_UNWRAP_USED, diff --git a/src/misc.rs b/src/misc.rs index a1b3dcb32b8..934e8a7fb77 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -270,75 +270,6 @@ fn is_str_arg(cx: &Context, args: &[P]) -> bool { walk_ptrs_ty(cx.tcx.expr_ty(&*args[0])).sty { true } else { false } } -declare_lint!(pub NEEDLESS_RETURN, Warn, - "Warn on using a return statement where an expression would be enough"); - -#[derive(Copy,Clone)] -pub struct NeedlessReturn; - -impl NeedlessReturn { - // Check the final stmt or expr in a block for unnecessary return. - fn check_block_return(&mut self, cx: &Context, block: &Block) { - if let Some(ref expr) = block.expr { - self.check_final_expr(cx, expr); - } else if let Some(stmt) = block.stmts.last() { - if let StmtSemi(ref expr, _) = stmt.node { - if let ExprRet(Some(ref inner)) = expr.node { - self.emit_lint(cx, (expr.span, inner.span)); - } - } - } - } - - // Check a the final expression in a block if it's a return. - fn check_final_expr(&mut self, cx: &Context, expr: &Expr) { - match expr.node { - // simple return is always "bad" - ExprRet(Some(ref inner)) => { - self.emit_lint(cx, (expr.span, inner.span)); - } - // a whole block? check it! - ExprBlock(ref block) => { - self.check_block_return(cx, block); - } - // an if/if let expr, check both exprs - // note, if without else is going to be a type checking error anyways - // (except for unit type functions) so we don't match it - ExprIf(_, ref ifblock, Some(ref elsexpr)) | - ExprIfLet(_, _, ref ifblock, Some(ref elsexpr)) => { - self.check_block_return(cx, ifblock); - self.check_final_expr(cx, elsexpr); - } - // a match expr, check all arms - ExprMatch(_, ref arms, _) => { - for arm in arms { - self.check_final_expr(cx, &*arm.body); - } - } - _ => { } - } - } - - fn emit_lint(&mut self, cx: &Context, spans: (Span, Span)) { - span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( - "unneeded return statement. Consider using {} \ - without the trailing semicolon", - snippet(cx, spans.1, ".."))) - } -} - -impl LintPass for NeedlessReturn { - fn get_lints(&self) -> LintArray { - lint_array!(NEEDLESS_RETURN) - } - - fn check_fn(&mut self, cx: &Context, _: FnKind, _: &FnDecl, - block: &Block, _: Span, _: ast::NodeId) { - self.check_block_return(cx, block); - } -} - - declare_lint!(pub MODULO_ONE, Warn, "Warn on expressions that include % 1, which is always 0"); #[derive(Copy,Clone)] diff --git a/src/returns.rs b/src/returns.rs new file mode 100644 index 00000000000..d6a4b33b6d1 --- /dev/null +++ b/src/returns.rs @@ -0,0 +1,75 @@ +use syntax::ast; +use syntax::ast::*; +use syntax::codemap::Span; +use syntax::visit::FnKind; +use rustc::lint::{Context, LintPass, LintArray}; + +use utils::{span_lint, snippet}; + +declare_lint!(pub NEEDLESS_RETURN, Warn, + "Warn on using a return statement where an expression would be enough"); + +#[derive(Copy,Clone)] +pub struct ReturnPass; + +impl ReturnPass { + // Check the final stmt or expr in a block for unnecessary return. + fn check_block_return(&mut self, cx: &Context, block: &Block) { + if let Some(ref expr) = block.expr { + self.check_final_expr(cx, expr); + } else if let Some(stmt) = block.stmts.last() { + if let StmtSemi(ref expr, _) = stmt.node { + if let ExprRet(Some(ref inner)) = expr.node { + self.emit_lint(cx, (expr.span, inner.span)); + } + } + } + } + + // Check a the final expression in a block if it's a return. + fn check_final_expr(&mut self, cx: &Context, expr: &Expr) { + match expr.node { + // simple return is always "bad" + ExprRet(Some(ref inner)) => { + self.emit_lint(cx, (expr.span, inner.span)); + } + // a whole block? check it! + ExprBlock(ref block) => { + self.check_block_return(cx, block); + } + // an if/if let expr, check both exprs + // note, if without else is going to be a type checking error anyways + // (except for unit type functions) so we don't match it + ExprIf(_, ref ifblock, Some(ref elsexpr)) | + ExprIfLet(_, _, ref ifblock, Some(ref elsexpr)) => { + self.check_block_return(cx, ifblock); + self.check_final_expr(cx, elsexpr); + } + // a match expr, check all arms + ExprMatch(_, ref arms, _) => { + for arm in arms { + self.check_final_expr(cx, &*arm.body); + } + } + _ => { } + } + } + + fn emit_lint(&mut self, cx: &Context, spans: (Span, Span)) { + span_lint(cx, NEEDLESS_RETURN, spans.0, &format!( + "unneeded return statement. Consider using {} \ + without the trailing semicolon", + snippet(cx, spans.1, ".."))) + } +} + +impl LintPass for ReturnPass { + fn get_lints(&self) -> LintArray { + lint_array!(NEEDLESS_RETURN) + } + + fn check_fn(&mut self, cx: &Context, _: FnKind, _: &FnDecl, + block: &Block, _: Span, _: ast::NodeId) { + self.check_block_return(cx, block); + } +}