From 204c12c99ea1d3266bf067700351e8e6468a35d2 Mon Sep 17 00:00:00 2001 From: mcarton Date: Tue, 1 Mar 2016 15:15:39 +0100 Subject: [PATCH] Lint unused labels --- README.md | 3 +- src/lib.rs | 3 ++ src/unused_label.rs | 78 +++++++++++++++++++++++++++++ tests/compile-fail/unused_labels.rs | 35 +++++++++++++ 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/unused_label.rs create mode 100755 tests/compile-fail/unused_labels.rs diff --git a/README.md b/README.md index 77518df6b..3b0a4f882 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A collection of lints to catch common mistakes and improve your Rust code. [Jump to usage instructions](#usage) ##Lints -There are 131 lints included in this crate: +There are 132 lints included in this crate: name | default | meaning ---------------------------------------------------------------------------------------------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @@ -131,6 +131,7 @@ name [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 [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 [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 +[unused_label](https://github.com/Manishearth/rust-clippy/wiki#unused_label) | warn | unused label [unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions [use_debug](https://github.com/Manishearth/rust-clippy/wiki#use_debug) | allow | use `Debug`-based formatting [used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | warn | using a binding which is prefixed with an underscore diff --git a/src/lib.rs b/src/lib.rs index 51292bea8..bb9d9b620 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,6 +94,7 @@ pub mod temporary_assignment; pub mod transmute; pub mod types; pub mod unicode; +pub mod unused_label; pub mod vec; pub mod zero_div_zero; // end lints modules, do not remove this comment, it’s used in `update_lints` @@ -175,6 +176,7 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box swap::Swap); reg.register_early_lint_pass(box if_not_else::IfNotElse); reg.register_late_lint_pass(box overflow_check_conditional::OverflowCheckConditional); + reg.register_late_lint_pass(box unused_label::UnusedLabel); reg.register_lint_group("clippy_pedantic", vec![ enum_glob_use::ENUM_GLOB_USE, @@ -309,6 +311,7 @@ pub fn plugin_registrar(reg: &mut Registry) { types::TYPE_COMPLEXITY, types::UNIT_CMP, unicode::ZERO_WIDTH_SPACE, + unused_label::UNUSED_LABEL, vec::USELESS_VEC, zero_div_zero::ZERO_DIVIDED_BY_ZERO, ]); diff --git a/src/unused_label.rs b/src/unused_label.rs new file mode 100644 index 000000000..f2ecad7cc --- /dev/null +++ b/src/unused_label.rs @@ -0,0 +1,78 @@ +use rustc::lint::*; +use rustc_front::hir; +use rustc_front::intravisit::{FnKind, Visitor, walk_expr, walk_fn}; +use std::collections::HashMap; +use syntax::ast; +use syntax::codemap::Span; +use syntax::parse::token::InternedString; +use utils::{in_macro, span_lint}; + +/// **What it does:** This lint checks for unused labels. +/// +/// **Why is this bad?** Maybe the label should be used in which case there is an error in the +/// code or it should be removed. +/// +/// **Known problems:** Hopefully none. +/// +/// **Example:** +/// ```rust,ignore +/// fn unused_label() { +/// 'label: for i in 1..2 { +/// if i > 4 { continue } +/// } +/// ``` +declare_lint! { + pub UNUSED_LABEL, + Warn, + "unused label" +} + +pub struct UnusedLabel; + +#[derive(Default)] +struct UnusedLabelVisitor { + labels: HashMap, +} + +impl UnusedLabelVisitor { + pub fn new() -> UnusedLabelVisitor { + ::std::default::Default::default() + } +} + +impl LintPass for UnusedLabel { + fn get_lints(&self) -> LintArray { + lint_array!(UNUSED_LABEL) + } +} + +impl LateLintPass for UnusedLabel { + fn check_fn(&mut self, cx: &LateContext, kind: FnKind, decl: &hir::FnDecl, body: &hir::Block, span: Span, _: ast::NodeId) { + if in_macro(cx, span) { + return; + } + + let mut v = UnusedLabelVisitor::new(); + walk_fn(&mut v, kind, decl, body, span); + + for (label, span) in v.labels { + span_lint(cx, UNUSED_LABEL, span, &format!("unused label `{}`", label)); + } + } +} + +impl<'v> Visitor<'v> for UnusedLabelVisitor { + fn visit_expr(&mut self, expr: &hir::Expr) { + match expr.node { + hir::ExprBreak(Some(label)) | hir::ExprAgain(Some(label)) => { + self.labels.remove(&label.node.name.as_str()); + } + hir::ExprLoop(_, Some(label)) | hir::ExprWhile(_, _, Some(label)) => { + self.labels.insert(label.name.as_str(), expr.span); + } + _ => (), + } + + walk_expr(self, expr); + } +} diff --git a/tests/compile-fail/unused_labels.rs b/tests/compile-fail/unused_labels.rs new file mode 100755 index 000000000..26b4d4a2f --- /dev/null +++ b/tests/compile-fail/unused_labels.rs @@ -0,0 +1,35 @@ +#![plugin(clippy)] +#![feature(plugin)] + +#![allow(dead_code, items_after_statements)] +#![deny(unused_label)] + +fn unused_label() { + 'label: for i in 1..2 { //~ERROR: unused label `'label` + if i > 4 { continue } + } +} + +fn foo() { + 'same_label_in_two_fns: loop { + break 'same_label_in_two_fns; + } +} + + +fn bla() { + 'a: loop { break } //~ERROR: unused label `'a` + fn blub() {} +} + +fn main() { + 'a: for _ in 0..10 { + while let Some(42) = None { + continue 'a; + } + } + + 'same_label_in_two_fns: loop { //~ERROR: unused label `'same_label_in_two_fns` + let _ = 1; + } +}