]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/mut_mut.rs
Auto merge of #3946 - rchaser53:issue-3920, r=flip1995
[rust.git] / clippy_lints / src / mut_mut.rs
1 use crate::utils::{higher, span_lint};
2 use rustc::hir;
3 use rustc::hir::intravisit;
4 use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
5 use rustc::ty;
6 use rustc::{declare_tool_lint, lint_array};
7
8 declare_clippy_lint! {
9     /// **What it does:** Checks for instances of `mut mut` references.
10     ///
11     /// **Why is this bad?** Multiple `mut`s don't add anything meaningful to the
12     /// source. This is either a copy'n'paste error, or it shows a fundamental
13     /// misunderstanding of references.
14     ///
15     /// **Known problems:** None.
16     ///
17     /// **Example:**
18     /// ```rust
19     /// let x = &mut &mut y;
20     /// ```
21     pub MUT_MUT,
22     pedantic,
23     "usage of double-mut refs, e.g., `&mut &mut ...`"
24 }
25
26 #[derive(Copy, Clone)]
27 pub struct MutMut;
28
29 impl LintPass for MutMut {
30     fn get_lints(&self) -> LintArray {
31         lint_array!(MUT_MUT)
32     }
33
34     fn name(&self) -> &'static str {
35         "MutMut"
36     }
37 }
38
39 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutMut {
40     fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) {
41         intravisit::walk_block(&mut MutVisitor { cx }, block);
42     }
43
44     fn check_ty(&mut self, cx: &LateContext<'a, 'tcx>, ty: &'tcx hir::Ty) {
45         use rustc::hir::intravisit::Visitor;
46
47         MutVisitor { cx }.visit_ty(ty);
48     }
49 }
50
51 pub struct MutVisitor<'a, 'tcx: 'a> {
52     cx: &'a LateContext<'a, 'tcx>,
53 }
54
55 impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
56     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
57         if in_external_macro(self.cx.sess(), expr.span) {
58             return;
59         }
60
61         if let Some((_, arg, body)) = higher::for_loop(expr) {
62             // A `for` loop lowers to:
63             // ```rust
64             // match ::std::iter::Iterator::next(&mut iter) {
65             // //                                ^^^^
66             // ```
67             // Let's ignore the generated code.
68             intravisit::walk_expr(self, arg);
69             intravisit::walk_expr(self, body);
70         } else if let hir::ExprKind::AddrOf(hir::MutMutable, ref e) = expr.node {
71             if let hir::ExprKind::AddrOf(hir::MutMutable, _) = e.node {
72                 span_lint(
73                     self.cx,
74                     MUT_MUT,
75                     expr.span,
76                     "generally you want to avoid `&mut &mut _` if possible",
77                 );
78             } else if let ty::Ref(_, _, hir::MutMutable) = self.cx.tables.expr_ty(e).sty {
79                 span_lint(
80                     self.cx,
81                     MUT_MUT,
82                     expr.span,
83                     "this expression mutably borrows a mutable reference. Consider reborrowing",
84                 );
85             }
86         }
87     }
88
89     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
90         if let hir::TyKind::Rptr(
91             _,
92             hir::MutTy {
93                 ty: ref pty,
94                 mutbl: hir::MutMutable,
95             },
96         ) = ty.node
97         {
98             if let hir::TyKind::Rptr(
99                 _,
100                 hir::MutTy {
101                     mutbl: hir::MutMutable, ..
102                 },
103             ) = pty.node
104             {
105                 span_lint(
106                     self.cx,
107                     MUT_MUT,
108                     ty.span,
109                     "generally you want to avoid `&mut &mut _` if possible",
110                 );
111             }
112         }
113
114         intravisit::walk_ty(self, ty);
115     }
116     fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
117         intravisit::NestedVisitorMap::None
118     }
119 }