]> git.lizzy.rs Git - rust.git/blob - src/librustc_lint/unused.rs
Rollup merge of #40521 - TimNN:panic-free-shift, r=alexcrichton
[rust.git] / src / librustc_lint / unused.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use rustc::ty;
12 use rustc::ty::adjustment;
13 use util::nodemap::FxHashMap;
14 use lint::{LateContext, EarlyContext, LintContext, LintArray};
15 use lint::{LintPass, EarlyLintPass, LateLintPass};
16
17 use std::collections::hash_map::Entry::{Occupied, Vacant};
18
19 use syntax::ast;
20 use syntax::attr;
21 use syntax::feature_gate::{BUILTIN_ATTRIBUTES, AttributeType};
22 use syntax::symbol::keywords;
23 use syntax::ptr::P;
24 use syntax_pos::Span;
25
26 use rustc_back::slice;
27 use rustc::hir;
28 use rustc::hir::intravisit::FnKind;
29
30 declare_lint! {
31     pub UNUSED_MUT,
32     Warn,
33     "detect mut variables which don't need to be mutable"
34 }
35
36 #[derive(Copy, Clone)]
37 pub struct UnusedMut;
38
39 impl UnusedMut {
40     fn check_unused_mut_pat(&self, cx: &LateContext, pats: &[P<hir::Pat>]) {
41         // collect all mutable pattern and group their NodeIDs by their Identifier to
42         // avoid false warnings in match arms with multiple patterns
43
44         let mut mutables = FxHashMap();
45         for p in pats {
46             p.each_binding(|mode, id, _, path1| {
47                 let name = path1.node;
48                 if let hir::BindByValue(hir::MutMutable) = mode {
49                     if !name.as_str().starts_with("_") {
50                         match mutables.entry(name) {
51                             Vacant(entry) => {
52                                 entry.insert(vec![id]);
53                             }
54                             Occupied(mut entry) => {
55                                 entry.get_mut().push(id);
56                             }
57                         }
58                     }
59                 }
60             });
61         }
62
63         let used_mutables = cx.tcx.used_mut_nodes.borrow();
64         for (_, v) in &mutables {
65             if !v.iter().any(|e| used_mutables.contains(e)) {
66                 cx.span_lint(UNUSED_MUT,
67                              cx.tcx.hir.span(v[0]),
68                              "variable does not need to be mutable");
69             }
70         }
71     }
72 }
73
74 impl LintPass for UnusedMut {
75     fn get_lints(&self) -> LintArray {
76         lint_array!(UNUSED_MUT)
77     }
78 }
79
80 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedMut {
81     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
82         if let hir::ExprMatch(_, ref arms, _) = e.node {
83             for a in arms {
84                 self.check_unused_mut_pat(cx, &a.pats)
85             }
86         }
87     }
88
89     fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
90         if let hir::StmtDecl(ref d, _) = s.node {
91             if let hir::DeclLocal(ref l) = d.node {
92                 self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat));
93             }
94         }
95     }
96
97     fn check_fn(&mut self,
98                 cx: &LateContext,
99                 _: FnKind,
100                 _: &hir::FnDecl,
101                 body: &hir::Body,
102                 _: Span,
103                 _: ast::NodeId) {
104         for a in &body.arguments {
105             self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
106         }
107     }
108 }
109
110 declare_lint! {
111     pub UNUSED_MUST_USE,
112     Warn,
113     "unused result of a type flagged as #[must_use]"
114 }
115
116 declare_lint! {
117     pub UNUSED_RESULTS,
118     Allow,
119     "unused result of an expression in a statement"
120 }
121
122 #[derive(Copy, Clone)]
123 pub struct UnusedResults;
124
125 impl LintPass for UnusedResults {
126     fn get_lints(&self) -> LintArray {
127         lint_array!(UNUSED_MUST_USE, UNUSED_RESULTS)
128     }
129 }
130
131 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
132     fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
133         let expr = match s.node {
134             hir::StmtSemi(ref expr, _) => &**expr,
135             _ => return,
136         };
137
138         if let hir::ExprRet(..) = expr.node {
139             return;
140         }
141
142         let t = cx.tables.expr_ty(&expr);
143         let warned = match t.sty {
144             ty::TyTuple(ref tys, _) if tys.is_empty() => return,
145             ty::TyNever => return,
146             ty::TyBool => return,
147             ty::TyAdt(def, _) => {
148                 let attrs = cx.tcx.get_attrs(def.did);
149                 check_must_use(cx, &attrs[..], s.span)
150             }
151             _ => false,
152         };
153         if !warned {
154             cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
155         }
156
157         fn check_must_use(cx: &LateContext, attrs: &[ast::Attribute], sp: Span) -> bool {
158             for attr in attrs {
159                 if attr.check_name("must_use") {
160                     let mut msg = "unused result which must be used".to_string();
161                     // check for #[must_use="..."]
162                     if let Some(s) = attr.value_str() {
163                         msg.push_str(": ");
164                         msg.push_str(&s.as_str());
165                     }
166                     cx.span_lint(UNUSED_MUST_USE, sp, &msg);
167                     return true;
168                 }
169             }
170             false
171         }
172     }
173 }
174
175 declare_lint! {
176     pub UNUSED_UNSAFE,
177     Warn,
178     "unnecessary use of an `unsafe` block"
179 }
180
181 #[derive(Copy, Clone)]
182 pub struct UnusedUnsafe;
183
184 impl LintPass for UnusedUnsafe {
185     fn get_lints(&self) -> LintArray {
186         lint_array!(UNUSED_UNSAFE)
187     }
188 }
189
190 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedUnsafe {
191     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
192         /// Return the NodeId for an enclosing scope that is also `unsafe`
193         fn is_enclosed(cx: &LateContext, id: ast::NodeId) -> Option<(String, ast::NodeId)> {
194             let parent_id = cx.tcx.hir.get_parent_node(id);
195             if parent_id != id {
196                 if cx.tcx.used_unsafe.borrow().contains(&parent_id) {
197                     Some(("block".to_string(), parent_id))
198                 } else if let Some(hir::map::NodeItem(&hir::Item {
199                     node: hir::ItemFn(_, hir::Unsafety::Unsafe, _, _, _, _),
200                     ..
201                 })) = cx.tcx.hir.find(parent_id) {
202                     Some(("fn".to_string(), parent_id))
203                 } else {
204                     is_enclosed(cx, parent_id)
205                 }
206             } else {
207                 None
208             }
209         }
210         if let hir::ExprBlock(ref blk) = e.node {
211             // Don't warn about generated blocks, that'll just pollute the output.
212             if blk.rules == hir::UnsafeBlock(hir::UserProvided) &&
213                !cx.tcx.used_unsafe.borrow().contains(&blk.id) {
214
215                 let mut db = cx.struct_span_lint(UNUSED_UNSAFE, blk.span,
216                                                  "unnecessary `unsafe` block");
217
218                 db.span_label(blk.span, &"unnecessary `unsafe` block");
219                 if let Some((kind, id)) = is_enclosed(cx, blk.id) {
220                     db.span_note(cx.tcx.hir.span(id),
221                                  &format!("because it's nested under this `unsafe` {}", kind));
222                 }
223                 db.emit();
224             }
225         }
226     }
227 }
228
229 declare_lint! {
230     pub PATH_STATEMENTS,
231     Warn,
232     "path statements with no effect"
233 }
234
235 #[derive(Copy, Clone)]
236 pub struct PathStatements;
237
238 impl LintPass for PathStatements {
239     fn get_lints(&self) -> LintArray {
240         lint_array!(PATH_STATEMENTS)
241     }
242 }
243
244 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements {
245     fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
246         if let hir::StmtSemi(ref expr, _) = s.node {
247             if let hir::ExprPath(_) = expr.node {
248                 cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
249             }
250         }
251     }
252 }
253
254 declare_lint! {
255     pub UNUSED_ATTRIBUTES,
256     Warn,
257     "detects attributes that were not used by the compiler"
258 }
259
260 #[derive(Copy, Clone)]
261 pub struct UnusedAttributes;
262
263 impl LintPass for UnusedAttributes {
264     fn get_lints(&self) -> LintArray {
265         lint_array!(UNUSED_ATTRIBUTES)
266     }
267 }
268
269 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
270     fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
271         debug!("checking attribute: {:?}", attr);
272         let name = unwrap_or!(attr.name(), return);
273
274         // Note that check_name() marks the attribute as used if it matches.
275         for &(ref name, ty, _) in BUILTIN_ATTRIBUTES {
276             match ty {
277                 AttributeType::Whitelisted if attr.check_name(name) => {
278                     debug!("{:?} is Whitelisted", name);
279                     break;
280                 }
281                 _ => (),
282             }
283         }
284
285         let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
286         for &(ref name, ty) in plugin_attributes.iter() {
287             if ty == AttributeType::Whitelisted && attr.check_name(&name) {
288                 debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty);
289                 break;
290             }
291         }
292
293         if !attr::is_used(attr) {
294             debug!("Emitting warning for: {:?}", attr);
295             cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
296             // Is it a builtin attribute that must be used at the crate level?
297             let known_crate = BUILTIN_ATTRIBUTES.iter()
298                 .find(|&&(builtin, ty, _)| name == builtin && ty == AttributeType::CrateLevel)
299                 .is_some();
300
301             // Has a plugin registered this attribute as one which must be used at
302             // the crate level?
303             let plugin_crate = plugin_attributes.iter()
304                 .find(|&&(ref x, t)| name == &**x && AttributeType::CrateLevel == t)
305                 .is_some();
306             if known_crate || plugin_crate {
307                 let msg = match attr.style {
308                     ast::AttrStyle::Outer => {
309                         "crate-level attribute should be an inner attribute: add an exclamation \
310                          mark: #![foo]"
311                     }
312                     ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
313                 };
314                 cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
315             }
316         } else {
317             debug!("Attr was used: {:?}", attr);
318         }
319     }
320 }
321
322 declare_lint! {
323     UNUSED_PARENS,
324     Warn,
325     "`if`, `match`, `while` and `return` do not need parentheses"
326 }
327
328 #[derive(Copy, Clone)]
329 pub struct UnusedParens;
330
331 impl UnusedParens {
332     fn check_unused_parens_core(&self,
333                                 cx: &EarlyContext,
334                                 value: &ast::Expr,
335                                 msg: &str,
336                                 struct_lit_needs_parens: bool) {
337         if let ast::ExprKind::Paren(ref inner) = value.node {
338             let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&inner);
339             if !necessary {
340                 cx.span_lint(UNUSED_PARENS,
341                              value.span,
342                              &format!("unnecessary parentheses around {}", msg))
343             }
344         }
345
346         /// Expressions that syntactically contain an "exterior" struct
347         /// literal i.e. not surrounded by any parens or other
348         /// delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo
349         /// == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X {
350         /// y: 1 }) == foo` does not.
351         fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
352             match value.node {
353                 ast::ExprKind::Struct(..) => true,
354
355                 ast::ExprKind::Assign(ref lhs, ref rhs) |
356                 ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
357                 ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
358                     // X { y: 1 } + X { y: 2 }
359                     contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
360                 }
361                 ast::ExprKind::Unary(_, ref x) |
362                 ast::ExprKind::Cast(ref x, _) |
363                 ast::ExprKind::Type(ref x, _) |
364                 ast::ExprKind::Field(ref x, _) |
365                 ast::ExprKind::TupField(ref x, _) |
366                 ast::ExprKind::Index(ref x, _) => {
367                     // &X { y: 1 }, X { y: 1 }.y
368                     contains_exterior_struct_lit(&x)
369                 }
370
371                 ast::ExprKind::MethodCall(.., ref exprs) => {
372                     // X { y: 1 }.bar(...)
373                     contains_exterior_struct_lit(&exprs[0])
374                 }
375
376                 _ => false,
377             }
378         }
379     }
380 }
381
382 impl LintPass for UnusedParens {
383     fn get_lints(&self) -> LintArray {
384         lint_array!(UNUSED_PARENS)
385     }
386 }
387
388 impl EarlyLintPass for UnusedParens {
389     fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) {
390         use syntax::ast::ExprKind::*;
391         let (value, msg, struct_lit_needs_parens) = match e.node {
392             If(ref cond, ..) => (cond, "`if` condition", true),
393             While(ref cond, ..) => (cond, "`while` condition", true),
394             IfLet(_, ref cond, ..) => (cond, "`if let` head expression", true),
395             WhileLet(_, ref cond, ..) => (cond, "`while let` head expression", true),
396             ForLoop(_, ref cond, ..) => (cond, "`for` head expression", true),
397             Match(ref head, _) => (head, "`match` head expression", true),
398             Ret(Some(ref value)) => (value, "`return` value", false),
399             Assign(_, ref value) => (value, "assigned value", false),
400             AssignOp(.., ref value) => (value, "assigned value", false),
401             InPlace(_, ref value) => (value, "emplacement value", false),
402             _ => return,
403         };
404         self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
405     }
406
407     fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) {
408         let (value, msg) = match s.node {
409             ast::StmtKind::Local(ref local) => {
410                 match local.init {
411                     Some(ref value) => (value, "assigned value"),
412                     None => return,
413                 }
414             }
415             _ => return,
416         };
417         self.check_unused_parens_core(cx, &value, msg, false);
418     }
419 }
420
421 declare_lint! {
422     UNUSED_IMPORT_BRACES,
423     Allow,
424     "unnecessary braces around an imported item"
425 }
426
427 #[derive(Copy, Clone)]
428 pub struct UnusedImportBraces;
429
430 impl LintPass for UnusedImportBraces {
431     fn get_lints(&self) -> LintArray {
432         lint_array!(UNUSED_IMPORT_BRACES)
433     }
434 }
435
436 impl EarlyLintPass for UnusedImportBraces {
437     fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) {
438         if let ast::ItemKind::Use(ref view_path) = item.node {
439             if let ast::ViewPathList(_, ref items) = view_path.node {
440                 if items.len() == 1 && items[0].node.name.name != keywords::SelfValue.name() {
441                     let msg = format!("braces around {} is unnecessary", items[0].node.name);
442                     cx.span_lint(UNUSED_IMPORT_BRACES, item.span, &msg);
443                 }
444             }
445         }
446     }
447 }
448
449 declare_lint! {
450     UNUSED_ALLOCATION,
451     Warn,
452     "detects unnecessary allocations that can be eliminated"
453 }
454
455 #[derive(Copy, Clone)]
456 pub struct UnusedAllocation;
457
458 impl LintPass for UnusedAllocation {
459     fn get_lints(&self) -> LintArray {
460         lint_array!(UNUSED_ALLOCATION)
461     }
462 }
463
464 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation {
465     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
466         match e.node {
467             hir::ExprBox(_) => {}
468             _ => return,
469         }
470
471         if let Some(adjustment) = cx.tables.adjustments.get(&e.id) {
472             if let adjustment::Adjust::DerefRef { autoref, .. } = adjustment.kind {
473                 match autoref {
474                     Some(adjustment::AutoBorrow::Ref(_, hir::MutImmutable)) => {
475                         cx.span_lint(UNUSED_ALLOCATION,
476                                      e.span,
477                                      "unnecessary allocation, use & instead");
478                     }
479                     Some(adjustment::AutoBorrow::Ref(_, hir::MutMutable)) => {
480                         cx.span_lint(UNUSED_ALLOCATION,
481                                      e.span,
482                                      "unnecessary allocation, use &mut instead");
483                     }
484                     _ => (),
485                 }
486             }
487         }
488     }
489 }