about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs10
-rw-r--r--src/tools/rustfmt/src/patterns.rs91
15 files changed, 91 insertions, 63 deletions
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
index bf96c0d62b0..8ac17e17688 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -24,13 +24,13 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
     let name = ident.name.as_str();
 
     let name = match decl.implicit_self {
-        ImplicitSelfKind::MutRef => {
+        ImplicitSelfKind::RefMut => {
             let Some(name) = name.strip_suffix("_mut") else {
                 return;
             };
             name
         },
-        ImplicitSelfKind::Imm | ImplicitSelfKind::Mut | ImplicitSelfKind::ImmRef => name,
+        ImplicitSelfKind::Imm | ImplicitSelfKind::Mut | ImplicitSelfKind::RefImm => name,
         ImplicitSelfKind::None => return,
     };
 
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index 5b5eb355f86..4d1f89b1d9d 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -97,7 +97,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
             value_hir_id,
             ident,
             sub_pat,
-        ) = pat.kind
+        ) = pat.kind && by_ref != hir::ByRef::Yes(hir::Mutability::Mut)
         {
             // This block catches bindings with sub patterns. It would be hard to build a correct suggestion
             // for them and it's likely that the user knows what they are doing in such a case.
@@ -115,7 +115,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
             if let ty::Slice(inner_ty) | ty::Array(inner_ty, _) = bound_ty.peel_refs().kind() {
                 // The values need to use the `ref` keyword if they can't be copied.
                 // This will need to be adjusted if the lint want to support mutable access in the future
-                let src_is_ref = bound_ty.is_ref() && by_ref != hir::ByRef::Yes;
+                let src_is_ref = bound_ty.is_ref() && by_ref == hir::ByRef::No;
                 let needs_ref = !(src_is_ref || is_copy(cx, *inner_ty));
 
                 let slice_info = slices
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index b5821d909f8..cf0ab88032c 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -216,8 +216,8 @@ impl {self_ty_without_ref} {{
     fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
         let item_did = item.owner_id.to_def_id();
         let (borrow_prefix, expected_implicit_self) = match item.ident.name {
-            sym::iter => ("&", ImplicitSelfKind::ImmRef),
-            sym::iter_mut => ("&mut ", ImplicitSelfKind::MutRef),
+            sym::iter => ("&", ImplicitSelfKind::RefImm),
+            sym::iter_mut => ("&mut ", ImplicitSelfKind::RefMut),
             _ => return,
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 27d85cde532..cae9ada5a33 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -384,8 +384,8 @@ impl LenOutput {
 
     fn expected_sig(self, self_kind: ImplicitSelfKind) -> String {
         let self_ref = match self_kind {
-            ImplicitSelfKind::ImmRef => "&",
-            ImplicitSelfKind::MutRef => "&mut ",
+            ImplicitSelfKind::RefImm => "&",
+            ImplicitSelfKind::RefMut => "&mut ",
             _ => "",
         };
         match self {
@@ -411,8 +411,8 @@ fn check_is_empty_sig<'tcx>(
         [arg, res] if len_output.matches_is_empty_output(cx, *res) => {
             matches!(
                 (arg.kind(), self_kind),
-                (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::ImmRef)
-                    | (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::MutRef)
+                (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::RefImm)
+                    | (ty::Ref(_, _, Mutability::Mut), ImplicitSelfKind::RefMut)
             ) || (!arg.is_ref() && matches!(self_kind, ImplicitSelfKind::Imm | ImplicitSelfKind::Mut))
         },
         _ => false,
diff --git a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
index 0f242e0b9e1..93d7683d2af 100644
--- a/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/infallible_destructuring_match.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{path_to_local_id, peel_blocks, strip_pat_refs};
 use rustc_errors::Applicability;
-use rustc_hir::{ByRef, ExprKind, LetStmt, MatchSource, PatKind, QPath};
+use rustc_hir::{ExprKind, LetStmt, MatchSource, PatKind, QPath};
 use rustc_lint::LateContext;
 
 use super::INFALLIBLE_DESTRUCTURING_MATCH;
@@ -30,7 +30,7 @@ pub(crate) fn check(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
             format!(
                 "let {}({}{}) = {};",
                 snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
-                if binding.0 == ByRef::Yes { "ref " } else { "" },
+                binding.prefix_str(),
                 snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
                 snippet_with_applicability(cx, target.span, "..", &mut applicability),
             ),
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
index 3f737da92c0..6b484ff2749 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
@@ -67,7 +67,7 @@ fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
     if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind
         && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionSome)
-        && let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind
+        && let PatKind::Binding(BindingAnnotation(ByRef::Yes(mutabl), _), .., ident, _) = first_pat.kind
         && let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind
         && is_res_lang_ctor(cx, path_res(cx, e), LangItem::OptionSome)
         && let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index cee77f62b61..fe83e784c3c 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -178,7 +178,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
                 },
             )),
         ) => {
-            return !matches!(annot, BindingAnnotation(ByRef::Yes, _)) && pat_ident.name == first_seg.ident.name;
+            return !matches!(annot, BindingAnnotation(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name;
         },
         // Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
         (PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
index 6bae51b45b8..50cbccc3968 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -182,7 +182,7 @@ fn get_pat_binding<'tcx>(
             if let PatKind::Binding(bind_annot, hir_id, ident, _) = pat.kind
                 && hir_id == local
             {
-                if matches!(bind_annot.0, rustc_ast::ByRef::Yes) {
+                if matches!(bind_annot.0, rustc_ast::ByRef::Yes(_)) {
                     let _ = byref_ident.insert(ident);
                 }
                 // the second call of `replace()` returns a `Some(span)`, meaning a multi-binding pattern
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index d4a5de3d1de..3e099004c47 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -69,7 +69,7 @@ pub(super) fn check(
                 _ => false,
             },
             // local binding capturing a reference
-            Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => {
+            Node::LetStmt(l) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes(_), _), ..)) => {
                 return;
             },
             _ => false,
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 6394f35f860..1431a5db2d9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -60,8 +60,6 @@ pub(super) fn check<'tcx>(
                 applicability,
             );
         } else {
-            let ref_annotation = if annotation.0 == ByRef::Yes { "ref " } else { "" };
-            let mut_annotation = if annotation.1 == Mutability::Mut { "mut " } else { "" };
             span_lint_and_sugg(
                 cx,
                 ITER_KV_MAP,
@@ -69,7 +67,8 @@ pub(super) fn check<'tcx>(
                 &format!("iterating on a map's {replacement_kind}s"),
                 "try",
                 format!(
-                    "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{ref_annotation}{mut_annotation}{bound_ident}| {})",
+                    "{recv_snippet}.{into_prefix}{replacement_kind}s().map(|{}{bound_ident}| {})",
+                    annotation.prefix_str(),
                     snippet_with_applicability(cx, body_expr.span, "/* body */", &mut applicability)
                 ),
                 applicability,
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index ea6e662b4be..11fecb7d72e 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -129,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
             if !is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) {
                 return;
             }
-            if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind {
+            if let PatKind::Binding(BindingAnnotation(ByRef::Yes(_), _), ..) = arg.pat.kind {
                 span_lint(
                     cx,
                     TOPLEVEL_REF_ARG,
@@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if !in_external_macro(cx.tcx.sess, stmt.span)
             && let StmtKind::Let(local) = stmt.kind
-            && let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind
+            && let PatKind::Binding(BindingAnnotation(ByRef::Yes(mutabl), _), .., name, None) = local.pat.kind
             && let Some(init) = local.init
             // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
             && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id)
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index f1db571e113..b57220e6cf0 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -14,7 +14,7 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
-    BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Node, PatKind, PathSegment, QPath, Stmt, StmtKind,
+    BindingAnnotation, Block, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
@@ -283,9 +283,13 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
         let mut applicability = Applicability::MachineApplicable;
         let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
         let requires_semi = matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(_));
+        let method_call_str = match by_ref {
+            ByRef::Yes(Mutability::Mut) => ".as_mut()",
+            ByRef::Yes(Mutability::Not) => ".as_ref()",
+            ByRef::No => "",
+        };
         let sugg = format!(
-            "{receiver_str}{}?{}",
-            if by_ref == ByRef::Yes { ".as_ref()" } else { "" },
+            "{receiver_str}{method_call_str}?{}",
             if requires_semi { ";" } else { "" }
         );
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 5319915b2ea..e45beb4910b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -649,6 +649,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                     BindingAnnotation::REF => "REF",
                     BindingAnnotation::MUT => "MUT",
                     BindingAnnotation::REF_MUT => "REF_MUT",
+                    BindingAnnotation::MUT_REF => "MUT_REF",
+                    BindingAnnotation::MUT_REF_MUT => "MUT_REF_MUT",
                 };
                 kind!("Binding(BindingAnnotation::{ann}, _, {name}, {sub})");
                 self.ident(name);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 8251bdf78fc..95bab5801d1 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -97,7 +97,7 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
-    self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
+    self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, ByRef, Closure, Destination, Expr,
     ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item,
     ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
     QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
@@ -107,7 +107,6 @@ use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::mir::Const;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
-use rustc_middle::ty::binding::BindingMode;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
@@ -1006,11 +1005,12 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind {
             .typeck_results()
             .extract_binding_mode(cx.sess(), id, span)
             .unwrap()
+            .0
         {
-            BindingMode::BindByValue(_) if !is_copy(cx, cx.typeck_results().node_type(id)) => {
+            ByRef::No if !is_copy(cx, cx.typeck_results().node_type(id)) => {
                 capture = CaptureKind::Value;
             },
-            BindingMode::BindByReference(Mutability::Mut) if capture != CaptureKind::Value => {
+            ByRef::Yes(Mutability::Mut) if capture != CaptureKind::Value => {
                 capture = CaptureKind::Ref(Mutability::Mut);
             },
             _ => (),
@@ -2035,7 +2035,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
             .typeck_results()
             .pat_binding_modes()
             .get(pat.hir_id)
-            .is_some_and(|mode| matches!(mode, BindingMode::BindByReference(_)))
+            .is_some_and(|mode| matches!(mode.0, ByRef::Yes(_)))
         {
             // If a tuple `(x, y)` is of type `&(i32, i32)`, then due to match ergonomics,
             // the inner patterns become references. Don't consider this the identity function
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index 47b48468a24..820eccb2dc2 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -107,18 +107,19 @@ impl Rewrite for Pat {
             }
             PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, shape),
             PatKind::Ident(BindingAnnotation(by_ref, mutability), ident, ref sub_pat) => {
-                let prefix = match by_ref {
-                    ByRef::Yes => "ref",
-                    ByRef::No => "",
+                let mut_prefix = format_mutability(mutability).trim();
+
+                let (ref_kw, mut_infix) = match by_ref {
+                    ByRef::Yes(rmutbl) => ("ref", format_mutability(rmutbl).trim()),
+                    ByRef::No => ("", ""),
                 };
-                let mut_infix = format_mutability(mutability).trim();
                 let id_str = rewrite_ident(context, ident);
                 let sub_pat = match *sub_pat {
                     Some(ref p) => {
                         // 2 - `@ `.
-                        let width = shape
-                            .width
-                            .checked_sub(prefix.len() + mut_infix.len() + id_str.len() + 2)?;
+                        let width = shape.width.checked_sub(
+                            mut_prefix.len() + ref_kw.len() + mut_infix.len() + id_str.len() + 2,
+                        )?;
                         let lo = context.snippet_provider.span_after(self.span, "@");
                         combine_strs_with_missing_comments(
                             context,
@@ -132,33 +133,55 @@ impl Rewrite for Pat {
                     None => "".to_owned(),
                 };
 
-                // combine prefix and mut
-                let (first_lo, first) = if !prefix.is_empty() && !mut_infix.is_empty() {
-                    let hi = context.snippet_provider.span_before(self.span, "mut");
-                    let lo = context.snippet_provider.span_after(self.span, "ref");
-                    (
+                // combine prefix and ref
+                let (first_lo, first) = match (mut_prefix.is_empty(), ref_kw.is_empty()) {
+                    (false, false) => {
+                        let lo = context.snippet_provider.span_after(self.span, "mut");
+                        let hi = context.snippet_provider.span_before(self.span, "ref");
+                        (
+                            context.snippet_provider.span_after(self.span, "ref"),
+                            combine_strs_with_missing_comments(
+                                context,
+                                mut_prefix,
+                                ref_kw,
+                                mk_sp(lo, hi),
+                                shape,
+                                true,
+                            )?,
+                        )
+                    }
+                    (false, true) => (
                         context.snippet_provider.span_after(self.span, "mut"),
-                        combine_strs_with_missing_comments(
-                            context,
-                            prefix,
-                            mut_infix,
-                            mk_sp(lo, hi),
-                            shape,
-                            true,
-                        )?,
-                    )
-                } else if !prefix.is_empty() {
-                    (
+                        mut_prefix.to_owned(),
+                    ),
+                    (true, false) => (
                         context.snippet_provider.span_after(self.span, "ref"),
-                        prefix.to_owned(),
-                    )
-                } else if !mut_infix.is_empty() {
-                    (
-                        context.snippet_provider.span_after(self.span, "mut"),
-                        mut_infix.to_owned(),
-                    )
-                } else {
-                    (self.span.lo(), "".to_owned())
+                        ref_kw.to_owned(),
+                    ),
+                    (true, true) => (self.span.lo(), "".to_owned()),
+                };
+
+                // combine result of above and mut
+                let (second_lo, second) = match (first.is_empty(), mut_infix.is_empty()) {
+                    (false, false) => {
+                        let lo = context.snippet_provider.span_after(self.span, "ref");
+                        let end_span = mk_sp(first_lo, self.span.hi());
+                        let hi = context.snippet_provider.span_before(end_span, "mut");
+                        (
+                            context.snippet_provider.span_after(end_span, "mut"),
+                            combine_strs_with_missing_comments(
+                                context,
+                                &first,
+                                mut_infix,
+                                mk_sp(lo, hi),
+                                shape,
+                                true,
+                            )?,
+                        )
+                    }
+                    (false, true) => (first_lo, first),
+                    (true, false) => unreachable!("mut_infix necessarily follows a ref"),
+                    (true, true) => (self.span.lo(), "".to_owned()),
                 };
 
                 let next = if !sub_pat.is_empty() {
@@ -177,9 +200,9 @@ impl Rewrite for Pat {
 
                 combine_strs_with_missing_comments(
                     context,
-                    &first,
+                    &second,
                     &next,
-                    mk_sp(first_lo, ident.span.lo()),
+                    mk_sp(second_lo, ident.span.lo()),
                     shape,
                     true,
                 )