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.
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.
11 use rustc
::hir
::pat_util
;
13 use rustc
::ty
::adjustment
;
14 use util
::nodemap
::FnvHashMap
;
15 use lint
::{LateContext, EarlyContext, LintContext, LintArray}
;
16 use lint
::{LintPass, EarlyLintPass, LateLintPass}
;
18 use std
::collections
::hash_map
::Entry
::{Occupied, Vacant}
;
22 use syntax
::feature_gate
::{KNOWN_ATTRIBUTES, AttributeType}
;
23 use syntax
::parse
::token
::keywords
;
27 use rustc_back
::slice
;
29 use rustc
::hir
::intravisit
::FnKind
;
34 "detect mut variables which don't need to be mutable"
37 #[derive(Copy, Clone)]
41 fn check_unused_mut_pat(&self, cx
: &LateContext
, pats
: &[P
<hir
::Pat
>]) {
42 // collect all mutable pattern and group their NodeIDs by their Identifier to
43 // avoid false warnings in match arms with multiple patterns
45 let mut mutables
= FnvHashMap();
47 pat_util
::pat_bindings(p
, |mode
, id
, _
, path1
| {
48 let name
= path1
.node
;
49 if let hir
::BindByValue(hir
::MutMutable
) = mode
{
50 if !name
.as_str().starts_with("_") {
51 match mutables
.entry(name
.0 as usize) {
52 Vacant(entry
) => { entry.insert(vec![id]); }
,
53 Occupied(mut entry
) => { entry.get_mut().push(id); }
,
60 let used_mutables
= cx
.tcx
.used_mut_nodes
.borrow();
61 for (_
, v
) in &mutables
{
62 if !v
.iter().any(|e
| used_mutables
.contains(e
)) {
63 cx
.span_lint(UNUSED_MUT
, cx
.tcx
.map
.span(v
[0]),
64 "variable does not need to be mutable");
70 impl LintPass
for UnusedMut
{
71 fn get_lints(&self) -> LintArray
{
72 lint_array
!(UNUSED_MUT
)
76 impl LateLintPass
for UnusedMut
{
77 fn check_expr(&mut self, cx
: &LateContext
, e
: &hir
::Expr
) {
78 if let hir
::ExprMatch(_
, ref arms
, _
) = e
.node
{
80 self.check_unused_mut_pat(cx
, &a
.pats
)
85 fn check_stmt(&mut self, cx
: &LateContext
, s
: &hir
::Stmt
) {
86 if let hir
::StmtDecl(ref d
, _
) = s
.node
{
87 if let hir
::DeclLocal(ref l
) = d
.node
{
88 self.check_unused_mut_pat(cx
, slice
::ref_slice(&l
.pat
));
93 fn check_fn(&mut self, cx
: &LateContext
,
94 _
: FnKind
, decl
: &hir
::FnDecl
,
95 _
: &hir
::Block
, _
: Span
, _
: ast
::NodeId
) {
96 for a
in &decl
.inputs
{
97 self.check_unused_mut_pat(cx
, slice
::ref_slice(&a
.pat
));
105 "unused result of a type flagged as #[must_use]"
111 "unused result of an expression in a statement"
114 #[derive(Copy, Clone)]
115 pub struct UnusedResults
;
117 impl LintPass
for UnusedResults
{
118 fn get_lints(&self) -> LintArray
{
119 lint_array
!(UNUSED_MUST_USE
, UNUSED_RESULTS
)
123 impl LateLintPass
for UnusedResults
{
124 fn check_stmt(&mut self, cx
: &LateContext
, s
: &hir
::Stmt
) {
125 let expr
= match s
.node
{
126 hir
::StmtSemi(ref expr
, _
) => &**expr
,
130 if let hir
::ExprRet(..) = expr
.node
{
134 let t
= cx
.tcx
.expr_ty(&expr
);
135 let warned
= match t
.sty
{
136 ty
::TyTuple(ref tys
) if tys
.is_empty() => return,
137 ty
::TyNever
=> return,
138 ty
::TyBool
=> return,
139 ty
::TyAdt(def
, _
) => {
140 let attrs
= cx
.tcx
.get_attrs(def
.did
);
141 check_must_use(cx
, &attrs
[..], s
.span
)
146 cx
.span_lint(UNUSED_RESULTS
, s
.span
, "unused result");
149 fn check_must_use(cx
: &LateContext
, attrs
: &[ast
::Attribute
], sp
: Span
) -> bool
{
151 if attr
.check_name("must_use") {
152 let mut msg
= "unused result which must be used".to_string();
153 // check for #[must_use="..."]
154 if let Some(s
) = attr
.value_str() {
158 cx
.span_lint(UNUSED_MUST_USE
, sp
, &msg
);
170 "unnecessary use of an `unsafe` block"
173 #[derive(Copy, Clone)]
174 pub struct UnusedUnsafe
;
176 impl LintPass
for UnusedUnsafe
{
177 fn get_lints(&self) -> LintArray
{
178 lint_array
!(UNUSED_UNSAFE
)
182 impl LateLintPass
for UnusedUnsafe
{
183 fn check_expr(&mut self, cx
: &LateContext
, e
: &hir
::Expr
) {
184 if let hir
::ExprBlock(ref blk
) = e
.node
{
185 // Don't warn about generated blocks, that'll just pollute the output.
186 if blk
.rules
== hir
::UnsafeBlock(hir
::UserProvided
) &&
187 !cx
.tcx
.used_unsafe
.borrow().contains(&blk
.id
) {
188 cx
.span_lint(UNUSED_UNSAFE
, blk
.span
, "unnecessary `unsafe` block");
197 "path statements with no effect"
200 #[derive(Copy, Clone)]
201 pub struct PathStatements
;
203 impl LintPass
for PathStatements
{
204 fn get_lints(&self) -> LintArray
{
205 lint_array
!(PATH_STATEMENTS
)
209 impl LateLintPass
for PathStatements
{
210 fn check_stmt(&mut self, cx
: &LateContext
, s
: &hir
::Stmt
) {
211 if let hir
::StmtSemi(ref expr
, _
) = s
.node
{
212 if let hir
::ExprPath(..) = expr
.node
{
213 cx
.span_lint(PATH_STATEMENTS
, s
.span
,
214 "path statement with no effect");
221 pub UNUSED_ATTRIBUTES
,
223 "detects attributes that were not used by the compiler"
226 #[derive(Copy, Clone)]
227 pub struct UnusedAttributes
;
229 impl LintPass
for UnusedAttributes
{
230 fn get_lints(&self) -> LintArray
{
231 lint_array
!(UNUSED_ATTRIBUTES
)
235 impl LateLintPass
for UnusedAttributes
{
236 fn check_attribute(&mut self, cx
: &LateContext
, attr
: &ast
::Attribute
) {
237 debug
!("checking attribute: {:?}", attr
);
239 // Note that check_name() marks the attribute as used if it matches.
240 for &(ref name
, ty
, _
) in KNOWN_ATTRIBUTES
{
242 AttributeType
::Whitelisted
if attr
.check_name(name
) => {
243 debug
!("{:?} is Whitelisted", name
);
250 let plugin_attributes
= cx
.sess().plugin_attributes
.borrow_mut();
251 for &(ref name
, ty
) in plugin_attributes
.iter() {
252 if ty
== AttributeType
::Whitelisted
&& attr
.check_name(&name
) {
253 debug
!("{:?} (plugin attr) is whitelisted with ty {:?}", name
, ty
);
258 if !attr
::is_used(attr
) {
259 debug
!("Emitting warning for: {:?}", attr
);
260 cx
.span_lint(UNUSED_ATTRIBUTES
, attr
.span
, "unused attribute");
261 // Is it a builtin attribute that must be used at the crate level?
262 let known_crate
= KNOWN_ATTRIBUTES
.iter().find(|&&(name
, ty
, _
)| {
263 attr
.name() == name
&&
264 ty
== AttributeType
::CrateLevel
267 // Has a plugin registered this attribute as one which must be used at
269 let plugin_crate
= plugin_attributes
.iter()
270 .find(|&&(ref x
, t
)| {
271 &*attr
.name() == x
&&
272 AttributeType
::CrateLevel
== t
274 if known_crate
|| plugin_crate
{
275 let msg
= match attr
.node
.style
{
276 ast
::AttrStyle
::Outer
=> "crate-level attribute should be an inner \
277 attribute: add an exclamation mark: #![foo]",
278 ast
::AttrStyle
::Inner
=> "crate-level attribute should be in the \
281 cx
.span_lint(UNUSED_ATTRIBUTES
, attr
.span
, msg
);
284 debug
!("Attr was used: {:?}", attr
);
292 "`if`, `match`, `while` and `return` do not need parentheses"
295 #[derive(Copy, Clone)]
296 pub struct UnusedParens
;
299 fn check_unused_parens_core(&self, cx
: &EarlyContext
, value
: &ast
::Expr
, msg
: &str,
300 struct_lit_needs_parens
: bool
) {
301 if let ast
::ExprKind
::Paren(ref inner
) = value
.node
{
302 let necessary
= struct_lit_needs_parens
&& contains_exterior_struct_lit(&inner
);
304 cx
.span_lint(UNUSED_PARENS
, value
.span
,
305 &format
!("unnecessary parentheses around {}", msg
))
309 /// Expressions that syntactically contain an "exterior" struct
310 /// literal i.e. not surrounded by any parens or other
311 /// delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo
312 /// == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X {
313 /// y: 1 }) == foo` does not.
314 fn contains_exterior_struct_lit(value
: &ast
::Expr
) -> bool
{
316 ast
::ExprKind
::Struct(..) => true,
318 ast
::ExprKind
::Assign(ref lhs
, ref rhs
) |
319 ast
::ExprKind
::AssignOp(_
, ref lhs
, ref rhs
) |
320 ast
::ExprKind
::Binary(_
, ref lhs
, ref rhs
) => {
321 // X { y: 1 } + X { y: 2 }
322 contains_exterior_struct_lit(&lhs
) ||
323 contains_exterior_struct_lit(&rhs
)
325 ast
::ExprKind
::Unary(_
, ref x
) |
326 ast
::ExprKind
::Cast(ref x
, _
) |
327 ast
::ExprKind
::Type(ref x
, _
) |
328 ast
::ExprKind
::Field(ref x
, _
) |
329 ast
::ExprKind
::TupField(ref x
, _
) |
330 ast
::ExprKind
::Index(ref x
, _
) => {
331 // &X { y: 1 }, X { y: 1 }.y
332 contains_exterior_struct_lit(&x
)
335 ast
::ExprKind
::MethodCall(.., ref exprs
) => {
336 // X { y: 1 }.bar(...)
337 contains_exterior_struct_lit(&exprs
[0])
346 impl LintPass
for UnusedParens
{
347 fn get_lints(&self) -> LintArray
{
348 lint_array
!(UNUSED_PARENS
)
352 impl EarlyLintPass
for UnusedParens
{
353 fn check_expr(&mut self, cx
: &EarlyContext
, e
: &ast
::Expr
) {
354 use syntax
::ast
::ExprKind
::*;
355 let (value
, msg
, struct_lit_needs_parens
) = match e
.node
{
356 If(ref cond
, ..) => (cond
, "`if` condition", true),
357 While(ref cond
, ..) => (cond
, "`while` condition", true),
358 IfLet(_
, ref cond
, ..) => (cond
, "`if let` head expression", true),
359 WhileLet(_
, ref cond
, ..) => (cond
, "`while let` head expression", true),
360 ForLoop(_
, ref cond
, ..) => (cond
, "`for` head expression", true),
361 Match(ref head
, _
) => (head
, "`match` head expression", true),
362 Ret(Some(ref value
)) => (value
, "`return` value", false),
363 Assign(_
, ref value
) => (value
, "assigned value", false),
364 AssignOp(.., ref value
) => (value
, "assigned value", false),
365 InPlace(_
, ref value
) => (value
, "emplacement value", false),
368 self.check_unused_parens_core(cx
, &value
, msg
, struct_lit_needs_parens
);
371 fn check_stmt(&mut self, cx
: &EarlyContext
, s
: &ast
::Stmt
) {
372 let (value
, msg
) = match s
.node
{
373 ast
::StmtKind
::Local(ref local
) => match local
.init
{
374 Some(ref value
) => (value
, "assigned value"),
379 self.check_unused_parens_core(cx
, &value
, msg
, false);
384 UNUSED_IMPORT_BRACES
,
386 "unnecessary braces around an imported item"
389 #[derive(Copy, Clone)]
390 pub struct UnusedImportBraces
;
392 impl LintPass
for UnusedImportBraces
{
393 fn get_lints(&self) -> LintArray
{
394 lint_array
!(UNUSED_IMPORT_BRACES
)
398 impl LateLintPass
for UnusedImportBraces
{
399 fn check_item(&mut self, cx
: &LateContext
, item
: &hir
::Item
) {
400 if let hir
::ItemUse(ref view_path
) = item
.node
{
401 if let hir
::ViewPathList(_
, ref items
) = view_path
.node
{
402 if items
.len() == 1 && items
[0].node
.name
!= keywords
::SelfValue
.name() {
403 let msg
= format
!("braces around {} is unnecessary", items
[0].node
.name
);
404 cx
.span_lint(UNUSED_IMPORT_BRACES
, item
.span
, &msg
);
414 "detects unnecessary allocations that can be eliminated"
417 #[derive(Copy, Clone)]
418 pub struct UnusedAllocation
;
420 impl LintPass
for UnusedAllocation
{
421 fn get_lints(&self) -> LintArray
{
422 lint_array
!(UNUSED_ALLOCATION
)
426 impl LateLintPass
for UnusedAllocation
{
427 fn check_expr(&mut self, cx
: &LateContext
, e
: &hir
::Expr
) {
429 hir
::ExprBox(_
) => {}
433 if let Some(adjustment
) = cx
.tcx
.tables
.borrow().adjustments
.get(&e
.id
) {
434 if let adjustment
::AdjustDerefRef(adjustment
::AutoDerefRef
{
438 &Some(adjustment
::AutoPtr(_
, hir
::MutImmutable
)) => {
439 cx
.span_lint(UNUSED_ALLOCATION
, e
.span
,
440 "unnecessary allocation, use & instead");
442 &Some(adjustment
::AutoPtr(_
, hir
::MutMutable
)) => {
443 cx
.span_lint(UNUSED_ALLOCATION
, e
.span
,
444 "unnecessary allocation, use &mut instead");