]> git.lizzy.rs Git - rust.git/blob - src/no_effect.rs
d928de415787209e20e89a0ca4285ac4fe8ee632
[rust.git] / src / no_effect.rs
1 use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
2 use rustc::hir::def::Def;
3 use rustc::hir::{Expr, Expr_, Stmt, StmtSemi};
4 use utils::{in_macro, span_lint};
5
6 /// **What it does:** This lint checks for statements which have no effect.
7 ///
8 /// **Why is this bad?** Similar to dead code, these statements are actually executed. However, as they have no effect, all they do is make the code less readable.
9 ///
10 /// **Known problems:** None.
11 ///
12 /// **Example:** `0;`
13 declare_lint! {
14     pub NO_EFFECT,
15     Warn,
16     "statements with no effect"
17 }
18
19 fn has_no_effect(cx: &LateContext, expr: &Expr) -> bool {
20     if in_macro(cx, expr.span) {
21         return false;
22     }
23     match expr.node {
24         Expr_::ExprLit(..) |
25         Expr_::ExprClosure(..) |
26         Expr_::ExprPath(..) => true,
27         Expr_::ExprIndex(ref a, ref b) |
28         Expr_::ExprBinary(_, ref a, ref b) => has_no_effect(cx, a) && has_no_effect(cx, b),
29         Expr_::ExprVec(ref v) |
30         Expr_::ExprTup(ref v) => v.iter().all(|val| has_no_effect(cx, val)),
31         Expr_::ExprRepeat(ref inner, _) |
32         Expr_::ExprCast(ref inner, _) |
33         Expr_::ExprType(ref inner, _) |
34         Expr_::ExprUnary(_, ref inner) |
35         Expr_::ExprField(ref inner, _) |
36         Expr_::ExprTupField(ref inner, _) |
37         Expr_::ExprAddrOf(_, ref inner) |
38         Expr_::ExprBox(ref inner) => has_no_effect(cx, inner),
39         Expr_::ExprStruct(_, ref fields, ref base) => {
40             fields.iter().all(|field| has_no_effect(cx, &field.expr)) &&
41             match *base {
42                 Some(ref base) => has_no_effect(cx, base),
43                 None => true,
44             }
45         }
46         Expr_::ExprCall(ref callee, ref args) => {
47             let def = cx.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def());
48             match def {
49                 Some(Def::Struct(..)) |
50                 Some(Def::Variant(..)) => args.iter().all(|arg| has_no_effect(cx, arg)),
51                 _ => false,
52             }
53         }
54         Expr_::ExprBlock(ref block) => {
55             block.stmts.is_empty() &&
56             if let Some(ref expr) = block.expr {
57                 has_no_effect(cx, expr)
58             } else {
59                 false
60             }
61         }
62         _ => false,
63     }
64 }
65
66 #[derive(Copy, Clone)]
67 pub struct NoEffectPass;
68
69 impl LintPass for NoEffectPass {
70     fn get_lints(&self) -> LintArray {
71         lint_array!(NO_EFFECT)
72     }
73 }
74
75 impl LateLintPass for NoEffectPass {
76     fn check_stmt(&mut self, cx: &LateContext, stmt: &Stmt) {
77         if let StmtSemi(ref expr, _) = stmt.node {
78             if has_no_effect(cx, expr) {
79                 span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect");
80             }
81         }
82     }
83 }