]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/unused_label.rs
Auto merge of #3597 - xfix:match-ergonomics, r=phansch
[rust.git] / clippy_lints / src / unused_label.rs
1 // Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9
10 use crate::utils::{in_macro, span_lint};
11 use rustc::hir;
12 use rustc::hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor};
13 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
14 use rustc::{declare_tool_lint, lint_array};
15 use rustc_data_structures::fx::FxHashMap;
16 use syntax::ast;
17 use syntax::source_map::Span;
18 use syntax::symbol::LocalInternedString;
19
20 /// **What it does:** Checks for unused labels.
21 ///
22 /// **Why is this bad?** Maybe the label should be used in which case there is
23 /// an error in the code or it should be removed.
24 ///
25 /// **Known problems:** Hopefully none.
26 ///
27 /// **Example:**
28 /// ```rust,ignore
29 /// fn unused_label() {
30 ///     'label: for i in 1..2 {
31 ///         if i > 4 { continue }
32 ///     }
33 /// ```
34 declare_clippy_lint! {
35     pub UNUSED_LABEL,
36     complexity,
37     "unused labels"
38 }
39
40 pub struct UnusedLabel;
41
42 struct UnusedLabelVisitor<'a, 'tcx: 'a> {
43     labels: FxHashMap<LocalInternedString, Span>,
44     cx: &'a LateContext<'a, 'tcx>,
45 }
46
47 impl LintPass for UnusedLabel {
48     fn get_lints(&self) -> LintArray {
49         lint_array!(UNUSED_LABEL)
50     }
51 }
52
53 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedLabel {
54     fn check_fn(
55         &mut self,
56         cx: &LateContext<'a, 'tcx>,
57         kind: FnKind<'tcx>,
58         decl: &'tcx hir::FnDecl,
59         body: &'tcx hir::Body,
60         span: Span,
61         fn_id: ast::NodeId,
62     ) {
63         if in_macro(span) {
64             return;
65         }
66
67         let mut v = UnusedLabelVisitor {
68             cx,
69             labels: FxHashMap::default(),
70         };
71         walk_fn(&mut v, kind, decl, body.id(), span, fn_id);
72
73         for (label, span) in v.labels {
74             span_lint(cx, UNUSED_LABEL, span, &format!("unused label `{}`", label));
75         }
76     }
77 }
78
79 impl<'a, 'tcx: 'a> Visitor<'tcx> for UnusedLabelVisitor<'a, 'tcx> {
80     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
81         match expr.node {
82             hir::ExprKind::Break(destination, _) | hir::ExprKind::Continue(destination) => {
83                 if let Some(label) = destination.label {
84                     self.labels.remove(&label.ident.as_str());
85                 }
86             },
87             hir::ExprKind::Loop(_, Some(label), _) | hir::ExprKind::While(_, _, Some(label)) => {
88                 self.labels.insert(label.ident.as_str(), expr.span);
89             },
90             _ => (),
91         }
92
93         walk_expr(self, expr);
94     }
95     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
96         NestedVisitorMap::All(&self.cx.tcx.hir())
97     }
98 }