Skip to content

Commit 3dfb5f0

Browse files
committed
Lint unused labels
1 parent 88ac226 commit 3dfb5f0

File tree

4 files changed

+117
-0
lines changed

4 files changed

+117
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ name
130130
[unstable_as_mut_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_mut_slice) | warn | as_mut_slice is not stable and can be replaced by &mut v[..]see https://github.com/rust-lang/rust/issues/27729
131131
[unstable_as_slice](https://github.com/Manishearth/rust-clippy/wiki#unstable_as_slice) | warn | as_slice is not stable and can be replaced by & v[..]see https://github.com/rust-lang/rust/issues/27729
132132
[unused_collect](https://github.com/Manishearth/rust-clippy/wiki#unused_collect) | warn | `collect()`ing an iterator without using the result; this is usually better written as a for loop
133+
[unused_label](https://github.com/Manishearth/rust-clippy/wiki#unused_label) | warn | unused label
133134
[unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions
134135
[use_debug](https://github.com/Manishearth/rust-clippy/wiki#use_debug) | allow | use `Debug`-based formatting
135136
[used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ pub mod temporary_assignment;
9393
pub mod transmute;
9494
pub mod types;
9595
pub mod unicode;
96+
pub mod unused_label;
9697
pub mod vec;
9798
pub mod zero_div_zero;
9899
// end lints modules, do not remove this comment, it’s used in `update_lints`
@@ -173,6 +174,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
173174
reg.register_early_lint_pass(box formatting::Formatting);
174175
reg.register_late_lint_pass(box swap::Swap);
175176
reg.register_early_lint_pass(box if_not_else::IfNotElse);
177+
reg.register_late_lint_pass(box unused_label::UnusedLabel);
176178

177179
reg.register_lint_group("clippy_pedantic", vec![
178180
enum_glob_use::ENUM_GLOB_USE,
@@ -306,6 +308,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
306308
types::TYPE_COMPLEXITY,
307309
types::UNIT_CMP,
308310
unicode::ZERO_WIDTH_SPACE,
311+
unused_label::UNUSED_LABEL,
309312
vec::USELESS_VEC,
310313
zero_div_zero::ZERO_DIVIDED_BY_ZERO,
311314
]);

src/unused_label.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use rustc::lint::*;
2+
use rustc_front::hir;
3+
use rustc_front::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
4+
use std::collections::HashMap;
5+
use syntax::ast;
6+
use syntax::codemap::Span;
7+
use syntax::parse::token::InternedString;
8+
use utils::{in_macro, span_lint};
9+
10+
/// **What it does:** This lint checks for unused labels.
11+
///
12+
/// **Why is this bad?** Maybe the label should be used in which case there is an error in the
13+
/// code or it should be removed.
14+
///
15+
/// **Known problems:** Hopefully none.
16+
///
17+
/// **Example:**
18+
/// ```rust,ignore
19+
/// fn unused_label() {
20+
/// 'label: for i in 1..2 {
21+
/// if i > 4 { continue }
22+
/// }
23+
/// ```
24+
declare_lint! {
25+
pub UNUSED_LABEL,
26+
Warn,
27+
"unused label"
28+
}
29+
30+
pub struct UnusedLabel;
31+
32+
#[derive(Default)]
33+
struct UnusedLabelVisitor {
34+
labels: HashMap<InternedString, Span>,
35+
}
36+
37+
impl UnusedLabelVisitor {
38+
pub fn new() -> UnusedLabelVisitor {
39+
::std::default::Default::default()
40+
}
41+
}
42+
43+
impl LintPass for UnusedLabel {
44+
fn get_lints(&self) -> LintArray {
45+
lint_array!(UNUSED_LABEL)
46+
}
47+
}
48+
49+
impl LateLintPass for UnusedLabel {
50+
fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, body: &hir::Block, span: Span, _: ast::NodeId) {
51+
if in_macro(cx, span) {
52+
return;
53+
}
54+
55+
let mut v = UnusedLabelVisitor::new();
56+
walk_fn(&mut v, kind, decl, body, span);
57+
58+
for (label, span) in v.labels {
59+
span_lint(cx, UNUSED_LABEL, span, &format!("unused label `{}`", label));
60+
}
61+
}
62+
}
63+
64+
impl<'v> Visitor<'v> for UnusedLabelVisitor {
65+
fn visit_expr(&mut self, expr: &hir::Expr) {
66+
match expr.node {
67+
hir::ExprBreak(Some(label)) | hir::ExprAgain(Some(label)) => {
68+
self.labels.remove(&label.node.name.as_str());
69+
}
70+
hir::ExprLoop(_, Some(label)) | hir::ExprWhile(_, _, Some(label)) => {
71+
self.labels.insert(label.name.as_str(), expr.span);
72+
}
73+
_ => (),
74+
}
75+
76+
walk_expr(self, expr);
77+
}
78+
}

tests/compile-fail/unused_labels.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#![plugin(clippy)]
2+
#![feature(plugin)]
3+
4+
#![allow(dead_code, items_after_statements)]
5+
#![deny(unused_label)]
6+
7+
fn unused_label() {
8+
'label: for i in 1..2 { //~ERROR: unused label `'label`
9+
if i > 4 { continue }
10+
}
11+
}
12+
13+
fn foo() {
14+
'same_label_in_two_fns: loop {
15+
break 'same_label_in_two_fns;
16+
}
17+
}
18+
19+
20+
fn bla() {
21+
'a: loop { break } //~ERROR: unused label `'a`
22+
fn blub() {}
23+
}
24+
25+
fn main() {
26+
'a: for _ in 0..10 {
27+
while let Some(42) = None {
28+
continue 'a;
29+
}
30+
}
31+
32+
'same_label_in_two_fns: loop { //~ERROR: unused label `'same_label_in_two_fns`
33+
let _ = 1;
34+
}
35+
}

0 commit comments

Comments
 (0)