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}
;
21 use syntax
::attr
::{self, AttrMetaMethods}
;
22 use syntax
::feature_gate
::{KNOWN_ATTRIBUTES, AttributeType}
;
26 use rustc_back
::slice
;
28 use rustc
::hir
::intravisit
::FnKind
;
33 "detect mut variables which don't need to be mutable"
36 #[derive(Copy, Clone)]
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
44 let mut mutables
= FnvHashMap();
46 pat_util
::pat_bindings(p
, |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
.0 as usize) {
51 Vacant(entry
) => { entry.insert(vec![id]); }
,
52 Occupied(mut entry
) => { entry.get_mut().push(id); }
,
59 let used_mutables
= cx
.tcx
.used_mut_nodes
.borrow();
60 for (_
, v
) in &mutables
{
61 if !v
.iter().any(|e
| used_mutables
.contains(e
)) {
62 cx
.span_lint(UNUSED_MUT
, cx
.tcx
.map
.span(v
[0]),
63 "variable does not need to be mutable");
69 impl LintPass
for UnusedMut
{
70 fn get_lints(&self) -> LintArray
{
71 lint_array
!(UNUSED_MUT
)
75 impl LateLintPass
for UnusedMut
{
76 fn check_expr(&mut self, cx
: &LateContext
, e
: &hir
::Expr
) {
77 if let hir
::ExprMatch(_
, ref arms
, _
) = e
.node
{
79 self.check_unused_mut_pat(cx
, &a
.pats
)
84 fn check_stmt(&mut self, cx
: &LateContext
, s
: &hir
::Stmt
) {
85 if let hir
::StmtDecl(ref d
, _
) = s
.node
{
86 if let hir
::DeclLocal(ref l
) = d
.node
{
87 self.check_unused_mut_pat(cx
, slice
::ref_slice(&l
.pat
));
92 fn check_fn(&mut self, cx
: &LateContext
,
93 _
: FnKind
, decl
: &hir
::FnDecl
,
94 _
: &hir
::Block
, _
: Span
, _
: ast
::NodeId
) {
95 for a
in &decl
.inputs
{
96 self.check_unused_mut_pat(cx
, slice
::ref_slice(&a
.pat
));
104 "unused result of a type flagged as #[must_use]"
110 "unused result of an expression in a statement"
113 #[derive(Copy, Clone)]
114 pub struct UnusedResults
;
116 impl LintPass
for UnusedResults
{
117 fn get_lints(&self) -> LintArray
{
118 lint_array
!(UNUSED_MUST_USE
, UNUSED_RESULTS
)
122 impl LateLintPass
for UnusedResults
{
123 fn check_stmt(&mut self, cx
: &LateContext
, s
: &hir
::Stmt
) {
124 let expr
= match s
.node
{
125 hir
::StmtSemi(ref expr
, _
) => &**expr
,
129 if let hir
::ExprRet(..) = expr
.node
{
133 let t
= cx
.tcx
.expr_ty(&expr
);
134 let warned
= match t
.sty
{
135 ty
::TyTuple(ref tys
) if tys
.is_empty() => return,
136 ty
::TyNever
=> return,
137 ty
::TyBool
=> return,
138 ty
::TyStruct(def
, _
) |
139 ty
::TyEnum(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 // Note that check_name() marks the attribute as used if it matches.
238 for &(ref name
, ty
, _
) in KNOWN_ATTRIBUTES
{
240 AttributeType
::Whitelisted
if attr
.check_name(name
) => {
247 let plugin_attributes
= cx
.sess().plugin_attributes
.borrow_mut();
248 for &(ref name
, ty
) in plugin_attributes
.iter() {
249 if ty
== AttributeType
::Whitelisted
&& attr
.check_name(&name
) {
254 if !attr
::is_used(attr
) {
255 cx
.span_lint(UNUSED_ATTRIBUTES
, attr
.span
, "unused attribute");
256 // Is it a builtin attribute that must be used at the crate level?
257 let known_crate
= KNOWN_ATTRIBUTES
.iter().find(|&&(name
, ty
, _
)| {
258 attr
.name() == name
&&
259 ty
== AttributeType
::CrateLevel
262 // Has a plugin registered this attribute as one which must be used at
264 let plugin_crate
= plugin_attributes
.iter()
265 .find(|&&(ref x
, t
)| {
266 &*attr
.name() == x
&&
267 AttributeType
::CrateLevel
== t
269 if known_crate
|| plugin_crate
{
270 let msg
= match attr
.node
.style
{
271 ast
::AttrStyle
::Outer
=> "crate-level attribute should be an inner \
272 attribute: add an exclamation mark: #![foo]",
273 ast
::AttrStyle
::Inner
=> "crate-level attribute should be in the \
276 cx
.span_lint(UNUSED_ATTRIBUTES
, attr
.span
, msg
);
285 "`if`, `match`, `while` and `return` do not need parentheses"
288 #[derive(Copy, Clone)]
289 pub struct UnusedParens
;
292 fn check_unused_parens_core(&self, cx
: &EarlyContext
, value
: &ast
::Expr
, msg
: &str,
293 struct_lit_needs_parens
: bool
) {
294 if let ast
::ExprKind
::Paren(ref inner
) = value
.node
{
295 let necessary
= struct_lit_needs_parens
&& contains_exterior_struct_lit(&inner
);
297 cx
.span_lint(UNUSED_PARENS
, value
.span
,
298 &format
!("unnecessary parentheses around {}", msg
))
302 /// Expressions that syntactically contain an "exterior" struct
303 /// literal i.e. not surrounded by any parens or other
304 /// delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo
305 /// == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X {
306 /// y: 1 }) == foo` does not.
307 fn contains_exterior_struct_lit(value
: &ast
::Expr
) -> bool
{
309 ast
::ExprKind
::Struct(..) => true,
311 ast
::ExprKind
::Assign(ref lhs
, ref rhs
) |
312 ast
::ExprKind
::AssignOp(_
, ref lhs
, ref rhs
) |
313 ast
::ExprKind
::Binary(_
, ref lhs
, ref rhs
) => {
314 // X { y: 1 } + X { y: 2 }
315 contains_exterior_struct_lit(&lhs
) ||
316 contains_exterior_struct_lit(&rhs
)
318 ast
::ExprKind
::Unary(_
, ref x
) |
319 ast
::ExprKind
::Cast(ref x
, _
) |
320 ast
::ExprKind
::Type(ref x
, _
) |
321 ast
::ExprKind
::Field(ref x
, _
) |
322 ast
::ExprKind
::TupField(ref x
, _
) |
323 ast
::ExprKind
::Index(ref x
, _
) => {
324 // &X { y: 1 }, X { y: 1 }.y
325 contains_exterior_struct_lit(&x
)
328 ast
::ExprKind
::MethodCall(_
, _
, ref exprs
) => {
329 // X { y: 1 }.bar(...)
330 contains_exterior_struct_lit(&exprs
[0])
339 impl LintPass
for UnusedParens
{
340 fn get_lints(&self) -> LintArray
{
341 lint_array
!(UNUSED_PARENS
)
345 impl EarlyLintPass
for UnusedParens
{
346 fn check_expr(&mut self, cx
: &EarlyContext
, e
: &ast
::Expr
) {
347 use syntax
::ast
::ExprKind
::*;
348 let (value
, msg
, struct_lit_needs_parens
) = match e
.node
{
349 If(ref cond
, _
, _
) => (cond
, "`if` condition", true),
350 While(ref cond
, _
, _
) => (cond
, "`while` condition", true),
351 IfLet(_
, ref cond
, _
, _
) => (cond
, "`if let` head expression", true),
352 WhileLet(_
, ref cond
, _
, _
) => (cond
, "`while let` head expression", true),
353 ForLoop(_
, ref cond
, _
, _
) => (cond
, "`for` head expression", true),
354 Match(ref head
, _
) => (head
, "`match` head expression", true),
355 Ret(Some(ref value
)) => (value
, "`return` value", false),
356 Assign(_
, ref value
) => (value
, "assigned value", false),
357 AssignOp(_
, _
, ref value
) => (value
, "assigned value", false),
358 InPlace(_
, ref value
) => (value
, "emplacement value", false),
361 self.check_unused_parens_core(cx
, &value
, msg
, struct_lit_needs_parens
);
364 fn check_stmt(&mut self, cx
: &EarlyContext
, s
: &ast
::Stmt
) {
365 let (value
, msg
) = match s
.node
{
366 ast
::StmtKind
::Local(ref local
) => match local
.init
{
367 Some(ref value
) => (value
, "assigned value"),
372 self.check_unused_parens_core(cx
, &value
, msg
, false);
377 UNUSED_IMPORT_BRACES
,
379 "unnecessary braces around an imported item"
382 #[derive(Copy, Clone)]
383 pub struct UnusedImportBraces
;
385 impl LintPass
for UnusedImportBraces
{
386 fn get_lints(&self) -> LintArray
{
387 lint_array
!(UNUSED_IMPORT_BRACES
)
391 impl LateLintPass
for UnusedImportBraces
{
392 fn check_item(&mut self, cx
: &LateContext
, item
: &hir
::Item
) {
393 if let hir
::ItemUse(ref view_path
) = item
.node
{
394 if let hir
::ViewPathList(_
, ref items
) = view_path
.node
{
395 if items
.len() == 1 {
396 if let hir
::PathListIdent {ref name, ..}
= items
[0].node
{
397 let m
= format
!("braces around {} is unnecessary",
399 cx
.span_lint(UNUSED_IMPORT_BRACES
, item
.span
,
411 "detects unnecessary allocations that can be eliminated"
414 #[derive(Copy, Clone)]
415 pub struct UnusedAllocation
;
417 impl LintPass
for UnusedAllocation
{
418 fn get_lints(&self) -> LintArray
{
419 lint_array
!(UNUSED_ALLOCATION
)
423 impl LateLintPass
for UnusedAllocation
{
424 fn check_expr(&mut self, cx
: &LateContext
, e
: &hir
::Expr
) {
426 hir
::ExprBox(_
) => {}
430 if let Some(adjustment
) = cx
.tcx
.tables
.borrow().adjustments
.get(&e
.id
) {
431 if let adjustment
::AdjustDerefRef(adjustment
::AutoDerefRef
{
435 &Some(adjustment
::AutoPtr(_
, hir
::MutImmutable
)) => {
436 cx
.span_lint(UNUSED_ALLOCATION
, e
.span
,
437 "unnecessary allocation, use & instead");
439 &Some(adjustment
::AutoPtr(_
, hir
::MutMutable
)) => {
440 cx
.span_lint(UNUSED_ALLOCATION
, e
.span
,
441 "unnecessary allocation, use &mut instead");