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