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