1 use clippy_utils
::diagnostics
::span_lint
;
2 use clippy_utils
::higher
;
4 use rustc_hir
::intravisit
;
5 use rustc_lint
::{LateContext, LateLintPass, LintContext}
;
6 use rustc_middle
::lint
::in_external_macro
;
8 use rustc_session
::{declare_lint_pass, declare_tool_lint}
;
10 declare_clippy_lint
! {
12 /// Checks for instances of `mut mut` references.
14 /// ### Why is this bad?
15 /// Multiple `mut`s don't add anything meaningful to the
16 /// source. This is either a copy'n'paste error, or it shows a fundamental
17 /// misunderstanding of references.
22 /// let x = &mut &mut y;
24 #[clippy::version = "pre 1.29.0"]
27 "usage of double-mut refs, e.g., `&mut &mut ...`"
30 declare_lint_pass
!(MutMut
=> [MUT_MUT
]);
32 impl<'tcx
> LateLintPass
<'tcx
> for MutMut
{
33 fn check_block(&mut self, cx
: &LateContext
<'tcx
>, block
: &'tcx hir
::Block
<'_
>) {
34 intravisit
::walk_block(&mut MutVisitor { cx }
, block
);
37 fn check_ty(&mut self, cx
: &LateContext
<'tcx
>, ty
: &'tcx hir
::Ty
<'_
>) {
38 use rustc_hir
::intravisit
::Visitor
;
40 MutVisitor { cx }
.visit_ty(ty
);
44 pub struct MutVisitor
<'a
, 'tcx
> {
45 cx
: &'a LateContext
<'tcx
>,
48 impl<'a
, 'tcx
> intravisit
::Visitor
<'tcx
> for MutVisitor
<'a
, 'tcx
> {
49 fn visit_expr(&mut self, expr
: &'tcx hir
::Expr
<'_
>) {
50 if in_external_macro(self.cx
.sess(), expr
.span
) {
54 if let Some(higher
::ForLoop { arg, body, .. }
) = higher
::ForLoop
::hir(expr
) {
55 // A `for` loop lowers to:
57 // match ::std::iter::Iterator::next(&mut iter) {
60 // Let's ignore the generated code.
61 intravisit
::walk_expr(self, arg
);
62 intravisit
::walk_expr(self, body
);
63 } else if let hir
::ExprKind
::AddrOf(hir
::BorrowKind
::Ref
, hir
::Mutability
::Mut
, e
) = expr
.kind
{
64 if let hir
::ExprKind
::AddrOf(hir
::BorrowKind
::Ref
, hir
::Mutability
::Mut
, _
) = e
.kind
{
69 "generally you want to avoid `&mut &mut _` if possible",
71 } else if let ty
::Ref(_
, ty
, hir
::Mutability
::Mut
) = self.cx
.typeck_results().expr_ty(e
).kind() {
72 if ty
.peel_refs().is_sized(self.cx
.tcx
, self.cx
.param_env
) {
77 "this expression mutably borrows a mutable reference. Consider reborrowing",
84 fn visit_ty(&mut self, ty
: &'tcx hir
::Ty
<'_
>) {
85 if in_external_macro(self.cx
.sess(), ty
.span
) {
89 if let hir
::TyKind
::Rptr(
93 mutbl
: hir
::Mutability
::Mut
,
97 if let hir
::TyKind
::Rptr(
100 mutbl
: hir
::Mutability
::Mut
,
109 "generally you want to avoid `&mut &mut _` if possible",
114 intravisit
::walk_ty(self, ty
);