]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/mut_mut.rs
Auto merge of #3987 - phansch:rustfix_option_map_or_none, 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_lint_pass, declare_tool_lint};
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 declare_lint_pass!(MutMut => [MUT_MUT]);
27
28 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutMut {
29     fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx hir::Block) {
30         intravisit::walk_block(&mut MutVisitor { cx }, block);
31     }
32
33     fn check_ty(&mut self, cx: &LateContext<'a, 'tcx>, ty: &'tcx hir::Ty) {
34         use rustc::hir::intravisit::Visitor;
35
36         MutVisitor { cx }.visit_ty(ty);
37     }
38 }
39
40 pub struct MutVisitor<'a, 'tcx: 'a> {
41     cx: &'a LateContext<'a, 'tcx>,
42 }
43
44 impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
45     fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
46         if in_external_macro(self.cx.sess(), expr.span) {
47             return;
48         }
49
50         if let Some((_, arg, body)) = higher::for_loop(expr) {
51             // A `for` loop lowers to:
52             // ```rust
53             // match ::std::iter::Iterator::next(&mut iter) {
54             // //                                ^^^^
55             // ```
56             // Let's ignore the generated code.
57             intravisit::walk_expr(self, arg);
58             intravisit::walk_expr(self, body);
59         } else if let hir::ExprKind::AddrOf(hir::MutMutable, ref e) = expr.node {
60             if let hir::ExprKind::AddrOf(hir::MutMutable, _) = e.node {
61                 span_lint(
62                     self.cx,
63                     MUT_MUT,
64                     expr.span,
65                     "generally you want to avoid `&mut &mut _` if possible",
66                 );
67             } else if let ty::Ref(_, _, hir::MutMutable) = self.cx.tables.expr_ty(e).sty {
68                 span_lint(
69                     self.cx,
70                     MUT_MUT,
71                     expr.span,
72                     "this expression mutably borrows a mutable reference. Consider reborrowing",
73                 );
74             }
75         }
76     }
77
78     fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
79         if let hir::TyKind::Rptr(
80             _,
81             hir::MutTy {
82                 ty: ref pty,
83                 mutbl: hir::MutMutable,
84             },
85         ) = ty.node
86         {
87             if let hir::TyKind::Rptr(
88                 _,
89                 hir::MutTy {
90                     mutbl: hir::MutMutable, ..
91                 },
92             ) = pty.node
93             {
94                 span_lint(
95                     self.cx,
96                     MUT_MUT,
97                     ty.span,
98                     "generally you want to avoid `&mut &mut _` if possible",
99                 );
100             }
101         }
102
103         intravisit::walk_ty(self, ty);
104     }
105     fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
106         intravisit::NestedVisitorMap::None
107     }
108 }