diff options
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | clippy_lints/src/forced_return.rs | 106 | ||||
| -rw-r--r-- | clippy_lints/src/lib.rs | 3 | ||||
| -rw-r--r-- | tests/ui/forced_return.rs | 55 | ||||
| -rw-r--r-- | tests/ui/forced_return.stderr | 46 |
5 files changed, 211 insertions, 1 deletions
diff --git a/README.md b/README.md index 0d83224e3f6..92bb4586688 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code. -[There are 289 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) +[There are 290 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: diff --git a/clippy_lints/src/forced_return.rs b/clippy_lints/src/forced_return.rs new file mode 100644 index 00000000000..ee30bd0ab1e --- /dev/null +++ b/clippy_lints/src/forced_return.rs @@ -0,0 +1,106 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::rustc::hir::{intravisit::FnKind, Body, ExprKind, FnDecl}; +use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use crate::rustc::{declare_tool_lint, lint_array}; +use crate::rustc_errors::Applicability; +use crate::syntax::{ast::NodeId, source_map::Span}; +use crate::utils::{snippet_opt, span_lint_and_then}; + +/// **What it does:** Checks for missing return statements at the end of a block. +/// +/// **Why is this bad?** Actually it is idiomatic Rust code. Programmers coming +/// from other languages might prefer the expressiveness of `return`. +/// +/// **Known problems:** None. +/// +/// **Example:** +/// ```rust +/// fn foo(x: usize) { +/// x +/// } +/// ``` +/// add return +/// ```rust +/// fn foo(x: usize) { +/// return x; +/// } +/// ``` +declare_clippy_lint! { + pub FORCED_RETURN, + restriction, + "use a return statement like `return expr` instead of an expression" +} + +pub struct ForcedReturnPass; + +impl ForcedReturnPass { + fn show_suggestion(cx: &LateContext<'_, '_>, span: syntax_pos::Span) { + span_lint_and_then(cx, FORCED_RETURN, span, "missing return statement", |db| { + if let Some(snippet) = snippet_opt(cx, span) { + db.span_suggestion_with_applicability( + span, + "add `return` as shown", + format!("return {}", snippet), + Applicability::MachineApplicable, + ); + } + }); + } + + fn expr_match(cx: &LateContext<'_, '_>, kind: &ExprKind) { + match kind { + ExprKind::Block(ref block, ..) => { + if let Some(ref expr) = block.expr { + Self::expr_match(cx, &expr.node); + } + }, + ExprKind::If(.., if_expr, else_expr) => { + Self::expr_match(cx, &if_expr.node); + + if let Some(else_expr) = else_expr { + Self::expr_match(cx, &else_expr.node); + } + }, + ExprKind::Match(_, arms, ..) => { + for arm in arms { + Self::expr_match(cx, &arm.body.node); + } + }, + ExprKind::Lit(lit) => Self::show_suggestion(cx, lit.span), + _ => (), + } + } +} + +impl LintPass for ForcedReturnPass { + fn get_lints(&self) -> LintArray { + lint_array!(FORCED_RETURN) + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ForcedReturnPass { + fn check_fn( + &mut self, + cx: &LateContext<'a, 'tcx>, + _: FnKind<'tcx>, + _: &'tcx FnDecl, + body: &'tcx Body, + _: Span, + _: NodeId, + ) { + let def_id = cx.tcx.hir.body_owner_def_id(body.id()); + let mir = cx.tcx.optimized_mir(def_id); + + if !mir.return_ty().is_unit() { + Self::expr_match(cx, &body.value.node); + } + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 326bf884e33..729e3a20c2c 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -185,6 +185,7 @@ pub mod reference; pub mod regex; pub mod replace_consts; pub mod returns; +pub mod forced_return; pub mod serde_api; pub mod shadow; pub mod slow_vector_initialization; @@ -371,6 +372,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { reg.register_late_lint_pass(box unicode::Unicode); reg.register_late_lint_pass(box strings::StringAdd); reg.register_early_lint_pass(box returns::ReturnPass); + reg.register_late_lint_pass(box forced_return::ForcedReturnPass); reg.register_late_lint_pass(box methods::Pass); reg.register_late_lint_pass(box map_clone::Pass); reg.register_late_lint_pass(box shadow::Pass); @@ -502,6 +504,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { strings::STRING_ADD, write::PRINT_STDOUT, write::USE_DEBUG, + forced_return::FORCED_RETURN, ]); reg.register_lint_group("clippy::pedantic", Some("clippy_pedantic"), vec![ diff --git a/tests/ui/forced_return.rs b/tests/ui/forced_return.rs new file mode 100644 index 00000000000..5f07d99528e --- /dev/null +++ b/tests/ui/forced_return.rs @@ -0,0 +1,55 @@ +// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + + + + +#![warn(clippy::forced_return)] + +fn test_end_of_fn() -> bool { + if true { + // no error! + return true; + } + true +} + +#[allow(clippy::needless_bool)] +fn test_if_block() -> bool { + if true { + true + } else { + false + } +} + +#[allow(clippy::match_bool)] +fn test_match(x: bool) -> bool { + match x { + true => false, + false => { + true + } + } +} + +fn test_closure() { + let _ = || { + true + }; + let _ = || true; +} + +fn main() { + let _ = test_end_of_fn(); + let _ = test_if_block(); + let _ = test_match(true); + test_closure(); +} diff --git a/tests/ui/forced_return.stderr b/tests/ui/forced_return.stderr new file mode 100644 index 00000000000..0b1dcc4ce33 --- /dev/null +++ b/tests/ui/forced_return.stderr @@ -0,0 +1,46 @@ +error: missing return statement + --> $DIR/forced_return.rs:21:5 + | +21 | true + | ^^^^ help: add `return` as shown: `return true` + | + = note: `-D clippy::forced-return` implied by `-D warnings` + +error: missing return statement + --> $DIR/forced_return.rs:27:9 + | +27 | true + | ^^^^ help: add `return` as shown: `return true` + +error: missing return statement + --> $DIR/forced_return.rs:29:9 + | +29 | false + | ^^^^^ help: add `return` as shown: `return false` + +error: missing return statement + --> $DIR/forced_return.rs:36:17 + | +36 | true => false, + | ^^^^^ help: add `return` as shown: `return false` + +error: missing return statement + --> $DIR/forced_return.rs:38:13 + | +38 | true + | ^^^^ help: add `return` as shown: `return true` + +error: missing return statement + --> $DIR/forced_return.rs:45:9 + | +45 | true + | ^^^^ help: add `return` as shown: `return true` + +error: missing return statement + --> $DIR/forced_return.rs:47:16 + | +47 | let _ = || true; + | ^^^^ help: add `return` as shown: `return true` + +error: aborting due to 7 previous errors + |
