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
::codemap
::Span
;
23 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(&cx
.tcx
.def_map
, 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
::TyBool
=> return,
137 ty
::TyStruct(def
, _
) |
138 ty
::TyEnum(def
, _
) => {
139 let attrs
= cx
.tcx
.get_attrs(def
.did
);
140 check_must_use(cx
, &attrs
[..], s
.span
)
145 cx
.span_lint(UNUSED_RESULTS
, s
.span
, "unused result");
148 fn check_must_use(cx
: &LateContext
, attrs
: &[ast
::Attribute
], sp
: Span
) -> bool
{
150 if attr
.check_name("must_use") {
151 let mut msg
= "unused result which must be used".to_string();
152 // check for #[must_use="..."]
153 match attr
.value_str() {
160 cx
.span_lint(UNUSED_MUST_USE
, sp
, &msg
);
172 "unnecessary use of an `unsafe` block"
175 #[derive(Copy, Clone)]
176 pub struct UnusedUnsafe
;
178 impl LintPass
for UnusedUnsafe
{
179 fn get_lints(&self) -> LintArray
{
180 lint_array
!(UNUSED_UNSAFE
)
184 impl LateLintPass
for UnusedUnsafe
{
185 fn check_expr(&mut self, cx
: &LateContext
, e
: &hir
::Expr
) {
186 if let hir
::ExprBlock(ref blk
) = e
.node
{
187 // Don't warn about generated blocks, that'll just pollute the output.
188 if blk
.rules
== hir
::UnsafeBlock(hir
::UserProvided
) &&
189 !cx
.tcx
.used_unsafe
.borrow().contains(&blk
.id
) {
190 cx
.span_lint(UNUSED_UNSAFE
, blk
.span
, "unnecessary `unsafe` block");
199 "path statements with no effect"
202 #[derive(Copy, Clone)]
203 pub struct PathStatements
;
205 impl LintPass
for PathStatements
{
206 fn get_lints(&self) -> LintArray
{
207 lint_array
!(PATH_STATEMENTS
)
211 impl LateLintPass
for PathStatements
{
212 fn check_stmt(&mut self, cx
: &LateContext
, s
: &hir
::Stmt
) {
213 if let hir
::StmtSemi(ref expr
, _
) = s
.node
{
214 if let hir
::ExprPath(..) = expr
.node
{
215 cx
.span_lint(PATH_STATEMENTS
, s
.span
,
216 "path statement with no effect");
223 pub UNUSED_ATTRIBUTES
,
225 "detects attributes that were not used by the compiler"
228 #[derive(Copy, Clone)]
229 pub struct UnusedAttributes
;
231 impl LintPass
for UnusedAttributes
{
232 fn get_lints(&self) -> LintArray
{
233 lint_array
!(UNUSED_ATTRIBUTES
)
237 impl LateLintPass
for UnusedAttributes
{
238 fn check_attribute(&mut self, cx
: &LateContext
, attr
: &ast
::Attribute
) {
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
) => {
249 let plugin_attributes
= cx
.sess().plugin_attributes
.borrow_mut();
250 for &(ref name
, ty
) in plugin_attributes
.iter() {
251 if ty
== AttributeType
::Whitelisted
&& attr
.check_name(&name
) {
256 if !attr
::is_used(attr
) {
257 cx
.span_lint(UNUSED_ATTRIBUTES
, attr
.span
, "unused attribute");
258 // Is it a builtin attribute that must be used at the crate level?
259 let known_crate
= KNOWN_ATTRIBUTES
.iter().find(|&&(name
, ty
, _
)| {
260 attr
.name() == name
&&
261 ty
== AttributeType
::CrateLevel
264 // Has a plugin registered this attribute as one which must be used at
266 let plugin_crate
= plugin_attributes
.iter()
267 .find(|&&(ref x
, t
)| {
268 &*attr
.name() == x
&&
269 AttributeType
::CrateLevel
== t
271 if known_crate
|| plugin_crate
{
272 let msg
= match attr
.node
.style
{
273 ast
::AttrStyle
::Outer
=> "crate-level attribute should be an inner \
274 attribute: add an exclamation mark: #![foo]",
275 ast
::AttrStyle
::Inner
=> "crate-level attribute should be in the \
278 cx
.span_lint(UNUSED_ATTRIBUTES
, attr
.span
, msg
);
287 "`if`, `match`, `while` and `return` do not need parentheses"
290 #[derive(Copy, Clone)]
291 pub struct UnusedParens
;
294 fn check_unused_parens_core(&self, cx
: &EarlyContext
, value
: &ast
::Expr
, msg
: &str,
295 struct_lit_needs_parens
: bool
) {
296 if let ast
::ExprKind
::Paren(ref inner
) = value
.node
{
297 let necessary
= struct_lit_needs_parens
&& contains_exterior_struct_lit(&inner
);
299 cx
.span_lint(UNUSED_PARENS
, value
.span
,
300 &format
!("unnecessary parentheses around {}", msg
))
304 /// Expressions that syntactically contain an "exterior" struct
305 /// literal i.e. not surrounded by any parens or other
306 /// delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo
307 /// == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X {
308 /// y: 1 }) == foo` does not.
309 fn contains_exterior_struct_lit(value
: &ast
::Expr
) -> bool
{
311 ast
::ExprKind
::Struct(..) => true,
313 ast
::ExprKind
::Assign(ref lhs
, ref rhs
) |
314 ast
::ExprKind
::AssignOp(_
, ref lhs
, ref rhs
) |
315 ast
::ExprKind
::Binary(_
, ref lhs
, ref rhs
) => {
316 // X { y: 1 } + X { y: 2 }
317 contains_exterior_struct_lit(&lhs
) ||
318 contains_exterior_struct_lit(&rhs
)
320 ast
::ExprKind
::Unary(_
, ref x
) |
321 ast
::ExprKind
::Cast(ref x
, _
) |
322 ast
::ExprKind
::Type(ref x
, _
) |
323 ast
::ExprKind
::Field(ref x
, _
) |
324 ast
::ExprKind
::TupField(ref x
, _
) |
325 ast
::ExprKind
::Index(ref x
, _
) => {
326 // &X { y: 1 }, X { y: 1 }.y
327 contains_exterior_struct_lit(&x
)
330 ast
::ExprKind
::MethodCall(_
, _
, ref exprs
) => {
331 // X { y: 1 }.bar(...)
332 contains_exterior_struct_lit(&exprs
[0])
341 impl LintPass
for UnusedParens
{
342 fn get_lints(&self) -> LintArray
{
343 lint_array
!(UNUSED_PARENS
)
347 impl EarlyLintPass
for UnusedParens
{
348 fn check_expr(&mut self, cx
: &EarlyContext
, e
: &ast
::Expr
) {
349 use syntax
::ast
::ExprKind
::*;
350 let (value
, msg
, struct_lit_needs_parens
) = match e
.node
{
351 If(ref cond
, _
, _
) => (cond
, "`if` condition", true),
352 While(ref cond
, _
, _
) => (cond
, "`while` condition", true),
353 IfLet(_
, ref cond
, _
, _
) => (cond
, "`if let` head expression", true),
354 WhileLet(_
, ref cond
, _
, _
) => (cond
, "`while let` head expression", true),
355 ForLoop(_
, ref cond
, _
, _
) => (cond
, "`for` head expression", true),
356 Match(ref head
, _
) => (head
, "`match` head expression", true),
357 Ret(Some(ref value
)) => (value
, "`return` value", false),
358 Assign(_
, ref value
) => (value
, "assigned value", false),
359 AssignOp(_
, _
, ref value
) => (value
, "assigned value", false),
360 InPlace(_
, ref value
) => (value
, "emplacement value", false),
363 self.check_unused_parens_core(cx
, &value
, msg
, struct_lit_needs_parens
);
366 fn check_stmt(&mut self, cx
: &EarlyContext
, s
: &ast
::Stmt
) {
367 let (value
, msg
) = match s
.node
{
368 ast
::StmtKind
::Decl(ref decl
, _
) => match decl
.node
{
369 ast
::DeclKind
::Local(ref local
) => match local
.init
{
370 Some(ref value
) => (value
, "assigned value"),
377 self.check_unused_parens_core(cx
, &value
, msg
, false);
382 UNUSED_IMPORT_BRACES
,
384 "unnecessary braces around an imported item"
387 #[derive(Copy, Clone)]
388 pub struct UnusedImportBraces
;
390 impl LintPass
for UnusedImportBraces
{
391 fn get_lints(&self) -> LintArray
{
392 lint_array
!(UNUSED_IMPORT_BRACES
)
396 impl LateLintPass
for UnusedImportBraces
{
397 fn check_item(&mut self, cx
: &LateContext
, item
: &hir
::Item
) {
398 if let hir
::ItemUse(ref view_path
) = item
.node
{
399 if let hir
::ViewPathList(_
, ref items
) = view_path
.node
{
400 if items
.len() == 1 {
401 if let hir
::PathListIdent {ref name, ..}
= items
[0].node
{
402 let m
= format
!("braces around {} is unnecessary",
404 cx
.span_lint(UNUSED_IMPORT_BRACES
, item
.span
,
416 "detects unnecessary allocations that can be eliminated"
419 #[derive(Copy, Clone)]
420 pub struct UnusedAllocation
;
422 impl LintPass
for UnusedAllocation
{
423 fn get_lints(&self) -> LintArray
{
424 lint_array
!(UNUSED_ALLOCATION
)
428 impl LateLintPass
for UnusedAllocation
{
429 fn check_expr(&mut self, cx
: &LateContext
, e
: &hir
::Expr
) {
431 hir
::ExprBox(_
) => {}
435 if let Some(adjustment
) = cx
.tcx
.tables
.borrow().adjustments
.get(&e
.id
) {
436 if let adjustment
::AdjustDerefRef(adjustment
::AutoDerefRef
{
440 &Some(adjustment
::AutoPtr(_
, hir
::MutImmutable
)) => {
441 cx
.span_lint(UNUSED_ALLOCATION
, e
.span
,
442 "unnecessary allocation, use & instead");
444 &Some(adjustment
::AutoPtr(_
, hir
::MutMutable
)) => {
445 cx
.span_lint(UNUSED_ALLOCATION
, e
.span
,
446 "unnecessary allocation, use &mut instead");