| use syntax::ast::{Expr, ExprKind, UnOp}; |
| use rustc::lint::*; |
| use utils::{span_lint_and_sugg, snippet}; |
| |
| /// **What it does:** Checks for usage of `*&` and `*&mut` in expressions. |
| /// |
| /// **Why is this bad?** Immediately dereferencing a reference is no-op and |
| /// makes the code less clear. |
| /// |
| /// **Known problems:** Multiple dereference/addrof pairs are not handled so |
| /// the suggested fix for `x = **&&y` is `x = *&y`, which is still incorrect. |
| /// |
| /// **Example:** |
| /// ```rust |
| /// let a = f(*&mut b); |
| /// let c = *&d; |
| /// ``` |
| declare_lint! { |
| pub DEREF_ADDROF, |
| Warn, |
| "use of `*&` or `*&mut` in an expression" |
| } |
| |
| pub struct Pass; |
| |
| impl LintPass for Pass { |
| fn get_lints(&self) -> LintArray { |
| lint_array!(DEREF_ADDROF) |
| } |
| } |
| |
| fn without_parens(mut e: &Expr) -> &Expr { |
| while let ExprKind::Paren(ref child_e) = e.node { |
| e = child_e; |
| } |
| e |
| } |
| |
| impl EarlyLintPass for Pass { |
| fn check_expr(&mut self, cx: &EarlyContext, e: &Expr) { |
| if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.node { |
| if let ExprKind::AddrOf(_, ref addrof_target) = without_parens(deref_target).node { |
| span_lint_and_sugg( |
| cx, |
| DEREF_ADDROF, |
| e.span, |
| "immediately dereferencing a reference", |
| "try this", |
| format!("{}", snippet(cx, addrof_target.span, "_")), |
| ); |
| } |
| } |
| } |
| } |