]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/reference.rs
Merge branch 'macro-use' into HEAD
[rust.git] / clippy_lints / src / reference.rs
1 use syntax::ast::{Expr, ExprKind, UnOp};
2 use rustc::lint::*;
3 use rustc::{declare_lint, lint_array};
4 use if_chain::if_chain;
5 use crate::utils::{snippet, span_lint_and_sugg};
6
7 /// **What it does:** Checks for usage of `*&` and `*&mut` in expressions.
8 ///
9 /// **Why is this bad?** Immediately dereferencing a reference is no-op and
10 /// makes the code less clear.
11 ///
12 /// **Known problems:** Multiple dereference/addrof pairs are not handled so
13 /// the suggested fix for `x = **&&y` is `x = *&y`, which is still incorrect.
14 ///
15 /// **Example:**
16 /// ```rust
17 /// let a = f(*&mut b);
18 /// let c = *&d;
19 /// ```
20 declare_clippy_lint! {
21     pub DEREF_ADDROF,
22     complexity,
23     "use of `*&` or `*&mut` in an expression"
24 }
25
26 pub struct Pass;
27
28 impl LintPass for Pass {
29     fn get_lints(&self) -> LintArray {
30         lint_array!(DEREF_ADDROF)
31     }
32 }
33
34 fn without_parens(mut e: &Expr) -> &Expr {
35     while let ExprKind::Paren(ref child_e) = e.node {
36         e = child_e;
37     }
38     e
39 }
40
41 impl EarlyLintPass for Pass {
42     fn check_expr(&mut self, cx: &EarlyContext, e: &Expr) {
43         if_chain! {
44             if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.node;
45             if let ExprKind::AddrOf(_, ref addrof_target) = without_parens(deref_target).node;
46             then {
47                 span_lint_and_sugg(
48                     cx,
49                     DEREF_ADDROF,
50                     e.span,
51                     "immediately dereferencing a reference",
52                     "try this",
53                     format!("{}", snippet(cx, addrof_target.span, "_")),
54                 );
55             }
56         }
57     }
58 }
59
60 /// **What it does:** Checks for references in expressions that use
61 /// auto dereference.
62 ///
63 /// **Why is this bad?** The reference is a no-op and is automatically
64 /// dereferenced by the compiler and makes the code less clear.
65 ///
66 /// **Example:**
67 /// ```rust
68 /// struct Point(u32, u32);
69 /// let point = Foo(30, 20);
70 /// let x = (&point).x;
71 /// ```
72 declare_clippy_lint! {
73     pub REF_IN_DEREF,
74     complexity,
75     "Use of reference in auto dereference expression."
76 }
77
78 pub struct DerefPass;
79
80 impl LintPass for DerefPass {
81     fn get_lints(&self) -> LintArray {
82         lint_array!(REF_IN_DEREF)
83     }
84 }
85
86 impl EarlyLintPass for DerefPass {
87     fn check_expr(&mut self, cx: &EarlyContext, e: &Expr) {
88         if_chain! {
89             if let ExprKind::Field(ref object, ref field_name) = e.node;
90             if let ExprKind::Paren(ref parened) = object.node;
91             if let ExprKind::AddrOf(_, ref inner) = parened.node;
92             then {
93                 span_lint_and_sugg(
94                     cx,
95                     REF_IN_DEREF,
96                     object.span,
97                     "Creating a reference that is immediately dereferenced.",
98                     "try this",
99                     format!(
100                         "{}.{}",
101                         snippet(cx, inner.span, "_"),
102                         snippet(cx, field_name.span, "_")
103                     )
104                 );
105             }
106         }
107     }
108 }