Skip to content

Commit 30c7ea8

Browse files
committed
Merge pull request #577 from oli-obk/items_after_statements
lint on items following statements
2 parents 5dd0424 + 2a51f8d commit 30c7ea8

File tree

6 files changed

+83
-7
lines changed

6 files changed

+83
-7
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A collection of lints to catch common mistakes and improve your Rust code.
66
[Jump to usage instructions](#usage)
77

88
##Lints
9-
There are 96 lints included in this crate:
9+
There are 97 lints included in this crate:
1010

1111
name | default | meaning
1212
---------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -37,6 +37,7 @@ name
3737
[identity_op](https://github.com/Manishearth/rust-clippy/wiki#identity_op) | warn | using identity operations, e.g. `x + 0` or `y / 1`
3838
[ineffective_bit_mask](https://github.com/Manishearth/rust-clippy/wiki#ineffective_bit_mask) | warn | expressions where a bit mask will be rendered useless by a comparison, e.g. `(x | 1) > 2`
3939
[inline_always](https://github.com/Manishearth/rust-clippy/wiki#inline_always) | warn | `#[inline(always)]` is a bad idea in most cases
40+
[items_after_statements](https://github.com/Manishearth/rust-clippy/wiki#items_after_statements) | warn | finds blocks where an item comes after a statement
4041
[iter_next_loop](https://github.com/Manishearth/rust-clippy/wiki#iter_next_loop) | warn | for-looping over `_.next()` which is probably not intended
4142
[len_without_is_empty](https://github.com/Manishearth/rust-clippy/wiki#len_without_is_empty) | warn | traits and impls that have `.len()` but not `.is_empty()`
4243
[len_zero](https://github.com/Manishearth/rust-clippy/wiki#len_zero) | warn | checking `.len() == 0` or `.len() > 0` (or similar) when `.is_empty()` could be used instead

src/items_after_statements.rs

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//! lint when items are used after statements
2+
3+
use rustc::lint::*;
4+
use syntax::attr::*;
5+
use syntax::ast::*;
6+
use utils::in_macro;
7+
8+
/// **What it does:** It `Warn`s on blocks where there are items that are declared in the middle of or after the statements
9+
///
10+
/// **Why is this bad?** Items live for the entire scope they are declared in. But statements are processed in order. This might cause confusion as it's hard to figure out which item is meant in a statement.
11+
///
12+
/// **Known problems:** None
13+
///
14+
/// **Example:**
15+
/// ```rust
16+
/// fn foo() {
17+
/// println!("cake");
18+
/// }
19+
/// fn main() {
20+
/// foo(); // prints "foo"
21+
/// fn foo() {
22+
/// println!("foo");
23+
/// }
24+
/// foo(); // prints "foo"
25+
/// }
26+
declare_lint! { pub ITEMS_AFTER_STATEMENTS, Warn, "finds blocks where an item comes after a statement" }
27+
28+
pub struct ItemsAfterStatemets;
29+
30+
impl LintPass for ItemsAfterStatemets {
31+
fn get_lints(&self) -> LintArray {
32+
lint_array!(ITEMS_AFTER_STATEMENTS)
33+
}
34+
}
35+
36+
impl EarlyLintPass for ItemsAfterStatemets {
37+
fn check_block(&mut self, cx: &EarlyContext, item: &Block) {
38+
if in_macro(cx, item.span) {
39+
return;
40+
}
41+
let mut stmts = item.stmts.iter().map(|stmt| &stmt.node);
42+
// skip initial items
43+
while let Some(&StmtDecl(ref decl, _)) = stmts.next() {
44+
if let DeclLocal(_) = decl.node {
45+
break;
46+
}
47+
}
48+
// lint on all further items
49+
for stmt in stmts {
50+
if let StmtDecl(ref decl, _) = *stmt {
51+
if let DeclItem(ref it) = decl.node {
52+
if in_macro(cx, it.span) {
53+
return;
54+
}
55+
cx.struct_span_lint(ITEMS_AFTER_STATEMENTS, it.span,
56+
"adding items after statements is confusing, since items exist from the start of the scope")
57+
.emit();
58+
}
59+
}
60+
}
61+
}
62+
}

src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub mod needless_bool;
4343
pub mod approx_const;
4444
pub mod eta_reduction;
4545
pub mod identity_op;
46+
pub mod items_after_statements;
4647
pub mod minmax;
4748
pub mod mut_mut;
4849
pub mod mut_reference;
@@ -97,6 +98,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
9798
reg.register_early_lint_pass(box precedence::Precedence);
9899
reg.register_late_lint_pass(box eta_reduction::EtaPass);
99100
reg.register_late_lint_pass(box identity_op::IdentityOp);
101+
reg.register_early_lint_pass(box items_after_statements::ItemsAfterStatemets);
100102
reg.register_late_lint_pass(box mut_mut::MutMut);
101103
reg.register_late_lint_pass(box mut_reference::UnnecessaryMutPassed);
102104
reg.register_late_lint_pass(box len_zero::LenZero);
@@ -176,6 +178,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
176178
escape::BOXED_LOCAL,
177179
eta_reduction::REDUNDANT_CLOSURE,
178180
identity_op::IDENTITY_OP,
181+
items_after_statements::ITEMS_AFTER_STATEMENTS,
179182
len_zero::LEN_WITHOUT_IS_EMPTY,
180183
len_zero::LEN_ZERO,
181184
lifetimes::NEEDLESS_LIFETIMES,

src/mut_mut.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,17 @@ impl LateLintPass for MutMut {
3737
}
3838

3939
fn check_expr_mut(cx: &LateContext, expr: &Expr) {
40-
if in_external_macro(cx, expr.span) {
41-
return;
42-
}
43-
4440
fn unwrap_addr(expr: &Expr) -> Option<&Expr> {
4541
match expr.node {
4642
ExprAddrOf(MutMutable, ref e) => Some(e),
4743
_ => None,
4844
}
4945
}
5046

47+
if in_external_macro(cx, expr.span) {
48+
return;
49+
}
50+
5151
unwrap_addr(expr).map_or((), |e| {
5252
unwrap_addr(e).map_or_else(|| {
5353
if let TyRef(_, TypeAndMut{mutbl: MutMutable, ..}) = cx.tcx.expr_ty(e).sty {

tests/compile-fail/cmp_owned.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
#[deny(cmp_owned)]
55
fn main() {
6-
let x = "oh";
7-
86
#[allow(str_to_string)]
97
fn with_to_string(x : &str) {
108
x != "foo".to_string();
@@ -13,6 +11,9 @@ fn main() {
1311
"foo".to_string() != x;
1412
//~^ ERROR this creates an owned instance just for comparison. Consider using `"foo" != x` to compare without allocation
1513
}
14+
15+
let x = "oh";
16+
1617
with_to_string(x);
1718

1819
x != "foo".to_owned(); //~ERROR this creates an owned instance
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![feature(plugin)]
2+
#![plugin(clippy)]
3+
#![deny(items_after_statements)]
4+
5+
fn main() {
6+
foo();
7+
fn foo() { println!("foo"); } //~ ERROR adding items after statements is confusing
8+
foo();
9+
}

0 commit comments

Comments
 (0)