]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/mut_mut.rs
rustup https://github.com/rust-lang/rust/pull/57726
[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 /// **What it does:** Checks for instances of `mut mut` references.
9 ///
10 /// **Why is this bad?** Multiple `mut`s don't add anything meaningful to the
11 /// source. This is either a copy'n'paste error, or it shows a fundamental
12 /// misunderstanding of references.
13 ///
14 /// **Known problems:** None.
15 ///
16 /// **Example:**
17 /// ```rust
18 /// let x = &mut &mut y;
19 /// ```
20 declare_clippy_lint! {
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 }