From 0fe5981870b4588d3412a31acec18cd5a12269fe Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Thu, 29 Oct 2015 01:50:00 +0900 Subject: [PATCH] New lint for statement with no effect --- README.md | 3 +- src/lib.rs | 3 ++ src/no_effect.rs | 61 +++++++++++++++++++++++++++ tests/compile-fail/needless_update.rs | 1 + tests/compile-fail/no_effect.rs | 39 +++++++++++++++++ tests/compile-fail/unit_cmp.rs | 1 + 6 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/no_effect.rs create mode 100644 tests/compile-fail/no_effect.rs diff --git a/README.md b/README.md index c602edca7df..29eb6750d16 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 69 lints included in this crate: +There are 70 lints included in this crate: name | default | meaning -------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -46,6 +46,7 @@ name [needless_range_loop](https://github.com/Manishearth/rust-clippy/wiki#needless_range_loop) | warn | for-looping over a range of indices where an iterator over items would do [needless_return](https://github.com/Manishearth/rust-clippy/wiki#needless_return) | warn | using a return statement like `return expr;` where an expression would suffice [needless_update](https://github.com/Manishearth/rust-clippy/wiki#needless_update) | warn | using `{ ..base }` when there are no missing fields +[no_effect](https://github.com/Manishearth/rust-clippy/wiki#no_effect) | warn | statements with no effect [non_ascii_literal](https://github.com/Manishearth/rust-clippy/wiki#non_ascii_literal) | allow | using any literal non-ASCII chars in a string literal; suggests using the \\u escape instead [nonsensical_open_options](https://github.com/Manishearth/rust-clippy/wiki#nonsensical_open_options) | warn | nonsensical combination of options for opening a file [option_unwrap_used](https://github.com/Manishearth/rust-clippy/wiki#option_unwrap_used) | allow | using `Option.unwrap()`, which should at least get a better message using `expect()` diff --git a/src/lib.rs b/src/lib.rs index b84c1e2aab6..60ab18566b8 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,6 +52,7 @@ pub mod zero_div_zero; pub mod open_options; pub mod needless_features; pub mod needless_update; +pub mod no_effect; mod reexport { pub use syntax::ast::{Name, Ident, NodeId}; @@ -98,6 +99,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box mutex_atomic::MutexAtomic); reg.register_late_lint_pass(box needless_features::NeedlessFeaturesPass); reg.register_late_lint_pass(box needless_update::NeedlessUpdatePass); + reg.register_late_lint_pass(box no_effect::NoEffectPass); reg.register_lint_group("clippy_pedantic", vec![ methods::OPTION_UNWRAP_USED, @@ -159,6 +161,7 @@ pub fn plugin_registrar(reg: &mut Registry) { needless_features::UNSTABLE_AS_MUT_SLICE, needless_features::UNSTABLE_AS_SLICE, needless_update::NEEDLESS_UPDATE, + no_effect::NO_EFFECT, open_options::NONSENSICAL_OPEN_OPTIONS, precedence::PRECEDENCE, ptr_arg::PTR_ARG, diff --git a/src/no_effect.rs b/src/no_effect.rs new file mode 100644 index 00000000000..82fcf92fd4c --- /dev/null +++ b/src/no_effect.rs @@ -0,0 +1,61 @@ +use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; +use rustc::middle::def::{DefStruct, DefVariant}; +use rustc_front::hir::{Expr, ExprCall, ExprLit, ExprPath, ExprStruct}; +use rustc_front::hir::{Stmt, StmtSemi}; + +use utils::in_macro; +use utils::span_lint; + +declare_lint! { + pub NO_EFFECT, + Warn, + "statements with no effect" +} + +fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool { + if in_macro(cx, expr.span) { + return false; + } + match expr.node { + ExprLit(..) | + ExprPath(..) => true, + ExprStruct(_, ref fields, ref base) => { + fields.iter().all(|field| has_no_effect(cx, &field.expr)) && + match *base { + Some(ref base) => has_no_effect(cx, base), + None => true, + } + } + ExprCall(ref callee, ref args) => { + let def = cx.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()); + match def { + Some(DefStruct(..)) | + Some(DefVariant(..)) => { + args.iter().all(|arg| has_no_effect(cx, arg)) + } + _ => false, + } + } + _ => false, + } +} + +#[derive(Copy, Clone)] +pub struct NoEffectPass; + +impl LintPass for NoEffectPass { + fn get_lints(&self) -> LintArray { + lint_array!(NO_EFFECT) + } +} + +impl LateLintPass for NoEffectPass { + fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) { + if let StmtSemi(ref expr, _) = stmt.node { + if has_no_effect(cx, expr) { + span_lint(cx, NO_EFFECT, stmt.span, + "statement with no effect"); + } + } + } +} diff --git a/tests/compile-fail/needless_update.rs b/tests/compile-fail/needless_update.rs index 55438d9d90a..55cfed76d5d 100644 --- a/tests/compile-fail/needless_update.rs +++ b/tests/compile-fail/needless_update.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #![deny(needless_update)] +#![allow(no_effect)] struct S { pub a: i32, diff --git a/tests/compile-fail/no_effect.rs b/tests/compile-fail/no_effect.rs new file mode 100644 index 00000000000..8da119eb16d --- /dev/null +++ b/tests/compile-fail/no_effect.rs @@ -0,0 +1,39 @@ +#![feature(plugin)] +#![plugin(clippy)] + +#![deny(no_effect)] +#![allow(dead_code)] +#![allow(path_statements)] + +struct Unit; +struct Tuple(i32); +struct Struct { + field: i32 +} +enum Enum { + TupleVariant(i32), + StructVariant { field: i32 }, +} + +fn get_number() -> i32 { 0 } +fn get_struct() -> Struct { Struct { field: 0 } } + +fn main() { + let s = get_struct(); + + 0; //~ERROR statement with no effect + Unit; //~ERROR statement with no effect + Tuple(0); //~ERROR statement with no effect + Struct { field: 0 }; //~ERROR statement with no effect + Struct { ..s }; //~ERROR statement with no effect + Enum::TupleVariant(0); //~ERROR statement with no effect + Enum::StructVariant { field: 0 }; //~ERROR statement with no effect + + // Do not warn + get_number(); + Tuple(get_number()); + Struct { field: get_number() }; + Struct { ..get_struct() }; + Enum::TupleVariant(get_number()); + Enum::StructVariant { field: get_number() }; +} diff --git a/tests/compile-fail/unit_cmp.rs b/tests/compile-fail/unit_cmp.rs index af28f849e8c..1a28953ace1 100755 --- a/tests/compile-fail/unit_cmp.rs +++ b/tests/compile-fail/unit_cmp.rs @@ -2,6 +2,7 @@ #![plugin(clippy)] #![deny(unit_cmp)] +#![allow(no_effect)] #[derive(PartialEq)] pub struct ContainsUnit(()); // should be fine