]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/unused_label.rs
remove nondeterminism by adjusting thresholds
[rust.git] / clippy_lints / src / unused_label.rs
1 use rustc::lint::*;
2 use rustc::hir;
3 use rustc::hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn, NestedVisitorMap};
4 use std::collections::HashMap;
5 use syntax::ast;
6 use syntax::codemap::Span;
7 use syntax::symbol::InternedString;
8 use utils::{in_macro, span_lint};
9
10 /// **What it does:** Checks for unused labels.
11 ///
12 /// **Why is this bad?** Maybe the label should be used in which case there is
13 /// an error in the 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 labels"
28 }
29
30 pub struct UnusedLabel;
31
32 struct UnusedLabelVisitor<'a, 'tcx: 'a> {
33     labels: HashMap<InternedString, Span>,
34     cx: &'a LateContext<'a, 'tcx>,
35 }
36
37 impl LintPass for UnusedLabel {
38     fn get_lints(&self) -> LintArray {
39         lint_array!(UNUSED_LABEL)
40     }
41 }
42
43 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedLabel {
44     fn check_fn(
45         &mut self, cx: &LateContext<'a, 'tcx>, kind: FnKind<'tcx>, decl: &'tcx hir::FnDecl, body: &'tcx hir::Expr,
46         span: Span, fn_id: ast::NodeId
47     ) {
48         if in_macro(cx, span) {
49             return;
50         }
51
52         let mut v = UnusedLabelVisitor {
53             cx: cx,
54             labels: HashMap::new(),
55         };
56         walk_fn(&mut v, kind, decl, body.expr_id(), span, fn_id);
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<'a, 'tcx: 'a> Visitor<'tcx> for UnusedLabelVisitor<'a, 'tcx> {
65     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
66         match expr.node {
67             hir::ExprBreak(Some(label), _) |
68             hir::ExprAgain(Some(label)) => {
69                 self.labels.remove(&label.name.as_str());
70             },
71             hir::ExprLoop(_, Some(label), _) |
72             hir::ExprWhile(_, _, Some(label)) => {
73                 self.labels.insert(label.node.as_str(), expr.span);
74             },
75             _ => (),
76         }
77
78         walk_expr(self, expr);
79     }
80     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
81         NestedVisitorMap::All(&self.cx.tcx.map)
82     }
83 }