@@ -2,11 +2,12 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
22use clippy_utils:: higher;
33use clippy_utils:: source:: snippet_with_applicability;
44use clippy_utils:: sugg:: Sugg ;
5+ use rustc_data_structures:: fx:: FxHashSet ;
56use rustc_errors:: Applicability ;
6- use rustc_hir:: { self as hir, AmbigArg , intravisit} ;
7+ use rustc_hir:: { self as hir, AmbigArg , HirId , intravisit} ;
78use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
89use rustc_middle:: ty;
9- use rustc_session:: declare_lint_pass ;
10+ use rustc_session:: impl_lint_pass ;
1011
1112declare_clippy_lint ! {
1213 /// ### What it does
@@ -28,7 +29,12 @@ declare_clippy_lint! {
2829 "usage of double-mut refs, e.g., `&mut &mut ...`"
2930}
3031
31- declare_lint_pass ! ( MutMut => [ MUT_MUT ] ) ;
32+ impl_lint_pass ! ( MutMut => [ MUT_MUT ] ) ;
33+
34+ #[ derive( Default ) ]
35+ pub ( crate ) struct MutMut {
36+ seen_tys : FxHashSet < HirId > ,
37+ }
3238
3339impl < ' tcx > LateLintPass < ' tcx > for MutMut {
3440 fn check_block ( & mut self , cx : & LateContext < ' tcx > , block : & ' tcx hir:: Block < ' _ > ) {
@@ -42,6 +48,14 @@ impl<'tcx> LateLintPass<'tcx> for MutMut {
4248 && mty2. mutbl == hir:: Mutability :: Mut
4349 && !ty. span . in_external_macro ( cx. sess ( ) . source_map ( ) )
4450 {
51+ if self . seen_tys . contains ( & ty. hir_id ) {
52+ // we have 2+ `&mut`s, e.g., `&mut &mut &mut x`
53+ // and we have already flagged on the outermost `&mut &mut (&mut x)`,
54+ // so don't flag the inner `&mut &mut (x)`
55+ return ;
56+ }
57+ self . seen_tys . insert ( mty. ty . hir_id ) ;
58+
4559 let mut applicability = Applicability :: MaybeIncorrect ;
4660 let sugg = snippet_with_applicability ( cx. sess ( ) , mty. ty . span , ".." , & mut applicability) ;
4761 span_lint_and_sugg (
0 commit comments