From a408e76098acc353d18ae43b0f02485954d80d5d Mon Sep 17 00:00:00 2001
From: koka <koka.code@gmail.com>
Date: Wed, 1 Feb 2023 19:17:39 +0900
Subject: [PATCH 01/78] Suggest the correct variable name for `manual_let_else`

---
 clippy_lints/src/manual_let_else.rs   | 59 +++++++++++++++------------
 tests/ui/manual_let_else.stderr       | 32 +++++++--------
 tests/ui/manual_let_else_match.stderr |  4 +-
 3 files changed, 52 insertions(+), 43 deletions(-)

diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs
index 9c6f8b43c07..4d53a664fa0 100644
--- a/clippy_lints/src/manual_let_else.rs
+++ b/clippy_lints/src/manual_let_else.rs
@@ -68,29 +68,21 @@ impl_lint_pass!(ManualLetElse => [MANUAL_LET_ELSE]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
-        let if_let_or_match = if_chain! {
-            if self.msrv.meets(msrvs::LET_ELSE);
-            if !in_external_macro(cx.sess(), stmt.span);
-            if let StmtKind::Local(local) = stmt.kind;
-            if let Some(init) = local.init;
-            if local.els.is_none();
-            if local.ty.is_none();
-            if init.span.ctxt() == stmt.span.ctxt();
-            if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init);
-            then {
-                if_let_or_match
-            } else {
-                return;
-            }
-        };
-
+        if self.msrv.meets(msrvs::LET_ELSE) &&
+            !in_external_macro(cx.sess(), stmt.span) &&
+            let StmtKind::Local(local) = stmt.kind &&
+            let Some(init) = local.init &&
+            local.els.is_none() &&
+            local.ty.is_none() &&
+            init.span.ctxt() == stmt.span.ctxt() &&
+            let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) {
         match if_let_or_match {
             IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! {
                 if expr_is_simple_identity(let_pat, if_then);
                 if let Some(if_else) = if_else;
                 if expr_diverges(cx, if_else);
                 then {
-                    emit_manual_let_else(cx, stmt.span, if_let_expr, let_pat, if_else);
+                    emit_manual_let_else(cx, stmt.span, if_let_expr, local.pat, let_pat, if_else);
                 }
             },
             IfLetOrMatch::Match(match_expr, arms, source) => {
@@ -120,15 +112,23 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
                     return;
                 }
 
-                emit_manual_let_else(cx, stmt.span, match_expr, pat_arm.pat, diverging_arm.body);
+                emit_manual_let_else(cx, stmt.span, match_expr, local.pat, pat_arm.pat, diverging_arm.body);
             },
         }
+        };
     }
 
     extract_msrv_attr!(LateContext);
 }
 
-fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: &Pat<'_>, else_body: &Expr<'_>) {
+fn emit_manual_let_else(
+    cx: &LateContext<'_>,
+    span: Span,
+    expr: &Expr<'_>,
+    local: &Pat<'_>,
+    pat: &Pat<'_>,
+    else_body: &Expr<'_>,
+) {
     span_lint_and_then(
         cx,
         MANUAL_LET_ELSE,
@@ -137,12 +137,11 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat:
         |diag| {
             // This is far from perfect, for example there needs to be:
             // * mut additions for the bindings
-            // * renamings of the bindings
+            // * renamings of the bindings for `PatKind::Or`
             // * unused binding collision detection with existing ones
             // * putting patterns with at the top level | inside ()
             // for this to be machine applicable.
             let mut app = Applicability::HasPlaceholders;
-            let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app);
             let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app);
             let (sn_else, _) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app);
 
@@ -151,10 +150,20 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat:
             } else {
                 format!("{{ {sn_else} }}")
             };
-            let sn_bl = if matches!(pat.kind, PatKind::Or(..)) {
-                format!("({sn_pat})")
-            } else {
-                sn_pat.into_owned()
+            let sn_bl = match pat.kind {
+                PatKind::Or(..) => {
+                    let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app);
+                    format!("({sn_pat})")
+                },
+                PatKind::TupleStruct(ref w, ..) => {
+                    let sn_wrapper = cx.sess().source_map().span_to_snippet(w.span()).unwrap_or_default();
+                    let (sn_inner, _) = snippet_with_context(cx, local.span, span.ctxt(), "", &mut app);
+                    format!("{sn_wrapper}({sn_inner})")
+                },
+                _ => {
+                    let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app);
+                    sn_pat.into_owned()
+                },
             };
             let sugg = format!("let {sn_bl} = {sn_expr} else {else_bl};");
             diag.span_suggestion(span, "consider writing", sugg, app);
diff --git a/tests/ui/manual_let_else.stderr b/tests/ui/manual_let_else.stderr
index 52aac6bc673..fe45cfd25b6 100644
--- a/tests/ui/manual_let_else.stderr
+++ b/tests/ui/manual_let_else.stderr
@@ -2,7 +2,7 @@ error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else.rs:18:5
    |
 LL |     let v = if let Some(v_some) = g() { v_some } else { return };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { return };`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };`
    |
    = note: `-D clippy::manual-let-else` implied by `-D warnings`
 
@@ -18,7 +18,7 @@ LL | |     };
    |
 help: consider writing
    |
-LL ~     let Some(v_some) = g() else {
+LL ~     let Some(v) = g() else {
 LL +         return;
 LL +     };
    |
@@ -48,19 +48,19 @@ error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else.rs:38:9
    |
 LL |         let v = if let Some(v_some) = g() { v_some } else { continue };
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { continue };`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };`
 
 error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else.rs:39:9
    |
 LL |         let v = if let Some(v_some) = g() { v_some } else { break };
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { break };`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };`
 
 error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else.rs:43:5
    |
 LL |     let v = if let Some(v_some) = g() { v_some } else { panic!() };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { panic!() };`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };`
 
 error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else.rs:46:5
@@ -74,7 +74,7 @@ LL | |     };
    |
 help: consider writing
    |
-LL ~     let Some(v_some) = g() else {
+LL ~     let Some(v) = g() else {
 LL +         std::process::abort()
 LL +     };
    |
@@ -91,7 +91,7 @@ LL | |     };
    |
 help: consider writing
    |
-LL ~     let Some(v_some) = g() else {
+LL ~     let Some(v) = g() else {
 LL +         if true { return } else { panic!() }
 LL +     };
    |
@@ -109,7 +109,7 @@ LL | |     };
    |
 help: consider writing
    |
-LL ~     let Some(v_some) = g() else {
+LL ~     let Some(v) = g() else {
 LL +         if true {}
 LL +         panic!();
 LL +     };
@@ -129,7 +129,7 @@ LL | |     };
    |
 help: consider writing
    |
-LL ~     let Some(v_some) = g() else {
+LL ~     let Some(v) = g() else {
 LL +         match () {
 LL +             _ if panic!() => {},
 LL +             _ => panic!(),
@@ -141,7 +141,7 @@ error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else.rs:80:5
    |
 LL |     let v = if let Some(v_some) = g() { v_some } else { if panic!() {} };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { if panic!() {} };`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { if panic!() {} };`
 
 error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else.rs:83:5
@@ -157,7 +157,7 @@ LL | |     };
    |
 help: consider writing
    |
-LL ~     let Some(v_some) = g() else {
+LL ~     let Some(v) = g() else {
 LL +         match panic!() {
 LL +             _ => {},
 LL +         }
@@ -178,7 +178,7 @@ LL | |     };
    |
 help: consider writing
    |
-LL ~     let Some(v_some) = g() else { if true {
+LL ~     let Some(v) = g() else { if true {
 LL +         return;
 LL +     } else {
 LL +         panic!("diverge");
@@ -199,7 +199,7 @@ LL | |     };
    |
 help: consider writing
    |
-LL ~     let Some(v_some) = g() else {
+LL ~     let Some(v) = g() else {
 LL +         match (g(), g()) {
 LL +             (Some(_), None) => return,
 LL +             (None, Some(_)) => {
@@ -226,7 +226,7 @@ LL | |     };
    |
 help: consider writing
    |
-LL ~     let Some(v_some) = g().map(|v| (v, 42)) else {
+LL ~     let Some((v, w)) = g().map(|v| (v, 42)) else {
 LL +         return;
 LL +     };
    |
@@ -252,7 +252,7 @@ error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else.rs:134:13
    |
 LL |             let $n = if let Some(v) = $e { v } else { return };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };`
 ...
 LL |     create_binding_if_some!(w, g());
    |     ------------------------------- in this macro invocation
@@ -266,7 +266,7 @@ LL | /     let _ = match ff {
 LL | |         Some(value) => value,
 LL | |         _ => macro_call!(),
 LL | |     };
-   | |______^ help: consider writing: `let Some(value) = ff else { macro_call!() };`
+   | |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };`
 
 error: aborting due to 18 previous errors
 
diff --git a/tests/ui/manual_let_else_match.stderr b/tests/ui/manual_let_else_match.stderr
index cd5e9a9ac39..867e459830d 100644
--- a/tests/ui/manual_let_else_match.stderr
+++ b/tests/ui/manual_let_else_match.stderr
@@ -5,7 +5,7 @@ LL | /     let v = match g() {
 LL | |         Some(v_some) => v_some,
 LL | |         None => return,
 LL | |     };
-   | |______^ help: consider writing: `let Some(v_some) = g() else { return };`
+   | |______^ help: consider writing: `let Some(v) = g() else { return };`
    |
    = note: `-D clippy::manual-let-else` implied by `-D warnings`
 
@@ -16,7 +16,7 @@ LL | /     let v = match g() {
 LL | |         Some(v_some) => v_some,
 LL | |         _ => return,
 LL | |     };
-   | |______^ help: consider writing: `let Some(v_some) = g() else { return };`
+   | |______^ help: consider writing: `let Some(v) = g() else { return };`
 
 error: this could be rewritten as `let...else`
   --> $DIR/manual_let_else_match.rs:44:9

From 4931f4549bb8622f3588ba835f8eb2201e687059 Mon Sep 17 00:00:00 2001
From: koka <koka.code@gmail.com>
Date: Wed, 1 Feb 2023 19:29:31 +0900
Subject: [PATCH 02/78] Split if conditions by its semantics

---
 clippy_lints/src/manual_let_else.rs | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs
index 4d53a664fa0..e461e538b5a 100644
--- a/clippy_lints/src/manual_let_else.rs
+++ b/clippy_lints/src/manual_let_else.rs
@@ -68,9 +68,11 @@ impl_lint_pass!(ManualLetElse => [MANUAL_LET_ELSE]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) {
-        if self.msrv.meets(msrvs::LET_ELSE) &&
-            !in_external_macro(cx.sess(), stmt.span) &&
-            let StmtKind::Local(local) = stmt.kind &&
+        if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) {
+            return;
+        }
+
+        if let StmtKind::Local(local) = stmt.kind &&
             let Some(init) = local.init &&
             local.els.is_none() &&
             local.ty.is_none() &&

From 20338fd378fb6ee937ee1171c2752c57ba385ab4 Mon Sep 17 00:00:00 2001
From: koka <koka.code@gmail.com>
Date: Wed, 1 Feb 2023 19:30:21 +0900
Subject: [PATCH 03/78] Remove old feature flag in code comment

Since let_else feature has been stable in 1.65.0, it's now unnecessary
---
 clippy_lints/src/manual_let_else.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs
index e461e538b5a..ccc0e475cb2 100644
--- a/clippy_lints/src/manual_let_else.rs
+++ b/clippy_lints/src/manual_let_else.rs
@@ -37,7 +37,6 @@ declare_clippy_lint! {
     /// Could be written:
     ///
     /// ```rust
-    /// # #![feature(let_else)]
     /// # fn main () {
     /// # let w = Some(0);
     /// let Some(v) = w else { return };

From 07c8c50a41dd4551ca3cb9155976a237eeefc1eb Mon Sep 17 00:00:00 2001
From: koka <koka.code@gmail.com>
Date: Wed, 1 Feb 2023 20:45:26 +0900
Subject: [PATCH 04/78] Avoid renaming for TupleStruct with multiple arguments

update spec

fix: move specs in fire
---
 clippy_lints/src/manual_let_else.rs |  3 +-
 tests/ui/manual_let_else.rs         | 15 +++++++++
 tests/ui/manual_let_else.stderr     | 50 ++++++++++++++++++-----------
 3 files changed, 48 insertions(+), 20 deletions(-)

diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs
index ccc0e475cb2..9554f5d5a77 100644
--- a/clippy_lints/src/manual_let_else.rs
+++ b/clippy_lints/src/manual_let_else.rs
@@ -156,7 +156,8 @@ fn emit_manual_let_else(
                     let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app);
                     format!("({sn_pat})")
                 },
-                PatKind::TupleStruct(ref w, ..) => {
+                // Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`.
+                PatKind::TupleStruct(ref w, args, ..) if args.len() == 1 => {
                     let sn_wrapper = cx.sess().source_map().span_to_snippet(w.span()).unwrap_or_default();
                     let (sn_inner, _) = snippet_with_context(cx, local.span, span.ctxt(), "", &mut app);
                     format!("{sn_wrapper}({sn_inner})")
diff --git a/tests/ui/manual_let_else.rs b/tests/ui/manual_let_else.rs
index 48a162c1360..23f530f41cd 100644
--- a/tests/ui/manual_let_else.rs
+++ b/tests/ui/manual_let_else.rs
@@ -8,6 +8,12 @@
 )]
 #![warn(clippy::manual_let_else)]
 
+enum Variant {
+    A(usize, usize),
+    B(usize),
+    C,
+}
+
 fn g() -> Option<()> {
     None
 }
@@ -135,6 +141,15 @@ fn fire() {
         };
     }
     create_binding_if_some!(w, g());
+
+    fn e() -> Variant {
+        Variant::A(0, 0)
+    }
+
+    // Should not be renamed
+    let v = if let Variant::A(a, 0) = e() { a } else { return };
+    // Should be renamed
+    let v = if let Variant::B(b) = e() { b } else { return };
 }
 
 fn not_fire() {
diff --git a/tests/ui/manual_let_else.stderr b/tests/ui/manual_let_else.stderr
index fe45cfd25b6..f6f56f7b00e 100644
--- a/tests/ui/manual_let_else.stderr
+++ b/tests/ui/manual_let_else.stderr
@@ -1,5 +1,5 @@
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:18:5
+  --> $DIR/manual_let_else.rs:24:5
    |
 LL |     let v = if let Some(v_some) = g() { v_some } else { return };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };`
@@ -7,7 +7,7 @@ LL |     let v = if let Some(v_some) = g() { v_some } else { return };
    = note: `-D clippy::manual-let-else` implied by `-D warnings`
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:19:5
+  --> $DIR/manual_let_else.rs:25:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |         v_some
@@ -24,7 +24,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:25:5
+  --> $DIR/manual_let_else.rs:31:5
    |
 LL | /     let v = if let Some(v) = g() {
 LL | |         // Blocks around the identity should have no impact
@@ -45,25 +45,25 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:38:9
+  --> $DIR/manual_let_else.rs:44:9
    |
 LL |         let v = if let Some(v_some) = g() { v_some } else { continue };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };`
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:39:9
+  --> $DIR/manual_let_else.rs:45:9
    |
 LL |         let v = if let Some(v_some) = g() { v_some } else { break };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };`
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:43:5
+  --> $DIR/manual_let_else.rs:49:5
    |
 LL |     let v = if let Some(v_some) = g() { v_some } else { panic!() };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };`
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:46:5
+  --> $DIR/manual_let_else.rs:52:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |         v_some
@@ -80,7 +80,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:53:5
+  --> $DIR/manual_let_else.rs:59:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |         v_some
@@ -97,7 +97,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:60:5
+  --> $DIR/manual_let_else.rs:66:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |         v_some
@@ -116,7 +116,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:70:5
+  --> $DIR/manual_let_else.rs:76:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |         v_some
@@ -138,13 +138,13 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:80:5
+  --> $DIR/manual_let_else.rs:86:5
    |
 LL |     let v = if let Some(v_some) = g() { v_some } else { if panic!() {} };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { if panic!() {} };`
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:83:5
+  --> $DIR/manual_let_else.rs:89:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |         v_some
@@ -165,7 +165,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:92:5
+  --> $DIR/manual_let_else.rs:98:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |         v_some
@@ -186,7 +186,7 @@ LL +     } };
    |
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:101:5
+  --> $DIR/manual_let_else.rs:107:5
    |
 LL | /     let v = if let Some(v_some) = g() {
 LL | |         v_some
@@ -215,7 +215,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:118:5
+  --> $DIR/manual_let_else.rs:124:5
    |
 LL | /     let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) {
 LL | |         v_some
@@ -232,7 +232,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:125:5
+  --> $DIR/manual_let_else.rs:131:5
    |
 LL | /     let v = if let (Some(v_some), w_some) = (g(), 0) {
 LL | |         (w_some, v_some)
@@ -249,7 +249,7 @@ LL +     };
    |
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:134:13
+  --> $DIR/manual_let_else.rs:140:13
    |
 LL |             let $n = if let Some(v) = $e { v } else { return };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };`
@@ -260,7 +260,19 @@ LL |     create_binding_if_some!(w, g());
    = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this could be rewritten as `let...else`
-  --> $DIR/manual_let_else.rs:247:5
+  --> $DIR/manual_let_else.rs:150:5
+   |
+LL |     let v = if let Variant::A(a, 0) = e() { a } else { return };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(a, 0) = e() else { return };`
+
+error: this could be rewritten as `let...else`
+  --> $DIR/manual_let_else.rs:152:5
+   |
+LL |     let v = if let Variant::B(b) = e() { b } else { return };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(v) = e() else { return };`
+
+error: this could be rewritten as `let...else`
+  --> $DIR/manual_let_else.rs:262:5
    |
 LL | /     let _ = match ff {
 LL | |         Some(value) => value,
@@ -268,5 +280,5 @@ LL | |         _ => macro_call!(),
 LL | |     };
    | |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };`
 
-error: aborting due to 18 previous errors
+error: aborting due to 20 previous errors
 

From 5fc1c79019519f7e02f8bfe59ca6df50c629c470 Mon Sep 17 00:00:00 2001
From: J-ZhengLi <lizheng135@huawei.com>
Date: Sat, 22 Apr 2023 11:17:10 +0800
Subject: [PATCH 05/78] bump up `regex-syntax` dependency version to 0.7.0

---
 clippy_lints/Cargo.toml   |  2 +-
 clippy_lints/src/regex.rs | 23 +++++++++++-----------
 tests/ui/regex.rs         |  2 ++
 tests/ui/regex.stderr     | 40 ++++++++++++++-------------------------
 4 files changed, 28 insertions(+), 39 deletions(-)

diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml
index 5c6040f63f5..11d9c7f89fe 100644
--- a/clippy_lints/Cargo.toml
+++ b/clippy_lints/Cargo.toml
@@ -17,7 +17,7 @@ if_chain = "1.0"
 itertools = "0.10.1"
 pulldown-cmark = { version = "0.9", default-features = false }
 quine-mc_cluskey = "0.2"
-regex-syntax = "0.6"
+regex-syntax = "0.7"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = { version = "1.0", optional = true }
 tempfile = { version = "3.3.0", optional = true }
diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs
index 9e6c6c73d4f..4b2634ee902 100644
--- a/clippy_lints/src/regex.rs
+++ b/clippy_lints/src/regex.rs
@@ -129,30 +129,32 @@ fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String>
 }
 
 fn is_trivial_regex(s: &regex_syntax::hir::Hir) -> Option<&'static str> {
-    use regex_syntax::hir::Anchor::{EndText, StartText};
-    use regex_syntax::hir::HirKind::{Alternation, Anchor, Concat, Empty, Literal};
+    use regex_syntax::hir::HirKind::{Alternation, Concat, Empty, Literal, Look};
+    use regex_syntax::hir::Look as HirLook;
 
     let is_literal = |e: &[regex_syntax::hir::Hir]| e.iter().all(|e| matches!(*e.kind(), Literal(_)));
 
     match *s.kind() {
-        Empty | Anchor(_) => Some("the regex is unlikely to be useful as it is"),
+        Empty | Look(_) => Some("the regex is unlikely to be useful as it is"),
         Literal(_) => Some("consider using `str::contains`"),
         Alternation(ref exprs) => {
-            if exprs.iter().all(|e| e.kind().is_empty()) {
+            if exprs.iter().all(|e| matches!(e.kind(), Empty)) {
                 Some("the regex is unlikely to be useful as it is")
             } else {
                 None
             }
         },
         Concat(ref exprs) => match (exprs[0].kind(), exprs[exprs.len() - 1].kind()) {
-            (&Anchor(StartText), &Anchor(EndText)) if exprs[1..(exprs.len() - 1)].is_empty() => {
+            (&Look(HirLook::Start), &Look(HirLook::End)) if exprs[1..(exprs.len() - 1)].is_empty() => {
                 Some("consider using `str::is_empty`")
             },
-            (&Anchor(StartText), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => {
+            (&Look(HirLook::Start), &Look(HirLook::End)) if is_literal(&exprs[1..(exprs.len() - 1)]) => {
                 Some("consider using `==` on `str`s")
             },
-            (&Anchor(StartText), &Literal(_)) if is_literal(&exprs[1..]) => Some("consider using `str::starts_with`"),
-            (&Literal(_), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => {
+            (&Look(HirLook::Start), &Literal(_)) if is_literal(&exprs[1..]) => {
+                Some("consider using `str::starts_with`")
+            },
+            (&Literal(_), &Look(HirLook::End)) if is_literal(&exprs[1..(exprs.len() - 1)]) => {
                 Some("consider using `str::ends_with`")
             },
             _ if is_literal(exprs) => Some("consider using `str::contains`"),
@@ -175,10 +177,7 @@ fn check_set<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
 }
 
 fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
-    let mut parser = regex_syntax::ParserBuilder::new()
-        .unicode(true)
-        .allow_invalid_utf8(!utf8)
-        .build();
+    let mut parser = regex_syntax::ParserBuilder::new().unicode(true).utf8(!utf8).build();
 
     if let ExprKind::Lit(ref lit) = expr.kind {
         if let LitKind::Str(ref r, style) = lit.node {
diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs
index ab8ac97a0e7..a5f79b139bc 100644
--- a/tests/ui/regex.rs
+++ b/tests/ui/regex.rs
@@ -34,8 +34,10 @@ fn syntax_error() {
     let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]);
     let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]);
 
+    // These following three cases are considering valid since regex-1.8.0
     let raw_string_error = Regex::new(r"[...\/...]");
     let raw_string_error = Regex::new(r#"[...\/...]"#);
+    let _ = Regex::new(r"(?<hi>hi)").unwrap();
 
     let escaped_string_span = Regex::new("\\b\\c");
 
diff --git a/tests/ui/regex.stderr b/tests/ui/regex.stderr
index c2440f39e0a..6b8a772e7f0 100644
--- a/tests/ui/regex.stderr
+++ b/tests/ui/regex.stderr
@@ -82,23 +82,11 @@ error: regex parse error:
 LL |     let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]);
    |                                       ^^^^^^^^^^^^^
 
-error: regex syntax error: unrecognized escape sequence
-  --> $DIR/regex.rs:37:45
-   |
-LL |     let raw_string_error = Regex::new(r"[...//...]");
-   |                                             ^^
-
-error: regex syntax error: unrecognized escape sequence
-  --> $DIR/regex.rs:38:46
-   |
-LL |     let raw_string_error = Regex::new(r#"[...//...]"#);
-   |                                              ^^
-
 error: regex parse error:
            /b/c
              ^^
        error: unrecognized escape sequence
-  --> $DIR/regex.rs:40:42
+  --> $DIR/regex.rs:42:42
    |
 LL |     let escaped_string_span = Regex::new("/b/c");
    |                                          ^^^^^^^^
@@ -106,13 +94,13 @@ LL |     let escaped_string_span = Regex::new("/b/c");
    = help: consider using a raw string literal: `r".."`
 
 error: regex syntax error: duplicate flag
-  --> $DIR/regex.rs:42:34
+  --> $DIR/regex.rs:44:34
    |
 LL |     let aux_span = Regex::new("(?ixi)");
    |                                  ^ ^
 
 error: trivial regex
-  --> $DIR/regex.rs:46:33
+  --> $DIR/regex.rs:48:33
    |
 LL |     let trivial_eq = Regex::new("^foobar$");
    |                                 ^^^^^^^^^^
@@ -120,7 +108,7 @@ LL |     let trivial_eq = Regex::new("^foobar$");
    = help: consider using `==` on `str`s
 
 error: trivial regex
-  --> $DIR/regex.rs:48:48
+  --> $DIR/regex.rs:50:48
    |
 LL |     let trivial_eq_builder = RegexBuilder::new("^foobar$");
    |                                                ^^^^^^^^^^
@@ -128,7 +116,7 @@ LL |     let trivial_eq_builder = RegexBuilder::new("^foobar$");
    = help: consider using `==` on `str`s
 
 error: trivial regex
-  --> $DIR/regex.rs:50:42
+  --> $DIR/regex.rs:52:42
    |
 LL |     let trivial_starts_with = Regex::new("^foobar");
    |                                          ^^^^^^^^^
@@ -136,7 +124,7 @@ LL |     let trivial_starts_with = Regex::new("^foobar");
    = help: consider using `str::starts_with`
 
 error: trivial regex
-  --> $DIR/regex.rs:52:40
+  --> $DIR/regex.rs:54:40
    |
 LL |     let trivial_ends_with = Regex::new("foobar$");
    |                                        ^^^^^^^^^
@@ -144,7 +132,7 @@ LL |     let trivial_ends_with = Regex::new("foobar$");
    = help: consider using `str::ends_with`
 
 error: trivial regex
-  --> $DIR/regex.rs:54:39
+  --> $DIR/regex.rs:56:39
    |
 LL |     let trivial_contains = Regex::new("foobar");
    |                                       ^^^^^^^^
@@ -152,7 +140,7 @@ LL |     let trivial_contains = Regex::new("foobar");
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:56:39
+  --> $DIR/regex.rs:58:39
    |
 LL |     let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
    |                                       ^^^^^^^^^^^^^^^^
@@ -160,7 +148,7 @@ LL |     let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:58:40
+  --> $DIR/regex.rs:60:40
    |
 LL |     let trivial_backslash = Regex::new("a/.b");
    |                                        ^^^^^^^
@@ -168,7 +156,7 @@ LL |     let trivial_backslash = Regex::new("a/.b");
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:61:36
+  --> $DIR/regex.rs:63:36
    |
 LL |     let trivial_empty = Regex::new("");
    |                                    ^^
@@ -176,7 +164,7 @@ LL |     let trivial_empty = Regex::new("");
    = help: the regex is unlikely to be useful as it is
 
 error: trivial regex
-  --> $DIR/regex.rs:63:36
+  --> $DIR/regex.rs:65:36
    |
 LL |     let trivial_empty = Regex::new("^");
    |                                    ^^^
@@ -184,7 +172,7 @@ LL |     let trivial_empty = Regex::new("^");
    = help: the regex is unlikely to be useful as it is
 
 error: trivial regex
-  --> $DIR/regex.rs:65:36
+  --> $DIR/regex.rs:67:36
    |
 LL |     let trivial_empty = Regex::new("^$");
    |                                    ^^^^
@@ -192,12 +180,12 @@ LL |     let trivial_empty = Regex::new("^$");
    = help: consider using `str::is_empty`
 
 error: trivial regex
-  --> $DIR/regex.rs:67:44
+  --> $DIR/regex.rs:69:44
    |
 LL |     let binary_trivial_empty = BRegex::new("^$");
    |                                            ^^^^
    |
    = help: consider using `str::is_empty`
 
-error: aborting due to 25 previous errors
+error: aborting due to 23 previous errors
 

From cc607fe32ed69ac35b60e962803a2fb2133471cd Mon Sep 17 00:00:00 2001
From: y21 <30553356+y21@users.noreply.github.com>
Date: Sun, 30 Apr 2023 01:30:15 +0200
Subject: [PATCH 06/78] don't remove `dbg!` in arbitrary expressions

---
 clippy_lints/src/dbg_macro.rs | 38 +++++++++++++++-------
 tests/ui/dbg_macro.rs         |  8 +++++
 tests/ui/dbg_macro.stderr     | 60 +++++++++++++++++++++++++++--------
 3 files changed, 82 insertions(+), 24 deletions(-)

diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs
index 799e71e847a..cea712f2fee 100644
--- a/clippy_lints/src/dbg_macro.rs
+++ b/clippy_lints/src/dbg_macro.rs
@@ -3,10 +3,10 @@ use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::sym;
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -31,6 +31,11 @@ declare_clippy_lint! {
     "`dbg!` macro is intended as a debugging tool"
 }
 
+fn span_including_semi(cx: &LateContext<'_>, span: Span) -> Span {
+    let span = cx.sess().source_map().span_extend_to_next_char(span, ';', true);
+    span.with_hi(span.hi() + rustc_span::BytePos(1))
+}
+
 #[derive(Copy, Clone)]
 pub struct DbgMacro {
     allow_dbg_in_tests: bool,
@@ -55,13 +60,24 @@ impl LateLintPass<'_> for DbgMacro {
                 return;
             }
             let mut applicability = Applicability::MachineApplicable;
-            let suggestion = match expr.peel_drop_temps().kind {
-                // dbg!()
-                ExprKind::Block(_, _) => String::new(),
-                // dbg!(1)
-                ExprKind::Match(val, ..) => {
-                    snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string()
+
+            let (sugg_span, suggestion) = match expr.peel_drop_temps().kind {
+                ExprKind::Block(..) => match cx.tcx.hir().find_parent(expr.hir_id) {
+                    // dbg!() as a standalone statement, suggest removing the whole statement entirely
+                    Some(Node::Stmt(
+                        stmt @ Stmt {
+                            kind: StmtKind::Semi(_),
+                            ..
+                        },
+                    )) => (span_including_semi(cx, stmt.span.source_callsite()), String::new()),
+                    // empty dbg!() in arbitrary position (e.g. `foo(dbg!())`), suggest replacing with `foo(())`
+                    _ => (macro_call.span, String::from("()")),
                 },
+                // dbg!(1)
+                ExprKind::Match(val, ..) => (
+                    macro_call.span,
+                    snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string(),
+                ),
                 // dbg!(2, 3)
                 ExprKind::Tup(
                     [
@@ -82,7 +98,7 @@ impl LateLintPass<'_> for DbgMacro {
                         "..",
                         &mut applicability,
                     );
-                    format!("({snippet})")
+                    (macro_call.span, format!("({snippet})"))
                 },
                 _ => return,
             };
@@ -90,7 +106,7 @@ impl LateLintPass<'_> for DbgMacro {
             span_lint_and_sugg(
                 cx,
                 DBG_MACRO,
-                macro_call.span,
+                sugg_span,
                 "the `dbg!` macro is intended as a debugging tool",
                 "remove the invocation before committing it to a version control system",
                 suggestion,
diff --git a/tests/ui/dbg_macro.rs b/tests/ui/dbg_macro.rs
index 8701e3cd29f..ae2075e7dad 100644
--- a/tests/ui/dbg_macro.rs
+++ b/tests/ui/dbg_macro.rs
@@ -4,6 +4,7 @@
 fn foo(n: u32) -> u32 {
     if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
 }
+fn bar(_: ()) {}
 
 fn factorial(n: u32) -> u32 {
     if dbg!(n <= 1) {
@@ -21,6 +22,13 @@ fn main() {
     dbg!(1, 2, 3, 4, 5);
 }
 
+fn issue9914() {
+    dbg!();
+    #[allow(clippy::let_unit_value)]
+    let _ = dbg!();
+    bar(dbg!());
+}
+
 mod issue7274 {
     trait Thing<'b> {
         fn foo(&self);
diff --git a/tests/ui/dbg_macro.stderr b/tests/ui/dbg_macro.stderr
index ddb5f1342e9..34329a06b97 100644
--- a/tests/ui/dbg_macro.stderr
+++ b/tests/ui/dbg_macro.stderr
@@ -11,7 +11,7 @@ LL |     if let Some(n) = n.checked_sub(4) { n } else { n }
    |                      ~~~~~~~~~~~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:9:8
+  --> $DIR/dbg_macro.rs:10:8
    |
 LL |     if dbg!(n <= 1) {
    |        ^^^^^^^^^^^^
@@ -22,7 +22,7 @@ LL |     if n <= 1 {
    |        ~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:10:9
+  --> $DIR/dbg_macro.rs:11:9
    |
 LL |         dbg!(1)
    |         ^^^^^^^
@@ -33,7 +33,7 @@ LL |         1
    |
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:12:9
+  --> $DIR/dbg_macro.rs:13:9
    |
 LL |         dbg!(n * factorial(n - 1))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -44,7 +44,7 @@ LL |         n * factorial(n - 1)
    |
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:17:5
+  --> $DIR/dbg_macro.rs:18:5
    |
 LL |     dbg!(42);
    |     ^^^^^^^^
@@ -55,7 +55,7 @@ LL |     42;
    |     ~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:18:5
+  --> $DIR/dbg_macro.rs:19:5
    |
 LL |     dbg!(dbg!(dbg!(42)));
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -66,7 +66,7 @@ LL |     dbg!(dbg!(42));
    |     ~~~~~~~~~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:19:14
+  --> $DIR/dbg_macro.rs:20:14
    |
 LL |     foo(3) + dbg!(factorial(4));
    |              ^^^^^^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ LL |     foo(3) + factorial(4);
    |              ~~~~~~~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:20:5
+  --> $DIR/dbg_macro.rs:21:5
    |
 LL |     dbg!(1, 2, dbg!(3, 4));
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -88,7 +88,7 @@ LL |     (1, 2, dbg!(3, 4));
    |     ~~~~~~~~~~~~~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:21:5
+  --> $DIR/dbg_macro.rs:22:5
    |
 LL |     dbg!(1, 2, 3, 4, 5);
    |     ^^^^^^^^^^^^^^^^^^^
@@ -99,7 +99,41 @@ LL |     (1, 2, 3, 4, 5);
    |     ~~~~~~~~~~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:41:9
+  --> $DIR/dbg_macro.rs:26:5
+   |
+LL |     dbg!();
+   |     ^^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL -     dbg!();
+LL +     
+   |
+
+error: the `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:28:13
+   |
+LL |     let _ = dbg!();
+   |             ^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL |     let _ = ();
+   |             ~~
+
+error: the `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:29:9
+   |
+LL |     bar(dbg!());
+   |         ^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL |     bar(());
+   |         ~~
+
+error: the `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:49:9
    |
 LL |         dbg!(2);
    |         ^^^^^^^
@@ -110,7 +144,7 @@ LL |         2;
    |         ~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:47:5
+  --> $DIR/dbg_macro.rs:55:5
    |
 LL |     dbg!(1);
    |     ^^^^^^^
@@ -121,7 +155,7 @@ LL |     1;
    |     ~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:52:5
+  --> $DIR/dbg_macro.rs:60:5
    |
 LL |     dbg!(1);
    |     ^^^^^^^
@@ -132,7 +166,7 @@ LL |     1;
    |     ~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:58:9
+  --> $DIR/dbg_macro.rs:66:9
    |
 LL |         dbg!(1);
    |         ^^^^^^^
@@ -142,5 +176,5 @@ help: remove the invocation before committing it to a version control system
 LL |         1;
    |         ~
 
-error: aborting due to 13 previous errors
+error: aborting due to 16 previous errors
 

From 478555d468d54105a0202220b7632b08a992b9be Mon Sep 17 00:00:00 2001
From: John Kelly <johnharrykelly@gmail.com>
Date: Sun, 30 Apr 2023 13:16:04 +0100
Subject: [PATCH 07/78] wip

---
 clippy_lints/src/trait_bounds.rs        | 45 +++++++++++++++++++++++--
 tests/ui/trait_duplication_in_bounds.rs |  8 +++++
 2 files changed, 50 insertions(+), 3 deletions(-)

diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index b5f11b4acae..13651c978e9 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -9,7 +9,7 @@ use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{
-    GenericArg, GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, PredicateOrigin, QPath,
+    GenericArg, GenericBound, Generics, Item, ItemKind, MutTy, Node, Path, PathSegment, PredicateOrigin, QPath,
     TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -37,12 +37,12 @@ declare_clippy_lint! {
     #[clippy::version = "1.38.0"]
     pub TYPE_REPETITION_IN_BOUNDS,
     nursery,
-    "types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`"
+    "types are repeated unnecessarily in trait bounds, use `+` instead of using `T: _, T: _`"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for cases where generics are being used and multiple
+    /// Checks for cases where generics or trait objects are being used and multiple
     /// syntax specifications for trait bounds are used simultaneously.
     ///
     /// ### Why is this bad?
@@ -167,6 +167,45 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
             }
         }
     }
+
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
+        let TyKind::Ref(
+            ..,
+            MutTy {
+                ty: Ty {
+                    kind: TyKind::TraitObject(
+                        bounds,
+                        ..
+                    ),
+                    ..
+                },
+                ..
+            }
+        ) = ty.kind else { return; };
+
+        if bounds.len() < 2 {
+            return;
+        }
+
+        let mut seen_def_ids = FxHashSet::default();
+
+        for bound in bounds.iter() {
+            let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; };
+
+            let already_seen = !seen_def_ids.insert(def_id);
+
+            if already_seen {
+                span_lint_and_help(
+                    cx,
+                    TRAIT_DUPLICATION_IN_BOUNDS,
+                    bound.span,
+                    "this trait bound is already specified in trait declaration",
+                    None,
+                    "consider removing this trait bound",
+                );
+            }
+        }
+    }
 }
 
 impl TraitBounds {
diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs
index a7a1caf2880..f4f4a9fcb08 100644
--- a/tests/ui/trait_duplication_in_bounds.rs
+++ b/tests/ui/trait_duplication_in_bounds.rs
@@ -109,4 +109,12 @@ fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
     unimplemented!();
 }
 
+fn good_trait_object(arg0: &(dyn Any + Send)) {
+    unimplemented!();
+}
+
+fn bad_trait_object(arg0: &(dyn Any + Send + Send)) {
+    unimplemented!();
+}
+
 fn main() {}

From 1eff408ca44ae15ffd6592714487f168a5549bcc Mon Sep 17 00:00:00 2001
From: John Kelly <johnharrykelly@gmail.com>
Date: Sun, 30 Apr 2023 13:45:45 +0100
Subject: [PATCH 08/78] WIP

---
 clippy_lints/src/trait_bounds.rs            |  5 +++--
 tests/ui/trait_duplication_in_bounds.fixed  | 10 +++++++++
 tests/ui/trait_duplication_in_bounds.rs     |  2 ++
 tests/ui/trait_duplication_in_bounds.stderr | 25 +++++++++++++--------
 4 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 13651c978e9..1af2c594243 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -195,13 +195,14 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
             let already_seen = !seen_def_ids.insert(def_id);
 
             if already_seen {
-                span_lint_and_help(
+                span_lint_and_sugg(
                     cx,
                     TRAIT_DUPLICATION_IN_BOUNDS,
                     bound.span,
                     "this trait bound is already specified in trait declaration",
-                    None,
                     "consider removing this trait bound",
+                    "".to_string(),
+                    Applicability::MaybeIncorrect,
                 );
             }
         }
diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed
index eef8024b131..fdac0e4cb1e 100644
--- a/tests/ui/trait_duplication_in_bounds.fixed
+++ b/tests/ui/trait_duplication_in_bounds.fixed
@@ -2,6 +2,8 @@
 #![deny(clippy::trait_duplication_in_bounds)]
 #![allow(unused)]
 
+use std::any::Any;
+
 fn bad_foo<T: Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
     unimplemented!();
 }
@@ -109,4 +111,12 @@ fn qualified_path<T: std::clone::Clone + foo::Clone>(arg0: T) {
     unimplemented!();
 }
 
+fn good_trait_object(arg0: &(dyn Any + Send)) {
+    unimplemented!();
+}
+
+fn bad_trait_object(arg0: &(dyn Any + Send)) {
+    unimplemented!();
+}
+
 fn main() {}
diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs
index f4f4a9fcb08..a0300da5555 100644
--- a/tests/ui/trait_duplication_in_bounds.rs
+++ b/tests/ui/trait_duplication_in_bounds.rs
@@ -2,6 +2,8 @@
 #![deny(clippy::trait_duplication_in_bounds)]
 #![allow(unused)]
 
+use std::any::Any;
+
 fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
     unimplemented!();
 }
diff --git a/tests/ui/trait_duplication_in_bounds.stderr b/tests/ui/trait_duplication_in_bounds.stderr
index af800ba7888..a6508eb86f3 100644
--- a/tests/ui/trait_duplication_in_bounds.stderr
+++ b/tests/ui/trait_duplication_in_bounds.stderr
@@ -1,5 +1,5 @@
 error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:5:15
+  --> $DIR/trait_duplication_in_bounds.rs:7:15
    |
 LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
@@ -11,46 +11,53 @@ LL | #![deny(clippy::trait_duplication_in_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: these where clauses contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:11:8
+  --> $DIR/trait_duplication_in_bounds.rs:13:8
    |
 LL |     T: Clone + Clone + Clone + Copy,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
 
 error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:39:26
+  --> $DIR/trait_duplication_in_bounds.rs:41:26
    |
 LL | trait BadSelfTraitBound: Clone + Clone + Clone {
    |                          ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
 
 error: these where clauses contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:46:15
+  --> $DIR/trait_duplication_in_bounds.rs:48:15
    |
 LL |         Self: Clone + Clone + Clone;
    |               ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
 
 error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:60:24
+  --> $DIR/trait_duplication_in_bounds.rs:62:24
    |
 LL | trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
 
 error: these where clauses contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:67:12
+  --> $DIR/trait_duplication_in_bounds.rs:69:12
    |
 LL |         T: Clone + Clone + Clone + Copy,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
 
 error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:100:19
+  --> $DIR/trait_duplication_in_bounds.rs:102:19
    |
 LL | fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait<u64> + GenericTrait<u32>`
 
 error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:108:22
+  --> $DIR/trait_duplication_in_bounds.rs:110:22
    |
 LL | fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone`
 
-error: aborting due to 8 previous errors
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds.rs:118:46
+   |
+LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) {
+   |                                              ^^^^ help: consider removing this trait bound
+   |
+
+error: aborting due to 9 previous errors
 

From 0fb3f3b25667c2e9c56a7fd83019cafec7ada1cf Mon Sep 17 00:00:00 2001
From: John Kelly <johnharrykelly@gmail.com>
Date: Sun, 30 Apr 2023 14:10:26 +0100
Subject: [PATCH 09/78] WIP

---
 clippy_lints/src/trait_bounds.rs | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 1af2c594243..4c70bae7529 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -177,6 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                         bounds,
                         ..
                     ),
+                    span,
                     ..
                 },
                 ..
@@ -189,6 +190,12 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
 
         let mut seen_def_ids = FxHashSet::default();
 
+        let traits = bounds
+            .iter()
+            .filter_map(|b| snippet_opt(cx, b.span))
+            .collect::<Vec<_>>();
+        let traits = traits.join(" + ");
+
         for bound in bounds.iter() {
             let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; };
 
@@ -198,10 +205,10 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                 span_lint_and_sugg(
                     cx,
                     TRAIT_DUPLICATION_IN_BOUNDS,
-                    bound.span,
+                    *span,
                     "this trait bound is already specified in trait declaration",
                     "consider removing this trait bound",
-                    "".to_string(),
+                    traits.clone(),
                     Applicability::MaybeIncorrect,
                 );
             }

From 8db21e9a9c63496271b5db11af665ada036fac4d Mon Sep 17 00:00:00 2001
From: John Kelly <johnharrykelly@gmail.com>
Date: Sun, 30 Apr 2023 14:14:47 +0100
Subject: [PATCH 10/78] WIP

---
 clippy_lints/src/trait_bounds.rs | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 4c70bae7529..2c1c63e808b 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -177,7 +177,6 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                         bounds,
                         ..
                     ),
-                    span,
                     ..
                 },
                 ..
@@ -188,6 +187,12 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
             return;
         }
 
+        let mut bounds_span = Span::default();
+
+        for bound in bounds.iter() {
+            bounds_span = bounds_span.to(bound.span);
+        }
+
         let mut seen_def_ids = FxHashSet::default();
 
         let traits = bounds
@@ -205,7 +210,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                 span_lint_and_sugg(
                     cx,
                     TRAIT_DUPLICATION_IN_BOUNDS,
-                    *span,
+                    bounds_span,
                     "this trait bound is already specified in trait declaration",
                     "consider removing this trait bound",
                     traits.clone(),

From b9788fef298815c2b8366a42ef0c8113170d11ed Mon Sep 17 00:00:00 2001
From: John Kelly <johnharrykelly@gmail.com>
Date: Sun, 30 Apr 2023 14:34:46 +0100
Subject: [PATCH 11/78] Working

---
 clippy_lints/src/trait_bounds.rs            | 43 ++++++++++++---------
 tests/ui/trait_duplication_in_bounds.stderr |  5 +--
 2 files changed, 26 insertions(+), 22 deletions(-)

diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 2c1c63e808b..8de0f92109b 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -187,37 +187,42 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
             return;
         }
 
-        let mut bounds_span = Span::default();
+        let mut bounds_span = bounds[0].span;
 
-        for bound in bounds.iter() {
+        for bound in bounds.iter().skip(1) {
             bounds_span = bounds_span.to(bound.span);
         }
 
         let mut seen_def_ids = FxHashSet::default();
-
-        let traits = bounds
-            .iter()
-            .filter_map(|b| snippet_opt(cx, b.span))
-            .collect::<Vec<_>>();
-        let traits = traits.join(" + ");
+        let mut fixed_traits = Vec::new();
 
         for bound in bounds.iter() {
             let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; };
 
-            let already_seen = !seen_def_ids.insert(def_id);
+            let new_trait = seen_def_ids.insert(def_id);
 
-            if already_seen {
-                span_lint_and_sugg(
-                    cx,
-                    TRAIT_DUPLICATION_IN_BOUNDS,
-                    bounds_span,
-                    "this trait bound is already specified in trait declaration",
-                    "consider removing this trait bound",
-                    traits.clone(),
-                    Applicability::MaybeIncorrect,
-                );
+            if new_trait {
+                fixed_traits.push(bound);
             }
         }
+
+        let fixed_trait_snippet = fixed_traits
+            .iter()
+            .filter_map(|b| snippet_opt(cx, b.span))
+            .collect::<Vec<_>>()
+            .join(" + ");
+
+        if bounds.len() != fixed_traits.len() {
+            span_lint_and_sugg(
+                cx,
+                TRAIT_DUPLICATION_IN_BOUNDS,
+                bounds_span,
+                "this trait bound is already specified in trait declaration",
+                "try",
+                fixed_trait_snippet,
+                Applicability::MaybeIncorrect,
+            );
+        }
     }
 }
 
diff --git a/tests/ui/trait_duplication_in_bounds.stderr b/tests/ui/trait_duplication_in_bounds.stderr
index a6508eb86f3..539b6114ca3 100644
--- a/tests/ui/trait_duplication_in_bounds.stderr
+++ b/tests/ui/trait_duplication_in_bounds.stderr
@@ -53,11 +53,10 @@ LL | fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone`
 
 error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:118:46
+  --> $DIR/trait_duplication_in_bounds.rs:118:33
    |
 LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) {
-   |                                              ^^^^ help: consider removing this trait bound
-   |
+   |                                 ^^^^^^^^^^^^^^^^^ help: try: `Any + Send`
 
 error: aborting due to 9 previous errors
 

From a233bd5e66f1846adf67ba3eb47a830f35f5bb5a Mon Sep 17 00:00:00 2001
From: jyn <github@jyn.dev>
Date: Sat, 29 Apr 2023 06:29:07 -0500
Subject: [PATCH 12/78] Make the BUG_REPORT_URL configurable by tools

This greatly simplifies how hard it is to set a custom bug report url; previously tools had to copy
the entire hook implementation.

- Switch clippy to the new hook

  This also adds a `extra_info` callback so clippy can include its own version number, which differs
  from rustc's.

- Call `install_ice_hook` in rustfmt
---
 src/driver.rs | 70 +++++++--------------------------------------------
 1 file changed, 9 insertions(+), 61 deletions(-)

diff --git a/src/driver.rs b/src/driver.rs
index 205905d5091..59bf447a7cd 100644
--- a/src/driver.rs
+++ b/src/driver.rs
@@ -11,7 +11,6 @@
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
 extern crate rustc_driver;
-extern crate rustc_errors;
 extern crate rustc_interface;
 extern crate rustc_session;
 extern crate rustc_span;
@@ -20,13 +19,10 @@ use rustc_interface::interface;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::Symbol;
 
-use std::borrow::Cow;
 use std::env;
 use std::ops::Deref;
-use std::panic;
 use std::path::Path;
 use std::process::exit;
-use std::sync::LazyLock;
 
 /// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
 /// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
@@ -198,66 +194,18 @@ You can use tool lints to allow or deny lints from your code, eg.:
 
 const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";
 
-type PanicCallback = dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static;
-static ICE_HOOK: LazyLock<Box<PanicCallback>> = LazyLock::new(|| {
-    let hook = panic::take_hook();
-    panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
-    hook
-});
-
-fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
-    // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace
-    (*ICE_HOOK)(info);
-
-    // Separate the output with an empty line
-    eprintln!();
-
-    let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
-    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
-        rustc_errors::ColorConfig::Auto,
-        None,
-        None,
-        fallback_bundle,
-        false,
-        false,
-        None,
-        false,
-        false,
-        rustc_errors::TerminalUrl::No,
-    ));
-    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
-
-    // a .span_bug or .bug call has already printed what
-    // it wants to print.
-    if !info.payload().is::<rustc_errors::ExplicitBug>() {
-        let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
-        handler.emit_diagnostic(&mut d);
-    }
-
-    let version_info = rustc_tools_util::get_version_info!();
-
-    let xs: Vec<Cow<'static, str>> = vec![
-        "the compiler unexpectedly panicked. this is a bug.".into(),
-        format!("we would appreciate a bug report: {bug_report_url}").into(),
-        format!("Clippy version: {version_info}").into(),
-    ];
-
-    for note in &xs {
-        handler.note_without_error(note.as_ref());
-    }
-
-    // If backtraces are enabled, also print the query stack
-    let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
-
-    let num_frames = if backtrace { None } else { Some(2) };
-
-    interface::try_print_query_stack(&handler, num_frames);
-}
-
 #[allow(clippy::too_many_lines)]
 pub fn main() {
     rustc_driver::init_rustc_env_logger();
-    LazyLock::force(&ICE_HOOK);
+
+    rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| {
+        // FIXME: this macro calls unwrap internally but is called in a panicking context!  It's not
+        // as simple as moving the call from the hook to main, because `install_ice_hook` doesn't
+        // accept a generic closure.
+        let version_info = rustc_tools_util::get_version_info!();
+        handler.note_without_error(format!("Clippy version: {version_info}"));
+    });
+
     exit(rustc_driver::catch_with_exit_code(move || {
         let mut orig_args: Vec<String> = env::args().collect();
         let has_sysroot_arg = arg_value(&orig_args, "--sysroot", |_| true).is_some();

From 37127b8d7018ecc4af69ebdee06adeff9527f757 Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Sun, 5 Mar 2023 15:03:22 +0000
Subject: [PATCH 13/78] initial step towards implementing C string literals

---
 clippy_lints/src/matches/match_same_arms.rs | 1 +
 clippy_lints/src/utils/author.rs            | 5 +++++
 clippy_utils/src/consts.rs                  | 1 +
 3 files changed, 7 insertions(+)

diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs
index 158e6caa4de..a48f4c77f85 100644
--- a/clippy_lints/src/matches/match_same_arms.rs
+++ b/clippy_lints/src/matches/match_same_arms.rs
@@ -284,6 +284,7 @@ impl<'a> NormalizedPat<'a> {
                     LitKind::Str(sym, _) => Self::LitStr(sym),
                     LitKind::ByteStr(ref bytes, _) => Self::LitBytes(bytes),
                     LitKind::Byte(val) => Self::LitInt(val.into()),
+                    LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes),
                     LitKind::Char(val) => Self::LitInt(val.into()),
                     LitKind::Int(val, _) => Self::LitInt(val),
                     LitKind::Bool(val) => Self::LitBool(val),
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index 01927b6b5f1..f75dff46624 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -304,6 +304,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("ByteStr(ref {vec})");
                 chain!(self, "let [{:?}] = **{vec}", vec.value);
             },
+            LitKind::CStr(ref vec, _) => {
+                bind!(self, vec);
+                kind!("CStr(ref {vec})");
+                chain!(self, "let [{:?}] = **{vec}", vec.value);
+            }
             LitKind::Str(s, _) => {
                 bind!(self, s);
                 kind!("Str({s}, _)");
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index 99bfc4b5717..7c7ec6d334d 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -211,6 +211,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
         LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
         LitKind::Byte(b) => Constant::Int(u128::from(b)),
         LitKind::ByteStr(ref s, _) => Constant::Binary(Lrc::clone(s)),
+        LitKind::CStr(ref s, _) => Constant::Binary(Lrc::clone(s)),
         LitKind::Char(c) => Constant::Char(c),
         LitKind::Int(n, _) => Constant::Int(n),
         LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {

From f7595e0745d05261fa2b025a4f6b3ee7e7cc4796 Mon Sep 17 00:00:00 2001
From: Deadbeef <ent3rm4n@gmail.com>
Date: Mon, 6 Mar 2023 14:09:28 +0000
Subject: [PATCH 14/78] rm diag item, use lang item

---
 clippy_lints/src/strlen_on_c_strings.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs
index 03324c66e8e..2f2e84fa35a 100644
--- a/clippy_lints/src/strlen_on_c_strings.rs
+++ b/clippy_lints/src/strlen_on_c_strings.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use clippy_utils::visitors::is_expr_unsafe;
 use clippy_utils::{get_parent_node, match_libc_symbol};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, Node, UnsafeSource};
+use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
                 let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
                 let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) {
                     "as_bytes"
-                } else if is_type_diagnostic_item(cx, ty, sym::CStr) {
+                } else if is_type_lang_item(cx, ty, LangItem::CStr) {
                     "to_bytes"
                 } else {
                     return;

From cbd0135bd2d2e546ca4c2c2147798d1f7c547128 Mon Sep 17 00:00:00 2001
From: John Kelly <johnharrykelly@gmail.com>
Date: Tue, 2 May 2023 18:15:02 +0100
Subject: [PATCH 15/78] Update trait_bounds.rs

---
 clippy_lints/src/trait_bounds.rs | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 8de0f92109b..ac61fb157b4 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -206,13 +206,13 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
             }
         }
 
-        let fixed_trait_snippet = fixed_traits
-            .iter()
-            .filter_map(|b| snippet_opt(cx, b.span))
-            .collect::<Vec<_>>()
-            .join(" + ");
-
         if bounds.len() != fixed_traits.len() {
+            let fixed_trait_snippet = fixed_traits
+                .iter()
+                .filter_map(|b| snippet_opt(cx, b.span))
+                .collect::<Vec<_>>()
+                .join(" + ");
+
             span_lint_and_sugg(
                 cx,
                 TRAIT_DUPLICATION_IN_BOUNDS,

From 122793b4947c2691efcb2ab6450c251a25311aaf Mon Sep 17 00:00:00 2001
From: John Kelly <johnharrykelly@gmail.com>
Date: Tue, 2 May 2023 18:21:23 +0100
Subject: [PATCH 16/78] Update trait_bounds.rs

---
 clippy_lints/src/trait_bounds.rs | 95 ++++++++++++++------------------
 1 file changed, 42 insertions(+), 53 deletions(-)

diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index ac61fb157b4..5acd44dccaf 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -9,7 +9,7 @@ use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{
-    GenericArg, GenericBound, Generics, Item, ItemKind, MutTy, Node, Path, PathSegment, PredicateOrigin, QPath,
+    GenericArg, GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, PredicateOrigin, QPath,
     TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -169,59 +169,48 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
     }
 
     fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
-        let TyKind::Ref(
-            ..,
-            MutTy {
-                ty: Ty {
-                    kind: TyKind::TraitObject(
-                        bounds,
-                        ..
-                    ),
-                    ..
-                },
-                ..
+        if_chain! {
+            if let TyKind::Ref(.., mut_ty) = &ty.kind;
+            if let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind;
+            if bounds.len() > 2;
+            then {
+                let mut bounds_span = bounds[0].span;
+
+                for bound in bounds.iter().skip(1) {
+                    bounds_span = bounds_span.to(bound.span);
+                }
+
+                let mut seen_def_ids = FxHashSet::default();
+                let mut fixed_traits = Vec::new();
+
+                for bound in bounds.iter() {
+                    let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; };
+
+                    let new_trait = seen_def_ids.insert(def_id);
+
+                    if new_trait {
+                        fixed_traits.push(bound);
+                    }
+                }
+
+                if bounds.len() != fixed_traits.len() {
+                    let fixed_trait_snippet = fixed_traits
+                        .iter()
+                        .filter_map(|b| snippet_opt(cx, b.span))
+                        .collect::<Vec<_>>()
+                        .join(" + ");
+
+                    span_lint_and_sugg(
+                        cx,
+                        TRAIT_DUPLICATION_IN_BOUNDS,
+                        bounds_span,
+                        "this trait bound is already specified in trait declaration",
+                        "try",
+                        fixed_trait_snippet,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
             }
-        ) = ty.kind else { return; };
-
-        if bounds.len() < 2 {
-            return;
-        }
-
-        let mut bounds_span = bounds[0].span;
-
-        for bound in bounds.iter().skip(1) {
-            bounds_span = bounds_span.to(bound.span);
-        }
-
-        let mut seen_def_ids = FxHashSet::default();
-        let mut fixed_traits = Vec::new();
-
-        for bound in bounds.iter() {
-            let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; };
-
-            let new_trait = seen_def_ids.insert(def_id);
-
-            if new_trait {
-                fixed_traits.push(bound);
-            }
-        }
-
-        if bounds.len() != fixed_traits.len() {
-            let fixed_trait_snippet = fixed_traits
-                .iter()
-                .filter_map(|b| snippet_opt(cx, b.span))
-                .collect::<Vec<_>>()
-                .join(" + ");
-
-            span_lint_and_sugg(
-                cx,
-                TRAIT_DUPLICATION_IN_BOUNDS,
-                bounds_span,
-                "this trait bound is already specified in trait declaration",
-                "try",
-                fixed_trait_snippet,
-                Applicability::MaybeIncorrect,
-            );
         }
     }
 }

From 477c8b3eb07142f477ddf5d3e7d4761f3c92ba9d Mon Sep 17 00:00:00 2001
From: alnoki <43892045+alnoki@users.noreply.github.com>
Date: Tue, 2 May 2023 19:04:51 -0700
Subject: [PATCH 17/78] Bump README copyright

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 6745e15c006..d712d3e6750 100644
--- a/README.md
+++ b/README.md
@@ -278,7 +278,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT
 
 <!-- REUSE-IgnoreStart -->
 
-Copyright 2014-2022 The Rust Project Developers
+Copyright 2014-2023 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license

From 2bc479a2011107bf241856871d5f638586c95ad3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev>
Date: Tue, 21 Mar 2023 01:46:52 +0100
Subject: [PATCH 18/78] IAT: Introduce AliasKind::Inherent

---
 clippy_lints/src/dereference.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index 7f3f26bed7c..b27ffe73ffd 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -1424,6 +1424,7 @@ fn ty_auto_deref_stability<'tcx>(
                 continue;
             },
             ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
+            ty::Alias(ty::Inherent, _) => unreachable!("inherent projection should have been normalized away above"),
             ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
                 TyPosition::new_deref_stable_for_result(precedence, ty)
             },

From 7e9abb311df2ecc61ea294f98a6eda03612178ef Mon Sep 17 00:00:00 2001
From: Philipp Krones <hello@philkrones.com>
Date: Fri, 5 May 2023 17:45:49 +0200
Subject: [PATCH 19/78] Merge commit '371120bdbf58a331db5dcfb2d9cddc040f486de8'
 into clippyup

---
 .github/workflows/remark.yml                  |   6 +
 CHANGELOG.md                                  |  25 ++--
 Cargo.toml                                    |   2 +-
 README.md                                     |   3 +-
 book/src/development/lint_passes.md           |   2 +-
 .../proposals/syntax-tree-patterns.md         |   2 +-
 book/src/lint_configuration.md                |  18 +++
 book/src/usage.md                             |   3 +-
 clippy_dev/src/dogfood.rs                     |   8 +-
 clippy_dev/src/lib.rs                         |  13 ++
 clippy_dev/src/lint.rs                        |  17 +--
 clippy_dev/src/update_lints.rs                |  54 --------
 clippy_lints/Cargo.toml                       |   2 +-
 clippy_lints/src/allow_attributes.rs          |   4 +-
 clippy_lints/src/casts/mod.rs                 |   2 +-
 clippy_lints/src/casts/unnecessary_cast.rs    |   4 +-
 clippy_lints/src/copies.rs                    |   2 +-
 clippy_lints/src/declared_lints.rs            |   3 +
 .../src/default_constructed_unit_structs.rs   |  72 ++++++++++
 clippy_lints/src/escape.rs                    |   6 +-
 clippy_lints/src/float_literal.rs             |   2 +-
 clippy_lints/src/floating_point_arithmetic.rs |  25 ++--
 clippy_lints/src/from_over_into.rs            |   2 +-
 .../src/functions/misnamed_getters.rs         |   2 +-
 clippy_lints/src/functions/mod.rs             |   7 +-
 clippy_lints/src/implicit_saturating_add.rs   |   2 +-
 clippy_lints/src/implicit_saturating_sub.rs   |   2 +-
 clippy_lints/src/indexing_slicing.rs          |   2 +-
 clippy_lints/src/items_after_test_module.rs   |  13 +-
 clippy_lints/src/large_futures.rs             |   2 +-
 clippy_lints/src/len_zero.rs                  |   2 +-
 clippy_lints/src/let_underscore.rs            |  10 +-
 clippy_lints/src/lib.rs                       |  11 +-
 clippy_lints/src/loops/manual_memcpy.rs       |   2 +-
 .../src/loops/manual_while_let_some.rs        | 110 +++++++++++++++
 clippy_lints/src/loops/mod.rs                 |  35 ++++-
 clippy_lints/src/loops/needless_range_loop.rs |   2 +-
 clippy_lints/src/manual_assert.rs             |   2 +-
 clippy_lints/src/manual_let_else.rs           |   2 +-
 clippy_lints/src/manual_retain.rs             |   2 +-
 clippy_lints/src/matches/match_bool.rs        |   2 +-
 .../src/matches/redundant_pattern_match.rs    |   9 +-
 .../src/methods/chars_cmp_with_unwrap.rs      |   2 +-
 clippy_lints/src/methods/iter_next_slice.rs   |   2 +-
 clippy_lints/src/methods/open_options.rs      |   4 +-
 .../src/methods/path_buf_push_overwrite.rs    |   2 +-
 clippy_lints/src/methods/seek_from_current.rs |   2 +-
 .../seek_to_start_instead_of_rewind.rs        |   2 +-
 clippy_lints/src/methods/unnecessary_fold.rs  |   2 +-
 clippy_lints/src/missing_trait_methods.rs     |   2 +-
 clippy_lints/src/needless_bool.rs             |  73 +++++++++-
 .../src/needless_parens_on_range_literals.rs  |   4 +-
 clippy_lints/src/neg_multiply.rs              |   2 +-
 .../src/operators/arithmetic_side_effects.rs  |   2 +-
 clippy_lints/src/regex.rs                     |   2 +-
 clippy_lints/src/semicolon_block.rs           | 125 ++++++++++++------
 clippy_lints/src/shadow.rs                    |   2 +-
 .../src/slow_vector_initialization.rs         |   2 +-
 clippy_lints/src/strings.rs                   |   1 +
 clippy_lints/src/trailing_empty_array.rs      |   2 +-
 clippy_lints/src/types/mod.rs                 |   4 +-
 clippy_lints/src/unicode.rs                   |   2 +-
 clippy_lints/src/unnecessary_box_returns.rs   |   2 +-
 clippy_lints/src/utils/author.rs              |   4 +-
 clippy_lints/src/utils/conf.rs                |   8 ++
 clippy_utils/Cargo.toml                       |   2 +-
 clippy_utils/src/check_proc_macro.rs          |   2 +-
 clippy_utils/src/consts.rs                    |   2 +-
 clippy_utils/src/higher.rs                    |   6 +-
 clippy_utils/src/hir_utils.rs                 |   4 +-
 clippy_utils/src/lib.rs                       |  51 ++-----
 clippy_utils/src/macros.rs                    |   2 +-
 clippy_utils/src/paths.rs                     |   4 +
 clippy_utils/src/qualify_min_const_fn.rs      |   4 +-
 clippy_utils/src/sugg.rs                      |  12 +-
 clippy_utils/src/ty.rs                        |   6 +-
 declare_clippy_lint/Cargo.toml                |   2 +-
 lintcheck/README.md                           |   4 +-
 lintcheck/src/main.rs                         |   2 +-
 rust-toolchain                                |   2 +-
 src/main.rs                                   |   2 +-
 tests/dogfood.rs                              |   2 +-
 tests/ui-toml/semicolon_block/both.fixed      |  86 ++++++++++++
 tests/ui-toml/semicolon_block/both.rs         |  86 ++++++++++++
 tests/ui-toml/semicolon_block/both.stderr     |  55 ++++++++
 tests/ui-toml/semicolon_block/clippy.toml     |   2 +
 .../semicolon_inside_block.fixed              |  85 ++++++++++++
 .../semicolon_block/semicolon_inside_block.rs |  85 ++++++++++++
 .../semicolon_inside_block.stderr             |  18 +++
 .../semicolon_outside_block.fixed             |  85 ++++++++++++
 .../semicolon_outside_block.rs                |  85 ++++++++++++
 .../semicolon_outside_block.stderr            |  39 ++++++
 .../toml_unknown_key/conf_unknown_key.stderr  |   2 +
 tests/ui/allow_attributes_false_positive.rs   |   5 +
 tests/ui/auxiliary/macro_rules.rs             |   7 +
 tests/ui/auxiliary/proc_macro_attr.rs         |   2 +-
 tests/ui/bool_to_int_with_if.fixed            |   9 +-
 tests/ui/bool_to_int_with_if.rs               |   9 +-
 tests/ui/bool_to_int_with_if.stderr           |   2 +-
 tests/ui/box_default.fixed                    |   1 +
 tests/ui/box_default.rs                       |   1 +
 tests/ui/box_default.stderr                   |  32 ++---
 tests/ui/cast_slice_different_sizes.rs        |   2 +-
 tests/ui/crashes/ice-10645.rs                 |   7 +
 .../{ice-5207.stderr => ice-10645.stderr}     |   4 +-
 tests/ui/crashes/ice-5207.rs                  |   4 -
 .../{ice_exacte_size.rs => ice_exact_size.rs} |   0
 .../ui/default_constructed_unit_structs.fixed | 119 +++++++++++++++++
 tests/ui/default_constructed_unit_structs.rs  | 119 +++++++++++++++++
 .../default_constructed_unit_structs.stderr   |  34 +++++
 tests/ui/floating_point_arithmetic_nostd.rs   |  31 +++++
 tests/ui/from_over_into.fixed                 |   2 +-
 tests/ui/from_over_into.rs                    |   2 +-
 tests/ui/from_over_into.stderr                |  12 +-
 tests/ui/from_over_into_unfixable.stderr      |   6 +-
 .../auxiliary/tests.rs                        |   1 +
 .../block_module.rs}                          |   0
 .../block_module.stderr}                      |   2 +-
 .../imported_module.rs                        |  20 +++
 tests/ui/let_underscore_untyped.stderr        |  30 ++++-
 tests/ui/let_with_type_underscore.rs          |   2 +-
 tests/ui/manual_retain.fixed                  |   4 +-
 tests/ui/manual_retain.rs                     |   4 +-
 tests/ui/manual_while_let_some.fixed          |  93 +++++++++++++
 tests/ui/manual_while_let_some.rs             |  93 +++++++++++++
 tests/ui/manual_while_let_some.stderr         |  87 ++++++++++++
 tests/ui/needless_bool_assign.fixed           |  33 +++++
 tests/ui/needless_bool_assign.rs              |  45 +++++++
 tests/ui/needless_bool_assign.stderr          |  53 ++++++++
 tests/ui/needless_for_each_fixable.fixed      |   2 +-
 tests/ui/needless_for_each_fixable.rs         |   2 +-
 tests/ui/no_mangle_with_rust_abi.rs           |   2 +-
 tests/ui/option_if_let_else.fixed             |   2 +-
 tests/ui/option_if_let_else.rs                |   2 +-
 .../redundant_pattern_matching_option.fixed   |   2 +
 tests/ui/redundant_pattern_matching_option.rs |   2 +
 .../redundant_pattern_matching_option.stderr  |  24 ++--
 tests/ui/rename.fixed                         |   1 +
 tests/ui/rename.rs                            |   1 +
 tests/ui/rename.stderr                        |  86 ++++++------
 tests/ui/same_name_method.rs                  |   2 +-
 tests/ui/shadow.rs                            |  12 ++
 tests/ui/shadow.stderr                        |  92 ++++++-------
 tests/ui/string_lit_as_bytes.fixed            |  14 ++
 tests/ui/string_lit_as_bytes.rs               |  14 ++
 tests/ui/string_lit_as_bytes.stderr           |  25 +++-
 tests/ui/trailing_empty_array.rs              |   2 +-
 tests/ui/uninit.rs                            |   4 +-
 tests/ui/use_self_trait.fixed                 |   4 +-
 tests/ui/use_self_trait.rs                    |   4 +-
 tests/ui/use_self_trait.stderr                |   2 +-
 util/gh-pages/index.html                      |   2 +-
 152 files changed, 2226 insertions(+), 440 deletions(-)
 create mode 100644 clippy_lints/src/default_constructed_unit_structs.rs
 create mode 100644 clippy_lints/src/loops/manual_while_let_some.rs
 create mode 100644 tests/ui-toml/semicolon_block/both.fixed
 create mode 100644 tests/ui-toml/semicolon_block/both.rs
 create mode 100644 tests/ui-toml/semicolon_block/both.stderr
 create mode 100644 tests/ui-toml/semicolon_block/clippy.toml
 create mode 100644 tests/ui-toml/semicolon_block/semicolon_inside_block.fixed
 create mode 100644 tests/ui-toml/semicolon_block/semicolon_inside_block.rs
 create mode 100644 tests/ui-toml/semicolon_block/semicolon_inside_block.stderr
 create mode 100644 tests/ui-toml/semicolon_block/semicolon_outside_block.fixed
 create mode 100644 tests/ui-toml/semicolon_block/semicolon_outside_block.rs
 create mode 100644 tests/ui-toml/semicolon_block/semicolon_outside_block.stderr
 create mode 100644 tests/ui/allow_attributes_false_positive.rs
 create mode 100644 tests/ui/crashes/ice-10645.rs
 rename tests/ui/crashes/{ice-5207.stderr => ice-10645.stderr} (89%)
 rename tests/ui/crashes/{ice_exacte_size.rs => ice_exact_size.rs} (100%)
 create mode 100644 tests/ui/default_constructed_unit_structs.fixed
 create mode 100644 tests/ui/default_constructed_unit_structs.rs
 create mode 100644 tests/ui/default_constructed_unit_structs.stderr
 create mode 100644 tests/ui/floating_point_arithmetic_nostd.rs
 create mode 100644 tests/ui/items_after_test_module/auxiliary/tests.rs
 rename tests/ui/{items_after_test_module.rs => items_after_test_module/block_module.rs} (100%)
 rename tests/ui/{items_after_test_module.stderr => items_after_test_module/block_module.stderr} (89%)
 create mode 100644 tests/ui/items_after_test_module/imported_module.rs
 create mode 100644 tests/ui/manual_while_let_some.fixed
 create mode 100644 tests/ui/manual_while_let_some.rs
 create mode 100644 tests/ui/manual_while_let_some.stderr
 create mode 100644 tests/ui/needless_bool_assign.fixed
 create mode 100644 tests/ui/needless_bool_assign.rs
 create mode 100644 tests/ui/needless_bool_assign.stderr

diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml
index 116058b7c75..0bc2f49f5e9 100644
--- a/.github/workflows/remark.yml
+++ b/.github/workflows/remark.yml
@@ -36,6 +36,12 @@ jobs:
     - name: Check *.md files
       run: git ls-files -z '*.md' | xargs -0 -n 1 -I {} ./node_modules/.bin/remark {} -u lint -f > /dev/null
 
+    - name: Linkcheck book
+      run: |
+        rustup toolchain install nightly --component rust-docs
+        curl https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh -o linkcheck.sh
+        sh linkcheck.sh clippy --path ./book
+        
     - name: Build mdbook
       run: mdbook build book
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d7102d2474e..ebf5b58a586 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -44,7 +44,7 @@ Current stable, released 2023-04-20
 
 ### Enhancements
 
-* [`arithmetic_side_effects`]: No longer lints, if safe constant values are used.
+* [`arithmetic_side_effects`]: No longer lints if safe constant values are used.
   [#10310](https://github.com/rust-lang/rust-clippy/pull/10310)
 * [`needless_lifetimes`]: Now works in local macros
   [#10257](https://github.com/rust-lang/rust-clippy/pull/10257)
@@ -60,39 +60,39 @@ Current stable, released 2023-04-20
 
 ### False Positive Fixes
 
-* [`explicit_auto_deref`]: Now considers projections, when determining if auto deref is applicable
+* [`explicit_auto_deref`]: Now considers projections when determining if auto deref is applicable
   [#10386](https://github.com/rust-lang/rust-clippy/pull/10386)
-* [`manual_let_else`]: Now considers side effects of branches, before linting 
+* [`manual_let_else`]: Now considers side effects of branches before linting
   [#10336](https://github.com/rust-lang/rust-clippy/pull/10336)
 * [`uninlined_format_args`]: No longer lints for arguments with generic parameters
   [#10343](https://github.com/rust-lang/rust-clippy/pull/10343)
-* [`needless_lifetimes`]: No longer lints signatures in macros, if the lifetime is a metavariable
+* [`needless_lifetimes`]: No longer lints signatures in macros if the lifetime is a metavariable
   [#10380](https://github.com/rust-lang/rust-clippy/pull/10380)
-* [`len_without_is_empty`]: No longer lints, if `len` as a non-default signature
+* [`len_without_is_empty`]: No longer lints if `len` as a non-default signature
   [#10255](https://github.com/rust-lang/rust-clippy/pull/10255)
-* [`unusual_byte_groupings`]: Relaxed the required restrictions for specific sizes, to reduce false
+* [`unusual_byte_groupings`]: Relaxed the required restrictions for specific sizes to reduce false
   positives
   [#10353](https://github.com/rust-lang/rust-clippy/pull/10353)
 * [`manual_let_else`]: No longer lints `if-else` blocks if they can divergent
   [#10332](https://github.com/rust-lang/rust-clippy/pull/10332)
 * [`expect_used`], [`unwrap_used`], [`dbg_macro`], [`print_stdout`], [`print_stderr`]: No longer lint
-  in test functions, if `allow-expect-in-tests` is set
+  in test functions if `allow-expect-in-tests` is set
   [#10391](https://github.com/rust-lang/rust-clippy/pull/10391)
 * [`unnecessary_safety_comment`]: No longer lints code inside macros
   [#10106](https://github.com/rust-lang/rust-clippy/pull/10106)
-* [`never_loop`]: No longer lints, for statements following break statements for outer blocks.
+* [`never_loop`]: No longer lints statements following break statements for outer blocks.
   [#10311](https://github.com/rust-lang/rust-clippy/pull/10311)
 
 ### Suggestion Fixes/Improvements
 
-* [`box_default`]: The suggestion now includes the type for trait objects, when needed
+* [`box_default`]: The suggestion now includes the type for trait objects when needed
   [#10382](https://github.com/rust-lang/rust-clippy/pull/10382)
 * [`cast_possible_truncation`]: Now suggests using `try_from` or allowing the lint
   [#10038](https://github.com/rust-lang/rust-clippy/pull/10038)
 * [`invalid_regex`]: Regex errors for non-literals or regular strings containing escape sequences will
   now show the complete error
   [#10231](https://github.com/rust-lang/rust-clippy/pull/10231)
-* [`transmutes_expressible_as_ptr_casts`]: The suggestion now works, if the base type is borrowed
+* [`transmutes_expressible_as_ptr_casts`]: The suggestion now works if the base type is borrowed
   [#10193](https://github.com/rust-lang/rust-clippy/pull/10193)
 * [`needless_return`]: Now removes all semicolons on the same line
   [#10187](https://github.com/rust-lang/rust-clippy/pull/10187)
@@ -113,7 +113,7 @@ Current stable, released 2023-04-20
 
 ### ICE Fixes
 
-* [`needless_pass_by_value`]: Fixed an ICE, caused by how late bounds were handled
+* [`needless_pass_by_value`]: Fixed an ICE caused by how late bounds were handled
   [#10328](https://github.com/rust-lang/rust-clippy/pull/10328)
 * [`needless_borrow`]: No longer panics on ambiguous projections
   [#10403](https://github.com/rust-lang/rust-clippy/pull/10403)
@@ -4582,6 +4582,7 @@ Released 2018-09-13
 [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
 [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
 [`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
+[`default_constructed_unit_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_constructed_unit_structs
 [`default_instead_of_iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_instead_of_iter_empty
 [`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
 [`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
@@ -4797,6 +4798,7 @@ Released 2018-09-13
 [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
 [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
+[`manual_while_let_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_while_let_some
 [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
 [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
 [`map_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit
@@ -4864,6 +4866,7 @@ Released 2018-09-13
 [`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type
 [`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool
 [`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
+[`needless_bool_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool_assign
 [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
 [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
 [`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect
diff --git a/Cargo.toml b/Cargo.toml
index 4db15ddb283..3c72bb62ed1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.70"
+version = "0.1.71"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/README.md b/README.md
index 85798e0e80c..6745e15c006 100644
--- a/README.md
+++ b/README.md
@@ -91,7 +91,8 @@ cargo clippy
 
 #### Automatically applying Clippy suggestions
 
-Clippy can automatically apply some lint suggestions, just like the compiler.
+Clippy can automatically apply some lint suggestions, just like the compiler. Note that `--fix` implies
+`--all-targets`, so it can fix as much code as it can.
 
 ```terminal
 cargo clippy --fix
diff --git a/book/src/development/lint_passes.md b/book/src/development/lint_passes.md
index 131f6455fde..621fc20972e 100644
--- a/book/src/development/lint_passes.md
+++ b/book/src/development/lint_passes.md
@@ -50,7 +50,7 @@ questions already, but the parser is okay with it. This is what we
 mean when we say `EarlyLintPass` deals with only syntax on the AST level.
 
 Alternatively, think of the `foo_functions` lint we mentioned in
-define new lints chapter.
+define new lints <!-- FIXME: add link --> chapter.
 
 We want the `foo_functions` lint to detect functions with `foo` as their name.
 Writing a lint that only checks for the name of a function means that we only
diff --git a/book/src/development/proposals/syntax-tree-patterns.md b/book/src/development/proposals/syntax-tree-patterns.md
index 36d722609f4..285488cec55 100644
--- a/book/src/development/proposals/syntax-tree-patterns.md
+++ b/book/src/development/proposals/syntax-tree-patterns.md
@@ -139,7 +139,7 @@ whether the pattern matched.
 
 ## Pattern syntax
 
-The following examples demonstate the pattern syntax:
+The following examples demonstrate the pattern syntax:
 
 
 #### Any (`_`)
diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md
index a702226e861..5646c9b1520 100644
--- a/book/src/lint_configuration.md
+++ b/book/src/lint_configuration.md
@@ -13,6 +13,8 @@ Please use that command to update the file and do not edit it by hand.
 | [msrv](#msrv) | `None` |
 | [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` |
 | [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` |
+| [semicolon-inside-block-ignore-singleline](#semicolon-inside-block-ignore-singleline) | `false` |
+| [semicolon-outside-block-ignore-multiline](#semicolon-outside-block-ignore-multiline) | `false` |
 | [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` |
 | [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` |
 | [type-complexity-threshold](#type-complexity-threshold) | `250` |
@@ -203,6 +205,22 @@ default configuration of Clippy. By default, any configuration will replace the
 * [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names)
 
 
+### semicolon-inside-block-ignore-singleline
+Whether to lint only if it's multiline.
+
+**Default Value:** `false` (`bool`)
+
+* [semicolon_inside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block)
+
+
+### semicolon-outside-block-ignore-multiline
+Whether to lint only if it's singleline.
+
+**Default Value:** `false` (`bool`)
+
+* [semicolon_outside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block)
+
+
 ### doc-valid-idents
 The list of words this lint should not consider as identifiers needing ticks. The value
 `".."` can be used as part of the list to indicate, that the configured values should be appended to the
diff --git a/book/src/usage.md b/book/src/usage.md
index 32084a9199b..36448e4cccf 100644
--- a/book/src/usage.md
+++ b/book/src/usage.md
@@ -111,7 +111,8 @@ fn main() {
 
 ### Automatically applying Clippy suggestions
 
-Clippy can automatically apply some lint suggestions, just like the compiler.
+Clippy can automatically apply some lint suggestions, just like the compiler. Note that `--fix` implies
+`--all-targets`, so it can fix as much code as it can.
 
 ```terminal
 cargo clippy --fix
diff --git a/clippy_dev/src/dogfood.rs b/clippy_dev/src/dogfood.rs
index b69e9f649ec..a0d57f5ab48 100644
--- a/clippy_dev/src/dogfood.rs
+++ b/clippy_dev/src/dogfood.rs
@@ -1,4 +1,4 @@
-use crate::clippy_project_root;
+use crate::{clippy_project_root, exit_if_err};
 use std::process::Command;
 
 /// # Panics
@@ -10,7 +10,7 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) {
     cmd.current_dir(clippy_project_root())
         .args(["test", "--test", "dogfood"])
         .args(["--features", "internal"])
-        .args(["--", "dogfood_clippy"]);
+        .args(["--", "dogfood_clippy", "--nocapture"]);
 
     let mut dogfood_args = Vec::new();
     if fix {
@@ -27,7 +27,5 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) {
 
     cmd.env("__CLIPPY_DOGFOOD_ARGS", dogfood_args.join(" "));
 
-    let output = cmd.output().expect("failed to run command");
-
-    println!("{}", String::from_utf8_lossy(&output.stdout));
+    exit_if_err(cmd.status());
 }
diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs
index 3a8b070d735..56a269288c0 100644
--- a/clippy_dev/src/lib.rs
+++ b/clippy_dev/src/lib.rs
@@ -10,7 +10,9 @@
 extern crate rustc_driver;
 extern crate rustc_lexer;
 
+use std::io;
 use std::path::PathBuf;
+use std::process::{self, ExitStatus};
 
 pub mod bless;
 pub mod dogfood;
@@ -58,3 +60,14 @@ pub fn clippy_project_root() -> PathBuf {
     }
     panic!("error: Can't determine root of project. Please run inside a Clippy working dir.");
 }
+
+pub fn exit_if_err(status: io::Result<ExitStatus>) {
+    match status.expect("failed to run command").code() {
+        Some(0) => {},
+        Some(n) => process::exit(n),
+        None => {
+            eprintln!("Killed by signal");
+            process::exit(1);
+        },
+    }
+}
diff --git a/clippy_dev/src/lint.rs b/clippy_dev/src/lint.rs
index aafd0f71a59..a19be1bca6c 100644
--- a/clippy_dev/src/lint.rs
+++ b/clippy_dev/src/lint.rs
@@ -1,17 +1,6 @@
-use crate::cargo_clippy_path;
-use std::process::{self, Command, ExitStatus};
-use std::{fs, io};
-
-fn exit_if_err(status: io::Result<ExitStatus>) {
-    match status.expect("failed to run command").code() {
-        Some(0) => {},
-        Some(n) => process::exit(n),
-        None => {
-            eprintln!("Killed by signal");
-            process::exit(1);
-        },
-    }
-}
+use crate::{cargo_clippy_path, exit_if_err};
+use std::fs;
+use std::process::{self, Command};
 
 pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
     let is_file = match fs::metadata(path) {
diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs
index dd90a38f757..7213c9dfede 100644
--- a/clippy_dev/src/update_lints.rs
+++ b/clippy_dev/src/update_lints.rs
@@ -36,60 +36,6 @@ pub enum UpdateMode {
 pub fn update(update_mode: UpdateMode) {
     let (lints, deprecated_lints, renamed_lints) = gather_all();
     generate_lint_files(update_mode, &lints, &deprecated_lints, &renamed_lints);
-    remove_old_files(update_mode);
-}
-
-/// Remove files no longer needed after <https://github.com/rust-lang/rust-clippy/pull/9541>
-/// that may be reintroduced unintentionally
-///
-/// FIXME: This is a temporary measure that should be removed when there are no more PRs that
-/// include the stray files
-fn remove_old_files(update_mode: UpdateMode) {
-    let mut failed = false;
-    let mut remove_file = |path: &Path| match update_mode {
-        UpdateMode::Check => {
-            if path.exists() {
-                failed = true;
-                println!("unexpected file: {}", path.display());
-            }
-        },
-        UpdateMode::Change => {
-            if fs::remove_file(path).is_ok() {
-                println!("removed file: {}", path.display());
-            }
-        },
-    };
-
-    let files = [
-        "clippy_lints/src/lib.register_all.rs",
-        "clippy_lints/src/lib.register_cargo.rs",
-        "clippy_lints/src/lib.register_complexity.rs",
-        "clippy_lints/src/lib.register_correctness.rs",
-        "clippy_lints/src/lib.register_internal.rs",
-        "clippy_lints/src/lib.register_lints.rs",
-        "clippy_lints/src/lib.register_nursery.rs",
-        "clippy_lints/src/lib.register_pedantic.rs",
-        "clippy_lints/src/lib.register_perf.rs",
-        "clippy_lints/src/lib.register_restriction.rs",
-        "clippy_lints/src/lib.register_style.rs",
-        "clippy_lints/src/lib.register_suspicious.rs",
-        "src/docs.rs",
-    ];
-
-    for file in files {
-        remove_file(Path::new(file));
-    }
-
-    if let Ok(docs_dir) = fs::read_dir("src/docs") {
-        for doc_file in docs_dir {
-            let path = doc_file.unwrap().path();
-            remove_file(&path);
-        }
-    }
-
-    if failed {
-        exit_with_failure();
-    }
 }
 
 fn generate_lint_files(
diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml
index 18e8bf77225..37e1e6a742f 100644
--- a/clippy_lints/Cargo.toml
+++ b/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.70"
+version = "0.1.71"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs
index b984132acf5..add73d0aeee 100644
--- a/clippy_lints/src/allow_attributes.rs
+++ b/clippy_lints/src/allow_attributes.rs
@@ -2,7 +2,8 @@ use ast::AttrStyle;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use rustc_ast as ast;
 use rustc_errors::Applicability;
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -51,6 +52,7 @@ impl LateLintPass<'_> for AllowAttribute {
     // Separate each crate's features.
     fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
         if_chain! {
+            if !in_external_macro(cx.sess(), attr.span);
             if cx.tcx.features().lint_reasons;
             if let AttrStyle::Outer = attr.style;
             if let Some(ident) = attr.ident();
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index d74bd57fe45..cfeb75eed3b 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -638,7 +638,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.66.0"]
     pub AS_PTR_CAST_MUT,
     nursery,
-    "casting the result of the `&self`-taking `as_ptr` to a mutabe pointer"
+    "casting the result of the `&self`-taking `as_ptr` to a mutable pointer"
 }
 
 declare_clippy_lint! {
diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs
index 7e23318076c..804ae841100 100644
--- a/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/clippy_lints/src/casts/unnecessary_cast.rs
@@ -141,9 +141,9 @@ fn lint_unnecessary_cast(
 
 fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
     match expr.kind {
-        ExprKind::Lit(ref lit) => Some(lit),
+        ExprKind::Lit(lit) => Some(lit),
         ExprKind::Unary(UnOp::Neg, e) => {
-            if let ExprKind::Lit(ref lit) = e.kind {
+            if let ExprKind::Lit(lit) = e.kind {
                 Some(lit)
             } else {
                 None
diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs
index 970f5004993..1c321f46e2d 100644
--- a/clippy_lints/src/copies.rs
+++ b/clippy_lints/src/copies.rs
@@ -591,7 +591,7 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &De
         conds,
         |e| hash_expr(cx, e),
         |lhs, rhs| {
-            // Ignore eq_expr side effects iff one of the expressin kind is a method call
+            // Ignore eq_expr side effects iff one of the expression kind is a method call
             // and the caller is not a mutable, including inner mutable type.
             if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind {
                 if method_caller_is_mutable(cx, caller, ignored_ty_ids) {
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index fa726a64937..79d0f6f3607 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -105,6 +105,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::dbg_macro::DBG_MACRO_INFO,
     crate::default::DEFAULT_TRAIT_ACCESS_INFO,
     crate::default::FIELD_REASSIGN_WITH_DEFAULT_INFO,
+    crate::default_constructed_unit_structs::DEFAULT_CONSTRUCTED_UNIT_STRUCTS_INFO,
     crate::default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY_INFO,
     crate::default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK_INFO,
     crate::default_union_representation::DEFAULT_UNION_REPRESENTATION_INFO,
@@ -249,6 +250,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::loops::MANUAL_FIND_INFO,
     crate::loops::MANUAL_FLATTEN_INFO,
     crate::loops::MANUAL_MEMCPY_INFO,
+    crate::loops::MANUAL_WHILE_LET_SOME_INFO,
     crate::loops::MISSING_SPIN_LOOP_INFO,
     crate::loops::MUT_RANGE_BOUND_INFO,
     crate::loops::NEEDLESS_RANGE_LOOP_INFO,
@@ -445,6 +447,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO,
     crate::needless_bool::BOOL_COMPARISON_INFO,
     crate::needless_bool::NEEDLESS_BOOL_INFO,
+    crate::needless_bool::NEEDLESS_BOOL_ASSIGN_INFO,
     crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO,
     crate::needless_continue::NEEDLESS_CONTINUE_INFO,
     crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs
new file mode 100644
index 00000000000..e529d81a7e9
--- /dev/null
+++ b/clippy_lints/src/default_constructed_unit_structs.rs
@@ -0,0 +1,72 @@
+use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro, match_def_path, paths};
+use hir::{def::Res, ExprKind};
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Check for construction on unit struct using `default`.
+    ///
+    /// ### Why is this bad?
+    /// This adds code complexity and an unnecessary function call.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::marker::PhantomData;
+    /// #[derive(Default)]
+    /// struct S<T> {
+    ///     _marker: PhantomData<T>
+    /// }
+    ///
+    /// let _: S<i32> = S {
+    ///     _marker: PhantomData::default()
+    /// };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::marker::PhantomData;
+    /// struct S<T> {
+    ///     _marker: PhantomData<T>
+    /// }
+    ///
+    /// let _: S<i32> = S {
+    ///     _marker: PhantomData
+    /// };
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
+    complexity,
+    "unit structs can be contructed without calling `default`"
+}
+declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]);
+
+impl LateLintPass<'_> for DefaultConstructedUnitStructs {
+    fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+        if_chain!(
+            // make sure we have a call to `Default::default`
+            if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind;
+            if let ExprKind::Path(ref qpath@ hir::QPath::TypeRelative(_,_)) = fn_expr.kind;
+            if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
+            if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
+            // make sure we have a struct with no fields (unit struct)
+            if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind();
+            if def.is_struct();
+            if let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant();
+            if !var.is_field_list_non_exhaustive() && !is_from_proc_macro(cx, expr);
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
+                    expr.span.with_lo(qpath.qself_span().hi()),
+                    "use of `default` to create a unit struct",
+                    "remove this call to `default`",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                )
+            }
+        );
+    }
+}
diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs
index 6615f9c9953..a51a8ee09f6 100644
--- a/clippy_lints/src/escape.rs
+++ b/clippy_lints/src/escape.rs
@@ -92,10 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
                     if trait_item.id.owner_id.def_id == fn_def_id {
                         // be sure we have `self` parameter in this function
                         if trait_item.kind == (AssocItemKind::Fn { has_self: true }) {
-                            trait_self_ty = Some(
-                                TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id())
-                                    .self_ty(),
-                            );
+                            trait_self_ty =
+                                Some(TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id()).self_ty());
                         }
                     }
                 }
diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs
index 6fee7fb308c..93bf50fd5e7 100644
--- a/clippy_lints/src/float_literal.rs
+++ b/clippy_lints/src/float_literal.rs
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
         let ty = cx.typeck_results().expr_ty(expr);
         if_chain! {
             if let ty::Float(fty) = *ty.kind();
-            if let hir::ExprKind::Lit(ref lit) = expr.kind;
+            if let hir::ExprKind::Lit(lit) = expr.kind;
             if let LitKind::Float(sym, lit_float_ty) = lit.node;
             then {
                 let sym_str = sym.as_str();
diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs
index f95b628e6c3..a1a2c398a8a 100644
--- a/clippy_lints/src/floating_point_arithmetic.rs
+++ b/clippy_lints/src/floating_point_arithmetic.rs
@@ -2,9 +2,10 @@ use clippy_utils::consts::{
     constant, constant_simple, Constant,
     Constant::{Int, F32, F64},
 };
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
-use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, peel_blocks, sugg};
+use clippy_utils::{
+    diagnostics::span_lint_and_sugg, eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate,
+    numeric_literal, peel_blocks, sugg,
+};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp};
@@ -677,7 +678,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             {
                 let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
                 if_chain! {
-                    if let ExprKind::Lit(ref literal) = mul_lhs.kind;
+                    if let ExprKind::Lit(literal) = mul_lhs.kind;
                     if let ast::LitKind::Float(ref value, float_type) = literal.node;
                     if float_type == ast::LitFloatType::Unsuffixed;
                     then {
@@ -703,7 +704,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             {
                 let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
                 if_chain! {
-                    if let ExprKind::Lit(ref literal) = mul_lhs.kind;
+                    if let ExprKind::Lit(literal) = mul_lhs.kind;
                     if let ast::LitKind::Float(ref value, float_type) = literal.node;
                     if float_type == ast::LitFloatType::Unsuffixed;
                     then {
@@ -730,7 +731,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
 impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        // All of these operations are currently not const.
+        // All of these operations are currently not const and are in std.
         if in_constant(cx, expr.hir_id) {
             return;
         }
@@ -738,7 +739,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
         if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
             let recv_ty = cx.typeck_results().expr_ty(receiver);
 
-            if recv_ty.is_floating_point() {
+            if recv_ty.is_floating_point() && !is_no_std_crate(cx) {
                 match path.ident.name.as_str() {
                     "ln" => check_ln1p(cx, expr, receiver),
                     "log" => check_log_base(cx, expr, receiver, args),
@@ -749,10 +750,12 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
                 }
             }
         } else {
-            check_expm1(cx, expr);
-            check_mul_add(cx, expr);
-            check_custom_abs(cx, expr);
-            check_log_division(cx, expr);
+            if !is_no_std_crate(cx) {
+                check_expm1(cx, expr);
+                check_mul_add(cx, expr);
+                check_custom_abs(cx, expr);
+                check_log_division(cx, expr);
+            }
             check_radians(cx, expr);
         }
     }
diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs
index bd66ace4500..10ce2a0f0c7 100644
--- a/clippy_lints/src/from_over_into.rs
+++ b/clippy_lints/src/from_over_into.rs
@@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
                         );
                     }
 
-                    let message = format!("replace the `Into` implentation with `From<{}>`", middle_trait_ref.self_ty());
+                    let message = format!("replace the `Into` implementation with `From<{}>`", middle_trait_ref.self_ty());
                     if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) {
                         diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable);
                     } else {
diff --git a/clippy_lints/src/functions/misnamed_getters.rs b/clippy_lints/src/functions/misnamed_getters.rs
index e5945939e60..b244b913314 100644
--- a/clippy_lints/src/functions/misnamed_getters.rs
+++ b/clippy_lints/src/functions/misnamed_getters.rs
@@ -40,7 +40,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
     };
 
     // Body must be &(mut) <self_data>.name
-    // self_data is not neccessarilly self, to also lint sub-getters, etc…
+    // self_data is not necessarily self, to also lint sub-getters, etc…
 
     let block_expr = if_chain! {
         if let ExprKind::Block(block,_) = body.value.kind;
diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs
index ac2d253fe83..ee10334c67f 100644
--- a/clippy_lints/src/functions/mod.rs
+++ b/clippy_lints/src/functions/mod.rs
@@ -252,6 +252,11 @@ declare_clippy_lint! {
     /// A `Result` is at least as large as the `Err`-variant. While we
     /// expect that variant to be seldomly used, the compiler needs to reserve
     /// and move that much memory every single time.
+    /// Furthermore, errors are often simply passed up the call-stack, making
+    /// use of the `?`-operator and its type-conversion mechanics. If the
+    /// `Err`-variant further up the call-stack stores the `Err`-variant in
+    /// question (as library code often does), it itself needs to be at least
+    /// as large, propagating the problem.
     ///
     /// ### Known problems
     /// The size determined by Clippy is platform-dependent.
@@ -330,7 +335,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Lints when `impl Trait` is being used in a function's paremeters.
+    /// Lints when `impl Trait` is being used in a function's parameters.
     /// ### Why is this bad?
     /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor.
     ///
diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs
index 57e6caa8711..012aa5a1d1d 100644
--- a/clippy_lints/src/implicit_saturating_add.rs
+++ b/clippy_lints/src/implicit_saturating_add.rs
@@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
             if expr1.span.ctxt() == ctxt;
             if clippy_utils::SpanlessEq::new(cx).eq_expr(l, target);
             if BinOpKind::Add == op1.node;
-            if let ExprKind::Lit(ref lit) = value.kind;
+            if let ExprKind::Lit(lit) = value.kind;
             if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
             if block.expr.is_none();
             then {
diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs
index 0c7aea6da8f..1e99b6faa6c 100644
--- a/clippy_lints/src/implicit_saturating_sub.rs
+++ b/clippy_lints/src/implicit_saturating_sub.rs
@@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
                 // Get the variable name
                 let var_name = ares_path.segments[0].ident.name.as_str();
                 match cond_num_val.kind {
-                    ExprKind::Lit(ref cond_lit) => {
+                    ExprKind::Lit(cond_lit) => {
                         // Check if the constant is zero
                         if let LitKind::Int(0, _) = cond_lit.node {
                             if cx.typeck_results().expr_ty(cond_left).is_signed() {
diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs
index c384172fbde..924a361c0f6 100644
--- a/clippy_lints/src/indexing_slicing.rs
+++ b/clippy_lints/src/indexing_slicing.rs
@@ -170,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
                         return;
                     }
                     // Index is a constant uint.
-                    if let Some(..) = constant(cx, cx.typeck_results(), index) {
+                    if constant(cx, cx.typeck_results(), index).is_some() {
                         // Let rustc's `const_err` lint handle constant `usize` indexing on arrays.
                         return;
                     }
diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs
index 52d716feea0..b992d689aa9 100644
--- a/clippy_lints/src/items_after_test_module.rs
+++ b/clippy_lints/src/items_after_test_module.rs
@@ -64,20 +64,21 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
                 span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined");
             }};
 
-            if matches!(item.kind, ItemKind::Mod(_)) {
-                for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
-                    if_chain! {
-                        if attr.has_name(sym::cfg);
+            if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() {
+			// Check that it works the same way, the only I way I've found for #10713
+				for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
+					if_chain! {
+						if attr.has_name(sym::cfg);
                         if let Some(mitems) = attr.meta_item_list();
                         if let [mitem] = &*mitems;
                         if mitem.has_name(sym::test);
                         then {
-                            was_test_mod_visited = true;
+							was_test_mod_visited = true;
                             test_mod_span = Some(item.span);
                         }
                     }
                 }
-            }
+			}
         }
     }
 }
diff --git a/clippy_lints/src/large_futures.rs b/clippy_lints/src/large_futures.rs
index 1b054481371..0ca31033b16 100644
--- a/clippy_lints/src/large_futures.rs
+++ b/clippy_lints/src/large_futures.rs
@@ -11,7 +11,7 @@ declare_clippy_lint! {
     /// It checks for the size of a `Future` created by `async fn` or `async {}`.
     ///
     /// ### Why is this bad?
-    /// Due to the current [unideal implemention](https://github.com/rust-lang/rust/issues/69826) of `Generator`,
+    /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Generator`,
     /// large size of a `Future` may cause stack overflows.
     ///
     /// ### Example
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index fec9c6f626c..17bd89efaee 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -532,7 +532,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex
 }
 
 fn is_empty_string(expr: &Expr<'_>) -> bool {
-    if let ExprKind::Lit(ref lit) = expr.kind {
+    if let ExprKind::Lit(lit) = expr.kind {
         if let LitKind::Str(lit, _) = lit.node {
             let lit = lit.as_str();
             return lit.is_empty();
diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs
index 637b7de920e..16772a9d598 100644
--- a/clippy_lints/src/let_underscore.rs
+++ b/clippy_lints/src/let_underscore.rs
@@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -205,8 +206,13 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                     LET_UNDERSCORE_UNTYPED,
                     local.span,
                     "non-binding `let` without a type annotation",
-                    None,
-                    "consider adding a type annotation or removing the `let` keyword",
+                    Some(
+						Span::new(local.pat.span.hi(),
+						local.pat.span.hi() + BytePos(1),
+						local.pat.span.ctxt(),
+						local.pat.span.parent()
+					)),
+                    "consider adding a type annotation",
                 );
             }
         }
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 9e65f9ecd16..3517842a01e 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -94,6 +94,7 @@ mod crate_in_macro_def;
 mod create_dir;
 mod dbg_macro;
 mod default;
+mod default_constructed_unit_structs;
 mod default_instead_of_iter_empty;
 mod default_numeric_fallback;
 mod default_union_representation;
@@ -933,7 +934,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr));
     store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow));
     store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv())));
-    store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock));
+    let semicolon_inside_block_ignore_singleline = conf.semicolon_inside_block_ignore_singleline;
+    let semicolon_outside_block_ignore_multiline = conf.semicolon_outside_block_ignore_multiline;
+    store.register_late_pass(move |_| {
+        Box::new(semicolon_block::SemicolonBlock::new(
+            semicolon_inside_block_ignore_singleline,
+            semicolon_outside_block_ignore_multiline,
+        ))
+    });
     store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck));
     store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
     store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
@@ -963,6 +971,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
     store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments));
     store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
+    store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs
index c87fc4f90e2..d4c3f76b864 100644
--- a/clippy_lints/src/loops/manual_memcpy.rs
+++ b/clippy_lints/src/loops/manual_memcpy.rs
@@ -15,7 +15,7 @@ use rustc_span::symbol::sym;
 use std::fmt::Display;
 use std::iter::Iterator;
 
-/// Checks for for loops that sequentially copy items from one slice-like
+/// Checks for `for` loops that sequentially copy items from one slice-like
 /// object to another.
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
diff --git a/clippy_lints/src/loops/manual_while_let_some.rs b/clippy_lints/src/loops/manual_while_let_some.rs
new file mode 100644
index 00000000000..cb9c84be4c7
--- /dev/null
+++ b/clippy_lints/src/loops/manual_while_let_some.rs
@@ -0,0 +1,110 @@
+use clippy_utils::{
+    diagnostics::{multispan_sugg_with_applicability, span_lint_and_then},
+    match_def_path, paths,
+    source::snippet,
+    SpanlessEq,
+};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+use std::borrow::Cow;
+
+use super::MANUAL_WHILE_LET_SOME;
+
+/// The kind of statement that the `pop()` call appeared in.
+///
+/// Depending on whether the value was assigned to a variable or not changes what pattern
+/// we use for the suggestion.
+#[derive(Copy, Clone)]
+enum PopStmt<'hir> {
+    /// `x.pop().unwrap()` was and assigned to a variable.
+    /// The pattern of this local variable will be used and the local statement
+    /// is deleted in the suggestion.
+    Local(&'hir Pat<'hir>),
+    /// `x.pop().unwrap()` appeared in an arbitrary expression and was not assigned to a variable.
+    /// The suggestion will use some placeholder identifier and the `x.pop().unwrap()` expression
+    /// is replaced with that identifier.
+    Anonymous,
+}
+
+fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>, loop_span: Span, receiver_span: Span) {
+    span_lint_and_then(
+        cx,
+        MANUAL_WHILE_LET_SOME,
+        pop_span,
+        "you seem to be trying to pop elements from a `Vec` in a loop",
+        |diag| {
+            let (pat, pop_replacement) = match pop_stmt_kind {
+                PopStmt::Local(pat) => (snippet(cx, pat.span, ".."), String::new()),
+                PopStmt::Anonymous => (Cow::Borrowed("element"), "element".into()),
+            };
+
+            let loop_replacement = format!("while let Some({}) = {}.pop()", pat, snippet(cx, receiver_span, ".."));
+            multispan_sugg_with_applicability(
+                diag,
+                "consider using a `while..let` loop",
+                Applicability::MachineApplicable,
+                [(loop_span, loop_replacement), (pop_span, pop_replacement)],
+            );
+        },
+    );
+}
+
+fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: &[&str]) -> bool {
+    if let ExprKind::MethodCall(..) = expr.kind
+        && let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+    {
+        match_def_path(cx, id, method)
+    } else {
+        false
+    }
+}
+
+fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, is_empty_recv: &Expr<'_>) -> bool {
+    if (match_method_call(cx, expr, &paths::OPTION_UNWRAP) || match_method_call(cx, expr, &paths::OPTION_EXPECT))
+        && let ExprKind::MethodCall(_, unwrap_recv, ..) = expr.kind
+        && match_method_call(cx, unwrap_recv, &paths::VEC_POP)
+        && let ExprKind::MethodCall(_, pop_recv, ..) = unwrap_recv.kind
+    {
+        // make sure they're the same `Vec`
+        SpanlessEq::new(cx).eq_expr(pop_recv, is_empty_recv)
+    } else {
+        false
+    }
+}
+
+fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) {
+    if let StmtKind::Local(local) = stmt.kind
+        && let Some(init) = local.init
+        && is_vec_pop_unwrap(cx, init, is_empty_recv)
+    {
+        report_lint(cx, stmt.span, PopStmt::Local(local.pat), loop_span, is_empty_recv.span);
+    }
+}
+
+fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) {
+    if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind {
+        if let ExprKind::MethodCall(.., args, _) | ExprKind::Call(_, args) = expr.kind {
+            let offending_arg = args
+                .iter()
+                .find_map(|arg| is_vec_pop_unwrap(cx, arg, is_empty_recv).then_some(arg.span));
+
+            if let Some(offending_arg) = offending_arg {
+                report_lint(cx, offending_arg, PopStmt::Anonymous, loop_span, is_empty_recv.span);
+            }
+        }
+    }
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, full_cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>, loop_span: Span) {
+    if let ExprKind::Unary(UnOp::Not, cond) = full_cond.kind
+        && let ExprKind::MethodCall(_, is_empty_recv, _, _) = cond.kind
+        && match_method_call(cx, cond, &paths::VEC_IS_EMPTY)
+        && let ExprKind::Block(body, _) = body.kind
+        && let Some(stmt) = body.stmts.first()
+    {
+        check_local(cx, stmt, is_empty_recv, loop_span);
+        check_call_arguments(cx, stmt, is_empty_recv, loop_span);
+    }
+}
diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs
index 610a0233eee..f83ad388a74 100644
--- a/clippy_lints/src/loops/mod.rs
+++ b/clippy_lints/src/loops/mod.rs
@@ -7,6 +7,7 @@ mod iter_next_loop;
 mod manual_find;
 mod manual_flatten;
 mod manual_memcpy;
+mod manual_while_let_some;
 mod missing_spin_loop;
 mod mut_range_bound;
 mod needless_range_loop;
@@ -575,6 +576,36 @@ declare_clippy_lint! {
     "manual implementation of `Iterator::find`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Looks for loops that check for emptiness of a `Vec` in the condition and pop an element
+    /// in the body as a separate operation.
+    ///
+    /// ### Why is this bad?
+    /// Such loops can be written in a more idiomatic way by using a while-let loop and directly
+    /// pattern matching on the return value of `Vec::pop()`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let mut numbers = vec![1, 2, 3, 4, 5];
+    /// while !numbers.is_empty() {
+    ///     let number = numbers.pop().unwrap();
+    ///     // use `number`
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let mut numbers = vec![1, 2, 3, 4, 5];
+    /// while let Some(number) = numbers.pop() {
+    ///     // use `number`
+    /// }
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub MANUAL_WHILE_LET_SOME,
+    style,
+    "checking for emptiness of a `Vec` in the loop condition and popping an element in the body"
+}
+
 declare_lint_pass!(Loops => [
     MANUAL_MEMCPY,
     MANUAL_FLATTEN,
@@ -594,6 +625,7 @@ declare_lint_pass!(Loops => [
     SINGLE_ELEMENT_LOOP,
     MISSING_SPIN_LOOP,
     MANUAL_FIND,
+    MANUAL_WHILE_LET_SOME
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Loops {
@@ -640,9 +672,10 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
 
         while_let_on_iterator::check(cx, expr);
 
-        if let Some(higher::While { condition, body }) = higher::While::hir(expr) {
+        if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) {
             while_immutable_condition::check(cx, condition, body);
             missing_spin_loop::check(cx, condition, body);
+            manual_while_let_some::check(cx, condition, body, span);
         }
     }
 }
diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs
index 5c317c2a5bb..cb446567506 100644
--- a/clippy_lints/src/loops/needless_range_loop.rs
+++ b/clippy_lints/src/loops/needless_range_loop.rs
@@ -208,7 +208,7 @@ fn is_end_eq_array_len<'tcx>(
     indexed_ty: Ty<'tcx>,
 ) -> bool {
     if_chain! {
-        if let ExprKind::Lit(ref lit) = end.kind;
+        if let ExprKind::Lit(lit) = end.kind;
         if let ast::LitKind::Int(end_int, _) = lit.node;
         if let ty::Array(_, arr_len_const) = indexed_ty.kind();
         if let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env);
diff --git a/clippy_lints/src/manual_assert.rs b/clippy_lints/src/manual_assert.rs
index ce5d657bcf0..45ea5aab4c2 100644
--- a/clippy_lints/src/manual_assert.rs
+++ b/clippy_lints/src/manual_assert.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
             };
             let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
             let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
-            // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block
+            // we show to the user the suggestion without the comments, but when applying the fix, include the comments in the block
             span_lint_and_then(
                 cx,
                 MANUAL_ASSERT,
diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs
index 98e698c6c2a..1247370b74a 100644
--- a/clippy_lints/src/manual_let_else.rs
+++ b/clippy_lints/src/manual_let_else.rs
@@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
                 if source != MatchSource::Normal {
                     return;
                 }
-                // Any other number than two arms doesn't (neccessarily)
+                // Any other number than two arms doesn't (necessarily)
                 // have a trivial mapping to let else.
                 if arms.len() != 2 {
                     return;
diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs
index 72cdb9c1736..5259066eb71 100644
--- a/clippy_lints/src/manual_retain.rs
+++ b/clippy_lints/src/manual_retain.rs
@@ -46,7 +46,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.64.0"]
     pub MANUAL_RETAIN,
     perf,
-    "`retain()` is simpler and the same functionalitys"
+    "`retain()` is simpler and the same functionalities"
 }
 
 pub struct ManualRetain {
diff --git a/clippy_lints/src/matches/match_bool.rs b/clippy_lints/src/matches/match_bool.rs
index df1e585f10b..69105ff0d5c 100644
--- a/clippy_lints/src/matches/match_bool.rs
+++ b/clippy_lints/src/matches/match_bool.rs
@@ -22,7 +22,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>]
                 if arms.len() == 2 {
                     // no guards
                     let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
-                        if let ExprKind::Lit(ref lit) = arm_bool.kind {
+                        if let ExprKind::Lit(lit) = arm_bool.kind {
                             match lit.node {
                                 LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
                                 LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 7b609ff3df8..af121f317cd 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -63,8 +63,11 @@ fn find_sugg_for_if_let<'tcx>(
     // Determine which function should be used, and the type contained by the corresponding
     // variant.
     let (good_method, inner_ty) = match check_pat.kind {
-        PatKind::TupleStruct(ref qpath, [sub_pat], _) => {
-            if let PatKind::Wild = sub_pat.kind {
+        PatKind::TupleStruct(ref qpath, args, rest) => {
+            let is_wildcard = matches!(args.first().map(|p| &p.kind), Some(PatKind::Wild));
+            let is_rest = matches!((args, rest.as_opt_usize()), ([], Some(_)));
+
+            if is_wildcard || is_rest {
                 let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
                 let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
                 let lang_items = cx.tcx.lang_items();
@@ -334,7 +337,7 @@ fn find_good_method_for_match<'a>(
     };
 
     match body_node_pair {
-        (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
+        (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) {
             (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
             (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
             _ => None,
diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
index 27a05337a29..8984b2cf8fd 100644
--- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
+++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
@@ -18,7 +18,7 @@ pub(super) fn check(
 ) -> bool {
     if_chain! {
         if let Some(args) = method_chain_args(info.chain, chain_methods);
-        if let hir::ExprKind::Lit(ref lit) = info.other.kind;
+        if let hir::ExprKind::Lit(lit) = info.other.kind;
         if let ast::LitKind::Char(c) = lit.node;
         then {
             let mut applicability = Applicability::MachineApplicable;
diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs
index 83c1bf20346..e2029da8081 100644
--- a/clippy_lints/src/methods/iter_next_slice.rs
+++ b/clippy_lints/src/methods/iter_next_slice.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
             if let hir::ExprKind::Index(caller_var, index_expr) = &caller_expr.kind;
             if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
                 = higher::Range::hir(index_expr);
-            if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
+            if let hir::ExprKind::Lit(start_lit) = &start_expr.kind;
             if let ast::LitKind::Int(start_idx, _) = start_lit.node;
             then {
                 let mut applicability = Applicability::MachineApplicable;
diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs
index 23d23f25f14..bd625a6914c 100644
--- a/clippy_lints/src/methods/open_options.rs
+++ b/clippy_lints/src/methods/open_options.rs
@@ -42,11 +42,11 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
         // Only proceed if this is a call on some object of type std::fs::OpenOptions
         if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() {
             let argument_option = match arguments[0].kind {
-                ExprKind::Lit(ref span) => {
+                ExprKind::Lit(span) => {
                     if let Spanned {
                         node: LitKind::Bool(lit),
                         ..
-                    } = *span
+                    } = span
                     {
                         if *lit { Argument::True } else { Argument::False }
                     } else {
diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs
index e3f2de3cd46..0284d9dea30 100644
--- a/clippy_lints/src/methods/path_buf_push_overwrite.rs
+++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs
@@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
         if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::PathBuf);
-        if let ExprKind::Lit(ref lit) = arg.kind;
+        if let ExprKind::Lit(lit) = arg.kind;
         if let LitKind::Str(ref path_lit, _) = lit.node;
         if let pushed_path = Path::new(path_lit.as_str());
         if let Some(pushed_path_lit) = pushed_path.to_str();
diff --git a/clippy_lints/src/methods/seek_from_current.rs b/clippy_lints/src/methods/seek_from_current.rs
index 361a3082f94..c028e954381 100644
--- a/clippy_lints/src/methods/seek_from_current.rs
+++ b/clippy_lints/src/methods/seek_from_current.rs
@@ -38,7 +38,7 @@ fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
         match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) {
         // check if argument of `SeekFrom::Current` is `0`
         if args.len() == 1 &&
-            let ExprKind::Lit(ref lit) = args[0].kind &&
+            let ExprKind::Lit(lit) = args[0].kind &&
             let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node {
             return true
         }
diff --git a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
index 660b7049cce..787e9e0ebd2 100644
--- a/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
+++ b/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
         let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() &&
         match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) &&
         args1.len() == 1 &&
-        let ExprKind::Lit(ref lit) = args1[0].kind &&
+        let ExprKind::Lit(lit) = args1[0].kind &&
         let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
     {
         let method_call_span = expr.span.with_lo(name_span.lo());
diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs
index aa87dead38f..5a3d12fd790 100644
--- a/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/clippy_lints/src/methods/unnecessary_fold.rs
@@ -78,7 +78,7 @@ pub(super) fn check(
     }
 
     // Check if the first argument to .fold is a suitable literal
-    if let hir::ExprKind::Lit(ref lit) = init.kind {
+    if let hir::ExprKind::Lit(lit) = init.kind {
         match lit.node {
             ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, "any", true),
             ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
diff --git a/clippy_lints/src/missing_trait_methods.rs b/clippy_lints/src/missing_trait_methods.rs
index e99081ad062..1adecd2caac 100644
--- a/clippy_lints/src/missing_trait_methods.rs
+++ b/clippy_lints/src/missing_trait_methods.rs
@@ -12,7 +12,7 @@ declare_clippy_lint! {
     /// Checks if a provided method is used implicitly by a trait
     /// implementation. A usage example would be a wrapper where every method
     /// should perform some operation before delegating to the inner type's
-    /// implemenation.
+    /// implementation.
     ///
     /// This lint should typically be enabled on a specific trait `impl` item
     /// rather than globally.
diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs
index c87059bf61d..71281a0b40b 100644
--- a/clippy_lints/src/needless_bool.rs
+++ b/clippy_lints/src/needless_bool.rs
@@ -3,10 +3,12 @@
 //! This lint is **warn** by default
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::higher;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt};
+use clippy_utils::{
+    get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment,
+};
+use clippy_utils::{higher, SpanlessEq};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp};
@@ -77,7 +79,39 @@ declare_clippy_lint! {
     "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`"
 }
 
-declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]);
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for expressions of the form `if c { x = true } else { x = false }`
+    /// (or vice versa) and suggest assigning the variable directly from the
+    /// condition.
+    ///
+    /// ### Why is this bad?
+    /// Redundant code.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// # fn must_keep(x: i32, y: i32) -> bool { x == y }
+    /// # let x = 32; let y = 10;
+    /// # let mut skip: bool;
+    /// if must_keep(x, y) {
+    ///     skip = false;
+    /// } else {
+    ///     skip = true;
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// # fn must_keep(x: i32, y: i32) -> bool { x == y }
+    /// # let x = 32; let y = 10;
+    /// # let mut skip: bool;
+    /// skip = !must_keep(x, y);
+    /// ```
+    #[clippy::version = "1.69.0"]
+    pub NEEDLESS_BOOL_ASSIGN,
+    complexity,
+    "setting the same boolean variable in both branches of an if-statement"
+}
+declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL, NEEDLESS_BOOL_ASSIGN]);
 
 fn condition_needs_parentheses(e: &Expr<'_>) -> bool {
     let mut inner = e;
@@ -173,6 +207,29 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
                     _ => (),
                 }
             }
+            if let Some((lhs_a, a)) = fetch_assign(then) &&
+                let Some((lhs_b, b)) = fetch_assign(r#else) &&
+                SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) &&
+                span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty()
+            {
+                let mut applicability = Applicability::MachineApplicable;
+                let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
+                let lhs = snippet_with_applicability(cx, lhs_a.span, "..", &mut applicability);
+                let sugg = if a == b {
+                    format!("{cond}; {lhs} = {a:?};")
+                } else {
+                    format!("{lhs} = {};", if a { cond } else { !cond })
+                };
+                span_lint_and_sugg(
+                    cx,
+                    NEEDLESS_BOOL_ASSIGN,
+                    e.span,
+                    "this if-then-else expression assigns a bool literal",
+                    "you can reduce it to",
+                    sugg,
+                    applicability
+                );
+            }
         }
     }
 }
@@ -369,10 +426,18 @@ fn fetch_bool_block(expr: &Expr<'_>) -> Option<Expression> {
 }
 
 fn fetch_bool_expr(expr: &Expr<'_>) -> Option<bool> {
-    if let ExprKind::Lit(ref lit_ptr) = peel_blocks(expr).kind {
+    if let ExprKind::Lit(lit_ptr) = peel_blocks(expr).kind {
         if let LitKind::Bool(value) = lit_ptr.node {
             return Some(value);
         }
     }
     None
 }
+
+fn fetch_assign<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, bool)> {
+    if let ExprKind::Assign(lhs, rhs, _) = peel_blocks_with_stmt(expr).kind {
+        fetch_bool_expr(rhs).map(|b| (lhs, b))
+    } else {
+        None
+    }
+}
diff --git a/clippy_lints/src/needless_parens_on_range_literals.rs b/clippy_lints/src/needless_parens_on_range_literals.rs
index 6e54b243c03..da1b9d99931 100644
--- a/clippy_lints/src/needless_parens_on_range_literals.rs
+++ b/clippy_lints/src/needless_parens_on_range_literals.rs
@@ -49,14 +49,14 @@ fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool {
 
 fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) {
     if is_start &&
-    let ExprKind::Lit(ref literal) = e.kind &&
+    let ExprKind::Lit(literal) = e.kind &&
     let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node
     {
         // don't check floating point literals on the start expression of a range
         return;
     }
     if_chain! {
-        if let ExprKind::Lit(ref literal) = e.kind;
+        if let ExprKind::Lit(literal) = e.kind;
         // the indicator that parenthesis surround the literal is that the span of the expression and the literal differ
         if (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo);
         // inspect the source code of the expression for parenthesis
diff --git a/clippy_lints/src/neg_multiply.rs b/clippy_lints/src/neg_multiply.rs
index ed3e2c6e7f4..db0e22842d1 100644
--- a/clippy_lints/src/neg_multiply.rs
+++ b/clippy_lints/src/neg_multiply.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply {
 
 fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
     if_chain! {
-        if let ExprKind::Lit(ref l) = lit.kind;
+        if let ExprKind::Lit(l) = lit.kind;
         if consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
         if cx.typeck_results().expr_ty(exp).is_integral();
 
diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs
index fafcf257094..f72595987ee 100644
--- a/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -110,7 +110,7 @@ impl ArithmeticSideEffects {
     /// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`,
     fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> {
         let actual = peel_hir_expr_unary(expr).0;
-        if let hir::ExprKind::Lit(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
+        if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
             return Some(n)
         }
         if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) {
diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs
index 9e6c6c73d4f..b8b32df6cc6 100644
--- a/clippy_lints/src/regex.rs
+++ b/clippy_lints/src/regex.rs
@@ -180,7 +180,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
         .allow_invalid_utf8(!utf8)
         .build();
 
-    if let ExprKind::Lit(ref lit) = expr.kind {
+    if let ExprKind::Lit(lit) = expr.kind {
         if let LitKind::Str(ref r, style) = lit.node {
             let r = r.as_str();
             let offset = if let StrStyle::Raw(n) = style { 2 + n } else { 1 };
diff --git a/clippy_lints/src/semicolon_block.rs b/clippy_lints/src/semicolon_block.rs
index 34a3e5ddf4f..419d7991f0e 100644
--- a/clippy_lints/src/semicolon_block.rs
+++ b/clippy_lints/src/semicolon_block.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -64,7 +64,78 @@ declare_clippy_lint! {
     restriction,
     "add a semicolon outside the block"
 }
-declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
+impl_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]);
+
+#[derive(Copy, Clone)]
+pub struct SemicolonBlock {
+    semicolon_inside_block_ignore_singleline: bool,
+    semicolon_outside_block_ignore_multiline: bool,
+}
+
+impl SemicolonBlock {
+    pub fn new(semicolon_inside_block_ignore_singleline: bool, semicolon_outside_block_ignore_multiline: bool) -> Self {
+        Self {
+            semicolon_inside_block_ignore_singleline,
+            semicolon_outside_block_ignore_multiline,
+        }
+    }
+
+    fn semicolon_inside_block(self, cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
+        let insert_span = tail.span.source_callsite().shrink_to_hi();
+        let remove_span = semi_span.with_lo(block.span.hi());
+
+        if self.semicolon_inside_block_ignore_singleline && get_line(cx, remove_span) == get_line(cx, insert_span) {
+            return;
+        }
+
+        span_lint_and_then(
+            cx,
+            SEMICOLON_INSIDE_BLOCK,
+            semi_span,
+            "consider moving the `;` inside the block for consistent formatting",
+            |diag| {
+                multispan_sugg_with_applicability(
+                    diag,
+                    "put the `;` here",
+                    Applicability::MachineApplicable,
+                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
+                );
+            },
+        );
+    }
+
+    fn semicolon_outside_block(
+        self,
+        cx: &LateContext<'_>,
+        block: &Block<'_>,
+        tail_stmt_expr: &Expr<'_>,
+        semi_span: Span,
+    ) {
+        let insert_span = block.span.with_lo(block.span.hi());
+        // account for macro calls
+        let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
+        let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
+
+        if self.semicolon_outside_block_ignore_multiline && get_line(cx, remove_span) != get_line(cx, insert_span) {
+            return;
+        }
+
+        span_lint_and_then(
+            cx,
+            SEMICOLON_OUTSIDE_BLOCK,
+            block.span,
+            "consider moving the `;` outside the block for consistent formatting",
+            |diag| {
+                multispan_sugg_with_applicability(
+                    diag,
+                    "put the `;` here",
+                    Applicability::MachineApplicable,
+                    [(remove_span, String::new()), (insert_span, ";".to_owned())],
+                );
+            },
+        );
+    }
+}
 
 impl LateLintPass<'_> for SemicolonBlock {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
@@ -83,55 +154,23 @@ impl LateLintPass<'_> for SemicolonBlock {
                     span,
                     ..
                 } = stmt else { return };
-                semicolon_outside_block(cx, block, expr, span);
+                self.semicolon_outside_block(cx, block, expr, span);
             },
             StmtKind::Semi(Expr {
                 kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _),
                 ..
-            }) if !block.span.from_expansion() => semicolon_inside_block(cx, block, tail, stmt.span),
+            }) if !block.span.from_expansion() => {
+                self.semicolon_inside_block(cx, block, tail, stmt.span);
+            },
             _ => (),
         }
     }
 }
 
-fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) {
-    let insert_span = tail.span.source_callsite().shrink_to_hi();
-    let remove_span = semi_span.with_lo(block.span.hi());
+fn get_line(cx: &LateContext<'_>, span: Span) -> Option<usize> {
+    if let Ok(line) = cx.sess().source_map().lookup_line(span.lo()) {
+        return Some(line.line);
+    }
 
-    span_lint_and_then(
-        cx,
-        SEMICOLON_INSIDE_BLOCK,
-        semi_span,
-        "consider moving the `;` inside the block for consistent formatting",
-        |diag| {
-            multispan_sugg_with_applicability(
-                diag,
-                "put the `;` here",
-                Applicability::MachineApplicable,
-                [(remove_span, String::new()), (insert_span, ";".to_owned())],
-            );
-        },
-    );
-}
-
-fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) {
-    let insert_span = block.span.with_lo(block.span.hi());
-    // account for macro calls
-    let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span);
-    let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi());
-
-    span_lint_and_then(
-        cx,
-        SEMICOLON_OUTSIDE_BLOCK,
-        block.span,
-        "consider moving the `;` outside the block for consistent formatting",
-        |diag| {
-            multispan_sugg_with_applicability(
-                diag,
-                "put the `;` here",
-                Applicability::MachineApplicable,
-                [(remove_span, String::new()), (insert_span, ";".to_owned())],
-            );
-        },
-    );
+    None
 }
diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs
index ae7d19624ba..993f9373d85 100644
--- a/clippy_lints/src/shadow.rs
+++ b/clippy_lints/src/shadow.rs
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for Shadow {
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
         let PatKind::Binding(_, id, ident, _) = pat.kind else { return };
 
-        if pat.span.desugaring_kind().is_some() {
+        if pat.span.desugaring_kind().is_some() || pat.span.from_expansion() {
             return;
         }
 
diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs
index a2109038a05..858135c8d46 100644
--- a/clippy_lints/src/slow_vector_initialization.rs
+++ b/clippy_lints/src/slow_vector_initialization.rs
@@ -74,7 +74,7 @@ enum InitializationType<'tcx> {
 
 impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        // Matches initialization on reassignements. For example: `vec = Vec::with_capacity(100)`
+        // Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)`
         if_chain! {
             if let ExprKind::Assign(left, right, _) = expr.kind;
 
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index b2f4b310915..5b588e914fd 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -292,6 +292,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         }
 
         if_chain! {
+            if !in_external_macro(cx.sess(), e.span);
             if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
             if path.ident.name == sym!(as_bytes);
             if let ExprKind::Lit(lit) = &receiver.kind;
diff --git a/clippy_lints/src/trailing_empty_array.rs b/clippy_lints/src/trailing_empty_array.rs
index 98f5b47f7a0..bb9da3a2047 100644
--- a/clippy_lints/src/trailing_empty_array.rs
+++ b/clippy_lints/src/trailing_empty_array.rs
@@ -60,7 +60,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_
         if let Some(last_field) = data.fields().last();
         if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind;
 
-        // Then check if that that array zero-sized
+        // Then check if that array is zero-sized
         let length = Const::from_anon_const(cx.tcx, length.def_id);
         let length = length.try_eval_target_usize(cx.tcx, cx.param_env);
         if let Some(length) = length;
diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs
index c6834a8fdaa..3c873a5901d 100644
--- a/clippy_lints/src/types/mod.rs
+++ b/clippy_lints/src/types/mod.rs
@@ -90,8 +90,8 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad?
     /// `Option<_>` represents an optional value. `Option<Option<_>>`
-    /// represents an optional optional value which is logically the same thing as an optional
-    /// value but has an unneeded extra level of wrapping.
+    /// represents an optional value which itself wraps an optional. This is logically the
+    /// same thing as an optional value but has an unneeded extra level of wrapping.
     ///
     /// If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases,
     /// consider a custom `enum` instead, with clear names for each case.
diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs
index 8980283e5c8..e275bfd37b0 100644
--- a/clippy_lints/src/unicode.rs
+++ b/clippy_lints/src/unicode.rs
@@ -76,7 +76,7 @@ declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_
 
 impl LateLintPass<'_> for Unicode {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
-        if let ExprKind::Lit(ref lit) = expr.kind {
+        if let ExprKind::Lit(lit) = expr.kind {
             if let LitKind::Str(_, _) | LitKind::Char(_) = lit.node {
                 check_str(cx, lit.span, expr.hir_id);
             }
diff --git a/clippy_lints/src/unnecessary_box_returns.rs b/clippy_lints/src/unnecessary_box_returns.rs
index af1c8d83b4f..e7449639f3a 100644
--- a/clippy_lints/src/unnecessary_box_returns.rs
+++ b/clippy_lints/src/unnecessary_box_returns.rs
@@ -109,7 +109,7 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns {
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
         // Ignore implementations of traits, because the lint should be on the
-        // trait, not on the implmentation of it.
+        // trait, not on the implementation of it.
         let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else { return };
         let ItemKind::Impl(parent) = parent.kind else { return };
         if parent.of_trait.is_some() {
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index 01927b6b5f1..108077b9d15 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -333,7 +333,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
     #[allow(clippy::too_many_lines)]
     fn expr(&self, expr: &Binding<&hir::Expr<'_>>) {
-        if let Some(higher::While { condition, body }) = higher::While::hir(expr.value) {
+        if let Some(higher::While { condition, body, .. }) = higher::While::hir(expr.value) {
             bind!(self, condition, body);
             chain!(
                 self,
@@ -561,7 +561,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             ExprKind::OffsetOf(container, ref fields) => {
                 bind!(self, container, fields);
                 kind!("OffsetOf({container}, {fields})");
-            }
+            },
             ExprKind::Struct(qpath, fields, base) => {
                 bind!(self, qpath, fields);
                 opt_bind!(self, base);
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 67bb499c455..5f05d971fce 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -277,6 +277,14 @@ define_Conf! {
     /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
     /// default configuration of Clippy. By default, any configuration will replace the default value.
     (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
+    /// Lint: SEMICOLON_INSIDE_BLOCK.
+    ///
+    /// Whether to lint only if it's multiline.
+    (semicolon_inside_block_ignore_singleline: bool = false),
+    /// Lint: SEMICOLON_OUTSIDE_BLOCK.
+    ///
+    /// Whether to lint only if it's singleline.
+    (semicolon_outside_block_ignore_multiline: bool = false),
     /// Lint: DOC_MARKDOWN.
     ///
     /// The list of words this lint should not consider as identifiers needing ticks. The value
diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml
index 124ebd164e6..66a5079fa85 100644
--- a/clippy_utils/Cargo.toml
+++ b/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.70"
+version = "0.1.71"
 edition = "2021"
 publish = false
 
diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs
index d3a6929f67e..9edaae85373 100644
--- a/clippy_utils/src/check_proc_macro.rs
+++ b/clippy_utils/src/check_proc_macro.rs
@@ -117,7 +117,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
         ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1),
         ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1),
         ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1),
-        ExprKind::Lit(ref lit) => lit_search_pat(&lit.node),
+        ExprKind::Lit(lit) => lit_search_pat(&lit.node),
         ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")),
         ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
         ExprKind::Call(first, [.., last])
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index 99bfc4b5717..b52caf6e405 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -324,7 +324,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         match e.kind {
             ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
             ExprKind::Block(block, _) => self.block(block),
-            ExprKind::Lit(ref lit) => {
+            ExprKind::Lit(lit) => {
                 if is_direct_expn_of(e.span, "cfg").is_some() {
                     None
                 } else {
diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs
index 50bef370930..a61e4c38088 100644
--- a/clippy_utils/src/higher.rs
+++ b/clippy_utils/src/higher.rs
@@ -311,6 +311,8 @@ pub struct While<'hir> {
     pub condition: &'hir Expr<'hir>,
     /// `while` loop body
     pub body: &'hir Expr<'hir>,
+    /// Span of the loop header
+    pub span: Span,
 }
 
 impl<'hir> While<'hir> {
@@ -336,10 +338,10 @@ impl<'hir> While<'hir> {
             },
             _,
             LoopSource::While,
-            _,
+            span,
         ) = expr.kind
         {
-            return Some(Self { condition, body });
+            return Some(Self { condition, body, span });
         }
         None
     }
diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs
index d972ed82c25..9b7408d5133 100644
--- a/clippy_utils/src/hir_utils.rs
+++ b/clippy_utils/src/hir_utils.rs
@@ -301,7 +301,7 @@ impl HirEqInterExpr<'_, '_, '_> {
             (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
             (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
             (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
-            (&ExprKind::OffsetOf(l_container, ref l_fields), &ExprKind::OffsetOf(r_container, ref r_fields)) => {
+            (&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => {
                 self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name)
             },
             _ => false,
@@ -718,7 +718,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 self.hash_pat(pat);
             },
             ExprKind::Err(_) => {},
-            ExprKind::Lit(ref l) => {
+            ExprKind::Lit(l) => {
                 l.node.hash(&mut self.s);
             },
             ExprKind::Loop(b, ref i, ..) => {
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 6b677df4641..964104fc31d 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -86,10 +86,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 use rustc_hir::{
-    self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination,
-    Expr, ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
+    self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
+    ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
     MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
-    TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
+    TraitItem, TraitItemRef, TraitRef, TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
@@ -197,31 +197,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
 /// }
 /// ```
 pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
-    let parent_id = cx.tcx.hir().get_parent_item(id).def_id;
-    match cx.tcx.hir().get_by_def_id(parent_id) {
-        Node::Item(&Item {
-            kind: ItemKind::Const(..) | ItemKind::Static(..) | ItemKind::Enum(..),
-            ..
-        })
-        | Node::TraitItem(&TraitItem {
-            kind: TraitItemKind::Const(..),
-            ..
-        })
-        | Node::ImplItem(&ImplItem {
-            kind: ImplItemKind::Const(..),
-            ..
-        })
-        | Node::AnonConst(_) => true,
-        Node::Item(&Item {
-            kind: ItemKind::Fn(ref sig, ..),
-            ..
-        })
-        | Node::ImplItem(&ImplItem {
-            kind: ImplItemKind::Fn(ref sig, _),
-            ..
-        }) => sig.header.constness == Constness::Const,
-        _ => false,
-    }
+    cx.tcx.hir().is_inside_const_context(id)
 }
 
 /// Checks if a `Res` refers to a constructor of a `LangItem`
@@ -846,7 +822,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
         },
         ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
         ExprKind::Repeat(x, ArrayLen::Body(len)) => if_chain! {
-            if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind;
+            if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind;
             if let LitKind::Int(v, _) = const_lit.node;
             if v <= 32 && is_default_equivalent(cx, x);
             then {
@@ -875,7 +851,7 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
             }) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String),
             ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
             ExprKind::Repeat(_, ArrayLen::Body(len)) => {
-                if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind &&
+                if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind &&
                     let LitKind::Int(v, _) = const_lit.node
                 {
                         return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
@@ -1569,7 +1545,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
 /// Checks whether the given expression is a constant literal of the given value.
 pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
     // FIXME: use constant folding
-    if let ExprKind::Lit(ref spanned) = expr.kind {
+    if let ExprKind::Lit(spanned) = expr.kind {
         if let LitKind::Int(v, _) = spanned.node {
             return v == value;
         }
@@ -2165,10 +2141,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
         .predicates
         .iter()
         .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
-    traits::impossible_predicates(
-        cx.tcx,
-        traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>(),
-    )
+    traits::impossible_predicates(cx.tcx, traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>())
 }
 
 /// Returns the `DefId` of the callee if the given expression is a function or method call.
@@ -2233,8 +2206,12 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S
     None
 }
 
-/// returns list of all pairs (a, b) from `exprs` such that `eq(a, b)`
-/// `hash` must be comformed with `eq`
+/// Returns list of all pairs `(a, b)` where `eq(a, b) == true`
+/// and `a` is before `b` in `exprs` for all `a` and `b` in
+/// `exprs`
+///
+/// Given functions `eq` and `hash` such that `eq(a, b) == true`
+/// implies `hash(a) == hash(b)`
 pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)>
 where
     Hash: Fn(&T) -> u64,
diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs
index 62d388a5ece..e4a4936ff42 100644
--- a/clippy_utils/src/macros.rs
+++ b/clippy_utils/src/macros.rs
@@ -362,7 +362,7 @@ thread_local! {
     /// able to access the many features of a [`LateContext`].
     ///
     /// A thread local is used because [`FormatArgs`] is `!Send` and `!Sync`, we are making an
-    /// assumption that the early pass the populates the map and the later late passes will all be
+    /// assumption that the early pass that populates the map and the later late passes will all be
     /// running on the same thread.
     static AST_FORMAT_ARGS: RefCell<FxHashMap<Span, FormatArgs>> = {
         static CALLED: AtomicBool = AtomicBool::new(false);
diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs
index 9be2d0eae80..0f0792fdaa9 100644
--- a/clippy_utils/src/paths.rs
+++ b/clippy_utils/src/paths.rs
@@ -159,3 +159,7 @@ pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
 pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
 pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
 pub const INSTANT: [&str; 3] = ["std", "time", "Instant"];
+pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"];
+pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"];
+pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
+pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs
index ecd712f32dc..c0d2c835d63 100644
--- a/clippy_utils/src/qualify_min_const_fn.rs
+++ b/clippy_utils/src/qualify_min_const_fn.rs
@@ -194,7 +194,9 @@ fn check_rvalue<'tcx>(
                 ))
             }
         },
-        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) | Rvalue::ShallowInitBox(_, _) => Ok(()),
+        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) | Rvalue::ShallowInitBox(_, _) => {
+            Ok(())
+        },
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
             if ty.is_integral() || ty.is_bool() {
diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs
index 03cd8e48b9a..14f7f03016f 100644
--- a/clippy_utils/src/sugg.rs
+++ b/clippy_utils/src/sugg.rs
@@ -162,7 +162,7 @@ impl<'a> Sugg<'a> {
                 get_snippet(lhs.span),
                 get_snippet(rhs.span),
             ),
-            hir::ExprKind::Cast(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
+            hir::ExprKind::Cast(lhs, ty) |
             //FIXME(chenyukang), remove this after type ascription is removed from AST
             hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)),
         }
@@ -254,11 +254,7 @@ impl<'a> Sugg<'a> {
                 snippet_with_context(cx, lhs.span, ctxt, default, app).0,
                 snippet_with_context(cx, rhs.span, ctxt, default, app).0,
             ),
-            ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp(
-                AssocOp::As,
-                snippet_with_context(cx, lhs.span, ctxt, default, app).0,
-                snippet_with_context(cx, ty.span, ctxt, default, app).0,
-            ),
+            ast::ExprKind::Cast(ref lhs, ref ty) |
             //FIXME(chenyukang), remove this after type ascription is removed from AST
             ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp(
                 AssocOp::As,
@@ -603,8 +599,8 @@ enum Associativity {
 #[must_use]
 fn associativity(op: AssocOp) -> Associativity {
     use rustc_ast::util::parser::AssocOp::{
-        Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Divide, DotDot, DotDotEq, Equal, Greater,
-        GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
+        Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Divide, DotDot, DotDotEq, Equal, Greater, GreaterEqual, LAnd,
+        LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
     };
 
     match op {
diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs
index a6572011644..7b4ed77e8ed 100644
--- a/clippy_utils/src/ty.rs
+++ b/clippy_utils/src/ty.rs
@@ -93,7 +93,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                     for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
-                            // and check substituions to find `U`.
+                            // and check substitutions to find `U`.
                             ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => {
                                 if trait_predicate
                                     .trait_ref
@@ -837,7 +837,7 @@ pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
     if let ty::Adt(adt, _) = ty.kind()
         && let &[krate, .., name] = &*cx.get_def_path(adt.did())
         && let sym::libc | sym::core | sym::std = krate
-        && name.as_str() == "c_void"
+        && name == rustc_span::sym::c_void
     {
         true
     } else {
@@ -1101,7 +1101,7 @@ pub fn make_projection<'tcx>(
 ///
 /// This function is for associated types which are "known" to be valid with the given
 /// substitutions, and as such, will only return `None` when debug assertions are disabled in order
-/// to prevent ICE's. With debug assertions enabled this will check that that type normalization
+/// to prevent ICE's. With debug assertions enabled this will check that type normalization
 /// succeeds as well as everything checked by `make_projection`.
 pub fn make_normalized_projection<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/declare_clippy_lint/Cargo.toml b/declare_clippy_lint/Cargo.toml
index bd26f4fc913..139102798c4 100644
--- a/declare_clippy_lint/Cargo.toml
+++ b/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "declare_clippy_lint"
-version = "0.1.70"
+version = "0.1.71"
 edition = "2021"
 publish = false
 
diff --git a/lintcheck/README.md b/lintcheck/README.md
index faf3ce9093a..37cc0453809 100644
--- a/lintcheck/README.md
+++ b/lintcheck/README.md
@@ -79,9 +79,11 @@ is explicitly specified in the options.
 
 ### Fix mode
 You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and
-print a warning if Clippy's suggestions fail to apply (if the resulting code does not build).  
+print a warning if Clippy's suggestions fail to apply (if the resulting code does not build). 
 This lets us spot bad suggestions or false positives automatically in some cases.  
 
+> Note: Fix mode implies `--all-targets`, so it can fix as much code as it can.
+
 Please note that the target dir should be cleaned afterwards since clippy will modify
 the downloaded sources which can lead to unexpected results when running lintcheck again afterwards.
 
diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs
index 23c85298027..03d1877d6c6 100644
--- a/lintcheck/src/main.rs
+++ b/lintcheck/src/main.rs
@@ -421,7 +421,7 @@ impl Crate {
             {
                 let subcrate = &stderr[63..];
                 println!(
-                    "ERROR: failed to apply some suggetion to {} / to (sub)crate {subcrate}",
+                    "ERROR: failed to apply some suggestion to {} / to (sub)crate {subcrate}",
                     self.name
                 );
             }
diff --git a/rust-toolchain b/rust-toolchain
index 91e8ccea1f4..60b8a5ac071 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-04-06"
+channel = "nightly-2023-05-05"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/main.rs b/src/main.rs
index c5e9b96cf3f..188ff87abfc 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -13,7 +13,7 @@ Usage:
 
 Common options:
     --no-deps                Run Clippy only on the given crate, without linting the dependencies
-    --fix                    Automatically apply lint suggestions. This flag implies `--no-deps`
+    --fix                    Automatically apply lint suggestions. This flag implies `--no-deps` and `--all-targets`
     -h, --help               Print this message
     -V, --version            Print version info and exit
     --explain LINT           Print the documentation for a given lint
diff --git a/tests/dogfood.rs b/tests/dogfood.rs
index 68a878e9a3d..afde31face1 100644
--- a/tests/dogfood.rs
+++ b/tests/dogfood.rs
@@ -39,7 +39,7 @@ fn dogfood_clippy() {
     assert!(
         failed_packages.is_empty(),
         "Dogfood failed for packages `{}`",
-        failed_packages.iter().format(", "),
+        failed_packages.iter().join(", "),
     );
 }
 
diff --git a/tests/ui-toml/semicolon_block/both.fixed b/tests/ui-toml/semicolon_block/both.fixed
new file mode 100644
index 00000000000..fc8038a0907
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/both.fixed
@@ -0,0 +1,86 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()) };
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/tests/ui-toml/semicolon_block/both.rs b/tests/ui-toml/semicolon_block/both.rs
new file mode 100644
index 00000000000..52ce1f0387e
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/both.rs
@@ -0,0 +1,86 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/tests/ui-toml/semicolon_block/both.stderr b/tests/ui-toml/semicolon_block/both.stderr
new file mode 100644
index 00000000000..2f58842eab0
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/both.stderr
@@ -0,0 +1,55 @@
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/both.rs:43:5
+   |
+LL |     { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL -     { unit_fn_block(); }
+LL +     { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/both.rs:44:5
+   |
+LL |     unsafe { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     unsafe { unit_fn_block(); }
+LL +     unsafe { unit_fn_block() };
+   |
+
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/both.rs:49:5
+   |
+LL | /     {
+LL | |         unit_fn_block();
+LL | |         unit_fn_block()
+LL | |     };
+   | |______^
+   |
+   = note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL ~         unit_fn_block();
+LL ~     }
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/both.rs:63:5
+   |
+LL |     { m!(()); }
+   |     ^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     { m!(()); }
+LL +     { m!(()) };
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui-toml/semicolon_block/clippy.toml b/tests/ui-toml/semicolon_block/clippy.toml
new file mode 100644
index 00000000000..4d03e88deba
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/clippy.toml
@@ -0,0 +1,2 @@
+semicolon-inside-block-ignore-singleline = true
+semicolon-outside-block-ignore-multiline = true
diff --git a/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed b/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed
new file mode 100644
index 00000000000..23df9830177
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/tests/ui-toml/semicolon_block/semicolon_inside_block.rs b/tests/ui-toml/semicolon_block/semicolon_inside_block.rs
new file mode 100644
index 00000000000..e8516f79b20
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/semicolon_inside_block.rs
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_inside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr b/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr
new file mode 100644
index 00000000000..2569dc4b4e4
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr
@@ -0,0 +1,18 @@
+error: consider moving the `;` inside the block for consistent formatting
+  --> $DIR/semicolon_inside_block.rs:48:5
+   |
+LL | /     {
+LL | |         unit_fn_block();
+LL | |         unit_fn_block()
+LL | |     };
+   | |______^
+   |
+   = note: `-D clippy::semicolon-inside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL ~         unit_fn_block();
+LL ~     }
+   |
+
+error: aborting due to previous error
+
diff --git a/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed b/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed
new file mode 100644
index 00000000000..7e9055e7110
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()) };
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/tests/ui-toml/semicolon_block/semicolon_outside_block.rs b/tests/ui-toml/semicolon_block/semicolon_outside_block.rs
new file mode 100644
index 00000000000..4dc956d8a4b
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/semicolon_outside_block.rs
@@ -0,0 +1,85 @@
+//@run-rustfix
+#![allow(
+    unused,
+    clippy::unused_unit,
+    clippy::unnecessary_operation,
+    clippy::no_effect,
+    clippy::single_element_loop
+)]
+#![warn(clippy::semicolon_outside_block)]
+
+macro_rules! m {
+    (()) => {
+        ()
+    };
+    (0) => {{
+        0
+    };};
+    (1) => {{
+        1;
+    }};
+    (2) => {{
+        2;
+    }};
+}
+
+fn unit_fn_block() {
+    ()
+}
+
+#[rustfmt::skip]
+fn main() {
+    { unit_fn_block() }
+    unsafe { unit_fn_block() }
+
+    {
+        unit_fn_block()
+    }
+
+    { unit_fn_block() };
+    unsafe { unit_fn_block() };
+
+    { unit_fn_block(); }
+    unsafe { unit_fn_block(); }
+
+    { unit_fn_block(); };
+    unsafe { unit_fn_block(); };
+
+    {
+        unit_fn_block();
+        unit_fn_block()
+    };
+    {
+        unit_fn_block();
+        unit_fn_block();
+    }
+    {
+        unit_fn_block();
+        unit_fn_block();
+    };
+
+    { m!(()) };
+    { m!(()); }
+    { m!(()); };
+    m!(0);
+    m!(1);
+    m!(2);
+
+    for _ in [()] {
+        unit_fn_block();
+    }
+    for _ in [()] {
+        unit_fn_block()
+    }
+
+    let _d = || {
+        unit_fn_block();
+    };
+    let _d = || {
+        unit_fn_block()
+    };
+
+    { unit_fn_block(); };
+
+    unit_fn_block()
+}
diff --git a/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr b/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr
new file mode 100644
index 00000000000..6dd3577dd09
--- /dev/null
+++ b/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr
@@ -0,0 +1,39 @@
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:42:5
+   |
+LL |     { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::semicolon-outside-block` implied by `-D warnings`
+help: put the `;` here
+   |
+LL -     { unit_fn_block(); }
+LL +     { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:43:5
+   |
+LL |     unsafe { unit_fn_block(); }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     unsafe { unit_fn_block(); }
+LL +     unsafe { unit_fn_block() };
+   |
+
+error: consider moving the `;` outside the block for consistent formatting
+  --> $DIR/semicolon_outside_block.rs:62:5
+   |
+LL |     { m!(()); }
+   |     ^^^^^^^^^^^
+   |
+help: put the `;` here
+   |
+LL -     { m!(()); }
+LL +     { m!(()) };
+   |
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 36b372b36f4..44710b09648 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -37,6 +37,8 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            missing-docs-in-crate-items
            msrv
            pass-by-value-size-limit
+           semicolon-inside-block-ignore-singleline
+           semicolon-outside-block-ignore-multiline
            single-char-binding-names-threshold
            standard-macro-braces
            suppress-restriction-lint-in-const
diff --git a/tests/ui/allow_attributes_false_positive.rs b/tests/ui/allow_attributes_false_positive.rs
new file mode 100644
index 00000000000..5c3407628be
--- /dev/null
+++ b/tests/ui/allow_attributes_false_positive.rs
@@ -0,0 +1,5 @@
+#![warn(clippy::allow_attributes)]
+#![feature(lint_reasons)]
+#![crate_type = "proc-macro"]
+
+fn main() {}
diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs
index a9bb61451dc..e5bb906663c 100644
--- a/tests/ui/auxiliary/macro_rules.rs
+++ b/tests/ui/auxiliary/macro_rules.rs
@@ -21,6 +21,13 @@ macro_rules! string_add {
     };
 }
 
+#[macro_export]
+macro_rules! string_lit_as_bytes {
+    ($s:literal) => {
+        const C: &[u8] = $s.as_bytes();
+    };
+}
+
 #[macro_export]
 macro_rules! mut_mut {
     () => {
diff --git a/tests/ui/auxiliary/proc_macro_attr.rs b/tests/ui/auxiliary/proc_macro_attr.rs
index 92c47b41a38..d164dd0e545 100644
--- a/tests/ui/auxiliary/proc_macro_attr.rs
+++ b/tests/ui/auxiliary/proc_macro_attr.rs
@@ -82,7 +82,7 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea
                     elided += 1;
 
                     // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it.
-                    // In order to avoid adding the dependency, get a default span from a non-existent token.
+                    // In order to avoid adding the dependency, get a default span from a nonexistent token.
                     // A default span is needed to mark the code as coming from expansion.
                     let span = Star::default().span();
 
diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed
index 9831c3373d4..fbb10a133e2 100644
--- a/tests/ui/bool_to_int_with_if.fixed
+++ b/tests/ui/bool_to_int_with_if.fixed
@@ -1,6 +1,6 @@
 //@run-rustfix
 
-#![feature(let_chains)]
+#![feature(let_chains, inline_const)]
 #![warn(clippy::bool_to_int_with_if)]
 #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
 
@@ -79,6 +79,13 @@ fn main() {
 
     pub const SHOULD_NOT_LINT: usize = if true { 1 } else { 0 };
 
+    // https://github.com/rust-lang/rust-clippy/issues/10452
+    let should_not_lint = [(); if true { 1 } else { 0 }];
+
+    let should_not_lint = const {
+        if true { 1 } else { 0 }
+    };
+
     some_fn(a);
 }
 
diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs
index 5e3047bb32c..709a18d63e4 100644
--- a/tests/ui/bool_to_int_with_if.rs
+++ b/tests/ui/bool_to_int_with_if.rs
@@ -1,6 +1,6 @@
 //@run-rustfix
 
-#![feature(let_chains)]
+#![feature(let_chains, inline_const)]
 #![warn(clippy::bool_to_int_with_if)]
 #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
 
@@ -111,6 +111,13 @@ fn main() {
 
     pub const SHOULD_NOT_LINT: usize = if true { 1 } else { 0 };
 
+    // https://github.com/rust-lang/rust-clippy/issues/10452
+    let should_not_lint = [(); if true { 1 } else { 0 }];
+
+    let should_not_lint = const {
+        if true { 1 } else { 0 }
+    };
+
     some_fn(a);
 }
 
diff --git a/tests/ui/bool_to_int_with_if.stderr b/tests/ui/bool_to_int_with_if.stderr
index 5cfb75cc0df..3bdae75cad2 100644
--- a/tests/ui/bool_to_int_with_if.stderr
+++ b/tests/ui/bool_to_int_with_if.stderr
@@ -98,7 +98,7 @@ LL | |     };
    = note: `!b as i32` or `(!b).into()` can also be valid options
 
 error: boolean to int conversion using if
-  --> $DIR/bool_to_int_with_if.rs:119:5
+  --> $DIR/bool_to_int_with_if.rs:126:5
    |
 LL |     if a { 1 } else { 0 }
    |     ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)`
diff --git a/tests/ui/box_default.fixed b/tests/ui/box_default.fixed
index 6afce208769..e6331290420 100644
--- a/tests/ui/box_default.fixed
+++ b/tests/ui/box_default.fixed
@@ -1,5 +1,6 @@
 //@run-rustfix
 #![warn(clippy::box_default)]
+#![allow(clippy::default_constructed_unit_structs)]
 
 #[derive(Default)]
 struct ImplementsDefault;
diff --git a/tests/ui/box_default.rs b/tests/ui/box_default.rs
index 09365618e63..34a05a29c5a 100644
--- a/tests/ui/box_default.rs
+++ b/tests/ui/box_default.rs
@@ -1,5 +1,6 @@
 //@run-rustfix
 #![warn(clippy::box_default)]
+#![allow(clippy::default_constructed_unit_structs)]
 
 #[derive(Default)]
 struct ImplementsDefault;
diff --git a/tests/ui/box_default.stderr b/tests/ui/box_default.stderr
index 78e17b9f035..c9834863601 100644
--- a/tests/ui/box_default.stderr
+++ b/tests/ui/box_default.stderr
@@ -1,5 +1,5 @@
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:22:32
+  --> $DIR/box_default.rs:23:32
    |
 LL |     let _string: Box<String> = Box::new(Default::default());
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
@@ -7,91 +7,91 @@ LL |     let _string: Box<String> = Box::new(Default::default());
    = note: `-D clippy::box-default` implied by `-D warnings`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:23:17
+  --> $DIR/box_default.rs:24:17
    |
 LL |     let _byte = Box::new(u8::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<u8>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:24:16
+  --> $DIR/box_default.rs:25:16
    |
 LL |     let _vec = Box::new(Vec::<u8>::new());
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<u8>>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:25:17
+  --> $DIR/box_default.rs:26:17
    |
 LL |     let _impl = Box::new(ImplementsDefault::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:26:18
+  --> $DIR/box_default.rs:27:18
    |
 LL |     let _impl2 = Box::new(<ImplementsDefault as Default>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:27:42
+  --> $DIR/box_default.rs:28:42
    |
 LL |     let _impl3: Box<ImplementsDefault> = Box::new(Default::default());
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:29:28
+  --> $DIR/box_default.rs:30:28
    |
 LL |     let _in_macro = outer!(Box::new(String::new()));
    |                            ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:30:34
+  --> $DIR/box_default.rs:31:34
    |
 LL |     let _string_default = outer!(Box::new(String::from("")));
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:31:46
+  --> $DIR/box_default.rs:32:46
    |
 LL |     let _vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]);
    |                                              ^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:32:33
+  --> $DIR/box_default.rs:33:33
    |
 LL |     let _vec3: Box<Vec<bool>> = Box::new(Vec::from([]));
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:33:25
+  --> $DIR/box_default.rs:34:25
    |
 LL |     let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<bool>>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:35:16
+  --> $DIR/box_default.rs:36:16
    |
 LL |     call_ty_fn(Box::new(u8::default()));
    |                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:40:5
+  --> $DIR/box_default.rs:41:5
    |
 LL |     Box::new(bool::default())
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:57:28
+  --> $DIR/box_default.rs:58:28
    |
 LL |     let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:66:17
+  --> $DIR/box_default.rs:67:17
    |
 LL |         let _ = Box::new(WeirdPathed::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:78:18
+  --> $DIR/box_default.rs:79:18
    |
 LL |             Some(Box::new(Foo::default()))
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Foo>::default()`
diff --git a/tests/ui/cast_slice_different_sizes.rs b/tests/ui/cast_slice_different_sizes.rs
index 24d7eb28a19..b77f01883bf 100644
--- a/tests/ui/cast_slice_different_sizes.rs
+++ b/tests/ui/cast_slice_different_sizes.rs
@@ -23,7 +23,7 @@ fn main() {
         r_x as *const [i32]
     } as *const [u8];
 
-    // Check that resores of the same size are detected through blocks
+    // Check that resources of the same size are detected through blocks
     let restore_block_1 = { r_x as *const [i32] } as *const [u8] as *const [u32];
     let restore_block_2 = { ({ r_x as *const [i32] }) as *const [u8] } as *const [u32];
     let restore_block_3 = {
diff --git a/tests/ui/crashes/ice-10645.rs b/tests/ui/crashes/ice-10645.rs
new file mode 100644
index 00000000000..4d8698d383b
--- /dev/null
+++ b/tests/ui/crashes/ice-10645.rs
@@ -0,0 +1,7 @@
+// compile-flags: --cap-lints=warn
+// https://github.com/rust-lang/rust-clippy/issues/10645
+
+#![warn(clippy::future_not_send)]
+pub async fn bar<'a, T: 'a>(_: T) {}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-5207.stderr b/tests/ui/crashes/ice-10645.stderr
similarity index 89%
rename from tests/ui/crashes/ice-5207.stderr
rename to tests/ui/crashes/ice-10645.stderr
index 59146c23e0d..fc084e30d7f 100644
--- a/tests/ui/crashes/ice-5207.stderr
+++ b/tests/ui/crashes/ice-10645.stderr
@@ -1,11 +1,11 @@
 error: future cannot be sent between threads safely
-  --> $DIR/ice-5207.rs:6:35
+  --> $DIR/ice-10645.rs:5:35
    |
 LL | pub async fn bar<'a, T: 'a>(_: T) {}
    |                                   ^ future returned by `bar` is not `Send`
    |
 note: captured value is not `Send`
-  --> $DIR/ice-5207.rs:6:29
+  --> $DIR/ice-10645.rs:5:29
    |
 LL | pub async fn bar<'a, T: 'a>(_: T) {}
    |                             ^ has type `T` which is not `Send`
diff --git a/tests/ui/crashes/ice-5207.rs b/tests/ui/crashes/ice-5207.rs
index 893c15f5d73..0df8b88fea2 100644
--- a/tests/ui/crashes/ice-5207.rs
+++ b/tests/ui/crashes/ice-5207.rs
@@ -1,8 +1,4 @@
-// compile-flags: --cap-lints=warn
-// ^ for https://github.com/rust-lang/rust-clippy/issues/10645
-
 // Regression test for https://github.com/rust-lang/rust-clippy/issues/5207
-#![warn(clippy::future_not_send)]
 pub async fn bar<'a, T: 'a>(_: T) {}
 
 fn main() {}
diff --git a/tests/ui/crashes/ice_exacte_size.rs b/tests/ui/crashes/ice_exact_size.rs
similarity index 100%
rename from tests/ui/crashes/ice_exacte_size.rs
rename to tests/ui/crashes/ice_exact_size.rs
diff --git a/tests/ui/default_constructed_unit_structs.fixed b/tests/ui/default_constructed_unit_structs.fixed
new file mode 100644
index 00000000000..4c2d1ea48e1
--- /dev/null
+++ b/tests/ui/default_constructed_unit_structs.fixed
@@ -0,0 +1,119 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::default_constructed_unit_structs)]
+use std::marker::PhantomData;
+
+#[derive(Default)]
+struct UnitStruct;
+
+impl UnitStruct {
+    fn new() -> Self {
+        //should lint
+        Self
+    }
+}
+
+#[derive(Default)]
+struct TupleStruct(usize);
+
+impl TupleStruct {
+    fn new() -> Self {
+        // should not lint
+        Self(Default::default())
+    }
+}
+
+// no lint for derived impl
+#[derive(Default)]
+struct NormalStruct {
+    inner: PhantomData<usize>,
+}
+
+struct NonDefaultStruct;
+
+impl NonDefaultStruct {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+enum SomeEnum {
+    #[default]
+    Unit,
+    Tuple(UnitStruct),
+    Struct {
+        inner: usize,
+    },
+}
+
+impl NormalStruct {
+    fn new() -> Self {
+        // should lint
+        Self {
+            inner: PhantomData,
+        }
+    }
+
+    fn new2() -> Self {
+        // should not lint
+        Self {
+            inner: Default::default(),
+        }
+    }
+}
+
+#[derive(Default)]
+struct GenericStruct<T> {
+    t: T,
+}
+
+impl<T: Default> GenericStruct<T> {
+    fn new() -> Self {
+        // should not lint
+        Self { t: T::default() }
+    }
+
+    fn new2() -> Self {
+        // should not lint
+        Self { t: Default::default() }
+    }
+}
+
+struct FakeDefault;
+impl FakeDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+impl Default for FakeDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+struct EmptyStruct {}
+
+#[derive(Default)]
+#[non_exhaustive]
+struct NonExhaustiveStruct;
+
+fn main() {
+    // should lint
+    let _ = PhantomData::<usize>;
+    let _: PhantomData<i32> = PhantomData;
+    let _ = UnitStruct;
+
+    // should not lint
+    let _ = TupleStruct::default();
+    let _ = NormalStruct::default();
+    let _ = NonExhaustiveStruct::default();
+    let _ = SomeEnum::default();
+    let _ = NonDefaultStruct::default();
+    let _ = EmptyStruct::default();
+    let _ = FakeDefault::default();
+    let _ = <FakeDefault as Default>::default();
+}
diff --git a/tests/ui/default_constructed_unit_structs.rs b/tests/ui/default_constructed_unit_structs.rs
new file mode 100644
index 00000000000..850793dd5de
--- /dev/null
+++ b/tests/ui/default_constructed_unit_structs.rs
@@ -0,0 +1,119 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::default_constructed_unit_structs)]
+use std::marker::PhantomData;
+
+#[derive(Default)]
+struct UnitStruct;
+
+impl UnitStruct {
+    fn new() -> Self {
+        //should lint
+        Self::default()
+    }
+}
+
+#[derive(Default)]
+struct TupleStruct(usize);
+
+impl TupleStruct {
+    fn new() -> Self {
+        // should not lint
+        Self(Default::default())
+    }
+}
+
+// no lint for derived impl
+#[derive(Default)]
+struct NormalStruct {
+    inner: PhantomData<usize>,
+}
+
+struct NonDefaultStruct;
+
+impl NonDefaultStruct {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+enum SomeEnum {
+    #[default]
+    Unit,
+    Tuple(UnitStruct),
+    Struct {
+        inner: usize,
+    },
+}
+
+impl NormalStruct {
+    fn new() -> Self {
+        // should lint
+        Self {
+            inner: PhantomData::default(),
+        }
+    }
+
+    fn new2() -> Self {
+        // should not lint
+        Self {
+            inner: Default::default(),
+        }
+    }
+}
+
+#[derive(Default)]
+struct GenericStruct<T> {
+    t: T,
+}
+
+impl<T: Default> GenericStruct<T> {
+    fn new() -> Self {
+        // should not lint
+        Self { t: T::default() }
+    }
+
+    fn new2() -> Self {
+        // should not lint
+        Self { t: Default::default() }
+    }
+}
+
+struct FakeDefault;
+impl FakeDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+impl Default for FakeDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+#[derive(Default)]
+struct EmptyStruct {}
+
+#[derive(Default)]
+#[non_exhaustive]
+struct NonExhaustiveStruct;
+
+fn main() {
+    // should lint
+    let _ = PhantomData::<usize>::default();
+    let _: PhantomData<i32> = PhantomData::default();
+    let _ = UnitStruct::default();
+
+    // should not lint
+    let _ = TupleStruct::default();
+    let _ = NormalStruct::default();
+    let _ = NonExhaustiveStruct::default();
+    let _ = SomeEnum::default();
+    let _ = NonDefaultStruct::default();
+    let _ = EmptyStruct::default();
+    let _ = FakeDefault::default();
+    let _ = <FakeDefault as Default>::default();
+}
diff --git a/tests/ui/default_constructed_unit_structs.stderr b/tests/ui/default_constructed_unit_structs.stderr
new file mode 100644
index 00000000000..4058943d087
--- /dev/null
+++ b/tests/ui/default_constructed_unit_structs.stderr
@@ -0,0 +1,34 @@
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:13:13
+   |
+LL |         Self::default()
+   |             ^^^^^^^^^^^ help: remove this call to `default`
+   |
+   = note: `-D clippy::default-constructed-unit-structs` implied by `-D warnings`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:55:31
+   |
+LL |             inner: PhantomData::default(),
+   |                               ^^^^^^^^^^^ help: remove this call to `default`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:106:33
+   |
+LL |     let _ = PhantomData::<usize>::default();
+   |                                 ^^^^^^^^^^^ help: remove this call to `default`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:107:42
+   |
+LL |     let _: PhantomData<i32> = PhantomData::default();
+   |                                          ^^^^^^^^^^^ help: remove this call to `default`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:108:23
+   |
+LL |     let _ = UnitStruct::default();
+   |                       ^^^^^^^^^^^ help: remove this call to `default`
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/floating_point_arithmetic_nostd.rs b/tests/ui/floating_point_arithmetic_nostd.rs
new file mode 100644
index 00000000000..a42c6383cce
--- /dev/null
+++ b/tests/ui/floating_point_arithmetic_nostd.rs
@@ -0,0 +1,31 @@
+#![feature(lang_items, start)]
+#![warn(clippy::imprecise_flops)]
+#![warn(clippy::suboptimal_flops)]
+#![no_std]
+
+// The following should not lint, as the suggested methods {f32,f64}.mul_add()
+// and {f32,f64}::abs() are not available in no_std
+
+pub fn mul_add() {
+    let a: f64 = 1234.567;
+    let b: f64 = 45.67834;
+    let c: f64 = 0.0004;
+    let _ = a * b + c;
+}
+
+fn fake_abs1(num: f64) -> f64 {
+    if num >= 0.0 { num } else { -num }
+}
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/tests/ui/from_over_into.fixed b/tests/ui/from_over_into.fixed
index fc6d937060d..d18f9387565 100644
--- a/tests/ui/from_over_into.fixed
+++ b/tests/ui/from_over_into.fixed
@@ -32,7 +32,7 @@ struct SelfKeywords;
 
 impl From<X> for SelfKeywords {
     fn from(val: X) -> Self {
-        let _ = X::default();
+        let _ = X;
         let _ = X::FOO;
         let _: X = val;
 
diff --git a/tests/ui/from_over_into.rs b/tests/ui/from_over_into.rs
index fe1ebee35f1..de8ff0b06bd 100644
--- a/tests/ui/from_over_into.rs
+++ b/tests/ui/from_over_into.rs
@@ -32,7 +32,7 @@ struct SelfKeywords;
 
 impl Into<SelfKeywords> for X {
     fn into(self) -> SelfKeywords {
-        let _ = Self::default();
+        let _ = Self;
         let _ = Self::FOO;
         let _: Self = self;
 
diff --git a/tests/ui/from_over_into.stderr b/tests/ui/from_over_into.stderr
index 3c4d011d6fb..6039f86fe67 100644
--- a/tests/ui/from_over_into.stderr
+++ b/tests/ui/from_over_into.stderr
@@ -5,7 +5,7 @@ LL | impl Into<StringWrapper> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::from-over-into` implied by `-D warnings`
-help: replace the `Into` implentation with `From<std::string::String>`
+help: replace the `Into` implementation with `From<std::string::String>`
    |
 LL ~ impl From<String> for StringWrapper {
 LL ~     fn from(val: String) -> Self {
@@ -18,7 +18,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL | impl Into<SelfType> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace the `Into` implentation with `From<std::string::String>`
+help: replace the `Into` implementation with `From<std::string::String>`
    |
 LL ~ impl From<String> for SelfType {
 LL ~     fn from(val: String) -> Self {
@@ -31,11 +31,11 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL | impl Into<SelfKeywords> for X {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace the `Into` implentation with `From<X>`
+help: replace the `Into` implementation with `From<X>`
    |
 LL ~ impl From<X> for SelfKeywords {
 LL ~     fn from(val: X) -> Self {
-LL ~         let _ = X::default();
+LL ~         let _ = X;
 LL ~         let _ = X::FOO;
 LL ~         let _: X = val;
    |
@@ -48,7 +48,7 @@ LL | impl core::convert::Into<bool> for crate::ExplicitPaths {
    |
    = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
            https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
-help: replace the `Into` implentation with `From<ExplicitPaths>`
+help: replace the `Into` implementation with `From<ExplicitPaths>`
    |
 LL ~ impl core::convert::From<crate::ExplicitPaths> for bool {
 LL ~     fn from(mut val: crate::ExplicitPaths) -> Self {
@@ -64,7 +64,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL |     impl<T> Into<FromOverInto<T>> for Vec<T> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace the `Into` implentation with `From<std::vec::Vec<T>>`
+help: replace the `Into` implementation with `From<std::vec::Vec<T>>`
    |
 LL ~     impl<T> From<Vec<T>> for FromOverInto<T> {
 LL ~         fn from(val: Vec<T>) -> Self {
diff --git a/tests/ui/from_over_into_unfixable.stderr b/tests/ui/from_over_into_unfixable.stderr
index 6f6ce351921..251f1d84e74 100644
--- a/tests/ui/from_over_into_unfixable.stderr
+++ b/tests/ui/from_over_into_unfixable.stderr
@@ -4,7 +4,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL | impl Into<InMacro> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: replace the `Into` implentation with `From<std::string::String>`
+   = help: replace the `Into` implementation with `From<std::string::String>`
    = note: `-D clippy::from-over-into` implied by `-D warnings`
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
@@ -13,7 +13,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for
 LL | impl Into<WeirdUpperSelf> for &'static [u8] {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: replace the `Into` implentation with `From<&'static [u8]>`
+   = help: replace the `Into` implementation with `From<&'static [u8]>`
 
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
   --> $DIR/from_over_into_unfixable.rs:28:1
@@ -23,7 +23,7 @@ LL | impl Into<u8> for ContainsVal {
    |
    = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
            https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
-   = help: replace the `Into` implentation with `From<ContainsVal>`
+   = help: replace the `Into` implementation with `From<ContainsVal>`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/items_after_test_module/auxiliary/tests.rs b/tests/ui/items_after_test_module/auxiliary/tests.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/ui/items_after_test_module/auxiliary/tests.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/ui/items_after_test_module.rs b/tests/ui/items_after_test_module/block_module.rs
similarity index 100%
rename from tests/ui/items_after_test_module.rs
rename to tests/ui/items_after_test_module/block_module.rs
diff --git a/tests/ui/items_after_test_module.stderr b/tests/ui/items_after_test_module/block_module.stderr
similarity index 89%
rename from tests/ui/items_after_test_module.stderr
rename to tests/ui/items_after_test_module/block_module.stderr
index 8f1616dabc1..597f1b9510c 100644
--- a/tests/ui/items_after_test_module.stderr
+++ b/tests/ui/items_after_test_module/block_module.stderr
@@ -1,5 +1,5 @@
 error: items were found after the testing module
-  --> $DIR/items_after_test_module.rs:13:1
+  --> $DIR/block_module.rs:13:1
    |
 LL | / mod tests {
 LL | |     #[test]
diff --git a/tests/ui/items_after_test_module/imported_module.rs b/tests/ui/items_after_test_module/imported_module.rs
new file mode 100644
index 00000000000..6a757aef48e
--- /dev/null
+++ b/tests/ui/items_after_test_module/imported_module.rs
@@ -0,0 +1,20 @@
+//@compile-flags: --test
+#![allow(unused)]
+#![warn(clippy::items_after_test_module)]
+
+// Nothing here should lint, as `tests` is an imported module (that has no body).
+
+fn main() {}
+
+fn should_not_lint() {}
+
+#[path = "auxiliary/tests.rs"]
+#[cfg(test)]
+mod tests; // Should not lint
+
+fn should_not_lint2() {}
+
+const SHOULD_ALSO_NOT_LINT: usize = 1;
+macro_rules! should_not_lint {
+    () => {};
+}
diff --git a/tests/ui/let_underscore_untyped.stderr b/tests/ui/let_underscore_untyped.stderr
index 47e76ea1d04..6844cb998f7 100644
--- a/tests/ui/let_underscore_untyped.stderr
+++ b/tests/ui/let_underscore_untyped.stderr
@@ -4,7 +4,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = a();
    |     ^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:36:10
+   |
+LL |     let _ = a();
+   |          ^
    = note: `-D clippy::let-underscore-untyped` implied by `-D warnings`
 
 error: non-binding `let` without a type annotation
@@ -13,7 +17,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = b(1);
    |     ^^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:37:10
+   |
+LL |     let _ = b(1);
+   |          ^
 
 error: non-binding `let` without a type annotation
   --> $DIR/let_underscore_untyped.rs:39:5
@@ -21,7 +29,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = d(&1);
    |     ^^^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:39:10
+   |
+LL |     let _ = d(&1);
+   |          ^
 
 error: non-binding `let` without a type annotation
   --> $DIR/let_underscore_untyped.rs:40:5
@@ -29,7 +41,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = e();
    |     ^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:40:10
+   |
+LL |     let _ = e();
+   |          ^
 
 error: non-binding `let` without a type annotation
   --> $DIR/let_underscore_untyped.rs:41:5
@@ -37,7 +53,11 @@ error: non-binding `let` without a type annotation
 LL |     let _ = f();
    |     ^^^^^^^^^^^^
    |
-   = help: consider adding a type annotation or removing the `let` keyword
+help: consider adding a type annotation
+  --> $DIR/let_underscore_untyped.rs:41:10
+   |
+LL |     let _ = f();
+   |          ^
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/let_with_type_underscore.rs b/tests/ui/let_with_type_underscore.rs
index 175718b94c8..7c1835e8cd1 100644
--- a/tests/ui/let_with_type_underscore.rs
+++ b/tests/ui/let_with_type_underscore.rs
@@ -12,7 +12,7 @@ fn main() {
     let _: _ = 2;
     let x: _ = func();
 
-    let x = 1; // Will not lint, Rust inferres this to an integer before Clippy
+    let x = 1; // Will not lint, Rust infers this to an integer before Clippy
     let x = func();
     let x: Vec<_> = Vec::<u32>::new();
     let x: [_; 1] = [1];
diff --git a/tests/ui/manual_retain.fixed b/tests/ui/manual_retain.fixed
index d3cac666763..09fb0d75852 100644
--- a/tests/ui/manual_retain.fixed
+++ b/tests/ui/manual_retain.fixed
@@ -23,8 +23,8 @@ fn main() {
 }
 
 fn binary_heap_retain() {
-    // NOTE: Do not lint now, because binary_heap_retain is nighyly API.
-    // And we need to add a test case for msrv if we update this implmention.
+    // NOTE: Do not lint now, because binary_heap_retain is nightly API.
+    // And we need to add a test case for msrv if we update this implementation.
     // https://github.com/rust-lang/rust/issues/71503
     let mut heap = BinaryHeap::from([1, 2, 3]);
     heap = heap.into_iter().filter(|x| x % 2 == 0).collect();
diff --git a/tests/ui/manual_retain.rs b/tests/ui/manual_retain.rs
index 34f0c4d5029..7fee4c95cea 100644
--- a/tests/ui/manual_retain.rs
+++ b/tests/ui/manual_retain.rs
@@ -23,8 +23,8 @@ fn main() {
 }
 
 fn binary_heap_retain() {
-    // NOTE: Do not lint now, because binary_heap_retain is nighyly API.
-    // And we need to add a test case for msrv if we update this implmention.
+    // NOTE: Do not lint now, because binary_heap_retain is nightly API.
+    // And we need to add a test case for msrv if we update this implementation.
     // https://github.com/rust-lang/rust/issues/71503
     let mut heap = BinaryHeap::from([1, 2, 3]);
     heap = heap.into_iter().filter(|x| x % 2 == 0).collect();
diff --git a/tests/ui/manual_while_let_some.fixed b/tests/ui/manual_while_let_some.fixed
new file mode 100644
index 00000000000..8b610919536
--- /dev/null
+++ b/tests/ui/manual_while_let_some.fixed
@@ -0,0 +1,93 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::manual_while_let_some)]
+
+struct VecInStruct {
+    numbers: Vec<i32>,
+    unrelated: String,
+}
+
+struct Foo {
+    a: i32,
+    b: i32,
+}
+
+fn accept_i32(_: i32) {}
+fn accept_optional_i32(_: Option<i32>) {}
+fn accept_i32_tuple(_: (i32, i32)) {}
+
+fn main() {
+    let mut numbers = vec![1, 2, 3, 4, 5];
+    while let Some(number) = numbers.pop() {
+        
+    }
+
+    let mut val = VecInStruct {
+        numbers: vec![1, 2, 3, 4, 5],
+        unrelated: String::new(),
+    };
+    while let Some(number) = val.numbers.pop() {
+        
+    }
+
+    while let Some(element) = numbers.pop() {
+        accept_i32(element);
+    }
+
+    while let Some(element) = numbers.pop() {
+        accept_i32(element);
+    }
+
+    // This should not warn. It "conditionally" pops elements.
+    while !numbers.is_empty() {
+        if true {
+            accept_i32(numbers.pop().unwrap());
+        }
+    }
+
+    // This should also not warn. It conditionally pops elements.
+    while !numbers.is_empty() {
+        if false {
+            continue;
+        }
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    // This should not warn. It pops elements, but does not unwrap it.
+    // Might handle the Option in some other arbitrary way.
+    while !numbers.is_empty() {
+        accept_optional_i32(numbers.pop());
+    }
+
+    let unrelated_vec: Vec<String> = Vec::new();
+    // This should not warn. It pops elements from a different vector.
+    while !unrelated_vec.is_empty() {
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    macro_rules! generate_loop {
+        () => {
+            while !numbers.is_empty() {
+                accept_i32(numbers.pop().unwrap());
+            }
+        };
+    }
+    // Do not warn if the loop comes from a macro.
+    generate_loop!();
+
+    // Try other kinds of patterns
+    let mut numbers = vec![(0, 0), (1, 1), (2, 2)];
+    while let Some((a, b)) = numbers.pop() {
+        
+    }
+
+    while let Some(element) = numbers.pop() {
+        accept_i32_tuple(element);
+    }
+
+    let mut results = vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }];
+    while let Some(Foo { a, b }) = results.pop() {
+        
+    }
+}
diff --git a/tests/ui/manual_while_let_some.rs b/tests/ui/manual_while_let_some.rs
new file mode 100644
index 00000000000..85a0a084a42
--- /dev/null
+++ b/tests/ui/manual_while_let_some.rs
@@ -0,0 +1,93 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::manual_while_let_some)]
+
+struct VecInStruct {
+    numbers: Vec<i32>,
+    unrelated: String,
+}
+
+struct Foo {
+    a: i32,
+    b: i32,
+}
+
+fn accept_i32(_: i32) {}
+fn accept_optional_i32(_: Option<i32>) {}
+fn accept_i32_tuple(_: (i32, i32)) {}
+
+fn main() {
+    let mut numbers = vec![1, 2, 3, 4, 5];
+    while !numbers.is_empty() {
+        let number = numbers.pop().unwrap();
+    }
+
+    let mut val = VecInStruct {
+        numbers: vec![1, 2, 3, 4, 5],
+        unrelated: String::new(),
+    };
+    while !val.numbers.is_empty() {
+        let number = val.numbers.pop().unwrap();
+    }
+
+    while !numbers.is_empty() {
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    while !numbers.is_empty() {
+        accept_i32(numbers.pop().expect(""));
+    }
+
+    // This should not warn. It "conditionally" pops elements.
+    while !numbers.is_empty() {
+        if true {
+            accept_i32(numbers.pop().unwrap());
+        }
+    }
+
+    // This should also not warn. It conditionally pops elements.
+    while !numbers.is_empty() {
+        if false {
+            continue;
+        }
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    // This should not warn. It pops elements, but does not unwrap it.
+    // Might handle the Option in some other arbitrary way.
+    while !numbers.is_empty() {
+        accept_optional_i32(numbers.pop());
+    }
+
+    let unrelated_vec: Vec<String> = Vec::new();
+    // This should not warn. It pops elements from a different vector.
+    while !unrelated_vec.is_empty() {
+        accept_i32(numbers.pop().unwrap());
+    }
+
+    macro_rules! generate_loop {
+        () => {
+            while !numbers.is_empty() {
+                accept_i32(numbers.pop().unwrap());
+            }
+        };
+    }
+    // Do not warn if the loop comes from a macro.
+    generate_loop!();
+
+    // Try other kinds of patterns
+    let mut numbers = vec![(0, 0), (1, 1), (2, 2)];
+    while !numbers.is_empty() {
+        let (a, b) = numbers.pop().unwrap();
+    }
+
+    while !numbers.is_empty() {
+        accept_i32_tuple(numbers.pop().unwrap());
+    }
+
+    let mut results = vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }];
+    while !results.is_empty() {
+        let Foo { a, b } = results.pop().unwrap();
+    }
+}
diff --git a/tests/ui/manual_while_let_some.stderr b/tests/ui/manual_while_let_some.stderr
new file mode 100644
index 00000000000..633fe05c49b
--- /dev/null
+++ b/tests/ui/manual_while_let_some.stderr
@@ -0,0 +1,87 @@
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:23:9
+   |
+LL |         let number = numbers.pop().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::manual-while-let-some` implied by `-D warnings`
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(number) = numbers.pop() {
+LL ~         
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:31:9
+   |
+LL |         let number = val.numbers.pop().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(number) = val.numbers.pop() {
+LL ~         
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:35:20
+   |
+LL |         accept_i32(numbers.pop().unwrap());
+   |                    ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(element) = numbers.pop() {
+LL ~         accept_i32(element);
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:39:20
+   |
+LL |         accept_i32(numbers.pop().expect(""));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(element) = numbers.pop() {
+LL ~         accept_i32(element);
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:82:9
+   |
+LL |         let (a, b) = numbers.pop().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some((a, b)) = numbers.pop() {
+LL ~         
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:86:26
+   |
+LL |         accept_i32_tuple(numbers.pop().unwrap());
+   |                          ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(element) = numbers.pop() {
+LL ~         accept_i32_tuple(element);
+   |
+
+error: you seem to be trying to pop elements from a `Vec` in a loop
+  --> $DIR/manual_while_let_some.rs:91:9
+   |
+LL |         let Foo { a, b } = results.pop().unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using a `while..let` loop
+   |
+LL ~     while let Some(Foo { a, b }) = results.pop() {
+LL ~         
+   |
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/needless_bool_assign.fixed b/tests/ui/needless_bool_assign.fixed
new file mode 100644
index 00000000000..3ed31d4d711
--- /dev/null
+++ b/tests/ui/needless_bool_assign.fixed
@@ -0,0 +1,33 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::needless_bool_assign)]
+
+fn random() -> bool {
+    true
+}
+
+fn main() {
+    struct Data {
+        field: bool,
+    };
+    let mut a = Data { field: false };
+    a.field = random() && random();
+    a.field = !(random() && random());
+    // Do not lint…
+    if random() {
+        a.field = false;
+    } else {
+        // …to avoid losing this comment
+        a.field = true
+    }
+    // This one also triggers lint `clippy::if_same_then_else`
+    // which does not suggest a rewrite.
+    random(); a.field = true;
+    let mut b = false;
+    if random() {
+        a.field = false;
+    } else {
+        b = true;
+    }
+}
diff --git a/tests/ui/needless_bool_assign.rs b/tests/ui/needless_bool_assign.rs
new file mode 100644
index 00000000000..efaeb67fa45
--- /dev/null
+++ b/tests/ui/needless_bool_assign.rs
@@ -0,0 +1,45 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::needless_bool_assign)]
+
+fn random() -> bool {
+    true
+}
+
+fn main() {
+    struct Data {
+        field: bool,
+    };
+    let mut a = Data { field: false };
+    if random() && random() {
+        a.field = true;
+    } else {
+        a.field = false
+    }
+    if random() && random() {
+        a.field = false;
+    } else {
+        a.field = true
+    }
+    // Do not lint…
+    if random() {
+        a.field = false;
+    } else {
+        // …to avoid losing this comment
+        a.field = true
+    }
+    // This one also triggers lint `clippy::if_same_then_else`
+    // which does not suggest a rewrite.
+    if random() {
+        a.field = true;
+    } else {
+        a.field = true;
+    }
+    let mut b = false;
+    if random() {
+        a.field = false;
+    } else {
+        b = true;
+    }
+}
diff --git a/tests/ui/needless_bool_assign.stderr b/tests/ui/needless_bool_assign.stderr
new file mode 100644
index 00000000000..601bbed5493
--- /dev/null
+++ b/tests/ui/needless_bool_assign.stderr
@@ -0,0 +1,53 @@
+error: this if-then-else expression assigns a bool literal
+  --> $DIR/needless_bool_assign.rs:15:5
+   |
+LL | /     if random() && random() {
+LL | |         a.field = true;
+LL | |     } else {
+LL | |         a.field = false
+LL | |     }
+   | |_____^ help: you can reduce it to: `a.field = random() && random();`
+   |
+   = note: `-D clippy::needless-bool-assign` implied by `-D warnings`
+
+error: this if-then-else expression assigns a bool literal
+  --> $DIR/needless_bool_assign.rs:20:5
+   |
+LL | /     if random() && random() {
+LL | |         a.field = false;
+LL | |     } else {
+LL | |         a.field = true
+LL | |     }
+   | |_____^ help: you can reduce it to: `a.field = !(random() && random());`
+
+error: this if-then-else expression assigns a bool literal
+  --> $DIR/needless_bool_assign.rs:34:5
+   |
+LL | /     if random() {
+LL | |         a.field = true;
+LL | |     } else {
+LL | |         a.field = true;
+LL | |     }
+   | |_____^ help: you can reduce it to: `random(); a.field = true;`
+
+error: this `if` has identical blocks
+  --> $DIR/needless_bool_assign.rs:34:17
+   |
+LL |       if random() {
+   |  _________________^
+LL | |         a.field = true;
+LL | |     } else {
+   | |_____^
+   |
+note: same as this
+  --> $DIR/needless_bool_assign.rs:36:12
+   |
+LL |       } else {
+   |  ____________^
+LL | |         a.field = true;
+LL | |     }
+   | |_____^
+   = note: `#[deny(clippy::if_same_then_else)]` on by default
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/needless_for_each_fixable.fixed b/tests/ui/needless_for_each_fixable.fixed
index a04f9ec651e..92572942bc0 100644
--- a/tests/ui/needless_for_each_fixable.fixed
+++ b/tests/ui/needless_for_each_fixable.fixed
@@ -110,7 +110,7 @@ fn should_not_lint() {
         }),
     }
 
-    // `for_each` is in a let bingind.
+    // `for_each` is in a let binding.
     let _ = v.iter().for_each(|elem| {
         acc += elem;
     });
diff --git a/tests/ui/needless_for_each_fixable.rs b/tests/ui/needless_for_each_fixable.rs
index 4975c705081..95acbdff8cc 100644
--- a/tests/ui/needless_for_each_fixable.rs
+++ b/tests/ui/needless_for_each_fixable.rs
@@ -110,7 +110,7 @@ fn should_not_lint() {
         }),
     }
 
-    // `for_each` is in a let bingind.
+    // `for_each` is in a let binding.
     let _ = v.iter().for_each(|elem| {
         acc += elem;
     });
diff --git a/tests/ui/no_mangle_with_rust_abi.rs b/tests/ui/no_mangle_with_rust_abi.rs
index b32e721110e..818119f7be5 100644
--- a/tests/ui/no_mangle_with_rust_abi.rs
+++ b/tests/ui/no_mangle_with_rust_abi.rs
@@ -25,7 +25,7 @@ fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lin
     0
 }
 
-// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"`
+// Must not run on functions that explicitly opt in to using the Rust ABI with `extern "Rust"`
 #[no_mangle]
 #[rustfmt::skip]
 extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {}
diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed
index 9aebcf47100..57f341e0276 100644
--- a/tests/ui/option_if_let_else.fixed
+++ b/tests/ui/option_if_let_else.fixed
@@ -97,7 +97,7 @@ enum DummyEnum {
     Two,
 }
 
-// should not warn since there is a compled complex subpat
+// should not warn since there is a complex subpat
 // see #7991
 fn complex_subpat() -> DummyEnum {
     let x = Some(DummyEnum::One(1));
diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs
index b40b324902a..19f9f704517 100644
--- a/tests/ui/option_if_let_else.rs
+++ b/tests/ui/option_if_let_else.rs
@@ -120,7 +120,7 @@ enum DummyEnum {
     Two,
 }
 
-// should not warn since there is a compled complex subpat
+// should not warn since there is a complex subpat
 // see #7991
 fn complex_subpat() -> DummyEnum {
     let x = Some(DummyEnum::One(1));
diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed
index 87100b97288..d62f7d26a35 100644
--- a/tests/ui/redundant_pattern_matching_option.fixed
+++ b/tests/ui/redundant_pattern_matching_option.fixed
@@ -54,6 +54,8 @@ fn main() {
     } else {
         3
     };
+
+    if gen_opt().is_some() {}
 }
 
 fn gen_opt() -> Option<()> {
diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs
index 0b69e13f655..d6429426573 100644
--- a/tests/ui/redundant_pattern_matching_option.rs
+++ b/tests/ui/redundant_pattern_matching_option.rs
@@ -63,6 +63,8 @@ fn main() {
     } else {
         3
     };
+
+    if let Some(..) = gen_opt() {}
 }
 
 fn gen_opt() -> Option<()> {
diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr
index 27ff812ba45..7c5a047e455 100644
--- a/tests/ui/redundant_pattern_matching_option.stderr
+++ b/tests/ui/redundant_pattern_matching_option.stderr
@@ -89,31 +89,37 @@ LL |     } else if let None = gen_opt() {
    |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:80:12
+  --> $DIR/redundant_pattern_matching_option.rs:67:12
+   |
+LL |     if let Some(..) = gen_opt() {}
+   |     -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:82:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:82:12
+  --> $DIR/redundant_pattern_matching_option.rs:84:12
    |
 LL |     if let None = None::<()> {}
    |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:84:15
+  --> $DIR/redundant_pattern_matching_option.rs:86:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:86:15
+  --> $DIR/redundant_pattern_matching_option.rs:88:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:88:5
+  --> $DIR/redundant_pattern_matching_option.rs:90:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -122,7 +128,7 @@ LL | |     };
    | |_____^ help: try this: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:93:5
+  --> $DIR/redundant_pattern_matching_option.rs:95:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -131,16 +137,16 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:101:12
+  --> $DIR/redundant_pattern_matching_option.rs:103:12
    |
 LL |     if let None = *(&None::<()>) {}
    |     -------^^^^----------------- help: try this: `if (&None::<()>).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:102:12
+  --> $DIR/redundant_pattern_matching_option.rs:104:12
    |
 LL |     if let None = *&None::<()> {}
    |     -------^^^^--------------- help: try this: `if (&None::<()>).is_none()`
 
-error: aborting due to 21 previous errors
+error: aborting due to 22 previous errors
 
diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed
index ff19a042825..42a59f6d43d 100644
--- a/tests/ui/rename.fixed
+++ b/tests/ui/rename.fixed
@@ -27,6 +27,7 @@
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::invisible_characters)]
+#![allow(suspicious_double_ref_op)]
 #![allow(drop_bounds)]
 #![allow(for_loops_over_fallibles)]
 #![allow(array_into_iter)]
diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs
index 38b1647c0cc..4d173e8cbbf 100644
--- a/tests/ui/rename.rs
+++ b/tests/ui/rename.rs
@@ -27,6 +27,7 @@
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
 #![allow(clippy::invisible_characters)]
+#![allow(suspicious_double_ref_op)]
 #![allow(drop_bounds)]
 #![allow(for_loops_over_fallibles)]
 #![allow(array_into_iter)]
diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr
index 70d15408b9f..0da4ed7520c 100644
--- a/tests/ui/rename.stderr
+++ b/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:43:9
+  --> $DIR/rename.rs:44:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,253 +7,253 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:44:9
+  --> $DIR/rename.rs:45:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:45:9
+  --> $DIR/rename.rs:46:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:46:9
+  --> $DIR/rename.rs:47:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:47:9
+  --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:48:9
+  --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> $DIR/rename.rs:50:9
+  --> $DIR/rename.rs:51:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:53:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:78:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:80:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:80:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:81:9
+  --> $DIR/rename.rs:82:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:83:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:83:9
+  --> $DIR/rename.rs:84:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:84:9
+  --> $DIR/rename.rs:85:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:85:9
+  --> $DIR/rename.rs:86:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
diff --git a/tests/ui/same_name_method.rs b/tests/ui/same_name_method.rs
index daef95a425c..f31a7e33c4b 100644
--- a/tests/ui/same_name_method.rs
+++ b/tests/ui/same_name_method.rs
@@ -62,7 +62,7 @@ mod should_lint {
         impl T1 for S {}
     }
 
-    mod multiply_conflicit_trait {
+    mod multiple_conflicting_traits {
         use crate::{T1, T2};
 
         struct S;
diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs
index 03337ec3564..2c0fc3e3fd8 100644
--- a/tests/ui/shadow.rs
+++ b/tests/ui/shadow.rs
@@ -8,6 +8,12 @@ extern crate proc_macro_derive;
 #[derive(proc_macro_derive::ShadowDerive)]
 pub struct Nothing;
 
+macro_rules! reuse {
+    ($v:ident) => {
+        let $v = $v + 1;
+    };
+}
+
 fn shadow_same() {
     let x = 1;
     let x = x;
@@ -33,6 +39,12 @@ fn shadow_reuse() -> Option<()> {
     None
 }
 
+fn shadow_reuse_macro() {
+    let x = 1;
+    // this should not warn
+    reuse!(x);
+}
+
 fn shadow_unrelated() {
     let x = 1;
     let x = 2;
diff --git a/tests/ui/shadow.stderr b/tests/ui/shadow.stderr
index 92bb937d086..8321f6df224 100644
--- a/tests/ui/shadow.stderr
+++ b/tests/ui/shadow.stderr
@@ -1,278 +1,278 @@
 error: `x` is shadowed by itself in `x`
-  --> $DIR/shadow.rs:13:9
+  --> $DIR/shadow.rs:19:9
    |
 LL |     let x = x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:12:9
+  --> $DIR/shadow.rs:18:9
    |
 LL |     let x = 1;
    |         ^
    = note: `-D clippy::shadow-same` implied by `-D warnings`
 
 error: `mut x` is shadowed by itself in `&x`
-  --> $DIR/shadow.rs:14:13
+  --> $DIR/shadow.rs:20:13
    |
 LL |     let mut x = &x;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:13:9
+  --> $DIR/shadow.rs:19:9
    |
 LL |     let x = x;
    |         ^
 
 error: `x` is shadowed by itself in `&mut x`
-  --> $DIR/shadow.rs:15:9
+  --> $DIR/shadow.rs:21:9
    |
 LL |     let x = &mut x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:14:9
+  --> $DIR/shadow.rs:20:9
    |
 LL |     let mut x = &x;
    |         ^^^^^
 
 error: `x` is shadowed by itself in `*x`
-  --> $DIR/shadow.rs:16:9
+  --> $DIR/shadow.rs:22:9
    |
 LL |     let x = *x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:15:9
+  --> $DIR/shadow.rs:21:9
    |
 LL |     let x = &mut x;
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:27:9
    |
 LL |     let x = x.0;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:20:9
+  --> $DIR/shadow.rs:26:9
    |
 LL |     let x = ([[0]], ());
    |         ^
    = note: `-D clippy::shadow-reuse` implied by `-D warnings`
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:22:9
+  --> $DIR/shadow.rs:28:9
    |
 LL |     let x = x[0];
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:27:9
    |
 LL |     let x = x.0;
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:23:10
+  --> $DIR/shadow.rs:29:10
    |
 LL |     let [x] = x;
    |          ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:22:9
+  --> $DIR/shadow.rs:28:9
    |
 LL |     let x = x[0];
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:24:9
+  --> $DIR/shadow.rs:30:9
    |
 LL |     let x = Some(x);
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:23:10
+  --> $DIR/shadow.rs:29:10
    |
 LL |     let [x] = x;
    |          ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:25:9
+  --> $DIR/shadow.rs:31:9
    |
 LL |     let x = foo(x);
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:24:9
+  --> $DIR/shadow.rs:30:9
    |
 LL |     let x = Some(x);
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:26:9
+  --> $DIR/shadow.rs:32:9
    |
 LL |     let x = || x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:25:9
+  --> $DIR/shadow.rs:31:9
    |
 LL |     let x = foo(x);
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:27:9
+  --> $DIR/shadow.rs:33:9
    |
 LL |     let x = Some(1).map(|_| x)?;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:26:9
+  --> $DIR/shadow.rs:32:9
    |
 LL |     let x = || x;
    |         ^
 
 error: `y` is shadowed
-  --> $DIR/shadow.rs:29:9
+  --> $DIR/shadow.rs:35:9
    |
 LL |     let y = match y {
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:28:9
+  --> $DIR/shadow.rs:34:9
    |
 LL |     let y = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:38:9
+  --> $DIR/shadow.rs:50:9
    |
 LL |     let x = 2;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:37:9
+  --> $DIR/shadow.rs:49:9
    |
 LL |     let x = 1;
    |         ^
    = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:43:13
+  --> $DIR/shadow.rs:55:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:42:10
+  --> $DIR/shadow.rs:54:10
    |
 LL |     fn f(x: u32) {
    |          ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:48:14
+  --> $DIR/shadow.rs:60:14
    |
 LL |         Some(x) => {
    |              ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:45:9
+  --> $DIR/shadow.rs:57:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:49:17
+  --> $DIR/shadow.rs:61:17
    |
 LL |             let x = 1;
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:48:14
+  --> $DIR/shadow.rs:60:14
    |
 LL |         Some(x) => {
    |              ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:53:17
+  --> $DIR/shadow.rs:65:17
    |
 LL |     if let Some(x) = Some(1) {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:45:9
+  --> $DIR/shadow.rs:57:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:54:20
+  --> $DIR/shadow.rs:66:20
    |
 LL |     while let Some(x) = Some(1) {}
    |                    ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:45:9
+  --> $DIR/shadow.rs:57:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:55:15
+  --> $DIR/shadow.rs:67:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:45:9
+  --> $DIR/shadow.rs:57:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:56:13
+  --> $DIR/shadow.rs:68:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:55:15
+  --> $DIR/shadow.rs:67:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
 
 error: `y` is shadowed
-  --> $DIR/shadow.rs:59:17
+  --> $DIR/shadow.rs:71:17
    |
 LL |     if let Some(y) = y {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:58:9
+  --> $DIR/shadow.rs:70:9
    |
 LL |     let y = Some(1);
    |         ^
 
 error: `_b` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:95:9
+  --> $DIR/shadow.rs:107:9
    |
 LL |     let _b = _a;
    |         ^^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:94:28
+  --> $DIR/shadow.rs:106:28
    |
 LL | pub async fn foo2(_a: i32, _b: i64) {
    |                            ^^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:101:21
+  --> $DIR/shadow.rs:113:21
    |
 LL |         if let Some(x) = Some(1) { x } else { 1 }
    |                     ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:100:13
+  --> $DIR/shadow.rs:112:13
    |
 LL |         let x = 1;
    |             ^
diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed
index 058f2aa54da..3fc11b8b088 100644
--- a/tests/ui/string_lit_as_bytes.fixed
+++ b/tests/ui/string_lit_as_bytes.fixed
@@ -1,8 +1,18 @@
 //@run-rustfix
+//@aux-build:macro_rules.rs
 
 #![allow(dead_code, unused_variables)]
 #![warn(clippy::string_lit_as_bytes)]
 
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! b {
+    ($b:literal) => {
+        const B: &[u8] = b"warning";
+    };
+}
+
 fn str_lit_as_bytes() {
     let bs = b"hello there";
 
@@ -11,6 +21,10 @@ fn str_lit_as_bytes() {
     let bs = b"lit to string".to_vec();
     let bs = b"lit to owned".to_vec();
 
+    b!("warning");
+
+    string_lit_as_bytes!("no warning");
+
     // no warning, because these cannot be written as byte string literals:
     let ubs = "☃".as_bytes();
     let ubs = "hello there! this is a very long string".as_bytes();
diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs
index b550bea001f..7d54acf630e 100644
--- a/tests/ui/string_lit_as_bytes.rs
+++ b/tests/ui/string_lit_as_bytes.rs
@@ -1,8 +1,18 @@
 //@run-rustfix
+//@aux-build:macro_rules.rs
 
 #![allow(dead_code, unused_variables)]
 #![warn(clippy::string_lit_as_bytes)]
 
+#[macro_use]
+extern crate macro_rules;
+
+macro_rules! b {
+    ($b:literal) => {
+        const B: &[u8] = $b.as_bytes();
+    };
+}
+
 fn str_lit_as_bytes() {
     let bs = "hello there".as_bytes();
 
@@ -11,6 +21,10 @@ fn str_lit_as_bytes() {
     let bs = "lit to string".to_string().into_bytes();
     let bs = "lit to owned".to_owned().into_bytes();
 
+    b!("warning");
+
+    string_lit_as_bytes!("no warning");
+
     // no warning, because these cannot be written as byte string literals:
     let ubs = "☃".as_bytes();
     let ubs = "hello there! this is a very long string".as_bytes();
diff --git a/tests/ui/string_lit_as_bytes.stderr b/tests/ui/string_lit_as_bytes.stderr
index f47d6161c6c..61b4e210e0f 100644
--- a/tests/ui/string_lit_as_bytes.stderr
+++ b/tests/ui/string_lit_as_bytes.stderr
@@ -1,5 +1,5 @@
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:7:14
+  --> $DIR/string_lit_as_bytes.rs:17:14
    |
 LL |     let bs = "hello there".as_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"`
@@ -7,34 +7,45 @@ LL |     let bs = "hello there".as_bytes();
    = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings`
 
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:9:14
+  --> $DIR/string_lit_as_bytes.rs:19:14
    |
 LL |     let bs = r###"raw string with 3# plus " ""###.as_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with 3# plus " ""###`
 
 error: calling `into_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:11:14
+  --> $DIR/string_lit_as_bytes.rs:21:14
    |
 LL |     let bs = "lit to string".to_string().into_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to string".to_vec()`
 
 error: calling `into_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:12:14
+  --> $DIR/string_lit_as_bytes.rs:22:14
    |
 LL |     let bs = "lit to owned".to_owned().into_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to owned".to_vec()`
 
+error: calling `as_bytes()` on a string literal
+  --> $DIR/string_lit_as_bytes.rs:12:26
+   |
+LL |         const B: &[u8] = $b.as_bytes();
+   |                          ^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"warning"`
+...
+LL |     b!("warning");
+   |     ------------- in this macro invocation
+   |
+   = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error: calling `as_bytes()` on `include_str!(..)`
-  --> $DIR/string_lit_as_bytes.rs:25:22
+  --> $DIR/string_lit_as_bytes.rs:39:22
    |
 LL |     let includestr = include_str!("string_lit_as_bytes.rs").as_bytes();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("string_lit_as_bytes.rs")`
 
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:27:13
+  --> $DIR/string_lit_as_bytes.rs:41:13
    |
 LL |     let _ = "string with newline/t/n".as_bytes();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline/t/n"`
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/trailing_empty_array.rs b/tests/ui/trailing_empty_array.rs
index 8e3749eef35..928475b5f35 100644
--- a/tests/ui/trailing_empty_array.rs
+++ b/tests/ui/trailing_empty_array.rs
@@ -144,7 +144,7 @@ struct ReprCAlign {
 
 // NOTE: because of https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-representation-of-enums-with-fields and I'm not sure when in the compilation pipeline that would happen
 #[repr(C)]
-enum DontLintAnonymousStructsFromDesuraging {
+enum DontLintAnonymousStructsFromDesugaring {
     A(u32),
     B(f32, [u64; 0]),
     C { x: u32, y: [u64; 0] },
diff --git a/tests/ui/uninit.rs b/tests/ui/uninit.rs
index c996de89422..2d567630e15 100644
--- a/tests/ui/uninit.rs
+++ b/tests/ui/uninit.rs
@@ -17,10 +17,10 @@ fn main() {
     // This is OK, because `MaybeUninit` allows uninitialized data.
     let _: MaybeUninit<usize> = unsafe { MaybeUninit::uninit().assume_init() };
 
-    // This is OK, because all constitutent types are uninit-compatible.
+    // This is OK, because all constituent types are uninit-compatible.
     let _: (MaybeUninit<usize>, MaybeUninit<bool>) = unsafe { MaybeUninit::uninit().assume_init() };
 
-    // This is OK, because all constitutent types are uninit-compatible.
+    // This is OK, because all constituent types are uninit-compatible.
     let _: (MaybeUninit<usize>, [MaybeUninit<bool>; 2]) = unsafe { MaybeUninit::uninit().assume_init() };
 
     // This is OK, because our own MaybeUninit is just as fine as the one from core.
diff --git a/tests/ui/use_self_trait.fixed b/tests/ui/use_self_trait.fixed
index 4623aeeb0eb..20138a29fd1 100644
--- a/tests/ui/use_self_trait.fixed
+++ b/tests/ui/use_self_trait.fixed
@@ -33,7 +33,7 @@ impl SelfTrait for Bad {
     fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
 
     fn vals(_: Self) -> Self {
-        Self::default()
+        Self
     }
 }
 
@@ -70,7 +70,7 @@ impl SelfTrait for Good {
     fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
 
     fn vals(_: Self) -> Self {
-        Self::default()
+        Self
     }
 }
 
diff --git a/tests/ui/use_self_trait.rs b/tests/ui/use_self_trait.rs
index d7d76dd9623..bf697b01a42 100644
--- a/tests/ui/use_self_trait.rs
+++ b/tests/ui/use_self_trait.rs
@@ -33,7 +33,7 @@ impl SelfTrait for Bad {
     fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {}
 
     fn vals(_: Bad) -> Bad {
-        Bad::default()
+        Bad
     }
 }
 
@@ -70,7 +70,7 @@ impl SelfTrait for Good {
     fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {}
 
     fn vals(_: Self) -> Self {
-        Self::default()
+        Self
     }
 }
 
diff --git a/tests/ui/use_self_trait.stderr b/tests/ui/use_self_trait.stderr
index 090729b9c3d..6257f802dd8 100644
--- a/tests/ui/use_self_trait.stderr
+++ b/tests/ui/use_self_trait.stderr
@@ -63,7 +63,7 @@ LL |     fn vals(_: Bad) -> Bad {
 error: unnecessary structure name repetition
   --> $DIR/use_self_trait.rs:36:9
    |
-LL |         Bad::default()
+LL |         Bad
    |         ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
diff --git a/util/gh-pages/index.html b/util/gh-pages/index.html
index e46ad2c6e0e..8791debad72 100644
--- a/util/gh-pages/index.html
+++ b/util/gh-pages/index.html
@@ -564,7 +564,7 @@ Otherwise, have a great day =^.^=
     </div>
 
     <a href="https://github.com/rust-lang/rust-clippy">
-        <img style="position: absolute; top: 0; right: 0; border: 0; clip-path: polygon(0% 0%, 100% 0%, 100% 100%);" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on Github"/>
+        <img style="position: absolute; top: 0; right: 0; border: 0; clip-path: polygon(0% 0%, 100% 0%, 100% 100%);" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"/>
     </a>
 
     <script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/12.3.2/markdown-it.min.js"></script>

From 68eb864c91a1937859fb5c2c6e96850c3443268c Mon Sep 17 00:00:00 2001
From: Alex Macleod <alex@macleod.io>
Date: Fri, 5 May 2023 18:30:41 +0000
Subject: [PATCH 20/78] Ignore expressions from macros in
 default_constructed_unit_structs

---
 .../src/default_constructed_unit_structs.rs    |  5 +++--
 .../ui/default_constructed_unit_structs.fixed  | 18 ++++++++++++++++++
 tests/ui/default_constructed_unit_structs.rs   | 18 ++++++++++++++++++
 .../ui/default_constructed_unit_structs.stderr | 10 ++++++++--
 4 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs
index e529d81a7e9..9bd7a0dc0f3 100644
--- a/clippy_lints/src/default_constructed_unit_structs.rs
+++ b/clippy_lints/src/default_constructed_unit_structs.rs
@@ -1,4 +1,4 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro, match_def_path, paths};
+use clippy_utils::{diagnostics::span_lint_and_sugg, match_def_path, paths};
 use hir::{def::Res, ExprKind};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -55,7 +55,8 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs {
             if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind();
             if def.is_struct();
             if let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant();
-            if !var.is_field_list_non_exhaustive() && !is_from_proc_macro(cx, expr);
+            if !var.is_field_list_non_exhaustive();
+            if !expr.span.from_expansion() && !qpath.span().from_expansion();
             then {
                 span_lint_and_sugg(
                     cx,
diff --git a/tests/ui/default_constructed_unit_structs.fixed b/tests/ui/default_constructed_unit_structs.fixed
index 4c2d1ea48e1..e1012f38bba 100644
--- a/tests/ui/default_constructed_unit_structs.fixed
+++ b/tests/ui/default_constructed_unit_structs.fixed
@@ -105,6 +105,7 @@ fn main() {
     // should lint
     let _ = PhantomData::<usize>;
     let _: PhantomData<i32> = PhantomData;
+    let _: PhantomData<i32> = std::marker::PhantomData;
     let _ = UnitStruct;
 
     // should not lint
@@ -116,4 +117,21 @@ fn main() {
     let _ = EmptyStruct::default();
     let _ = FakeDefault::default();
     let _ = <FakeDefault as Default>::default();
+
+    macro_rules! in_macro {
+        ($i:ident) => {{
+            let _ = UnitStruct::default();
+            let _ = $i::default();
+        }};
+    }
+
+    in_macro!(UnitStruct);
+
+    macro_rules! struct_from_macro {
+        () => {
+            UnitStruct
+        };
+    }
+
+    let _ = <struct_from_macro!()>::default();
 }
diff --git a/tests/ui/default_constructed_unit_structs.rs b/tests/ui/default_constructed_unit_structs.rs
index 850793dd5de..c7b4313dbf0 100644
--- a/tests/ui/default_constructed_unit_structs.rs
+++ b/tests/ui/default_constructed_unit_structs.rs
@@ -105,6 +105,7 @@ fn main() {
     // should lint
     let _ = PhantomData::<usize>::default();
     let _: PhantomData<i32> = PhantomData::default();
+    let _: PhantomData<i32> = std::marker::PhantomData::default();
     let _ = UnitStruct::default();
 
     // should not lint
@@ -116,4 +117,21 @@ fn main() {
     let _ = EmptyStruct::default();
     let _ = FakeDefault::default();
     let _ = <FakeDefault as Default>::default();
+
+    macro_rules! in_macro {
+        ($i:ident) => {{
+            let _ = UnitStruct::default();
+            let _ = $i::default();
+        }};
+    }
+
+    in_macro!(UnitStruct);
+
+    macro_rules! struct_from_macro {
+        () => {
+            UnitStruct
+        };
+    }
+
+    let _ = <struct_from_macro!()>::default();
 }
diff --git a/tests/ui/default_constructed_unit_structs.stderr b/tests/ui/default_constructed_unit_structs.stderr
index 4058943d087..61a32fb10e5 100644
--- a/tests/ui/default_constructed_unit_structs.stderr
+++ b/tests/ui/default_constructed_unit_structs.stderr
@@ -25,10 +25,16 @@ LL |     let _: PhantomData<i32> = PhantomData::default();
    |                                          ^^^^^^^^^^^ help: remove this call to `default`
 
 error: use of `default` to create a unit struct
-  --> $DIR/default_constructed_unit_structs.rs:108:23
+  --> $DIR/default_constructed_unit_structs.rs:108:55
+   |
+LL |     let _: PhantomData<i32> = std::marker::PhantomData::default();
+   |                                                       ^^^^^^^^^^^ help: remove this call to `default`
+
+error: use of `default` to create a unit struct
+  --> $DIR/default_constructed_unit_structs.rs:109:23
    |
 LL |     let _ = UnitStruct::default();
    |                       ^^^^^^^^^^^ help: remove this call to `default`
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 

From afa2741e6a51f94ec408b78bb7589fa0a0534a3c Mon Sep 17 00:00:00 2001
From: disco07 <koneenok@outlook.fr>
Date: Fri, 5 May 2023 21:33:16 +0200
Subject: [PATCH 21/78] redundant_pattern_matching

---
 .../src/matches/redundant_pattern_match.rs    | 91 +++++++++++++++++-
 .../redundant_pattern_matching_option.fixed   | 19 ++++
 tests/ui/redundant_pattern_matching_option.rs | 43 +++++++++
 .../redundant_pattern_matching_option.stderr  | 96 ++++++++++++++++---
 .../redundant_pattern_matching_result.fixed   | 11 +++
 tests/ui/redundant_pattern_matching_result.rs | 23 +++++
 .../redundant_pattern_matching_result.stderr  | 62 +++++++++---
 7 files changed, 319 insertions(+), 26 deletions(-)

diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index af121f317cd..9656049feeb 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -186,9 +186,9 @@ fn find_sugg_for_if_let<'tcx>(
 }
 
 pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
+    //eprintln!("{:#?}", expr);
     if arms.len() == 2 {
         let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
-
         let found_good_method = match node_pair {
             (
                 PatKind::TupleStruct(ref path_left, patterns_left, _),
@@ -252,6 +252,68 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
                     None
                 }
             },
+            (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Wild) if patterns.len() == 1 => {
+                if let PatKind::Wild = patterns[0].kind {
+                    let ident = match path_left {
+                        QPath::Resolved(_, path) => {
+                            let name = path.segments[0].ident;
+                            Some(name)
+                        },
+                        _ => None,
+                    };
+                    if let Some(name) = ident {
+                        match name.as_str() {
+                            "Ok" => find_good_method_for_matches_macro(
+                                cx,
+                                arms,
+                                path_left,
+                                Item::Lang(ResultOk),
+                                "is_ok()",
+                                "is_err()",
+                            ),
+                            "Some" => find_good_method_for_matches_macro(
+                                cx,
+                                arms,
+                                path_left,
+                                Item::Lang(OptionSome),
+                                "is_some()",
+                                "is_none()",
+                            ),
+                            _ => None,
+                        }
+                    } else {
+                        None
+                    }
+                } else {
+                    None
+                }
+            },
+            (PatKind::Path(ref path_left), PatKind::Wild) => {
+                let ident = match path_left {
+                    QPath::Resolved(_, path) => {
+                        let name = path.segments[0].ident;
+                        Some(name)
+                    },
+                    _ => None,
+                };
+
+                if let Some(name) = ident {
+                    match name.as_str() {
+                        "None" => find_good_method_for_matches_macro(
+                            cx,
+                            arms,
+                            path_left,
+                            Item::Lang(OptionNone),
+                            "is_none()",
+                            "is_some()",
+                        ),
+                        _ => None,
+                    }
+                } else {
+                    None
+                }
+                
+            }
             _ => None,
         };
 
@@ -345,3 +407,30 @@ fn find_good_method_for_match<'a>(
         _ => None,
     }
 }
+
+#[expect(clippy::too_many_arguments)]
+fn find_good_method_for_matches_macro<'a>(
+    cx: &LateContext<'_>,
+    arms: &[Arm<'_>],
+    path_left: &QPath<'_>,
+    expected_item_left: Item,
+    should_be_left: &'a str,
+    should_be_right: &'a str,
+) -> Option<&'a str> {
+    let first_pat = arms[0].pat;
+
+    let body_node_pair = if is_pat_variant(cx, first_pat, path_left, expected_item_left) {
+        (&arms[0].body.kind, &arms[1].body.kind)
+    } else {
+        return None;
+    };
+
+    match body_node_pair {
+        (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) {
+            (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
+            (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+            _ => None,
+        },
+        _ => None,
+    }
+}
diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed
index d62f7d26a35..c22a4d7456e 100644
--- a/tests/ui/redundant_pattern_matching_option.fixed
+++ b/tests/ui/redundant_pattern_matching_option.fixed
@@ -46,6 +46,7 @@ fn main() {
     let _ = if opt.is_some() { true } else { false };
 
     issue6067();
+    issue10726();
 
     let _ = if gen_opt().is_some() {
         1
@@ -88,3 +89,21 @@ fn issue7921() {
     if (&None::<()>).is_none() {}
     if (&None::<()>).is_none() {}
 }
+
+fn issue10726() {
+    Some(42).is_some();
+
+    Some(42).is_none();
+
+    Some(42).is_none();
+
+    Some(42).is_some();
+
+    None::<()>.is_none();
+
+    None::<()>.is_none();
+
+    None::<()>.is_none();
+
+    None::<()>.is_some();
+}
diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs
index d6429426573..cd96e0d29a5 100644
--- a/tests/ui/redundant_pattern_matching_option.rs
+++ b/tests/ui/redundant_pattern_matching_option.rs
@@ -55,6 +55,7 @@ fn main() {
     let _ = if let Some(_) = opt { true } else { false };
 
     issue6067();
+    issue10726();
 
     let _ = if let Some(_) = gen_opt() {
         1
@@ -103,3 +104,45 @@ fn issue7921() {
     if let None = *(&None::<()>) {}
     if let None = *&None::<()> {}
 }
+
+fn issue10726() {
+    match Some(42) {
+        Some(_) => true,
+        _ => false,
+    };
+
+    match Some(42) {
+        Some(_) => false,
+        _ => true,
+    };
+
+    match Some(42) {
+        None => true,
+        _ => false,
+    };
+
+    match Some(42) {
+        None => false,
+        _ => true,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        _ => true,
+    };
+
+    match None::<()> {
+        Some(_) => false,
+        _ => true,
+    };
+
+    match None::<()> {
+        None => true,
+        _ => false,
+    };
+
+    match None::<()> {
+        None => false,
+        _ => true,
+    };
+}
diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr
index 7c5a047e455..d397297074b 100644
--- a/tests/ui/redundant_pattern_matching_option.stderr
+++ b/tests/ui/redundant_pattern_matching_option.stderr
@@ -77,49 +77,49 @@ LL |     let _ = if let Some(_) = opt { true } else { false };
    |             -------^^^^^^^------ help: try this: `if opt.is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:59:20
+  --> $DIR/redundant_pattern_matching_option.rs:60:20
    |
 LL |     let _ = if let Some(_) = gen_opt() {
    |             -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:61:19
+  --> $DIR/redundant_pattern_matching_option.rs:62:19
    |
 LL |     } else if let None = gen_opt() {
    |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:67:12
+  --> $DIR/redundant_pattern_matching_option.rs:68:12
    |
 LL |     if let Some(..) = gen_opt() {}
    |     -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:82:12
+  --> $DIR/redundant_pattern_matching_option.rs:83:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:84:12
+  --> $DIR/redundant_pattern_matching_option.rs:85:12
    |
 LL |     if let None = None::<()> {}
    |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:86:15
+  --> $DIR/redundant_pattern_matching_option.rs:87:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:88:15
+  --> $DIR/redundant_pattern_matching_option.rs:89:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:90:5
+  --> $DIR/redundant_pattern_matching_option.rs:91:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -128,7 +128,7 @@ LL | |     };
    | |_____^ help: try this: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:95:5
+  --> $DIR/redundant_pattern_matching_option.rs:96:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -137,16 +137,88 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:103:12
+  --> $DIR/redundant_pattern_matching_option.rs:104:12
    |
 LL |     if let None = *(&None::<()>) {}
    |     -------^^^^----------------- help: try this: `if (&None::<()>).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:104:12
+  --> $DIR/redundant_pattern_matching_option.rs:105:12
    |
 LL |     if let None = *&None::<()> {}
    |     -------^^^^--------------- help: try this: `if (&None::<()>).is_none()`
 
-error: aborting due to 22 previous errors
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:109:5
+   |
+LL | /     match Some(42) {
+LL | |         Some(_) => true,
+LL | |         _ => false,
+LL | |     };
+   | |_____^ help: try this: `Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:114:5
+   |
+LL | /     match Some(42) {
+LL | |         Some(_) => false,
+LL | |         _ => true,
+LL | |     };
+   | |_____^ help: try this: `Some(42).is_none()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:119:5
+   |
+LL | /     match Some(42) {
+LL | |         None => true,
+LL | |         _ => false,
+LL | |     };
+   | |_____^ help: try this: `Some(42).is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:124:5
+   |
+LL | /     match Some(42) {
+LL | |         None => false,
+LL | |         _ => true,
+LL | |     };
+   | |_____^ help: try this: `Some(42).is_some()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:129:5
+   |
+LL | /     match None::<()> {
+LL | |         Some(_) => false,
+LL | |         _ => true,
+LL | |     };
+   | |_____^ help: try this: `None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:134:5
+   |
+LL | /     match None::<()> {
+LL | |         Some(_) => false,
+LL | |         _ => true,
+LL | |     };
+   | |_____^ help: try this: `None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:139:5
+   |
+LL | /     match None::<()> {
+LL | |         None => true,
+LL | |         _ => false,
+LL | |     };
+   | |_____^ help: try this: `None::<()>.is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:144:5
+   |
+LL | /     match None::<()> {
+LL | |         None => false,
+LL | |         _ => true,
+LL | |     };
+   | |_____^ help: try this: `None::<()>.is_some()`
+
+error: aborting due to 30 previous errors
 
diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed
index c48d1522935..a51e14a5b56 100644
--- a/tests/ui/redundant_pattern_matching_result.fixed
+++ b/tests/ui/redundant_pattern_matching_result.fixed
@@ -43,6 +43,7 @@ fn main() {
     issue5504();
     issue6067();
     issue6065();
+    issue10726();
 
     let _ = if gen_res().is_ok() {
         1
@@ -107,3 +108,13 @@ const fn issue6067() {
 
     Err::<i32, i32>(42).is_err();
 }
+
+fn issue10726() {
+    Ok::<i32, i32>(42).is_ok();
+
+    Ok::<i32, i32>(42).is_err();
+
+    Err::<i32, i32>(42).is_err();
+
+    Err::<i32, i32>(42).is_ok();
+}
diff --git a/tests/ui/redundant_pattern_matching_result.rs b/tests/ui/redundant_pattern_matching_result.rs
index 26f37d169fa..709e3d526a8 100644
--- a/tests/ui/redundant_pattern_matching_result.rs
+++ b/tests/ui/redundant_pattern_matching_result.rs
@@ -55,6 +55,7 @@ fn main() {
     issue5504();
     issue6067();
     issue6065();
+    issue10726();
 
     let _ = if let Ok(_) = gen_res() {
         1
@@ -125,3 +126,25 @@ const fn issue6067() {
         Err(_) => true,
     };
 }
+
+fn issue10726() {
+    match Ok::<i32, i32>(42) {
+        Ok(_) => true,
+        _ => false,
+    };
+
+    match Ok::<i32, i32>(42) {
+        Ok(_) => false,
+        _ => true,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => false,
+        _ => true,
+    };
+
+    match Err::<i32, i32>(42) {
+        Ok(_) => true,
+        _ => false,
+    };
+}
diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr
index d6a46babb77..0e8a983bf44 100644
--- a/tests/ui/redundant_pattern_matching_result.stderr
+++ b/tests/ui/redundant_pattern_matching_result.stderr
@@ -73,67 +73,67 @@ LL |     let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
    |             -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:59:20
+  --> $DIR/redundant_pattern_matching_result.rs:60:20
    |
 LL |     let _ = if let Ok(_) = gen_res() {
    |             -------^^^^^------------ help: try this: `if gen_res().is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:61:19
+  --> $DIR/redundant_pattern_matching_result.rs:62:19
    |
 LL |     } else if let Err(_) = gen_res() {
    |            -------^^^^^^------------ help: try this: `if gen_res().is_err()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_result.rs:84:19
+  --> $DIR/redundant_pattern_matching_result.rs:85:19
    |
 LL |         while let Some(_) = r#try!(result_opt()) {}
    |         ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_result.rs:85:16
+  --> $DIR/redundant_pattern_matching_result.rs:86:16
    |
 LL |         if let Some(_) = r#try!(result_opt()) {}
    |         -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_result.rs:91:12
+  --> $DIR/redundant_pattern_matching_result.rs:92:12
    |
 LL |     if let Some(_) = m!() {}
    |     -------^^^^^^^------- help: try this: `if m!().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_result.rs:92:15
+  --> $DIR/redundant_pattern_matching_result.rs:93:15
    |
 LL |     while let Some(_) = m!() {}
    |     ----------^^^^^^^------- help: try this: `while m!().is_some()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:110:12
+  --> $DIR/redundant_pattern_matching_result.rs:111:12
    |
 LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
    |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:112:12
+  --> $DIR/redundant_pattern_matching_result.rs:113:12
    |
 LL |     if let Err(_) = Err::<i32, i32>(42) {}
    |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:114:15
+  --> $DIR/redundant_pattern_matching_result.rs:115:15
    |
 LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:116:15
+  --> $DIR/redundant_pattern_matching_result.rs:117:15
    |
 LL |     while let Err(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:118:5
+  --> $DIR/redundant_pattern_matching_result.rs:119:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -142,7 +142,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:123:5
+  --> $DIR/redundant_pattern_matching_result.rs:124:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => false,
@@ -150,5 +150,41 @@ LL | |         Err(_) => true,
 LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
 
-error: aborting due to 22 previous errors
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching_result.rs:131:5
+   |
+LL | /     match Ok::<i32, i32>(42) {
+LL | |         Ok(_) => true,
+LL | |         _ => false,
+LL | |     };
+   | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_result.rs:136:5
+   |
+LL | /     match Ok::<i32, i32>(42) {
+LL | |         Ok(_) => false,
+LL | |         _ => true,
+LL | |     };
+   | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_result.rs:141:5
+   |
+LL | /     match Err::<i32, i32>(42) {
+LL | |         Ok(_) => false,
+LL | |         _ => true,
+LL | |     };
+   | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
+
+error: redundant pattern matching, consider using `is_ok()`
+  --> $DIR/redundant_pattern_matching_result.rs:146:5
+   |
+LL | /     match Err::<i32, i32>(42) {
+LL | |         Ok(_) => true,
+LL | |         _ => false,
+LL | |     };
+   | |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
+
+error: aborting due to 26 previous errors
 

From d2bbe760081f52b2afa237944a78b93097aad51c Mon Sep 17 00:00:00 2001
From: disco07 <koneenok@outlook.fr>
Date: Fri, 5 May 2023 21:49:55 +0200
Subject: [PATCH 22/78] redundant_pattern_matching

---
 clippy_lints/src/matches/redundant_pattern_match.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 9656049feeb..53480a257c5 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -312,8 +312,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
                 } else {
                     None
                 }
-                
-            }
+            },
             _ => None,
         };
 

From d80ca09f5e254a113f1c6d4a63d12d9e215e0f39 Mon Sep 17 00:00:00 2001
From: Elias Holzmann <9659253+EliasHolzmann@users.noreply.github.com>
Date: Sun, 12 Feb 2023 20:00:19 +0100
Subject: [PATCH 23/78] Fix: Some suggestions generated by the
 option_if_let_else lint did not compile

---
 clippy_lints/src/option_if_let_else.rs | 12 ++++----
 tests/ui/option_if_let_else.fixed      | 10 +++++++
 tests/ui/option_if_let_else.rs         | 10 +++++++
 tests/ui/option_if_let_else.stderr     | 39 +++++++++++++++++++-------
 4 files changed, 56 insertions(+), 15 deletions(-)

diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs
index bbbcda069c5..aa6d4004268 100644
--- a/clippy_lints/src/option_if_let_else.rs
+++ b/clippy_lints/src/option_if_let_else.rs
@@ -122,7 +122,7 @@ fn try_get_option_occurrence<'tcx>(
         ExprKind::Unary(UnOp::Deref, inner_expr) | ExprKind::AddrOf(_, _, inner_expr) => inner_expr,
         _ => expr,
     };
-    let inner_pat = try_get_inner_pat(cx, pat)?;
+    let (inner_pat, is_result) = try_get_inner_pat_and_is_result(cx, pat)?;
     if_chain! {
         if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind;
         if let Some(some_captures) = can_move_expr_to_closure(cx, if_then);
@@ -176,7 +176,7 @@ fn try_get_option_occurrence<'tcx>(
                 ),
                 none_expr: format!(
                     "{}{}",
-                    if method_sugg == "map_or" { "" } else { "|| " },
+                    if method_sugg == "map_or" { "" } else if is_result { "|_| " } else { "|| "},
                     Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app),
                 ),
             });
@@ -186,11 +186,13 @@ fn try_get_option_occurrence<'tcx>(
     None
 }
 
-fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&'tcx Pat<'tcx>> {
+fn try_get_inner_pat_and_is_result<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<(&'tcx Pat<'tcx>, bool)> {
     if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind {
         let res = cx.qpath_res(qpath, pat.hir_id);
-        if is_res_lang_ctor(cx, res, OptionSome) || is_res_lang_ctor(cx, res, ResultOk) {
-            return Some(inner_pat);
+        if is_res_lang_ctor(cx, res, OptionSome) {
+            return Some((inner_pat, false));
+        } else if is_res_lang_ctor(cx, res, ResultOk) {
+            return Some((inner_pat, true));
         }
     }
     None
diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed
index 57f341e0276..2b8ce5477cc 100644
--- a/tests/ui/option_if_let_else.fixed
+++ b/tests/ui/option_if_let_else.fixed
@@ -92,6 +92,15 @@ fn pattern_to_vec(pattern: &str) -> Vec<String> {
         .collect::<Vec<_>>()
 }
 
+// #10335
+fn test_result_impure_else(variable: Result<u32, &str>) {
+    variable.map_or_else(|_| {
+        println!("Err");
+    }, |binding| {
+        println!("Ok {binding}");
+    })
+}
+
 enum DummyEnum {
     One(u8),
     Two,
@@ -113,6 +122,7 @@ fn main() {
     unop_bad(&None, None);
     let _ = longer_body(None);
     test_map_or_else(None);
+    test_result_impure_else(Ok(42));
     let _ = negative_tests(None);
     let _ = impure_else(None);
 
diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs
index 19f9f704517..cfbec8cb27d 100644
--- a/tests/ui/option_if_let_else.rs
+++ b/tests/ui/option_if_let_else.rs
@@ -115,6 +115,15 @@ fn pattern_to_vec(pattern: &str) -> Vec<String> {
         .collect::<Vec<_>>()
 }
 
+// #10335
+fn test_result_impure_else(variable: Result<u32, &str>) {
+    if let Ok(binding) = variable {
+        println!("Ok {binding}");
+    } else {
+        println!("Err");
+    }
+}
+
 enum DummyEnum {
     One(u8),
     Two,
@@ -136,6 +145,7 @@ fn main() {
     unop_bad(&None, None);
     let _ = longer_body(None);
     test_map_or_else(None);
+    test_result_impure_else(Ok(42));
     let _ = negative_tests(None);
     let _ = impure_else(None);
 
diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr
index f5e4affb672..91d52fc79b8 100644
--- a/tests/ui/option_if_let_else.stderr
+++ b/tests/ui/option_if_let_else.stderr
@@ -152,14 +152,33 @@ LL | |                 vec![s.to_string()]
 LL | |             }
    | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
 
+error: use Option::map_or_else instead of an if let/else
+  --> $DIR/option_if_let_else.rs:120:5
+   |
+LL | /     if let Ok(binding) = variable {
+LL | |         println!("Ok {binding}");
+LL | |     } else {
+LL | |         println!("Err");
+LL | |     }
+   | |_____^
+   |
+help: try
+   |
+LL ~     variable.map_or_else(|_| {
+LL +         println!("Err");
+LL +     }, |binding| {
+LL +         println!("Ok {binding}");
+LL +     })
+   |
+
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:133:13
+  --> $DIR/option_if_let_else.rs:142:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:142:13
+  --> $DIR/option_if_let_else.rs:152:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -181,13 +200,13 @@ LL ~         });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:170:13
+  --> $DIR/option_if_let_else.rs:180:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:174:13
+  --> $DIR/option_if_let_else.rs:184:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -207,7 +226,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:213:13
+  --> $DIR/option_if_let_else.rs:223:13
    |
 LL |       let _ = match s {
    |  _____________^
@@ -217,7 +236,7 @@ LL | |     };
    | |_____^ help: try: `s.map_or(1, |string| string.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:217:13
+  --> $DIR/option_if_let_else.rs:227:13
    |
 LL |       let _ = match Some(10) {
    |  _____________^
@@ -227,7 +246,7 @@ LL | |     };
    | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:223:13
+  --> $DIR/option_if_let_else.rs:233:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -237,7 +256,7 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:227:13
+  --> $DIR/option_if_let_else.rs:237:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -247,10 +266,10 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:231:13
+  --> $DIR/option_if_let_else.rs:241:13
    |
 LL |     let _ = if let Ok(a) = res { a + 1 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
 
-error: aborting due to 20 previous errors
+error: aborting due to 21 previous errors
 

From 2a4571d959615cf8e2859a0bb8af66cbd9a8af83 Mon Sep 17 00:00:00 2001
From: blyxyas <blyxyas@gmail.com>
Date: Sat, 6 May 2023 08:38:47 +0200
Subject: [PATCH 24/78] Minimizing changes

---
 clippy_lints/src/lib.rs                       |  24 ++-
 clippy_lints/src/utils/conf.rs                |   5 +-
 .../internal_lints/metadata_collector.rs      | 111 +-------------
 clippy_lints/src/utils/mod.rs                 | 140 ++++++++++++++++++
 4 files changed, 168 insertions(+), 112 deletions(-)

diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 657a3d1f431..8b88dab6ae6 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -331,8 +331,11 @@ mod zero_div_zero;
 mod zero_sized_map_values;
 // end lints modules, do not remove this comment, it’s used in `update_lints`
 
-use crate::utils::conf::{format_error, TryConf};
 pub use crate::utils::conf::{lookup_conf_file, Conf};
+use crate::utils::{
+    conf::{format_error, metadata::get_configuration_metadata, TryConf},
+    FindAll,
+};
 
 /// Register all pre expansion lints
 ///
@@ -388,7 +391,7 @@ pub fn read_conf(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>
     conf
 }
 
-#[derive(Default)]
+#[derive(Default)] //~ ERROR no such field
 struct RegistrationGroups {
     all: Vec<LintId>,
     cargo: Vec<LintId>,
@@ -471,7 +474,22 @@ pub(crate) struct LintInfo {
 pub fn explain(name: &str) {
     let target = format!("clippy::{}", name.to_ascii_uppercase());
     match declared_lints::LINTS.iter().find(|info| info.lint.name == target) {
-        Some(info) => print!("{}", info.explanation),
+        Some(info) => {
+            println!("{}", info.explanation);
+            // Check if the lint has configuration
+            let mdconf = get_configuration_metadata();
+            if let Some(config_vec_positions) = mdconf
+                .iter()
+                .find_all(|cconf| cconf.lints.contains(&info.lint.name_lower()[8..].to_owned()))
+            {
+                // If it has, print it
+                println!("### Configuration for {}:", info.lint.name_lower());
+                for position in config_vec_positions {
+                    let conf = &mdconf[position];
+                    println!("    - {}: {} (default: {})", conf.name, conf.doc, conf.default);
+                }
+            }
+        },
         None => println!("unknown lint: {name}"),
     }
 }
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 5f05d971fce..f6de66bb514 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -174,16 +174,15 @@ macro_rules! define_Conf {
             }
         }
 
-        #[cfg(feature = "internal")]
         pub mod metadata {
-            use crate::utils::internal_lints::metadata_collector::ClippyConfiguration;
+            use crate::utils::ClippyConfiguration;
 
             macro_rules! wrap_option {
                 () => (None);
                 ($x:literal) => (Some($x));
             }
 
-            pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
+            pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
                 vec![
                     $(
                         {
diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 3d0d4a52511..7a1cd3effae 100644
--- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -8,7 +8,11 @@
 //! a simple mistake)
 
 use crate::renamed_lints::RENAMED_LINTS;
-use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type};
+use crate::utils::{
+    collect_configs,
+    internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type},
+    ClippyConfiguration,
+};
 
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
@@ -520,111 +524,6 @@ impl Serialize for ApplicabilityInfo {
     }
 }
 
-// ==================================================================
-// Configuration
-// ==================================================================
-#[derive(Debug, Clone, Default)]
-pub struct ClippyConfiguration {
-    name: String,
-    config_type: &'static str,
-    default: String,
-    lints: Vec<String>,
-    doc: String,
-    #[allow(dead_code)]
-    deprecation_reason: Option<&'static str>,
-}
-
-impl ClippyConfiguration {
-    pub fn new(
-        name: &'static str,
-        config_type: &'static str,
-        default: String,
-        doc_comment: &'static str,
-        deprecation_reason: Option<&'static str>,
-    ) -> Self {
-        let (lints, doc) = parse_config_field_doc(doc_comment)
-            .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
-
-        Self {
-            name: to_kebab(name),
-            lints,
-            doc,
-            config_type,
-            default,
-            deprecation_reason,
-        }
-    }
-
-    fn to_markdown_paragraph(&self) -> String {
-        format!(
-            "### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n",
-            self.name,
-            self.doc
-                .lines()
-                .map(|line| line.strip_prefix("    ").unwrap_or(line))
-                .join("\n"),
-            self.default,
-            self.config_type,
-            self.lints
-                .iter()
-                .map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
-                .map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
-                .join("\n"),
-        )
-    }
-
-    fn to_markdown_table_entry(&self) -> String {
-        format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default)
-    }
-}
-
-fn collect_configs() -> Vec<ClippyConfiguration> {
-    crate::utils::conf::metadata::get_configuration_metadata()
-}
-
-/// This parses the field documentation of the config struct.
-///
-/// ```rust, ignore
-/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
-/// ```
-///
-/// Would yield:
-/// ```rust, ignore
-/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
-/// ```
-fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
-    const DOC_START: &str = " Lint: ";
-    if_chain! {
-        if doc_comment.starts_with(DOC_START);
-        if let Some(split_pos) = doc_comment.find('.');
-        then {
-            let mut doc_comment = doc_comment.to_string();
-            let mut documentation = doc_comment.split_off(split_pos);
-
-            // Extract lints
-            doc_comment.make_ascii_lowercase();
-            let lints: Vec<String> = doc_comment
-                .split_off(DOC_START.len())
-                .split(", ")
-                .map(str::to_string)
-                .collect();
-
-            // Format documentation correctly
-            // split off leading `.` from lint name list and indent for correct formatting
-            documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n    ");
-
-            Some((lints, documentation))
-        } else {
-            None
-        }
-    }
-}
-
-/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
-fn to_kebab(config_name: &str) -> String {
-    config_name.replace('_', "-")
-}
-
 impl fmt::Display for ClippyConfiguration {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
         writeln!(
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index dc647af264c..d3ea7cafa80 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -4,3 +4,143 @@ pub mod dump_hir;
 pub mod format_args_collector;
 #[cfg(feature = "internal")]
 pub mod internal_lints;
+#[cfg(feature = "internal")]
+use itertools::Itertools;
+
+/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
+fn to_kebab(config_name: &str) -> String {
+    config_name.replace('_', "-")
+}
+
+// ==================================================================
+// Configuration
+// ==================================================================
+#[derive(Debug, Clone, Default)] //~ ERROR no such field
+pub struct ClippyConfiguration {
+    pub name: String,
+    #[allow(dead_code)]
+    config_type: &'static str,
+    pub default: String,
+    pub lints: Vec<String>,
+    pub doc: String,
+    #[allow(dead_code)]
+    deprecation_reason: Option<&'static str>,
+}
+
+impl ClippyConfiguration {
+    pub fn new(
+        name: &'static str,
+        config_type: &'static str,
+        default: String,
+        doc_comment: &'static str,
+        deprecation_reason: Option<&'static str>,
+    ) -> Self {
+        let (lints, doc) = parse_config_field_doc(doc_comment)
+            .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
+
+        Self {
+            name: to_kebab(name),
+            lints,
+            doc,
+            config_type,
+            default,
+            deprecation_reason,
+        }
+    }
+
+    #[cfg(feature = "internal")]
+    fn to_markdown_paragraph(&self) -> String {
+        format!(
+            "### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n",
+            self.name,
+            self.doc
+                .lines()
+                .map(|line| line.strip_prefix("    ").unwrap_or(line))
+                .join("\n"),
+            self.default,
+            self.config_type,
+            self.lints
+                .iter()
+                .map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
+                .map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
+                .join("\n"),
+        )
+    }
+
+    #[cfg(feature = "internal")]
+    fn to_markdown_table_entry(&self) -> String {
+        format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default)
+    }
+}
+
+#[cfg(feature = "internal")]
+fn collect_configs() -> Vec<ClippyConfiguration> {
+    crate::utils::conf::metadata::get_configuration_metadata()
+}
+
+/// This parses the field documentation of the config struct.
+///
+/// ```rust, ignore
+/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
+/// ```
+///
+/// Would yield:
+/// ```rust, ignore
+/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
+/// ```
+fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
+    const DOC_START: &str = " Lint: ";
+    if_chain! {
+        if doc_comment.starts_with(DOC_START);
+        if let Some(split_pos) = doc_comment.find('.');
+        then {
+            let mut doc_comment = doc_comment.to_string();
+            let mut documentation = doc_comment.split_off(split_pos);
+
+            // Extract lints
+            doc_comment.make_ascii_lowercase();
+            let lints: Vec<String> = doc_comment
+                .split_off(DOC_START.len())
+                .split(", ")
+                .map(str::to_string)
+                .collect();
+
+            // Format documentation correctly
+            // split off leading `.` from lint name list and indent for correct formatting
+            documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n    ");
+
+            Some((lints, documentation))
+        } else {
+            None
+        }
+    }
+}
+
+// Shamelessly stolen from find_all (https://github.com/nectariner/find_all)
+pub trait FindAll: Iterator + Sized {
+    fn find_all<P>(&mut self, predicate: P) -> Option<Vec<usize>>
+    where
+        P: FnMut(&Self::Item) -> bool;
+}
+
+impl<I> FindAll for I
+where
+    I: Iterator,
+{
+    fn find_all<P>(&mut self, mut predicate: P) -> Option<Vec<usize>>
+    where
+        P: FnMut(&Self::Item) -> bool,
+    {
+        let mut occurences = Vec::<usize>::default();
+        for (index, element) in self.enumerate() {
+            if predicate(&element) {
+                occurences.push(index);
+            }
+        }
+
+        match occurences.len() {
+            0 => None,
+            _ => Some(occurences),
+        }
+    }
+}

From f4b8cb1b28eedee1b3c0404a9718087d2ee71434 Mon Sep 17 00:00:00 2001
From: Daniel Hofstetter <daniel.hofstetter@42dh.com>
Date: Sat, 6 May 2023 16:21:45 +0200
Subject: [PATCH 25/78] Add missing word "are"

---
 clippy_lints/src/lines_filter_map_ok.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs
index bba9bb445a7..09b2032e20f 100644
--- a/clippy_lints/src/lines_filter_map_ok.rs
+++ b/clippy_lints/src/lines_filter_map_ok.rs
@@ -25,7 +25,7 @@ declare_clippy_lint! {
     ///
     /// ### Known problems
     /// This lint suggests replacing `filter_map()` or `flat_map()` applied to a `Lines`
-    /// instance in all cases. There two cases where the suggestion might not be
+    /// instance in all cases. There are two cases where the suggestion might not be
     /// appropriate or necessary:
     ///
     /// - If the `Lines` instance can never produce any error, or if an error is produced

From 9e535f62888b691e50ae8d3cc32af45f2c82528d Mon Sep 17 00:00:00 2001
From: disco07 <koneenok@outlook.fr>
Date: Sun, 7 May 2023 00:59:52 +0200
Subject: [PATCH 26/78] fix conflict with matches macro

---
 .../src/matches/match_like_matches.rs         | 28 ++++++++++++++++++-
 .../src/matches/redundant_pattern_match.rs    |  1 -
 tests/ui/match_expr_like_matches_macro.fixed  |  2 +-
 tests/ui/match_expr_like_matches_macro.stderr |  8 +++---
 4 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs
index 33bc20dad6b..107c2cd844b 100644
--- a/clippy_lints/src/matches/match_like_matches.rs
+++ b/clippy_lints/src/matches/match_like_matches.rs
@@ -1,10 +1,12 @@
+use super::REDUNDANT_PATTERN_MATCHING;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_lint_allowed;
 use clippy_utils::is_wild;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::span_contains_comment;
 use rustc_ast::{Attribute, LitKind};
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat};
+use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat, PatKind, QPath};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty;
 use rustc_span::source_map::Spanned;
@@ -99,6 +101,14 @@ where
                 }
             }
 
+            for arm in iter_without_last.clone() {
+                if let Some(pat) = arm.1 {
+                    if !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id) && is_some(pat.kind) {
+                        return false;
+                    }
+                }
+            }
+
             // The suggestion may be incorrect, because some arms can have `cfg` attributes
             // evaluated into `false` and so such arms will be stripped before.
             let mut applicability = Applicability::MaybeIncorrect;
@@ -170,3 +180,19 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option<bool> {
         _ => None,
     }
 }
+
+fn is_some(path_kind: PatKind<'_>) -> bool {
+    match path_kind {
+        PatKind::TupleStruct(ref path_left, patterns, _) if is_wild(&patterns[0]) => match path_left {
+            QPath::Resolved(_, path) => {
+                let name = path.segments[0].ident;
+                if name.as_str() == "Some" {
+                    return true;
+                }
+                return false;
+            },
+            _ => false,
+        },
+        _ => false,
+    }
+}
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 53480a257c5..2ad11995325 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -186,7 +186,6 @@ fn find_sugg_for_if_let<'tcx>(
 }
 
 pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
-    //eprintln!("{:#?}", expr);
     if arms.len() == 2 {
         let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
         let found_good_method = match node_pair {
diff --git a/tests/ui/match_expr_like_matches_macro.fixed b/tests/ui/match_expr_like_matches_macro.fixed
index 7215660da67..60f59066173 100644
--- a/tests/ui/match_expr_like_matches_macro.fixed
+++ b/tests/ui/match_expr_like_matches_macro.fixed
@@ -15,7 +15,7 @@ fn main() {
     let _y = matches!(x, Some(0));
 
     // Lint
-    let _w = matches!(x, Some(_));
+    let _w = x.is_some();
 
     // Turn into is_none
     let _z = x.is_none();
diff --git a/tests/ui/match_expr_like_matches_macro.stderr b/tests/ui/match_expr_like_matches_macro.stderr
index 46f67ef4900..b72fe10b748 100644
--- a/tests/ui/match_expr_like_matches_macro.stderr
+++ b/tests/ui/match_expr_like_matches_macro.stderr
@@ -10,7 +10,7 @@ LL | |     };
    |
    = note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
 
-error: match expression looks like `matches!` macro
+error: redundant pattern matching, consider using `is_some()`
   --> $DIR/match_expr_like_matches_macro.rs:21:14
    |
 LL |       let _w = match x {
@@ -18,7 +18,9 @@ LL |       let _w = match x {
 LL | |         Some(_) => true,
 LL | |         _ => false,
 LL | |     };
-   | |_____^ help: try this: `matches!(x, Some(_))`
+   | |_____^ help: try this: `x.is_some()`
+   |
+   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
 error: redundant pattern matching, consider using `is_none()`
   --> $DIR/match_expr_like_matches_macro.rs:27:14
@@ -29,8 +31,6 @@ LL | |         Some(_) => false,
 LL | |         None => true,
 LL | |     };
    | |_____^ help: try this: `x.is_none()`
-   |
-   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
 error: match expression looks like `matches!` macro
   --> $DIR/match_expr_like_matches_macro.rs:33:15

From 630f31ce5ed38d13baf6cd16f26f1251183521c0 Mon Sep 17 00:00:00 2001
From: disco07 <koneenok@outlook.fr>
Date: Sun, 7 May 2023 02:45:11 +0200
Subject: [PATCH 27/78] fix conflict with matches macro

---
 .../src/matches/match_like_matches.rs         |  15 +-
 .../src/matches/redundant_pattern_match.rs    | 254 +++++++++---------
 2 files changed, 133 insertions(+), 136 deletions(-)

diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs
index 107c2cd844b..fe3b440ff58 100644
--- a/clippy_lints/src/matches/match_like_matches.rs
+++ b/clippy_lints/src/matches/match_like_matches.rs
@@ -183,15 +183,12 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option<bool> {
 
 fn is_some(path_kind: PatKind<'_>) -> bool {
     match path_kind {
-        PatKind::TupleStruct(ref path_left, patterns, _) if is_wild(&patterns[0]) => match path_left {
-            QPath::Resolved(_, path) => {
-                let name = path.segments[0].ident;
-                if name.as_str() == "Some" {
-                    return true;
-                }
-                return false;
-            },
-            _ => false,
+        PatKind::TupleStruct(QPath::Resolved(_, path), patterns, _) if is_wild(&patterns[0]) => {
+            let name = path.segments[0].ident;
+            if name.as_str() == "Some" {
+                return true;
+            }
+            false
         },
         _ => false,
     }
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 2ad11995325..2ac6d9938eb 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -188,132 +188,7 @@ fn find_sugg_for_if_let<'tcx>(
 pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
     if arms.len() == 2 {
         let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
-        let found_good_method = match node_pair {
-            (
-                PatKind::TupleStruct(ref path_left, patterns_left, _),
-                PatKind::TupleStruct(ref path_right, patterns_right, _),
-            ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
-                if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
-                    find_good_method_for_match(
-                        cx,
-                        arms,
-                        path_left,
-                        path_right,
-                        Item::Lang(ResultOk),
-                        Item::Lang(ResultErr),
-                        "is_ok()",
-                        "is_err()",
-                    )
-                    .or_else(|| {
-                        find_good_method_for_match(
-                            cx,
-                            arms,
-                            path_left,
-                            path_right,
-                            Item::Diag(sym::IpAddr, sym!(V4)),
-                            Item::Diag(sym::IpAddr, sym!(V6)),
-                            "is_ipv4()",
-                            "is_ipv6()",
-                        )
-                    })
-                } else {
-                    None
-                }
-            },
-            (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right))
-            | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _))
-                if patterns.len() == 1 =>
-            {
-                if let PatKind::Wild = patterns[0].kind {
-                    find_good_method_for_match(
-                        cx,
-                        arms,
-                        path_left,
-                        path_right,
-                        Item::Lang(OptionSome),
-                        Item::Lang(OptionNone),
-                        "is_some()",
-                        "is_none()",
-                    )
-                    .or_else(|| {
-                        find_good_method_for_match(
-                            cx,
-                            arms,
-                            path_left,
-                            path_right,
-                            Item::Lang(PollReady),
-                            Item::Lang(PollPending),
-                            "is_ready()",
-                            "is_pending()",
-                        )
-                    })
-                } else {
-                    None
-                }
-            },
-            (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Wild) if patterns.len() == 1 => {
-                if let PatKind::Wild = patterns[0].kind {
-                    let ident = match path_left {
-                        QPath::Resolved(_, path) => {
-                            let name = path.segments[0].ident;
-                            Some(name)
-                        },
-                        _ => None,
-                    };
-                    if let Some(name) = ident {
-                        match name.as_str() {
-                            "Ok" => find_good_method_for_matches_macro(
-                                cx,
-                                arms,
-                                path_left,
-                                Item::Lang(ResultOk),
-                                "is_ok()",
-                                "is_err()",
-                            ),
-                            "Some" => find_good_method_for_matches_macro(
-                                cx,
-                                arms,
-                                path_left,
-                                Item::Lang(OptionSome),
-                                "is_some()",
-                                "is_none()",
-                            ),
-                            _ => None,
-                        }
-                    } else {
-                        None
-                    }
-                } else {
-                    None
-                }
-            },
-            (PatKind::Path(ref path_left), PatKind::Wild) => {
-                let ident = match path_left {
-                    QPath::Resolved(_, path) => {
-                        let name = path.segments[0].ident;
-                        Some(name)
-                    },
-                    _ => None,
-                };
-
-                if let Some(name) = ident {
-                    match name.as_str() {
-                        "None" => find_good_method_for_matches_macro(
-                            cx,
-                            arms,
-                            path_left,
-                            Item::Lang(OptionNone),
-                            "is_none()",
-                            "is_some()",
-                        ),
-                        _ => None,
-                    }
-                } else {
-                    None
-                }
-            },
-            _ => None,
-        };
+        let found_good_method = found_good_method(cx, arms, node_pair);
 
         if let Some(good_method) = found_good_method {
             let span = expr.span.to(op.span);
@@ -339,6 +214,132 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
     }
 }
 
+fn found_good_method<'a>(
+    cx: &LateContext<'_>,
+    arms: &[Arm<'_>],
+    node: (&PatKind<'_>, &PatKind<'_>),
+) -> Option<&'a str> {
+    match node {
+        (
+            PatKind::TupleStruct(ref path_left, patterns_left, _),
+            PatKind::TupleStruct(ref path_right, patterns_right, _),
+        ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
+            if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
+                find_good_method_for_match(
+                    cx,
+                    arms,
+                    path_left,
+                    path_right,
+                    Item::Lang(ResultOk),
+                    Item::Lang(ResultErr),
+                    "is_ok()",
+                    "is_err()",
+                )
+                .or_else(|| {
+                    find_good_method_for_match(
+                        cx,
+                        arms,
+                        path_left,
+                        path_right,
+                        Item::Diag(sym::IpAddr, sym!(V4)),
+                        Item::Diag(sym::IpAddr, sym!(V6)),
+                        "is_ipv4()",
+                        "is_ipv6()",
+                    )
+                })
+            } else {
+                None
+            }
+        },
+        (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right))
+        | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _))
+            if patterns.len() == 1 =>
+        {
+            if let PatKind::Wild = patterns[0].kind {
+                find_good_method_for_match(
+                    cx,
+                    arms,
+                    path_left,
+                    path_right,
+                    Item::Lang(OptionSome),
+                    Item::Lang(OptionNone),
+                    "is_some()",
+                    "is_none()",
+                )
+                .or_else(|| {
+                    find_good_method_for_match(
+                        cx,
+                        arms,
+                        path_left,
+                        path_right,
+                        Item::Lang(PollReady),
+                        Item::Lang(PollPending),
+                        "is_ready()",
+                        "is_pending()",
+                    )
+                })
+            } else {
+                None
+            }
+        },
+        (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Wild) if patterns.len() == 1 => {
+            if let PatKind::Wild = patterns[0].kind {
+                get_good_method(cx, arms, path_left)
+            } else {
+                None
+            }
+        },
+        (PatKind::Path(ref path_left), PatKind::Wild) => {
+            if let Some(name) = get_ident(path_left) {
+                match name.as_str() {
+                    "None" => find_good_method_for_matches_macro(
+                        cx,
+                        arms,
+                        path_left,
+                        Item::Lang(OptionNone),
+                        "is_none()",
+                        "is_some()",
+                    ),
+                    _ => None,
+                }
+            } else {
+                None
+            }
+        },
+        _ => None,
+    }
+}
+
+fn get_ident(path: &QPath<'_>) -> Option<rustc_span::symbol::Ident> {
+    match path {
+        QPath::Resolved(_, path) => {
+            let name = path.segments[0].ident;
+            Some(name)
+        },
+        _ => None,
+    }
+}
+
+fn get_good_method<'a>(cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath<'_>) -> Option<&'a str> {
+    if let Some(name) = get_ident(path_left) {
+        return match name.as_str() {
+            "Ok" => {
+                find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultOk), "is_ok()", "is_err()")
+            },
+            "Some" => find_good_method_for_matches_macro(
+                cx,
+                arms,
+                path_left,
+                Item::Lang(OptionSome),
+                "is_some()",
+                "is_none()",
+            ),
+            _ => None,
+        };
+    }
+    None
+}
+
 #[derive(Clone, Copy)]
 enum Item {
     Lang(LangItem),
@@ -406,7 +407,6 @@ fn find_good_method_for_match<'a>(
     }
 }
 
-#[expect(clippy::too_many_arguments)]
 fn find_good_method_for_matches_macro<'a>(
     cx: &LateContext<'_>,
     arms: &[Arm<'_>],

From 450a22f2dc18949ba2db96570dc5270060fabd43 Mon Sep 17 00:00:00 2001
From: disco07 <koneenok@outlook.fr>
Date: Sun, 7 May 2023 02:56:46 +0200
Subject: [PATCH 28/78] fix error test

---
 clippy_lints/src/matches/match_like_matches.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs
index fe3b440ff58..438d1437562 100644
--- a/clippy_lints/src/matches/match_like_matches.rs
+++ b/clippy_lints/src/matches/match_like_matches.rs
@@ -185,7 +185,7 @@ fn is_some(path_kind: PatKind<'_>) -> bool {
     match path_kind {
         PatKind::TupleStruct(QPath::Resolved(_, path), patterns, _) if is_wild(&patterns[0]) => {
             let name = path.segments[0].ident;
-            if name.as_str() == "Some" {
+            if name.name == rustc_span::sym::Some {
                 return true;
             }
             false

From 39db64e0ab60dfaa5e510075d5bd6ea8362e6cf2 Mon Sep 17 00:00:00 2001
From: Kyle Matsuda <kyle.yoshio.matsuda@gmail.com>
Date: Mon, 20 Feb 2023 12:46:39 -0700
Subject: [PATCH 29/78] make (try_)subst_and_normalize_erasing_regions take
 EarlyBinder

---
 clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index 4c4c003ca46..87641c686dc 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -435,7 +435,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                         let output_ty = fn_sig.output();
                         if output_ty.contains(*param_ty) {
                             if let Ok(new_ty)  = cx.tcx.try_subst_and_normalize_erasing_regions(
-                                new_subst, cx.param_env, output_ty) {
+                                new_subst, cx.param_env, EarlyBinder(output_ty)) {
                                 expr = parent_expr;
                                 ty = new_ty;
                                 continue;

From 3fc11553a8b2462306b9fd0f15db3faf12e1b6ed Mon Sep 17 00:00:00 2001
From: Kyle Matsuda <kyle.yoshio.matsuda@gmail.com>
Date: Sat, 6 May 2023 22:56:51 -0600
Subject: [PATCH 30/78] changes from review: add FIXME to clippy and change
 subst_identity to skip_binder in mir subst methods

---
 clippy_lints/src/methods/unnecessary_to_owned.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index 87641c686dc..67b7d3691dc 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -385,6 +385,9 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
             Node::Expr(parent_expr) => {
                 if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
                 {
+                    // FIXME: the `subst_identity()` below seems incorrect, since we eventually
+                    // call `tcx.try_subst_and_normalize_erasing_regions` further down
+                    // (i.e., we are explicitly not in the identity context).
                     let fn_sig = cx.tcx.fn_sig(callee_def_id).subst_identity().skip_binder();
                     if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
                         && let Some(param_ty) = fn_sig.inputs().get(arg_index)

From fb6bf1ebf66497386ea4c90a953b7b287ae19706 Mon Sep 17 00:00:00 2001
From: disco07 <koneenok@outlook.fr>
Date: Sun, 7 May 2023 08:12:36 +0200
Subject: [PATCH 31/78] update a func

---
 .../src/matches/redundant_pattern_match.rs    | 26 +++++++------------
 1 file changed, 9 insertions(+), 17 deletions(-)

diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 2ac6d9938eb..28478987821 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -289,23 +289,7 @@ fn found_good_method<'a>(
                 None
             }
         },
-        (PatKind::Path(ref path_left), PatKind::Wild) => {
-            if let Some(name) = get_ident(path_left) {
-                match name.as_str() {
-                    "None" => find_good_method_for_matches_macro(
-                        cx,
-                        arms,
-                        path_left,
-                        Item::Lang(OptionNone),
-                        "is_none()",
-                        "is_some()",
-                    ),
-                    _ => None,
-                }
-            } else {
-                None
-            }
-        },
+        (PatKind::Path(ref path_left), PatKind::Wild) => get_good_method(cx, arms, path_left),
         _ => None,
     }
 }
@@ -334,6 +318,14 @@ fn get_good_method<'a>(cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath
                 "is_some()",
                 "is_none()",
             ),
+            "None" => find_good_method_for_matches_macro(
+                cx,
+                arms,
+                path_left,
+                Item::Lang(OptionNone),
+                "is_none()",
+                "is_some()",
+            ),
             _ => None,
         };
     }

From 5c8a00923bc435cec37820c32768871b9e8a9ca1 Mon Sep 17 00:00:00 2001
From: John Kelly <johnharrykelly@gmail.com>
Date: Sun, 7 May 2023 10:10:44 +0100
Subject: [PATCH 32/78] Comments

---
 clippy_lints/src/trait_bounds.rs | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 5acd44dccaf..c4e4410e9fd 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -174,15 +174,11 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
             if let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind;
             if bounds.len() > 2;
             then {
-                let mut bounds_span = bounds[0].span;
-
-                for bound in bounds.iter().skip(1) {
-                    bounds_span = bounds_span.to(bound.span);
-                }
-
                 let mut seen_def_ids = FxHashSet::default();
                 let mut fixed_traits = Vec::new();
 
+                // Iterate the bounds and add them to our seen hash
+                // If we haven't yet seen it, add it to the fixed traits
                 for bound in bounds.iter() {
                     let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; };
 
@@ -193,7 +189,15 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                     }
                 }
 
+                // If the number added to fixed (which are not duplicates) isn't the same as the number found,
+                // there must be 1 or more duplicates
                 if bounds.len() != fixed_traits.len() {
+                    let mut bounds_span = bounds[0].span;
+
+                    for bound in bounds.iter().skip(1) {
+                        bounds_span = bounds_span.to(bound.span);
+                    }
+
                     let fixed_trait_snippet = fixed_traits
                         .iter()
                         .filter_map(|b| snippet_opt(cx, b.span))

From 394b4c1906ed8eb0484f70a7697b452dbb8fa483 Mon Sep 17 00:00:00 2001
From: Renato Lochetti <renato.lochetti@gmail.com>
Date: Sun, 7 May 2023 12:35:17 +0100
Subject: [PATCH 33/78] Ignore `borrow_deref_ref` warnings in code from
 procedural macros.

---
 clippy_lints/src/borrow_deref_ref.rs |  6 ++++--
 tests/ui/borrow_deref_ref.fixed      | 15 +++++++++++++++
 tests/ui/borrow_deref_ref.rs         | 15 +++++++++++++++
 tests/ui/borrow_deref_ref.stderr     |  6 +++---
 4 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs
index c4520d00392..814108ed8a7 100644
--- a/clippy_lints/src/borrow_deref_ref.rs
+++ b/clippy_lints/src/borrow_deref_ref.rs
@@ -1,5 +1,6 @@
 use crate::reference::DEREF_ADDROF;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::{get_parent_expr, is_lint_allowed};
@@ -47,8 +48,8 @@ declare_clippy_lint! {
 
 declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]);
 
-impl LateLintPass<'_> for BorrowDerefRef {
-    fn check_expr(&mut self, cx: &LateContext<'_>, e: &rustc_hir::Expr<'_>) {
+impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
         if_chain! {
             if !e.span.from_expansion();
             if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind;
@@ -58,6 +59,7 @@ impl LateLintPass<'_> for BorrowDerefRef {
             if !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..) );
             let ref_ty = cx.typeck_results().expr_ty(deref_target);
             if let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind();
+            if !is_from_proc_macro(cx, e);
             then{
 
                 if let Some(parent_expr) = get_parent_expr(cx, e){
diff --git a/tests/ui/borrow_deref_ref.fixed b/tests/ui/borrow_deref_ref.fixed
index 165e4bc8272..75526461792 100644
--- a/tests/ui/borrow_deref_ref.fixed
+++ b/tests/ui/borrow_deref_ref.fixed
@@ -1,7 +1,11 @@
 //@run-rustfix
+//@aux-build: proc_macros.rs
 
 #![allow(dead_code, unused_variables)]
 
+extern crate proc_macros;
+use proc_macros::with_span;
+
 fn main() {}
 
 mod should_lint {
@@ -47,6 +51,17 @@ mod should_not_lint2 {
     }
 }
 
+with_span!(
+    span
+
+    fn just_returning(x: &u32) -> &u32 {
+        x
+    }
+
+    fn dont_lint_proc_macro() {
+        let a = &mut &*just_returning(&12);
+    }
+);
 // this mod explains why we should not lint `& &* (&T)`
 mod false_negative {
     fn foo() {
diff --git a/tests/ui/borrow_deref_ref.rs b/tests/ui/borrow_deref_ref.rs
index 66c8d69bef9..e319d365f7e 100644
--- a/tests/ui/borrow_deref_ref.rs
+++ b/tests/ui/borrow_deref_ref.rs
@@ -1,7 +1,11 @@
 //@run-rustfix
+//@aux-build: proc_macros.rs
 
 #![allow(dead_code, unused_variables)]
 
+extern crate proc_macros;
+use proc_macros::with_span;
+
 fn main() {}
 
 mod should_lint {
@@ -47,6 +51,17 @@ mod should_not_lint2 {
     }
 }
 
+with_span!(
+    span
+
+    fn just_returning(x: &u32) -> &u32 {
+        x
+    }
+
+    fn dont_lint_proc_macro() {
+        let a = &mut &*just_returning(&12);
+    }
+);
 // this mod explains why we should not lint `& &* (&T)`
 mod false_negative {
     fn foo() {
diff --git a/tests/ui/borrow_deref_ref.stderr b/tests/ui/borrow_deref_ref.stderr
index d72de37c69f..1e47cda6796 100644
--- a/tests/ui/borrow_deref_ref.stderr
+++ b/tests/ui/borrow_deref_ref.stderr
@@ -1,5 +1,5 @@
 error: deref on an immutable reference
-  --> $DIR/borrow_deref_ref.rs:10:17
+  --> $DIR/borrow_deref_ref.rs:14:17
    |
 LL |         let b = &*a;
    |                 ^^^ help: if you would like to reborrow, try removing `&*`: `a`
@@ -7,13 +7,13 @@ LL |         let b = &*a;
    = note: `-D clippy::borrow-deref-ref` implied by `-D warnings`
 
 error: deref on an immutable reference
-  --> $DIR/borrow_deref_ref.rs:12:22
+  --> $DIR/borrow_deref_ref.rs:16:22
    |
 LL |         let b = &mut &*bar(&12);
    |                      ^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `bar(&12)`
 
 error: deref on an immutable reference
-  --> $DIR/borrow_deref_ref.rs:55:23
+  --> $DIR/borrow_deref_ref.rs:70:23
    |
 LL |         let addr_y = &&*x as *const _ as usize; // assert ok
    |                       ^^^ help: if you would like to reborrow, try removing `&*`: `x`

From 56e8e1a27da1a204a5ed6ace2132c09abe49178b Mon Sep 17 00:00:00 2001
From: NotAPenguin <michiel.vandeginste@gmail.com>
Date: Mon, 8 May 2023 13:20:33 +0200
Subject: [PATCH 34/78] new lint: clippy::ref_patterns

---
 CHANGELOG.md                       |  1 +
 clippy_lints/src/declared_lints.rs |  1 +
 clippy_lints/src/lib.rs            |  2 ++
 clippy_lints/src/misc.rs           | 11 +++++++-
 clippy_lints/src/ref_patterns.rs   | 44 ++++++++++++++++++++++++++++++
 tests/ui/ref_patterns.rs           | 19 +++++++++++++
 tests/ui/ref_patterns.stderr       | 27 ++++++++++++++++++
 7 files changed, 104 insertions(+), 1 deletion(-)
 create mode 100644 clippy_lints/src/ref_patterns.rs
 create mode 100644 tests/ui/ref_patterns.rs
 create mode 100644 tests/ui/ref_patterns.stderr

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ebf5b58a586..85d451a87d0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4978,6 +4978,7 @@ Released 2018-09-13
 [`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
 [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
 [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
+[`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns
 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
 [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 79d0f6f3607..6614b99713a 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -539,6 +539,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::redundant_slicing::REDUNDANT_SLICING_INFO,
     crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO,
     crate::ref_option_ref::REF_OPTION_REF_INFO,
+    crate::ref_patterns::REF_PATTERNS_INFO,
     crate::reference::DEREF_ADDROF_INFO,
     crate::regex::INVALID_REGEX_INFO,
     crate::regex::TRIVIAL_REGEX_INFO,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 3517842a01e..766a701fad8 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -266,6 +266,7 @@ mod redundant_pub_crate;
 mod redundant_slicing;
 mod redundant_static_lifetimes;
 mod ref_option_ref;
+mod ref_patterns;
 mod reference;
 mod regex;
 mod return_self_not_must_use;
@@ -971,6 +972,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
     store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments));
     store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
+    store.register_early_pass(|| Box::new(ref_patterns::RefPatterns));
     store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs
index 3752b9a946f..303f0125690 100644
--- a/clippy_lints/src/misc.rs
+++ b/clippy_lints/src/misc.rs
@@ -16,9 +16,12 @@ use rustc_span::source_map::{ExpnKind, Span};
 
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
-    get_parent_expr, in_constant, is_integer_literal, is_no_std_crate, iter_input_pats, last_path_segment, SpanlessEq,
+    get_parent_expr, in_constant, is_integer_literal, is_lint_allowed, is_no_std_crate, iter_input_pats,
+    last_path_segment, SpanlessEq,
 };
 
+use crate::ref_patterns::REF_PATTERNS;
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for function arguments and let bindings denoted as
@@ -162,6 +165,10 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
             return;
         }
         for arg in iter_input_pats(decl, body) {
+            // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
+            if !is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) {
+                return;
+            }
             if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind {
                 span_lint(
                     cx,
@@ -180,6 +187,8 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
             if let StmtKind::Local(local) = stmt.kind;
             if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind;
             if let Some(init) = local.init;
+            // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
+            if is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id);
             then {
                 let ctxt = local.span.ctxt();
                 let mut app = Applicability::MachineApplicable;
diff --git a/clippy_lints/src/ref_patterns.rs b/clippy_lints/src/ref_patterns.rs
new file mode 100644
index 00000000000..b1530eed1c1
--- /dev/null
+++ b/clippy_lints/src/ref_patterns.rs
@@ -0,0 +1,44 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_ast::ast::{BindingAnnotation, Pat, PatKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usages of the `ref` keyword.
+    /// ### Why is this bad?
+    /// The `ref` keyword can be confusing for people unfamiliar with it, and often
+    /// it is more concise to use `&` instead.
+    /// ### Example
+    /// ```rust
+    /// let opt = Some(5);
+    /// if let Some(ref foo) = opt {}
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let opt = Some(5);
+    /// if let Some(foo) = &opt {}
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub REF_PATTERNS,
+    restriction,
+    "use of a ref pattern, e.g. Some(ref value)"
+}
+declare_lint_pass!(RefPatterns => [REF_PATTERNS]);
+
+impl EarlyLintPass for RefPatterns {
+    fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
+        if let PatKind::Ident(BindingAnnotation::REF, _, _) = pat.kind
+                && !pat.span.from_expansion()
+        {
+            span_lint_and_help(
+                cx,
+                REF_PATTERNS,
+                pat.span,
+                "usage of ref pattern",
+                None,
+                "consider using `&` for clarity instead",
+            );
+        }
+    }
+}
diff --git a/tests/ui/ref_patterns.rs b/tests/ui/ref_patterns.rs
new file mode 100644
index 00000000000..c51e0bc76ef
--- /dev/null
+++ b/tests/ui/ref_patterns.rs
@@ -0,0 +1,19 @@
+#![allow(unused)]
+#![warn(clippy::ref_patterns)]
+
+fn use_in_pattern() {
+    let opt = Some(5);
+    match opt {
+        None => {},
+        Some(ref opt) => {},
+    }
+}
+
+fn use_in_binding() {
+    let x = 5;
+    let ref y = x;
+}
+
+fn use_in_parameter(ref x: i32) {}
+
+fn main() {}
diff --git a/tests/ui/ref_patterns.stderr b/tests/ui/ref_patterns.stderr
new file mode 100644
index 00000000000..aa007782683
--- /dev/null
+++ b/tests/ui/ref_patterns.stderr
@@ -0,0 +1,27 @@
+error: usage of ref pattern
+  --> $DIR/ref_patterns.rs:8:14
+   |
+LL |         Some(ref opt) => {},
+   |              ^^^^^^^
+   |
+   = help: consider using `&` for clarity instead
+   = note: `-D clippy::ref-patterns` implied by `-D warnings`
+
+error: usage of ref pattern
+  --> $DIR/ref_patterns.rs:14:9
+   |
+LL |     let ref y = x;
+   |         ^^^^^
+   |
+   = help: consider using `&` for clarity instead
+
+error: usage of ref pattern
+  --> $DIR/ref_patterns.rs:17:21
+   |
+LL | fn use_in_parameter(ref x: i32) {}
+   |                     ^^^^^
+   |
+   = help: consider using `&` for clarity instead
+
+error: aborting due to 3 previous errors
+

From 54912410c71bd2547d008c0a5ba3c8c296f1ae74 Mon Sep 17 00:00:00 2001
From: blyxyas <blyxyas@gmail.com>
Date: Sun, 2 Apr 2023 01:51:44 +0200
Subject: [PATCH 35/78] `Wildcard_imports` ignore `test.rs` files

---
 clippy_lints/src/wildcard_imports.rs          | 22 ++++++++++++++++++-
 tests/ui/wildcard_imports/another_file.fixed  | 18 +++++++++++++++
 tests/ui/wildcard_imports/another_file.rs     | 18 +++++++++++++++
 tests/ui/wildcard_imports/another_file.stderr | 10 +++++++++
 tests/ui/wildcard_imports/test.rs             | 17 ++++++++++++++
 tests/ui/wildcard_imports/tests.rs            | 17 ++++++++++++++
 6 files changed, 101 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/wildcard_imports/another_file.fixed
 create mode 100644 tests/ui/wildcard_imports/another_file.rs
 create mode 100644 tests/ui/wildcard_imports/another_file.stderr
 create mode 100644 tests/ui/wildcard_imports/test.rs
 create mode 100644 tests/ui/wildcard_imports/tests.rs

diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs
index 36f910c983f..f062cafdd4f 100644
--- a/clippy_lints/src/wildcard_imports.rs
+++ b/clippy_lints/src/wildcard_imports.rs
@@ -7,7 +7,8 @@ use rustc_hir::{
     def::{DefKind, Res},
     Item, ItemKind, PathSegment, UseKind,
 };
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_hir::{HirId, Mod};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::kw;
@@ -102,6 +103,7 @@ declare_clippy_lint! {
 pub struct WildcardImports {
     warn_on_all: bool,
     test_modules_deep: u32,
+    ignore: bool,
 }
 
 impl WildcardImports {
@@ -109,6 +111,7 @@ impl WildcardImports {
         Self {
             warn_on_all,
             test_modules_deep: 0,
+            ignore: false,
         }
     }
 }
@@ -116,7 +119,24 @@ impl WildcardImports {
 impl_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]);
 
 impl LateLintPass<'_> for WildcardImports {
+    fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) {
+        let filename = cx
+            .sess()
+            .source_map()
+            .span_to_filename(module.spans.inner_span)
+            .display(rustc_span::FileNameDisplayPreference::Local)
+            .to_string();
+
+        if filename.ends_with("test.rs") || filename.ends_with("tests.rs") {
+            self.ignore = true;
+        }
+    }
+
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+        if self.ignore {
+            return;
+        }
+
         if is_test_module_or_function(cx.tcx, item) {
             self.test_modules_deep = self.test_modules_deep.saturating_add(1);
         }
diff --git a/tests/ui/wildcard_imports/another_file.fixed b/tests/ui/wildcard_imports/another_file.fixed
new file mode 100644
index 00000000000..726808e598f
--- /dev/null
+++ b/tests/ui/wildcard_imports/another_file.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+
+// Test for #10580, the lint should **not** ignore it.
+
+fn foofoo() {}
+
+mod outer {
+    mod inner {
+        use super::super::foofoo;
+        fn barbar() {
+            let _ = foofoo();
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/wildcard_imports/another_file.rs b/tests/ui/wildcard_imports/another_file.rs
new file mode 100644
index 00000000000..057332ef706
--- /dev/null
+++ b/tests/ui/wildcard_imports/another_file.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+
+// Test for #10580, the lint should **not** ignore it.
+
+fn foofoo() {}
+
+mod outer {
+    mod inner {
+        use super::super::*;
+        fn barbar() {
+            let _ = foofoo();
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/wildcard_imports/another_file.stderr b/tests/ui/wildcard_imports/another_file.stderr
new file mode 100644
index 00000000000..56923eff58b
--- /dev/null
+++ b/tests/ui/wildcard_imports/another_file.stderr
@@ -0,0 +1,10 @@
+error: usage of wildcard import
+  --> $DIR/another_file.rs:11:13
+   |
+LL |         use super::super::*;
+   |             ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+   |
+   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/wildcard_imports/test.rs b/tests/ui/wildcard_imports/test.rs
new file mode 100644
index 00000000000..9029e5ba503
--- /dev/null
+++ b/tests/ui/wildcard_imports/test.rs
@@ -0,0 +1,17 @@
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+
+// Test for #10580, the lint **should** not ignore it.
+
+fn foofoo() {}
+
+mod outer {
+    mod inner {
+        use super::super::*;
+        fn barbar() {
+            let _ = foofoo();
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/wildcard_imports/tests.rs b/tests/ui/wildcard_imports/tests.rs
new file mode 100644
index 00000000000..b7483853388
--- /dev/null
+++ b/tests/ui/wildcard_imports/tests.rs
@@ -0,0 +1,17 @@
+#![warn(clippy::wildcard_imports)]
+#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
+
+// Test for #10580, the lint **should** ignore it.
+
+fn foofoo() {}
+
+mod outer {
+    mod inner {
+        use super::super::*;
+        fn barbar() {
+            let _ = foofoo();
+        }
+    }
+}
+
+fn main() {}

From 5acc2993e74506780e0a20331f58e78e125aad92 Mon Sep 17 00:00:00 2001
From: blyxyas <blyxyas@gmail.com>
Date: Mon, 3 Apr 2023 14:16:46 +0200
Subject: [PATCH 36/78] Really mini minor irrelevant change for formatting

---
 clippy_lints/src/wildcard_imports.rs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs
index f062cafdd4f..53ab9e94631 100644
--- a/clippy_lints/src/wildcard_imports.rs
+++ b/clippy_lints/src/wildcard_imports.rs
@@ -127,9 +127,7 @@ impl LateLintPass<'_> for WildcardImports {
             .display(rustc_span::FileNameDisplayPreference::Local)
             .to_string();
 
-        if filename.ends_with("test.rs") || filename.ends_with("tests.rs") {
-            self.ignore = true;
-        }
+        self.ignore = filename.ends_with("test.rs") || filename.ends_with("tests.rs");
     }
 
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {

From ba0e7e88cb69587bc1e639509999d3f39ee0dae2 Mon Sep 17 00:00:00 2001
From: blyxyas <blyxyas@gmail.com>
Date: Wed, 5 Apr 2023 20:38:44 +0200
Subject: [PATCH 37/78] Now the lint ignores any crates with `--cfg test`

---
 clippy_lints/src/wildcard_imports.rs           | 14 ++++----------
 tests/ui/wildcard_imports/another_file.fixed   | 18 ------------------
 tests/ui/wildcard_imports/another_file.stderr  | 10 ----------
 tests/ui/wildcard_imports/test.rs              | 17 -----------------
 tests/ui/wildcard_imports/tests.rs             | 17 -----------------
 ...her_file.rs => wildcard_imports_cfgtest.rs} |  5 +++--
 6 files changed, 7 insertions(+), 74 deletions(-)
 delete mode 100644 tests/ui/wildcard_imports/another_file.fixed
 delete mode 100644 tests/ui/wildcard_imports/another_file.stderr
 delete mode 100644 tests/ui/wildcard_imports/test.rs
 delete mode 100644 tests/ui/wildcard_imports/tests.rs
 rename tests/ui/{wildcard_imports/another_file.rs => wildcard_imports_cfgtest.rs} (70%)

diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs
index 53ab9e94631..0cae6e00a95 100644
--- a/clippy_lints/src/wildcard_imports.rs
+++ b/clippy_lints/src/wildcard_imports.rs
@@ -7,7 +7,6 @@ use rustc_hir::{
     def::{DefKind, Res},
     Item, ItemKind, PathSegment, UseKind,
 };
-use rustc_hir::{HirId, Mod};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -119,15 +118,10 @@ impl WildcardImports {
 impl_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]);
 
 impl LateLintPass<'_> for WildcardImports {
-    fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) {
-        let filename = cx
-            .sess()
-            .source_map()
-            .span_to_filename(module.spans.inner_span)
-            .display(rustc_span::FileNameDisplayPreference::Local)
-            .to_string();
-
-        self.ignore = filename.ends_with("test.rs") || filename.ends_with("tests.rs");
+    fn check_crate(&mut self, cx: &LateContext<'_>) {
+        if cx.sess().opts.test {
+            self.ignore = true;
+        }
     }
 
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
diff --git a/tests/ui/wildcard_imports/another_file.fixed b/tests/ui/wildcard_imports/another_file.fixed
deleted file mode 100644
index 726808e598f..00000000000
--- a/tests/ui/wildcard_imports/another_file.fixed
+++ /dev/null
@@ -1,18 +0,0 @@
-// run-rustfix
-#![warn(clippy::wildcard_imports)]
-#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
-
-// Test for #10580, the lint should **not** ignore it.
-
-fn foofoo() {}
-
-mod outer {
-    mod inner {
-        use super::super::foofoo;
-        fn barbar() {
-            let _ = foofoo();
-        }
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/wildcard_imports/another_file.stderr b/tests/ui/wildcard_imports/another_file.stderr
deleted file mode 100644
index 56923eff58b..00000000000
--- a/tests/ui/wildcard_imports/another_file.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: usage of wildcard import
-  --> $DIR/another_file.rs:11:13
-   |
-LL |         use super::super::*;
-   |             ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
-   |
-   = note: `-D clippy::wildcard-imports` implied by `-D warnings`
-
-error: aborting due to previous error
-
diff --git a/tests/ui/wildcard_imports/test.rs b/tests/ui/wildcard_imports/test.rs
deleted file mode 100644
index 9029e5ba503..00000000000
--- a/tests/ui/wildcard_imports/test.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-#![warn(clippy::wildcard_imports)]
-#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
-
-// Test for #10580, the lint **should** not ignore it.
-
-fn foofoo() {}
-
-mod outer {
-    mod inner {
-        use super::super::*;
-        fn barbar() {
-            let _ = foofoo();
-        }
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/wildcard_imports/tests.rs b/tests/ui/wildcard_imports/tests.rs
deleted file mode 100644
index b7483853388..00000000000
--- a/tests/ui/wildcard_imports/tests.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-#![warn(clippy::wildcard_imports)]
-#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
-
-// Test for #10580, the lint **should** ignore it.
-
-fn foofoo() {}
-
-mod outer {
-    mod inner {
-        use super::super::*;
-        fn barbar() {
-            let _ = foofoo();
-        }
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/wildcard_imports/another_file.rs b/tests/ui/wildcard_imports_cfgtest.rs
similarity index 70%
rename from tests/ui/wildcard_imports/another_file.rs
rename to tests/ui/wildcard_imports_cfgtest.rs
index 057332ef706..a5e4e92b32c 100644
--- a/tests/ui/wildcard_imports/another_file.rs
+++ b/tests/ui/wildcard_imports_cfgtest.rs
@@ -1,8 +1,9 @@
-// run-rustfix
+// compile-flags: --test
+
 #![warn(clippy::wildcard_imports)]
 #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]
 
-// Test for #10580, the lint should **not** ignore it.
+// Test for #10580, the lint should ignore it because of the crate's cfg test flag.
 
 fn foofoo() {}
 

From 4c3e2ff2a40a54bc37669bbdb0861a50ec418ff3 Mon Sep 17 00:00:00 2001
From: blyxyas <blyxyas@gmail.com>
Date: Mon, 8 May 2023 18:38:41 +0200
Subject: [PATCH 38/78] Fix header

---
 clippy_lints/src/wildcard_imports.rs | 10 +---------
 tests/ui/wildcard_imports_cfgtest.rs |  2 +-
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs
index 0cae6e00a95..a9089fba3c5 100644
--- a/clippy_lints/src/wildcard_imports.rs
+++ b/clippy_lints/src/wildcard_imports.rs
@@ -102,7 +102,6 @@ declare_clippy_lint! {
 pub struct WildcardImports {
     warn_on_all: bool,
     test_modules_deep: u32,
-    ignore: bool,
 }
 
 impl WildcardImports {
@@ -110,7 +109,6 @@ impl WildcardImports {
         Self {
             warn_on_all,
             test_modules_deep: 0,
-            ignore: false,
         }
     }
 }
@@ -118,14 +116,8 @@ impl WildcardImports {
 impl_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]);
 
 impl LateLintPass<'_> for WildcardImports {
-    fn check_crate(&mut self, cx: &LateContext<'_>) {
-        if cx.sess().opts.test {
-            self.ignore = true;
-        }
-    }
-
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if self.ignore {
+        if cx.sess().is_test_crate() {
             return;
         }
 
diff --git a/tests/ui/wildcard_imports_cfgtest.rs b/tests/ui/wildcard_imports_cfgtest.rs
index a5e4e92b32c..203c4e15b50 100644
--- a/tests/ui/wildcard_imports_cfgtest.rs
+++ b/tests/ui/wildcard_imports_cfgtest.rs
@@ -1,4 +1,4 @@
-// compile-flags: --test
+//@compile-flags: --test
 
 #![warn(clippy::wildcard_imports)]
 #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)]

From b169bdb732c1a0751a32c4ede1c16a3bba3ffb09 Mon Sep 17 00:00:00 2001
From: John Kelly <johnharrykelly@gmail.com>
Date: Tue, 9 May 2023 10:06:38 +0100
Subject: [PATCH 39/78] Comments

---
 clippy_lints/src/trait_bounds.rs | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index c4e4410e9fd..4ccda15068b 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -174,8 +174,13 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
             if let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind;
             if bounds.len() > 2;
             then {
+
+                // Build up a hash of every trait we've seen
+                // When we see a trait for the first time, add it to unique_traits
+                // so we can later use it to build a string of all traits exactly once, without duplicates
+
                 let mut seen_def_ids = FxHashSet::default();
-                let mut fixed_traits = Vec::new();
+                let mut unique_traits = Vec::new();
 
                 // Iterate the bounds and add them to our seen hash
                 // If we haven't yet seen it, add it to the fixed traits
@@ -185,20 +190,20 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                     let new_trait = seen_def_ids.insert(def_id);
 
                     if new_trait {
-                        fixed_traits.push(bound);
+                        unique_traits.push(bound);
                     }
                 }
 
-                // If the number added to fixed (which are not duplicates) isn't the same as the number found,
+                // If the number of unique traits isn't the same as the number of traits in the bounds,
                 // there must be 1 or more duplicates
-                if bounds.len() != fixed_traits.len() {
+                if bounds.len() != unique_traits.len() {
                     let mut bounds_span = bounds[0].span;
 
                     for bound in bounds.iter().skip(1) {
                         bounds_span = bounds_span.to(bound.span);
                     }
 
-                    let fixed_trait_snippet = fixed_traits
+                    let fixed_trait_snippet = unique_traits
                         .iter()
                         .filter_map(|b| snippet_opt(cx, b.span))
                         .collect::<Vec<_>>()

From 3e8fea612dd8ab8d03aaa264652ced97b800bb91 Mon Sep 17 00:00:00 2001
From: blyxyas <blyxyas@gmail.com>
Date: Tue, 9 May 2023 20:35:03 +0200
Subject: [PATCH 40/78] Fix config formatting, less indenting, more spacing

---
 clippy_lints/src/lib.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 8b88dab6ae6..091f30b78c8 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -483,10 +483,10 @@ pub fn explain(name: &str) {
                 .find_all(|cconf| cconf.lints.contains(&info.lint.name_lower()[8..].to_owned()))
             {
                 // If it has, print it
-                println!("### Configuration for {}:", info.lint.name_lower());
+                println!("### Configuration for {}:\n", info.lint.name_lower());
                 for position in config_vec_positions {
                     let conf = &mdconf[position];
-                    println!("    - {}: {} (default: {})", conf.name, conf.doc, conf.default);
+                    println!("  - {}: {} (default: {})", conf.name, conf.doc, conf.default);
                 }
             }
         },

From 342ce3da05eea9f119ecf367052d681a386b1761 Mon Sep 17 00:00:00 2001
From: disco07 <koneenok@outlook.fr>
Date: Tue, 9 May 2023 20:50:47 +0200
Subject: [PATCH 41/78] fix reviewer comments

---
 .../src/matches/match_like_matches.rs         |  7 +-
 .../src/matches/redundant_pattern_match.rs    |  6 +-
 .../redundant_pattern_matching_option.fixed   | 17 ++---
 tests/ui/redundant_pattern_matching_option.rs | 25 ++-----
 .../redundant_pattern_matching_option.stderr  | 66 +++++--------------
 .../redundant_pattern_matching_result.fixed   |  7 +-
 tests/ui/redundant_pattern_matching_result.rs | 19 ++++--
 .../redundant_pattern_matching_result.stderr  | 24 +++----
 8 files changed, 63 insertions(+), 108 deletions(-)

diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs
index 438d1437562..0064619ef89 100644
--- a/clippy_lints/src/matches/match_like_matches.rs
+++ b/clippy_lints/src/matches/match_like_matches.rs
@@ -183,12 +183,9 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option<bool> {
 
 fn is_some(path_kind: PatKind<'_>) -> bool {
     match path_kind {
-        PatKind::TupleStruct(QPath::Resolved(_, path), patterns, _) if is_wild(&patterns[0]) => {
+        PatKind::TupleStruct(QPath::Resolved(_, path), [first, ..], _) if is_wild(first) => {
             let name = path.segments[0].ident;
-            if name.name == rustc_span::sym::Some {
-                return true;
-            }
-            false
+            name.name == rustc_span::sym::Some
         },
         _ => false,
     }
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 28478987821..7a06443f5d9 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -188,9 +188,8 @@ fn find_sugg_for_if_let<'tcx>(
 pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
     if arms.len() == 2 {
         let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
-        let found_good_method = found_good_method(cx, arms, node_pair);
 
-        if let Some(good_method) = found_good_method {
+        if let Some(good_method) = found_good_method(cx, arms, node_pair) {
             let span = expr.span.to(op.span);
             let result_expr = match &op.kind {
                 ExprKind::AddrOf(_, _, borrowed) => borrowed,
@@ -310,6 +309,9 @@ fn get_good_method<'a>(cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath
             "Ok" => {
                 find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultOk), "is_ok()", "is_err()")
             },
+            "Err" => {
+                find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultErr), "is_err()", "is_ok()")
+            },
             "Some" => find_good_method_for_matches_macro(
                 cx,
                 arms,
diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed
index c22a4d7456e..2f907f7ae3d 100644
--- a/tests/ui/redundant_pattern_matching_option.fixed
+++ b/tests/ui/redundant_pattern_matching_option.fixed
@@ -95,15 +95,12 @@ fn issue10726() {
 
     Some(42).is_none();
 
-    Some(42).is_none();
-
-    Some(42).is_some();
-
-    None::<()>.is_none();
-
-    None::<()>.is_none();
-
-    None::<()>.is_none();
-
     None::<()>.is_some();
+
+    None::<()>.is_none();
+
+    match Some(42) {
+        Some(21) => true,
+        _ => false,
+    };
 }
diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs
index cd96e0d29a5..5e80a2b384b 100644
--- a/tests/ui/redundant_pattern_matching_option.rs
+++ b/tests/ui/redundant_pattern_matching_option.rs
@@ -111,29 +111,14 @@ fn issue10726() {
         _ => false,
     };
 
-    match Some(42) {
-        Some(_) => false,
-        _ => true,
-    };
-
     match Some(42) {
         None => true,
         _ => false,
     };
 
-    match Some(42) {
-        None => false,
-        _ => true,
-    };
-
     match None::<()> {
-        Some(_) => false,
-        _ => true,
-    };
-
-    match None::<()> {
-        Some(_) => false,
-        _ => true,
+        Some(_) => true,
+        _ => false,
     };
 
     match None::<()> {
@@ -141,8 +126,8 @@ fn issue10726() {
         _ => false,
     };
 
-    match None::<()> {
-        None => false,
-        _ => true,
+    match Some(42) {
+        Some(21) => true,
+        _ => false,
     };
 }
diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr
index d397297074b..97de2f1c86f 100644
--- a/tests/ui/redundant_pattern_matching_option.stderr
+++ b/tests/ui/redundant_pattern_matching_option.stderr
@@ -161,64 +161,28 @@ error: redundant pattern matching, consider using `is_none()`
   --> $DIR/redundant_pattern_matching_option.rs:114:5
    |
 LL | /     match Some(42) {
-LL | |         Some(_) => false,
-LL | |         _ => true,
+LL | |         None => true,
+LL | |         _ => false,
 LL | |     };
    | |_____^ help: try this: `Some(42).is_none()`
 
-error: redundant pattern matching, consider using `is_none()`
+error: redundant pattern matching, consider using `is_some()`
   --> $DIR/redundant_pattern_matching_option.rs:119:5
    |
-LL | /     match Some(42) {
-LL | |         None => true,
+LL | /     match None::<()> {
+LL | |         Some(_) => true,
 LL | |         _ => false,
-LL | |     };
-   | |_____^ help: try this: `Some(42).is_none()`
-
-error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:124:5
-   |
-LL | /     match Some(42) {
-LL | |         None => false,
-LL | |         _ => true,
-LL | |     };
-   | |_____^ help: try this: `Some(42).is_some()`
-
-error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:129:5
-   |
-LL | /     match None::<()> {
-LL | |         Some(_) => false,
-LL | |         _ => true,
-LL | |     };
-   | |_____^ help: try this: `None::<()>.is_none()`
-
-error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:134:5
-   |
-LL | /     match None::<()> {
-LL | |         Some(_) => false,
-LL | |         _ => true,
-LL | |     };
-   | |_____^ help: try this: `None::<()>.is_none()`
-
-error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:139:5
-   |
-LL | /     match None::<()> {
-LL | |         None => true,
-LL | |         _ => false,
-LL | |     };
-   | |_____^ help: try this: `None::<()>.is_none()`
-
-error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:144:5
-   |
-LL | /     match None::<()> {
-LL | |         None => false,
-LL | |         _ => true,
 LL | |     };
    | |_____^ help: try this: `None::<()>.is_some()`
 
-error: aborting due to 30 previous errors
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:124:5
+   |
+LL | /     match None::<()> {
+LL | |         None => true,
+LL | |         _ => false,
+LL | |     };
+   | |_____^ help: try this: `None::<()>.is_none()`
+
+error: aborting due to 26 previous errors
 
diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed
index a51e14a5b56..a242c38e833 100644
--- a/tests/ui/redundant_pattern_matching_result.fixed
+++ b/tests/ui/redundant_pattern_matching_result.fixed
@@ -114,7 +114,12 @@ fn issue10726() {
 
     Ok::<i32, i32>(42).is_err();
 
+    Err::<i32, i32>(42).is_ok();
+
     Err::<i32, i32>(42).is_err();
 
-    Err::<i32, i32>(42).is_ok();
+    match Ok::<i32, i32>(42) {
+        Ok(21) => true,
+        _ => false,
+    };
 }
diff --git a/tests/ui/redundant_pattern_matching_result.rs b/tests/ui/redundant_pattern_matching_result.rs
index 709e3d526a8..a4b0673ae5b 100644
--- a/tests/ui/redundant_pattern_matching_result.rs
+++ b/tests/ui/redundant_pattern_matching_result.rs
@@ -134,17 +134,22 @@ fn issue10726() {
     };
 
     match Ok::<i32, i32>(42) {
-        Ok(_) => false,
-        _ => true,
-    };
-
-    match Err::<i32, i32>(42) {
-        Ok(_) => false,
-        _ => true,
+        Err(_) => true,
+        _ => false,
     };
 
     match Err::<i32, i32>(42) {
         Ok(_) => true,
         _ => false,
     };
+
+    match Err::<i32, i32>(42) {
+        Err(_) => true,
+        _ => false,
+    };
+
+    match Ok::<i32, i32>(42) {
+        Ok(21) => true,
+        _ => false,
+    };
 }
diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr
index 0e8a983bf44..151a7440251 100644
--- a/tests/ui/redundant_pattern_matching_result.stderr
+++ b/tests/ui/redundant_pattern_matching_result.stderr
@@ -163,22 +163,13 @@ error: redundant pattern matching, consider using `is_err()`
   --> $DIR/redundant_pattern_matching_result.rs:136:5
    |
 LL | /     match Ok::<i32, i32>(42) {
-LL | |         Ok(_) => false,
-LL | |         _ => true,
+LL | |         Err(_) => true,
+LL | |         _ => false,
 LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
 
-error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:141:5
-   |
-LL | /     match Err::<i32, i32>(42) {
-LL | |         Ok(_) => false,
-LL | |         _ => true,
-LL | |     };
-   | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
-
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:146:5
+  --> $DIR/redundant_pattern_matching_result.rs:141:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -186,5 +177,14 @@ LL | |         _ => false,
 LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
 
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_result.rs:146:5
+   |
+LL | /     match Err::<i32, i32>(42) {
+LL | |         Err(_) => true,
+LL | |         _ => false,
+LL | |     };
+   | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
+
 error: aborting due to 26 previous errors
 

From 6af0359f2a8057e77b5d364e4140314e35abe5cf Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Sun, 26 Mar 2023 16:18:43 +0200
Subject: [PATCH 42/78] Drop uplifted clippy::drop_ref

---
 clippy_lints/src/declared_lints.rs  |   1 -
 clippy_lints/src/drop_forget_ref.rs |  30 +-----
 clippy_lints/src/renamed_lints.rs   |   1 +
 tests/ui/drop_forget_copy.rs        |   2 +-
 tests/ui/drop_ref.rs                |  97 ------------------
 tests/ui/drop_ref.stderr            | 147 ----------------------------
 tests/ui/rename.fixed               |   2 +
 tests/ui/rename.rs                  |   2 +
 tests/ui/rename.stderr              |  94 +++++++++---------
 9 files changed, 58 insertions(+), 318 deletions(-)
 delete mode 100644 tests/ui/drop_ref.rs
 delete mode 100644 tests/ui/drop_ref.stderr

diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 79d0f6f3607..07978d971db 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -134,7 +134,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::double_parens::DOUBLE_PARENS_INFO,
     crate::drop_forget_ref::DROP_COPY_INFO,
     crate::drop_forget_ref::DROP_NON_DROP_INFO,
-    crate::drop_forget_ref::DROP_REF_INFO,
     crate::drop_forget_ref::FORGET_COPY_INFO,
     crate::drop_forget_ref::FORGET_NON_DROP_INFO,
     crate::drop_forget_ref::FORGET_REF_INFO,
diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs
index 11e1bcdf12d..55d7c3247cd 100644
--- a/clippy_lints/src/drop_forget_ref.rs
+++ b/clippy_lints/src/drop_forget_ref.rs
@@ -7,30 +7,6 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for calls to `std::mem::drop` with a reference
-    /// instead of an owned value.
-    ///
-    /// ### Why is this bad?
-    /// Calling `drop` on a reference will only drop the
-    /// reference itself, which is a no-op. It will not call the `drop` method (from
-    /// the `Drop` trait implementation) on the underlying referenced value, which
-    /// is likely what was intended.
-    ///
-    /// ### Example
-    /// ```ignore
-    /// let mut lock_guard = mutex.lock();
-    /// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex
-    /// // still locked
-    /// operation_that_requires_mutex_to_be_unlocked();
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub DROP_REF,
-    correctness,
-    "calls to `std::mem::drop` with a reference instead of an owned value"
-}
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for calls to `std::mem::forget` with a reference
@@ -172,8 +148,6 @@ declare_clippy_lint! {
     "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value"
 }
 
-const DROP_REF_SUMMARY: &str = "calls to `std::mem::drop` with a reference instead of an owned value. \
-                                Dropping a reference does nothing";
 const FORGET_REF_SUMMARY: &str = "calls to `std::mem::forget` with a reference instead of an owned value. \
                                   Forgetting a reference does nothing";
 const DROP_COPY_SUMMARY: &str = "calls to `std::mem::drop` with a value that implements `Copy`. \
@@ -186,7 +160,6 @@ const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value t
                                    Forgetting such a type is the same as dropping it";
 
 declare_lint_pass!(DropForgetRef => [
-    DROP_REF,
     FORGET_REF,
     DROP_COPY,
     FORGET_COPY,
@@ -206,7 +179,8 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
             let is_copy = is_copy(cx, arg_ty);
             let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
             let (lint, msg) = match fn_name {
-                sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => (DROP_REF, DROP_REF_SUMMARY),
+                // early return for uplifted lints: drop_ref
+                sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return,
                 sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY),
                 sym::mem_drop if is_copy && !drop_is_single_call_in_arm => (DROP_COPY, DROP_COPY_SUMMARY),
                 sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY),
diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs
index 5e81a01a461..c55eaa809cf 100644
--- a/clippy_lints/src/renamed_lints.rs
+++ b/clippy_lints/src/renamed_lints.rs
@@ -32,6 +32,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::zero_width_space", "clippy::invisible_characters"),
     ("clippy::clone_double_ref", "suspicious_double_ref_op"),
     ("clippy::drop_bounds", "drop_bounds"),
+    ("clippy::drop_ref", "drop_ref"),
     ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
     ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
     ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
diff --git a/tests/ui/drop_forget_copy.rs b/tests/ui/drop_forget_copy.rs
index a7276dd59f4..04293eb16bb 100644
--- a/tests/ui/drop_forget_copy.rs
+++ b/tests/ui/drop_forget_copy.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::drop_copy, clippy::forget_copy)]
-#![allow(clippy::toplevel_ref_arg, clippy::drop_ref, clippy::forget_ref, unused_mut)]
+#![allow(clippy::toplevel_ref_arg, drop_ref, clippy::forget_ref, unused_mut)]
 
 use std::mem::{drop, forget};
 use std::vec::Vec;
diff --git a/tests/ui/drop_ref.rs b/tests/ui/drop_ref.rs
deleted file mode 100644
index 10044e65f11..00000000000
--- a/tests/ui/drop_ref.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-#![warn(clippy::drop_ref)]
-#![allow(clippy::toplevel_ref_arg)]
-#![allow(clippy::map_err_ignore)]
-#![allow(clippy::unnecessary_wraps, clippy::drop_non_drop)]
-
-use std::mem::drop;
-
-struct SomeStruct;
-
-fn main() {
-    drop(&SomeStruct);
-
-    let mut owned1 = SomeStruct;
-    drop(&owned1);
-    drop(&&owned1);
-    drop(&mut owned1);
-    drop(owned1); //OK
-
-    let reference1 = &SomeStruct;
-    drop(reference1);
-
-    let reference2 = &mut SomeStruct;
-    drop(reference2);
-
-    let ref reference3 = SomeStruct;
-    drop(reference3);
-}
-
-#[allow(dead_code)]
-fn test_generic_fn_drop<T>(val: T) {
-    drop(&val);
-    drop(val); //OK
-}
-
-#[allow(dead_code)]
-fn test_similarly_named_function() {
-    fn drop<T>(_val: T) {}
-    drop(&SomeStruct); //OK; call to unrelated function which happens to have the same name
-    std::mem::drop(&SomeStruct);
-}
-
-#[derive(Copy, Clone)]
-pub struct Error;
-fn produce_half_owl_error() -> Result<(), Error> {
-    Ok(())
-}
-
-fn produce_half_owl_ok() -> Result<bool, ()> {
-    Ok(true)
-}
-
-#[allow(dead_code)]
-fn test_owl_result() -> Result<(), ()> {
-    produce_half_owl_error().map_err(|_| ())?;
-    produce_half_owl_ok().map(|_| ())?;
-    // the following should not be linted,
-    // we should not force users to use toilet closures
-    // to produce owl results when drop is more convenient
-    produce_half_owl_error().map_err(drop)?;
-    produce_half_owl_ok().map_err(drop)?;
-    Ok(())
-}
-
-#[allow(dead_code)]
-fn test_owl_result_2() -> Result<u8, ()> {
-    produce_half_owl_error().map_err(|_| ())?;
-    produce_half_owl_ok().map(|_| ())?;
-    // the following should not be linted,
-    // we should not force users to use toilet closures
-    // to produce owl results when drop is more convenient
-    produce_half_owl_error().map_err(drop)?;
-    produce_half_owl_ok().map(drop)?;
-    Ok(1)
-}
-
-#[allow(unused)]
-#[allow(clippy::unit_cmp)]
-fn issue10122(x: u8) {
-    // This is a function which returns a reference and has a side-effect, which means
-    // that calling drop() on the function is considered an idiomatic way of achieving the side-effect
-    // in a match arm.
-    fn println_and<T>(t: &T) -> &T {
-        println!("foo");
-        t
-    }
-
-    match x {
-        0 => drop(println_and(&12)), // Don't lint (copy type), we only care about side-effects
-        1 => drop(println_and(&String::new())), // Don't lint (no copy type), we only care about side-effects
-        2 => {
-            drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block
-        },
-        3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
-        4 => drop(&2),                           // Lint, not a fn/method call
-        _ => (),
-    }
-}
diff --git a/tests/ui/drop_ref.stderr b/tests/ui/drop_ref.stderr
deleted file mode 100644
index 293b9f6de83..00000000000
--- a/tests/ui/drop_ref.stderr
+++ /dev/null
@@ -1,147 +0,0 @@
-error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
-  --> $DIR/drop_ref.rs:11:5
-   |
-LL |     drop(&SomeStruct);
-   |     ^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&SomeStruct`
-  --> $DIR/drop_ref.rs:11:10
-   |
-LL |     drop(&SomeStruct);
-   |          ^^^^^^^^^^^
-   = note: `-D clippy::drop-ref` implied by `-D warnings`
-
-error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
-  --> $DIR/drop_ref.rs:14:5
-   |
-LL |     drop(&owned1);
-   |     ^^^^^^^^^^^^^
-   |
-note: argument has type `&SomeStruct`
-  --> $DIR/drop_ref.rs:14:10
-   |
-LL |     drop(&owned1);
-   |          ^^^^^^^
-
-error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
-  --> $DIR/drop_ref.rs:15:5
-   |
-LL |     drop(&&owned1);
-   |     ^^^^^^^^^^^^^^
-   |
-note: argument has type `&&SomeStruct`
-  --> $DIR/drop_ref.rs:15:10
-   |
-LL |     drop(&&owned1);
-   |          ^^^^^^^^
-
-error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
-  --> $DIR/drop_ref.rs:16:5
-   |
-LL |     drop(&mut owned1);
-   |     ^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&mut SomeStruct`
-  --> $DIR/drop_ref.rs:16:10
-   |
-LL |     drop(&mut owned1);
-   |          ^^^^^^^^^^^
-
-error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
-  --> $DIR/drop_ref.rs:20:5
-   |
-LL |     drop(reference1);
-   |     ^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&SomeStruct`
-  --> $DIR/drop_ref.rs:20:10
-   |
-LL |     drop(reference1);
-   |          ^^^^^^^^^^
-
-error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
-  --> $DIR/drop_ref.rs:23:5
-   |
-LL |     drop(reference2);
-   |     ^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&mut SomeStruct`
-  --> $DIR/drop_ref.rs:23:10
-   |
-LL |     drop(reference2);
-   |          ^^^^^^^^^^
-
-error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
-  --> $DIR/drop_ref.rs:26:5
-   |
-LL |     drop(reference3);
-   |     ^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&SomeStruct`
-  --> $DIR/drop_ref.rs:26:10
-   |
-LL |     drop(reference3);
-   |          ^^^^^^^^^^
-
-error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
-  --> $DIR/drop_ref.rs:31:5
-   |
-LL |     drop(&val);
-   |     ^^^^^^^^^^
-   |
-note: argument has type `&T`
-  --> $DIR/drop_ref.rs:31:10
-   |
-LL |     drop(&val);
-   |          ^^^^
-
-error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
-  --> $DIR/drop_ref.rs:39:5
-   |
-LL |     std::mem::drop(&SomeStruct);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&SomeStruct`
-  --> $DIR/drop_ref.rs:39:20
-   |
-LL |     std::mem::drop(&SomeStruct);
-   |                    ^^^^^^^^^^^
-
-error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
-  --> $DIR/drop_ref.rs:91:13
-   |
-LL |             drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block
-   |             ^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&i32`
-  --> $DIR/drop_ref.rs:91:18
-   |
-LL |             drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block
-   |                  ^^^^^^^^^^^^^^^^
-
-error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
-  --> $DIR/drop_ref.rs:93:14
-   |
-LL |         3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
-   |              ^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&i32`
-  --> $DIR/drop_ref.rs:93:19
-   |
-LL |         3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
-   |                   ^^^^^^^^^^^^^^^^
-
-error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing
-  --> $DIR/drop_ref.rs:94:14
-   |
-LL |         4 => drop(&2),                           // Lint, not a fn/method call
-   |              ^^^^^^^^
-   |
-note: argument has type `&i32`
-  --> $DIR/drop_ref.rs:94:19
-   |
-LL |         4 => drop(&2),                           // Lint, not a fn/method call
-   |                   ^^
-
-error: aborting due to 12 previous errors
-
diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed
index 42a59f6d43d..1beb878fc75 100644
--- a/tests/ui/rename.fixed
+++ b/tests/ui/rename.fixed
@@ -29,6 +29,7 @@
 #![allow(clippy::invisible_characters)]
 #![allow(suspicious_double_ref_op)]
 #![allow(drop_bounds)]
+#![allow(drop_ref)]
 #![allow(for_loops_over_fallibles)]
 #![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
@@ -71,6 +72,7 @@
 #![warn(clippy::invisible_characters)]
 #![warn(suspicious_double_ref_op)]
 #![warn(drop_bounds)]
+#![warn(drop_ref)]
 #![warn(for_loops_over_fallibles)]
 #![warn(for_loops_over_fallibles)]
 #![warn(for_loops_over_fallibles)]
diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs
index 4d173e8cbbf..7034daffdd6 100644
--- a/tests/ui/rename.rs
+++ b/tests/ui/rename.rs
@@ -29,6 +29,7 @@
 #![allow(clippy::invisible_characters)]
 #![allow(suspicious_double_ref_op)]
 #![allow(drop_bounds)]
+#![allow(drop_ref)]
 #![allow(for_loops_over_fallibles)]
 #![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
@@ -71,6 +72,7 @@
 #![warn(clippy::zero_width_space)]
 #![warn(clippy::clone_double_ref)]
 #![warn(clippy::drop_bounds)]
+#![warn(clippy::drop_ref)]
 #![warn(clippy::for_loop_over_option)]
 #![warn(clippy::for_loop_over_result)]
 #![warn(clippy::for_loops_over_fallibles)]
diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr
index 0da4ed7520c..7cf5562a7e3 100644
--- a/tests/ui/rename.stderr
+++ b/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:44:9
+  --> $DIR/rename.rs:45:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,256 +7,262 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:45:9
+  --> $DIR/rename.rs:46:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:46:9
+  --> $DIR/rename.rs:47:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:47:9
+  --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:48:9
+  --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:50:9
+  --> $DIR/rename.rs:51:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:53:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
+error: lint `clippy::drop_ref` has been renamed to `drop_ref`
+  --> $DIR/rename.rs:75:9
+   |
+LL | #![warn(clippy::drop_ref)]
+   |         ^^^^^^^^^^^^^^^^ help: use the new name: `drop_ref`
+
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:78:9
+  --> $DIR/rename.rs:80:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:80:9
+  --> $DIR/rename.rs:82:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:81:9
+  --> $DIR/rename.rs:83:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:84:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:83:9
+  --> $DIR/rename.rs:85:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:84:9
+  --> $DIR/rename.rs:86:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:85:9
+  --> $DIR/rename.rs:87:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:86:9
+  --> $DIR/rename.rs:88:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 43 previous errors
+error: aborting due to 44 previous errors
 

From 551f6e61545fba981cb378edc066672ea3275785 Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Mon, 27 Mar 2023 21:05:43 +0200
Subject: [PATCH 43/78] Drop uplifted clippy::drop_copy

---
 clippy_lints/src/declared_lints.rs        |  1 -
 clippy_lints/src/drop_forget_ref.rs       | 29 +------
 clippy_lints/src/renamed_lints.rs         |  1 +
 tests/ui/drop_forget_copy.rs              |  2 +-
 tests/ui/drop_forget_copy.stderr          | 80 +++++++++----------
 tests/ui/multiple_unsafe_ops_per_block.rs |  2 +-
 tests/ui/rename.fixed                     |  2 +
 tests/ui/rename.rs                        |  2 +
 tests/ui/rename.stderr                    | 96 ++++++++++++-----------
 tests/ui/unknown_clippy_lints.fixed       |  2 +-
 tests/ui/unknown_clippy_lints.stderr      |  2 +-
 11 files changed, 102 insertions(+), 117 deletions(-)

diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 07978d971db..81288ca9101 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -132,7 +132,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::doc::NEEDLESS_DOCTEST_MAIN_INFO,
     crate::doc::UNNECESSARY_SAFETY_DOC_INFO,
     crate::double_parens::DOUBLE_PARENS_INFO,
-    crate::drop_forget_ref::DROP_COPY_INFO,
     crate::drop_forget_ref::DROP_NON_DROP_INFO,
     crate::drop_forget_ref::FORGET_COPY_INFO,
     crate::drop_forget_ref::FORGET_NON_DROP_INFO,
diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs
index 55d7c3247cd..9858243f339 100644
--- a/clippy_lints/src/drop_forget_ref.rs
+++ b/clippy_lints/src/drop_forget_ref.rs
@@ -29,28 +29,6 @@ declare_clippy_lint! {
     "calls to `std::mem::forget` with a reference instead of an owned value"
 }
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for calls to `std::mem::drop` with a value
-    /// that derives the Copy trait
-    ///
-    /// ### Why is this bad?
-    /// Calling `std::mem::drop` [does nothing for types that
-    /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the
-    /// value will be copied and moved into the function on invocation.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let x: i32 = 42; // i32 implements Copy
-    /// std::mem::drop(x) // A copy of x is passed to the function, leaving the
-    ///                   // original unaffected
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub DROP_COPY,
-    correctness,
-    "calls to `std::mem::drop` with a value that implements Copy"
-}
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for calls to `std::mem::forget` with a value that
@@ -150,8 +128,6 @@ declare_clippy_lint! {
 
 const FORGET_REF_SUMMARY: &str = "calls to `std::mem::forget` with a reference instead of an owned value. \
                                   Forgetting a reference does nothing";
-const DROP_COPY_SUMMARY: &str = "calls to `std::mem::drop` with a value that implements `Copy`. \
-                                 Dropping a copy leaves the original intact";
 const FORGET_COPY_SUMMARY: &str = "calls to `std::mem::forget` with a value that implements `Copy`. \
                                    Forgetting a copy leaves the original intact";
 const DROP_NON_DROP_SUMMARY: &str = "call to `std::mem::drop` with a value that does not implement `Drop`. \
@@ -161,7 +137,6 @@ const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value t
 
 declare_lint_pass!(DropForgetRef => [
     FORGET_REF,
-    DROP_COPY,
     FORGET_COPY,
     DROP_NON_DROP,
     FORGET_NON_DROP,
@@ -179,10 +154,10 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
             let is_copy = is_copy(cx, arg_ty);
             let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
             let (lint, msg) = match fn_name {
-                // early return for uplifted lints: drop_ref
+                // early return for uplifted lints: drop_ref, drop_copy
                 sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return,
                 sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY),
-                sym::mem_drop if is_copy && !drop_is_single_call_in_arm => (DROP_COPY, DROP_COPY_SUMMARY),
+                sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return,
                 sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY),
                 sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => {
                     span_lint_and_help(
diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs
index c55eaa809cf..31c9f39c9bf 100644
--- a/clippy_lints/src/renamed_lints.rs
+++ b/clippy_lints/src/renamed_lints.rs
@@ -32,6 +32,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::zero_width_space", "clippy::invisible_characters"),
     ("clippy::clone_double_ref", "suspicious_double_ref_op"),
     ("clippy::drop_bounds", "drop_bounds"),
+    ("clippy::drop_copy", "drop_copy"),
     ("clippy::drop_ref", "drop_ref"),
     ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
     ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
diff --git a/tests/ui/drop_forget_copy.rs b/tests/ui/drop_forget_copy.rs
index 04293eb16bb..f723b03a979 100644
--- a/tests/ui/drop_forget_copy.rs
+++ b/tests/ui/drop_forget_copy.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::drop_copy, clippy::forget_copy)]
+#![warn(drop_copy, clippy::forget_copy)]
 #![allow(clippy::toplevel_ref_arg, drop_ref, clippy::forget_ref, unused_mut)]
 
 use std::mem::{drop, forget};
diff --git a/tests/ui/drop_forget_copy.stderr b/tests/ui/drop_forget_copy.stderr
index 90bef1c3c43..3b19cf3968f 100644
--- a/tests/ui/drop_forget_copy.stderr
+++ b/tests/ui/drop_forget_copy.stderr
@@ -1,40 +1,3 @@
-error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
-  --> $DIR/drop_forget_copy.rs:33:5
-   |
-LL |     drop(s1);
-   |     ^^^^^^^^
-   |
-note: argument has type `SomeStruct`
-  --> $DIR/drop_forget_copy.rs:33:10
-   |
-LL |     drop(s1);
-   |          ^^
-   = note: `-D clippy::drop-copy` implied by `-D warnings`
-
-error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
-  --> $DIR/drop_forget_copy.rs:34:5
-   |
-LL |     drop(s2);
-   |     ^^^^^^^^
-   |
-note: argument has type `SomeStruct`
-  --> $DIR/drop_forget_copy.rs:34:10
-   |
-LL |     drop(s2);
-   |          ^^
-
-error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
-  --> $DIR/drop_forget_copy.rs:36:5
-   |
-LL |     drop(s4);
-   |     ^^^^^^^^
-   |
-note: argument has type `SomeStruct`
-  --> $DIR/drop_forget_copy.rs:36:10
-   |
-LL |     drop(s4);
-   |          ^^
-
 error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact
   --> $DIR/drop_forget_copy.rs:39:5
    |
@@ -72,7 +35,44 @@ note: argument has type `SomeStruct`
 LL |     forget(s4);
    |            ^^
 
-error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
+error: calls to `std::mem::drop` with a value that implements `Copy`.
+  --> $DIR/drop_forget_copy.rs:33:5
+   |
+LL |     drop(s1);
+   |     ^^^^^^^^
+   |
+note: argument has type `SomeStruct`
+  --> $DIR/drop_forget_copy.rs:33:10
+   |
+LL |     drop(s1);
+   |          ^^
+   = note: `-D drop-copy` implied by `-D warnings`
+
+error: calls to `std::mem::drop` with a value that implements `Copy`.
+  --> $DIR/drop_forget_copy.rs:34:5
+   |
+LL |     drop(s2);
+   |     ^^^^^^^^
+   |
+note: argument has type `SomeStruct`
+  --> $DIR/drop_forget_copy.rs:34:10
+   |
+LL |     drop(s2);
+   |          ^^
+
+error: calls to `std::mem::drop` with a value that implements `Copy`.
+  --> $DIR/drop_forget_copy.rs:36:5
+   |
+LL |     drop(s4);
+   |     ^^^^^^^^
+   |
+note: argument has type `SomeStruct`
+  --> $DIR/drop_forget_copy.rs:36:10
+   |
+LL |     drop(s4);
+   |          ^^
+
+error: calls to `std::mem::drop` with a value that implements `Copy`.
   --> $DIR/drop_forget_copy.rs:80:13
    |
 LL |             drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block
@@ -84,7 +84,7 @@ note: argument has type `i32`
 LL |             drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block
    |                  ^^^^^^^^^^^^^^^
 
-error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
+error: calls to `std::mem::drop` with a value that implements `Copy`.
   --> $DIR/drop_forget_copy.rs:82:14
    |
 LL |         3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
@@ -96,7 +96,7 @@ note: argument has type `i32`
 LL |         3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
    |                   ^^^^^^^^^^^^^^^
 
-error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact
+error: calls to `std::mem::drop` with a value that implements `Copy`.
   --> $DIR/drop_forget_copy.rs:83:14
    |
 LL |         4 => drop(2),                           // Lint, not a fn/method call
diff --git a/tests/ui/multiple_unsafe_ops_per_block.rs b/tests/ui/multiple_unsafe_ops_per_block.rs
index 73ef35c8c36..f28153e56b0 100644
--- a/tests/ui/multiple_unsafe_ops_per_block.rs
+++ b/tests/ui/multiple_unsafe_ops_per_block.rs
@@ -2,7 +2,7 @@
 #![allow(unused)]
 #![allow(deref_nullptr)]
 #![allow(clippy::unnecessary_operation)]
-#![allow(clippy::drop_copy)]
+#![allow(drop_copy)]
 #![warn(clippy::multiple_unsafe_ops_per_block)]
 
 extern crate proc_macros;
diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed
index 1beb878fc75..a618dcd806f 100644
--- a/tests/ui/rename.fixed
+++ b/tests/ui/rename.fixed
@@ -29,6 +29,7 @@
 #![allow(clippy::invisible_characters)]
 #![allow(suspicious_double_ref_op)]
 #![allow(drop_bounds)]
+#![allow(drop_copy)]
 #![allow(drop_ref)]
 #![allow(for_loops_over_fallibles)]
 #![allow(array_into_iter)]
@@ -72,6 +73,7 @@
 #![warn(clippy::invisible_characters)]
 #![warn(suspicious_double_ref_op)]
 #![warn(drop_bounds)]
+#![warn(drop_copy)]
 #![warn(drop_ref)]
 #![warn(for_loops_over_fallibles)]
 #![warn(for_loops_over_fallibles)]
diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs
index 7034daffdd6..bca0cba7ee8 100644
--- a/tests/ui/rename.rs
+++ b/tests/ui/rename.rs
@@ -29,6 +29,7 @@
 #![allow(clippy::invisible_characters)]
 #![allow(suspicious_double_ref_op)]
 #![allow(drop_bounds)]
+#![allow(drop_copy)]
 #![allow(drop_ref)]
 #![allow(for_loops_over_fallibles)]
 #![allow(array_into_iter)]
@@ -72,6 +73,7 @@
 #![warn(clippy::zero_width_space)]
 #![warn(clippy::clone_double_ref)]
 #![warn(clippy::drop_bounds)]
+#![warn(clippy::drop_copy)]
 #![warn(clippy::drop_ref)]
 #![warn(clippy::for_loop_over_option)]
 #![warn(clippy::for_loop_over_result)]
diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr
index 7cf5562a7e3..1f1cc932b38 100644
--- a/tests/ui/rename.stderr
+++ b/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:45:9
+  --> $DIR/rename.rs:46:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,262 +7,268 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:46:9
+  --> $DIR/rename.rs:47:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:47:9
+  --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:48:9
+  --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:50:9
+  --> $DIR/rename.rs:51:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:53:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
+error: lint `clippy::drop_copy` has been renamed to `drop_copy`
+  --> $DIR/rename.rs:76:9
+   |
+LL | #![warn(clippy::drop_copy)]
+   |         ^^^^^^^^^^^^^^^^^ help: use the new name: `drop_copy`
+
 error: lint `clippy::drop_ref` has been renamed to `drop_ref`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `drop_ref`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:78:9
+  --> $DIR/rename.rs:80:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:80:9
+  --> $DIR/rename.rs:82:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:81:9
+  --> $DIR/rename.rs:83:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:84:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:83:9
+  --> $DIR/rename.rs:85:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:84:9
+  --> $DIR/rename.rs:86:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:85:9
+  --> $DIR/rename.rs:87:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:86:9
+  --> $DIR/rename.rs:88:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:87:9
+  --> $DIR/rename.rs:89:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:88:9
+  --> $DIR/rename.rs:90:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 44 previous errors
+error: aborting due to 45 previous errors
 
diff --git a/tests/ui/unknown_clippy_lints.fixed b/tests/ui/unknown_clippy_lints.fixed
index 0c269d650c8..49c0e4dc7eb 100644
--- a/tests/ui/unknown_clippy_lints.fixed
+++ b/tests/ui/unknown_clippy_lints.fixed
@@ -10,7 +10,7 @@
 #[warn(clippy::unnecessary_cast)]
 #[warn(clippy::useless_transmute)]
 // Shouldn't suggest rustc lint name(`dead_code`)
-#[warn(clippy::drop_copy)]
+#[warn(clippy::eq_op)]
 // Shouldn't suggest removed/deprecated clippy lint name(`unused_collect`)
 #[warn(clippy::unused_self)]
 // Shouldn't suggest renamed clippy lint name(`const_static_lifetime`)
diff --git a/tests/ui/unknown_clippy_lints.stderr b/tests/ui/unknown_clippy_lints.stderr
index 421bf5ffa9a..584c428932f 100644
--- a/tests/ui/unknown_clippy_lints.stderr
+++ b/tests/ui/unknown_clippy_lints.stderr
@@ -34,7 +34,7 @@ error: unknown lint: `clippy::dead_cod`
   --> $DIR/unknown_clippy_lints.rs:13:8
    |
 LL | #[warn(clippy::dead_cod)]
-   |        ^^^^^^^^^^^^^^^^ help: did you mean: `clippy::drop_copy`
+   |        ^^^^^^^^^^^^^^^^ help: did you mean: `clippy::eq_op`
 
 error: unknown lint: `clippy::unused_colle`
   --> $DIR/unknown_clippy_lints.rs:15:8

From 22688fc91f2d8811c50518499dcfb5691c6f2588 Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Tue, 28 Mar 2023 18:40:54 +0200
Subject: [PATCH 44/78] Drop uplifted clippy::forget_ref

---
 clippy_lints/src/declared_lints.rs  |   1 -
 clippy_lints/src/drop_forget_ref.rs |  29 +-------
 clippy_lints/src/renamed_lints.rs   |   1 +
 tests/ui/drop_forget_copy.rs        |   2 +-
 tests/ui/forget_ref.rs              |  50 -------------
 tests/ui/forget_ref.stderr          | 111 ----------------------------
 tests/ui/rename.fixed               |   2 +
 tests/ui/rename.rs                  |   2 +
 tests/ui/rename.stderr              |  98 ++++++++++++------------
 9 files changed, 60 insertions(+), 236 deletions(-)
 delete mode 100644 tests/ui/forget_ref.rs
 delete mode 100644 tests/ui/forget_ref.stderr

diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 81288ca9101..255df2b7e46 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -135,7 +135,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::drop_forget_ref::DROP_NON_DROP_INFO,
     crate::drop_forget_ref::FORGET_COPY_INFO,
     crate::drop_forget_ref::FORGET_NON_DROP_INFO,
-    crate::drop_forget_ref::FORGET_REF_INFO,
     crate::drop_forget_ref::UNDROPPED_MANUALLY_DROPS_INFO,
     crate::duplicate_mod::DUPLICATE_MOD_INFO,
     crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO,
diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs
index 9858243f339..23ec7f15aaa 100644
--- a/clippy_lints/src/drop_forget_ref.rs
+++ b/clippy_lints/src/drop_forget_ref.rs
@@ -7,28 +7,6 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for calls to `std::mem::forget` with a reference
-    /// instead of an owned value.
-    ///
-    /// ### Why is this bad?
-    /// Calling `forget` on a reference will only forget the
-    /// reference itself, which is a no-op. It will not forget the underlying
-    /// referenced
-    /// value, which is likely what was intended.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let x = Box::new(1);
-    /// std::mem::forget(&x) // Should have been forget(x), x will still be dropped
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub FORGET_REF,
-    correctness,
-    "calls to `std::mem::forget` with a reference instead of an owned value"
-}
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for calls to `std::mem::forget` with a value that
@@ -126,8 +104,6 @@ declare_clippy_lint! {
     "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value"
 }
 
-const FORGET_REF_SUMMARY: &str = "calls to `std::mem::forget` with a reference instead of an owned value. \
-                                  Forgetting a reference does nothing";
 const FORGET_COPY_SUMMARY: &str = "calls to `std::mem::forget` with a value that implements `Copy`. \
                                    Forgetting a copy leaves the original intact";
 const DROP_NON_DROP_SUMMARY: &str = "call to `std::mem::drop` with a value that does not implement `Drop`. \
@@ -136,7 +112,6 @@ const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value t
                                    Forgetting such a type is the same as dropping it";
 
 declare_lint_pass!(DropForgetRef => [
-    FORGET_REF,
     FORGET_COPY,
     DROP_NON_DROP,
     FORGET_NON_DROP,
@@ -154,9 +129,9 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
             let is_copy = is_copy(cx, arg_ty);
             let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
             let (lint, msg) = match fn_name {
-                // early return for uplifted lints: drop_ref, drop_copy
+                // early return for uplifted lints: drop_ref, drop_copy, forget_ref
                 sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return,
-                sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY),
+                sym::mem_forget if arg_ty.is_ref() => return,
                 sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return,
                 sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY),
                 sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => {
diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs
index 31c9f39c9bf..d5b1883e0b2 100644
--- a/clippy_lints/src/renamed_lints.rs
+++ b/clippy_lints/src/renamed_lints.rs
@@ -37,6 +37,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
     ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
     ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
+    ("clippy::forget_ref", "forget_ref"),
     ("clippy::into_iter_on_array", "array_into_iter"),
     ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
     ("clippy::invalid_ref", "invalid_value"),
diff --git a/tests/ui/drop_forget_copy.rs b/tests/ui/drop_forget_copy.rs
index f723b03a979..ebe60ebbd30 100644
--- a/tests/ui/drop_forget_copy.rs
+++ b/tests/ui/drop_forget_copy.rs
@@ -1,5 +1,5 @@
 #![warn(drop_copy, clippy::forget_copy)]
-#![allow(clippy::toplevel_ref_arg, drop_ref, clippy::forget_ref, unused_mut)]
+#![allow(clippy::toplevel_ref_arg, drop_ref, forget_ref, unused_mut)]
 
 use std::mem::{drop, forget};
 use std::vec::Vec;
diff --git a/tests/ui/forget_ref.rs b/tests/ui/forget_ref.rs
deleted file mode 100644
index 031b415f56f..00000000000
--- a/tests/ui/forget_ref.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-#![warn(clippy::forget_ref)]
-#![allow(clippy::toplevel_ref_arg)]
-#![allow(clippy::unnecessary_wraps, clippy::forget_non_drop)]
-#![allow(clippy::borrow_deref_ref)]
-
-use std::mem::forget;
-
-struct SomeStruct;
-
-fn main() {
-    forget(&SomeStruct);
-
-    let mut owned = SomeStruct;
-    forget(&owned);
-    forget(&&owned);
-    forget(&mut owned);
-    forget(owned); //OK
-
-    let reference1 = &SomeStruct;
-    forget(&*reference1);
-
-    let reference2 = &mut SomeStruct;
-    forget(reference2);
-
-    let ref reference3 = SomeStruct;
-    forget(reference3);
-}
-
-#[allow(dead_code)]
-fn test_generic_fn_forget<T>(val: T) {
-    forget(&val);
-    forget(val); //OK
-}
-
-#[allow(dead_code)]
-fn test_similarly_named_function() {
-    fn forget<T>(_val: T) {}
-    forget(&SomeStruct); //OK; call to unrelated function which happens to have the same name
-    std::mem::forget(&SomeStruct);
-}
-
-#[derive(Copy, Clone)]
-pub struct Error;
-fn produce_half_owl_error() -> Result<(), Error> {
-    Ok(())
-}
-
-fn produce_half_owl_ok() -> Result<bool, ()> {
-    Ok(true)
-}
diff --git a/tests/ui/forget_ref.stderr b/tests/ui/forget_ref.stderr
deleted file mode 100644
index 011cdefc665..00000000000
--- a/tests/ui/forget_ref.stderr
+++ /dev/null
@@ -1,111 +0,0 @@
-error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:11:5
-   |
-LL |     forget(&SomeStruct);
-   |     ^^^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&SomeStruct`
-  --> $DIR/forget_ref.rs:11:12
-   |
-LL |     forget(&SomeStruct);
-   |            ^^^^^^^^^^^
-   = note: `-D clippy::forget-ref` implied by `-D warnings`
-
-error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:14:5
-   |
-LL |     forget(&owned);
-   |     ^^^^^^^^^^^^^^
-   |
-note: argument has type `&SomeStruct`
-  --> $DIR/forget_ref.rs:14:12
-   |
-LL |     forget(&owned);
-   |            ^^^^^^
-
-error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:15:5
-   |
-LL |     forget(&&owned);
-   |     ^^^^^^^^^^^^^^^
-   |
-note: argument has type `&&SomeStruct`
-  --> $DIR/forget_ref.rs:15:12
-   |
-LL |     forget(&&owned);
-   |            ^^^^^^^
-
-error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:16:5
-   |
-LL |     forget(&mut owned);
-   |     ^^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&mut SomeStruct`
-  --> $DIR/forget_ref.rs:16:12
-   |
-LL |     forget(&mut owned);
-   |            ^^^^^^^^^^
-
-error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:20:5
-   |
-LL |     forget(&*reference1);
-   |     ^^^^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&SomeStruct`
-  --> $DIR/forget_ref.rs:20:12
-   |
-LL |     forget(&*reference1);
-   |            ^^^^^^^^^^^^
-
-error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:23:5
-   |
-LL |     forget(reference2);
-   |     ^^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&mut SomeStruct`
-  --> $DIR/forget_ref.rs:23:12
-   |
-LL |     forget(reference2);
-   |            ^^^^^^^^^^
-
-error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:26:5
-   |
-LL |     forget(reference3);
-   |     ^^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&SomeStruct`
-  --> $DIR/forget_ref.rs:26:12
-   |
-LL |     forget(reference3);
-   |            ^^^^^^^^^^
-
-error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:31:5
-   |
-LL |     forget(&val);
-   |     ^^^^^^^^^^^^
-   |
-note: argument has type `&T`
-  --> $DIR/forget_ref.rs:31:12
-   |
-LL |     forget(&val);
-   |            ^^^^
-
-error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:39:5
-   |
-LL |     std::mem::forget(&SomeStruct);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `&SomeStruct`
-  --> $DIR/forget_ref.rs:39:22
-   |
-LL |     std::mem::forget(&SomeStruct);
-   |                      ^^^^^^^^^^^
-
-error: aborting due to 9 previous errors
-
diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed
index a618dcd806f..6cb2f82c117 100644
--- a/tests/ui/rename.fixed
+++ b/tests/ui/rename.fixed
@@ -32,6 +32,7 @@
 #![allow(drop_copy)]
 #![allow(drop_ref)]
 #![allow(for_loops_over_fallibles)]
+#![allow(forget_ref)]
 #![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
 #![allow(invalid_value)]
@@ -78,6 +79,7 @@
 #![warn(for_loops_over_fallibles)]
 #![warn(for_loops_over_fallibles)]
 #![warn(for_loops_over_fallibles)]
+#![warn(forget_ref)]
 #![warn(array_into_iter)]
 #![warn(invalid_atomic_ordering)]
 #![warn(invalid_value)]
diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs
index bca0cba7ee8..72acc312d54 100644
--- a/tests/ui/rename.rs
+++ b/tests/ui/rename.rs
@@ -32,6 +32,7 @@
 #![allow(drop_copy)]
 #![allow(drop_ref)]
 #![allow(for_loops_over_fallibles)]
+#![allow(forget_ref)]
 #![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
 #![allow(invalid_value)]
@@ -78,6 +79,7 @@
 #![warn(clippy::for_loop_over_option)]
 #![warn(clippy::for_loop_over_result)]
 #![warn(clippy::for_loops_over_fallibles)]
+#![warn(clippy::forget_ref)]
 #![warn(clippy::into_iter_on_array)]
 #![warn(clippy::invalid_atomic_ordering)]
 #![warn(clippy::invalid_ref)]
diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr
index 1f1cc932b38..2847cdbba5d 100644
--- a/tests/ui/rename.stderr
+++ b/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:46:9
+  --> $DIR/rename.rs:47:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,268 +7,274 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:47:9
+  --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:48:9
+  --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:50:9
+  --> $DIR/rename.rs:51:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:53:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `drop_copy`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `drop_copy`
 
 error: lint `clippy::drop_ref` has been renamed to `drop_ref`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `drop_ref`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:78:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:80:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:80:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
+error: lint `clippy::forget_ref` has been renamed to `forget_ref`
+  --> $DIR/rename.rs:82:9
+   |
+LL | #![warn(clippy::forget_ref)]
+   |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forget_ref`
+
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:81:9
+  --> $DIR/rename.rs:83:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:84:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:83:9
+  --> $DIR/rename.rs:85:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:84:9
+  --> $DIR/rename.rs:86:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:85:9
+  --> $DIR/rename.rs:87:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:86:9
+  --> $DIR/rename.rs:88:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:87:9
+  --> $DIR/rename.rs:89:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:88:9
+  --> $DIR/rename.rs:90:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:89:9
+  --> $DIR/rename.rs:91:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:90:9
+  --> $DIR/rename.rs:92:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 45 previous errors
+error: aborting due to 46 previous errors
 

From 35e5aac5c8f033fd89b5070e6b201f046be21862 Mon Sep 17 00:00:00 2001
From: Urgau <urgau@numericable.fr>
Date: Tue, 28 Mar 2023 19:26:35 +0200
Subject: [PATCH 45/78] Drop uplifted clippy::forget_copy

---
 clippy_lints/src/declared_lints.rs  |   1 -
 clippy_lints/src/drop_forget_ref.rs |  35 +--------
 clippy_lints/src/renamed_lints.rs   |   1 +
 tests/ui/drop_forget_copy.rs        |  86 ---------------------
 tests/ui/drop_forget_copy.stderr    | 112 ----------------------------
 tests/ui/mem_forget.rs              |   2 +-
 tests/ui/rename.fixed               |   2 +
 tests/ui/rename.rs                  |   2 +
 tests/ui/rename.stderr              | 100 +++++++++++++------------
 9 files changed, 61 insertions(+), 280 deletions(-)
 delete mode 100644 tests/ui/drop_forget_copy.rs
 delete mode 100644 tests/ui/drop_forget_copy.stderr

diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 255df2b7e46..04993e49287 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -133,7 +133,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::doc::UNNECESSARY_SAFETY_DOC_INFO,
     crate::double_parens::DOUBLE_PARENS_INFO,
     crate::drop_forget_ref::DROP_NON_DROP_INFO,
-    crate::drop_forget_ref::FORGET_COPY_INFO,
     crate::drop_forget_ref::FORGET_NON_DROP_INFO,
     crate::drop_forget_ref::UNDROPPED_MANUALLY_DROPS_INFO,
     crate::duplicate_mod::DUPLICATE_MOD_INFO,
diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs
index 23ec7f15aaa..b2f7d026cc8 100644
--- a/clippy_lints/src/drop_forget_ref.rs
+++ b/clippy_lints/src/drop_forget_ref.rs
@@ -7,34 +7,6 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for calls to `std::mem::forget` with a value that
-    /// derives the Copy trait
-    ///
-    /// ### Why is this bad?
-    /// Calling `std::mem::forget` [does nothing for types that
-    /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the
-    /// value will be copied and moved into the function on invocation.
-    ///
-    /// An alternative, but also valid, explanation is that Copy types do not
-    /// implement
-    /// the Drop trait, which means they have no destructors. Without a destructor,
-    /// there
-    /// is nothing for `std::mem::forget` to ignore.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let x: i32 = 42; // i32 implements Copy
-    /// std::mem::forget(x) // A copy of x is passed to the function, leaving the
-    ///                     // original unaffected
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub FORGET_COPY,
-    correctness,
-    "calls to `std::mem::forget` with a value that implements Copy"
-}
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for calls to `std::mem::drop` with a value that does not implement `Drop`.
@@ -104,15 +76,12 @@ declare_clippy_lint! {
     "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value"
 }
 
-const FORGET_COPY_SUMMARY: &str = "calls to `std::mem::forget` with a value that implements `Copy`. \
-                                   Forgetting a copy leaves the original intact";
 const DROP_NON_DROP_SUMMARY: &str = "call to `std::mem::drop` with a value that does not implement `Drop`. \
                                  Dropping such a type only extends its contained lifetimes";
 const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value that does not implement `Drop`. \
                                    Forgetting such a type is the same as dropping it";
 
 declare_lint_pass!(DropForgetRef => [
-    FORGET_COPY,
     DROP_NON_DROP,
     FORGET_NON_DROP,
     UNDROPPED_MANUALLY_DROPS
@@ -129,11 +98,11 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
             let is_copy = is_copy(cx, arg_ty);
             let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
             let (lint, msg) = match fn_name {
-                // early return for uplifted lints: drop_ref, drop_copy, forget_ref
+                // early return for uplifted lints: drop_ref, drop_copy, forget_ref, forget_copy
                 sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return,
                 sym::mem_forget if arg_ty.is_ref() => return,
                 sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return,
-                sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY),
+                sym::mem_forget if is_copy => return,
                 sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => {
                     span_lint_and_help(
                         cx,
diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs
index d5b1883e0b2..52e22c0c630 100644
--- a/clippy_lints/src/renamed_lints.rs
+++ b/clippy_lints/src/renamed_lints.rs
@@ -37,6 +37,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::for_loop_over_option", "for_loops_over_fallibles"),
     ("clippy::for_loop_over_result", "for_loops_over_fallibles"),
     ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
+    ("clippy::forget_copy", "forget_copy"),
     ("clippy::forget_ref", "forget_ref"),
     ("clippy::into_iter_on_array", "array_into_iter"),
     ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
diff --git a/tests/ui/drop_forget_copy.rs b/tests/ui/drop_forget_copy.rs
deleted file mode 100644
index ebe60ebbd30..00000000000
--- a/tests/ui/drop_forget_copy.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-#![warn(drop_copy, clippy::forget_copy)]
-#![allow(clippy::toplevel_ref_arg, drop_ref, forget_ref, unused_mut)]
-
-use std::mem::{drop, forget};
-use std::vec::Vec;
-
-#[derive(Copy, Clone)]
-struct SomeStruct;
-
-struct AnotherStruct {
-    x: u8,
-    y: u8,
-    z: Vec<u8>,
-}
-
-impl Clone for AnotherStruct {
-    fn clone(&self) -> AnotherStruct {
-        AnotherStruct {
-            x: self.x,
-            y: self.y,
-            z: self.z.clone(),
-        }
-    }
-}
-
-fn main() {
-    let s1 = SomeStruct {};
-    let s2 = s1;
-    let s3 = &s1;
-    let mut s4 = s1;
-    let ref s5 = s1;
-
-    drop(s1);
-    drop(s2);
-    drop(s3);
-    drop(s4);
-    drop(s5);
-
-    forget(s1);
-    forget(s2);
-    forget(s3);
-    forget(s4);
-    forget(s5);
-
-    let a1 = AnotherStruct {
-        x: 255,
-        y: 0,
-        z: vec![1, 2, 3],
-    };
-    let a2 = &a1;
-    let mut a3 = a1.clone();
-    let ref a4 = a1;
-    let a5 = a1.clone();
-
-    drop(a2);
-    drop(a3);
-    drop(a4);
-    drop(a5);
-
-    forget(a2);
-    let a3 = &a1;
-    forget(a3);
-    forget(a4);
-    let a5 = a1.clone();
-    forget(a5);
-}
-
-#[allow(unused)]
-#[allow(clippy::unit_cmp)]
-fn issue9482(x: u8) {
-    fn println_and<T>(t: T) -> T {
-        println!("foo");
-        t
-    }
-
-    match x {
-        0 => drop(println_and(12)), // Don't lint (copy type), we only care about side-effects
-        1 => drop(println_and(String::new())), // Don't lint (no copy type), we only care about side-effects
-        2 => {
-            drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block
-        },
-        3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
-        4 => drop(2),                           // Lint, not a fn/method call
-        _ => (),
-    }
-}
diff --git a/tests/ui/drop_forget_copy.stderr b/tests/ui/drop_forget_copy.stderr
deleted file mode 100644
index 3b19cf3968f..00000000000
--- a/tests/ui/drop_forget_copy.stderr
+++ /dev/null
@@ -1,112 +0,0 @@
-error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact
-  --> $DIR/drop_forget_copy.rs:39:5
-   |
-LL |     forget(s1);
-   |     ^^^^^^^^^^
-   |
-note: argument has type `SomeStruct`
-  --> $DIR/drop_forget_copy.rs:39:12
-   |
-LL |     forget(s1);
-   |            ^^
-   = note: `-D clippy::forget-copy` implied by `-D warnings`
-
-error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact
-  --> $DIR/drop_forget_copy.rs:40:5
-   |
-LL |     forget(s2);
-   |     ^^^^^^^^^^
-   |
-note: argument has type `SomeStruct`
-  --> $DIR/drop_forget_copy.rs:40:12
-   |
-LL |     forget(s2);
-   |            ^^
-
-error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact
-  --> $DIR/drop_forget_copy.rs:42:5
-   |
-LL |     forget(s4);
-   |     ^^^^^^^^^^
-   |
-note: argument has type `SomeStruct`
-  --> $DIR/drop_forget_copy.rs:42:12
-   |
-LL |     forget(s4);
-   |            ^^
-
-error: calls to `std::mem::drop` with a value that implements `Copy`.
-  --> $DIR/drop_forget_copy.rs:33:5
-   |
-LL |     drop(s1);
-   |     ^^^^^^^^
-   |
-note: argument has type `SomeStruct`
-  --> $DIR/drop_forget_copy.rs:33:10
-   |
-LL |     drop(s1);
-   |          ^^
-   = note: `-D drop-copy` implied by `-D warnings`
-
-error: calls to `std::mem::drop` with a value that implements `Copy`.
-  --> $DIR/drop_forget_copy.rs:34:5
-   |
-LL |     drop(s2);
-   |     ^^^^^^^^
-   |
-note: argument has type `SomeStruct`
-  --> $DIR/drop_forget_copy.rs:34:10
-   |
-LL |     drop(s2);
-   |          ^^
-
-error: calls to `std::mem::drop` with a value that implements `Copy`.
-  --> $DIR/drop_forget_copy.rs:36:5
-   |
-LL |     drop(s4);
-   |     ^^^^^^^^
-   |
-note: argument has type `SomeStruct`
-  --> $DIR/drop_forget_copy.rs:36:10
-   |
-LL |     drop(s4);
-   |          ^^
-
-error: calls to `std::mem::drop` with a value that implements `Copy`.
-  --> $DIR/drop_forget_copy.rs:80:13
-   |
-LL |             drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block
-   |             ^^^^^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `i32`
-  --> $DIR/drop_forget_copy.rs:80:18
-   |
-LL |             drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block
-   |                  ^^^^^^^^^^^^^^^
-
-error: calls to `std::mem::drop` with a value that implements `Copy`.
-  --> $DIR/drop_forget_copy.rs:82:14
-   |
-LL |         3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
-   |              ^^^^^^^^^^^^^^^^^^^^^
-   |
-note: argument has type `i32`
-  --> $DIR/drop_forget_copy.rs:82:19
-   |
-LL |         3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm`
-   |                   ^^^^^^^^^^^^^^^
-
-error: calls to `std::mem::drop` with a value that implements `Copy`.
-  --> $DIR/drop_forget_copy.rs:83:14
-   |
-LL |         4 => drop(2),                           // Lint, not a fn/method call
-   |              ^^^^^^^
-   |
-note: argument has type `i32`
-  --> $DIR/drop_forget_copy.rs:83:19
-   |
-LL |         4 => drop(2),                           // Lint, not a fn/method call
-   |                   ^
-
-error: aborting due to 9 previous errors
-
diff --git a/tests/ui/mem_forget.rs b/tests/ui/mem_forget.rs
index e5b35c098a2..5137448a6d4 100644
--- a/tests/ui/mem_forget.rs
+++ b/tests/ui/mem_forget.rs
@@ -5,7 +5,7 @@ use std::mem as memstuff;
 use std::mem::forget as forgetSomething;
 
 #[warn(clippy::mem_forget)]
-#[allow(clippy::forget_copy)]
+#[allow(forget_copy)]
 fn main() {
     let five: i32 = 5;
     forgetSomething(five);
diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed
index 6cb2f82c117..9036f892612 100644
--- a/tests/ui/rename.fixed
+++ b/tests/ui/rename.fixed
@@ -32,6 +32,7 @@
 #![allow(drop_copy)]
 #![allow(drop_ref)]
 #![allow(for_loops_over_fallibles)]
+#![allow(forget_copy)]
 #![allow(forget_ref)]
 #![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
@@ -79,6 +80,7 @@
 #![warn(for_loops_over_fallibles)]
 #![warn(for_loops_over_fallibles)]
 #![warn(for_loops_over_fallibles)]
+#![warn(forget_copy)]
 #![warn(forget_ref)]
 #![warn(array_into_iter)]
 #![warn(invalid_atomic_ordering)]
diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs
index 72acc312d54..43cabe810f3 100644
--- a/tests/ui/rename.rs
+++ b/tests/ui/rename.rs
@@ -32,6 +32,7 @@
 #![allow(drop_copy)]
 #![allow(drop_ref)]
 #![allow(for_loops_over_fallibles)]
+#![allow(forget_copy)]
 #![allow(forget_ref)]
 #![allow(array_into_iter)]
 #![allow(invalid_atomic_ordering)]
@@ -79,6 +80,7 @@
 #![warn(clippy::for_loop_over_option)]
 #![warn(clippy::for_loop_over_result)]
 #![warn(clippy::for_loops_over_fallibles)]
+#![warn(clippy::forget_copy)]
 #![warn(clippy::forget_ref)]
 #![warn(clippy::into_iter_on_array)]
 #![warn(clippy::invalid_atomic_ordering)]
diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr
index 2847cdbba5d..1ad7cf412c8 100644
--- a/tests/ui/rename.stderr
+++ b/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:47:9
+  --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,274 +7,280 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:48:9
+  --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:50:9
+  --> $DIR/rename.rs:51:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:53:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `drop_copy`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `drop_copy`
 
 error: lint `clippy::drop_ref` has been renamed to `drop_ref`
-  --> $DIR/rename.rs:78:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `drop_ref`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:80:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:80:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:81:9
+  --> $DIR/rename.rs:82:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
+error: lint `clippy::forget_copy` has been renamed to `forget_copy`
+  --> $DIR/rename.rs:83:9
+   |
+LL | #![warn(clippy::forget_copy)]
+   |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forget_copy`
+
 error: lint `clippy::forget_ref` has been renamed to `forget_ref`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:84:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forget_ref`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:83:9
+  --> $DIR/rename.rs:85:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:84:9
+  --> $DIR/rename.rs:86:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:85:9
+  --> $DIR/rename.rs:87:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:86:9
+  --> $DIR/rename.rs:88:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:87:9
+  --> $DIR/rename.rs:89:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:88:9
+  --> $DIR/rename.rs:90:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:89:9
+  --> $DIR/rename.rs:91:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:90:9
+  --> $DIR/rename.rs:92:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:91:9
+  --> $DIR/rename.rs:93:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:92:9
+  --> $DIR/rename.rs:94:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 46 previous errors
+error: aborting due to 47 previous errors
 

From c5d4b04dd51bc470469c72ee22816a2c634b8a3d Mon Sep 17 00:00:00 2001
From: "Samuel \"Sam\" Tardieu" <sam@rfc1149.net>
Date: Wed, 10 May 2023 21:06:36 +0200
Subject: [PATCH 46/78] needless_bool: do not simplify code if it loses
 comments

---
 clippy_lints/src/needless_bool.rs     |  5 ++---
 tests/ui/needless_bool/fixable.fixed  |  7 +++++++
 tests/ui/needless_bool/fixable.rs     |  7 +++++++
 tests/ui/needless_bool/fixable.stderr | 24 ++++++++++++------------
 4 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs
index 71281a0b40b..62af42a3961 100644
--- a/clippy_lints/src/needless_bool.rs
+++ b/clippy_lints/src/needless_bool.rs
@@ -146,7 +146,7 @@ fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool {
 impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         use self::Expression::{Bool, RetBool};
-        if e.span.from_expansion() {
+        if e.span.from_expansion() || !span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty() {
             return;
         }
         if let Some(higher::If {
@@ -209,8 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
             }
             if let Some((lhs_a, a)) = fetch_assign(then) &&
                 let Some((lhs_b, b)) = fetch_assign(r#else) &&
-                SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) &&
-                span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty()
+                SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b)
             {
                 let mut applicability = Applicability::MachineApplicable;
                 let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
diff --git a/tests/ui/needless_bool/fixable.fixed b/tests/ui/needless_bool/fixable.fixed
index f860852e7b7..bf1911881c8 100644
--- a/tests/ui/needless_bool/fixable.fixed
+++ b/tests/ui/needless_bool/fixable.fixed
@@ -63,6 +63,13 @@ fn main() {
     needless_bool2(x);
     needless_bool3(x);
     needless_bool_condition();
+
+    if a == b {
+        true
+    } else {
+        // Do not lint as this comment might be important
+        false
+    };
 }
 
 fn bool_ret3(x: bool) -> bool {
diff --git a/tests/ui/needless_bool/fixable.rs b/tests/ui/needless_bool/fixable.rs
index 6680dab5b6d..a6c465d4fbd 100644
--- a/tests/ui/needless_bool/fixable.rs
+++ b/tests/ui/needless_bool/fixable.rs
@@ -99,6 +99,13 @@ fn main() {
     needless_bool2(x);
     needless_bool3(x);
     needless_bool_condition();
+
+    if a == b {
+        true
+    } else {
+        // Do not lint as this comment might be important
+        false
+    };
 }
 
 fn bool_ret3(x: bool) -> bool {
diff --git a/tests/ui/needless_bool/fixable.stderr b/tests/ui/needless_bool/fixable.stderr
index d2c48376f76..fa906374fb3 100644
--- a/tests/ui/needless_bool/fixable.stderr
+++ b/tests/ui/needless_bool/fixable.stderr
@@ -91,7 +91,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `a < b`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:105:5
+  --> $DIR/fixable.rs:112:5
    |
 LL | /     if x {
 LL | |         return true;
@@ -101,7 +101,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `return x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:113:5
+  --> $DIR/fixable.rs:120:5
    |
 LL | /     if x {
 LL | |         return false;
@@ -111,7 +111,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `return !x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:121:5
+  --> $DIR/fixable.rs:128:5
    |
 LL | /     if x && y {
 LL | |         return true;
@@ -121,7 +121,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `return x && y`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:129:5
+  --> $DIR/fixable.rs:136:5
    |
 LL | /     if x && y {
 LL | |         return false;
@@ -131,7 +131,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `return !(x && y)`
 
 error: equality checks against true are unnecessary
-  --> $DIR/fixable.rs:137:8
+  --> $DIR/fixable.rs:144:8
    |
 LL |     if x == true {};
    |        ^^^^^^^^^ help: try simplifying it as shown: `x`
@@ -139,25 +139,25 @@ LL |     if x == true {};
    = note: `-D clippy::bool-comparison` implied by `-D warnings`
 
 error: equality checks against false can be replaced by a negation
-  --> $DIR/fixable.rs:141:8
+  --> $DIR/fixable.rs:148:8
    |
 LL |     if x == false {};
    |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 
 error: equality checks against true are unnecessary
-  --> $DIR/fixable.rs:151:8
+  --> $DIR/fixable.rs:158:8
    |
 LL |     if x == true {};
    |        ^^^^^^^^^ help: try simplifying it as shown: `x`
 
 error: equality checks against false can be replaced by a negation
-  --> $DIR/fixable.rs:152:8
+  --> $DIR/fixable.rs:159:8
    |
 LL |     if x == false {};
    |        ^^^^^^^^^^ help: try simplifying it as shown: `!x`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:161:12
+  --> $DIR/fixable.rs:168:12
    |
 LL |       } else if returns_bool() {
    |  ____________^
@@ -168,7 +168,7 @@ LL | |     };
    | |_____^ help: you can reduce it to: `{ !returns_bool() }`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:174:5
+  --> $DIR/fixable.rs:181:5
    |
 LL | /     if unsafe { no(4) } & 1 != 0 {
 LL | |         true
@@ -178,13 +178,13 @@ LL | |     };
    | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:179:30
+  --> $DIR/fixable.rs:186:30
    |
 LL |     let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0`
 
 error: this if-then-else expression returns a bool literal
-  --> $DIR/fixable.rs:182:9
+  --> $DIR/fixable.rs:189:9
    |
 LL |         if unsafe { no(4) } & 1 != 0 { true } else { false }
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`

From 0a4cfbf1f85b283586a446234b72662d32602fea Mon Sep 17 00:00:00 2001
From: Jake Swensen <jake@swensen.io>
Date: Sun, 2 Apr 2023 15:32:10 -0500
Subject: [PATCH 47/78] fix: warn on empty line outer AttrKind::DocComment

changelog: [`empty_line_after_doc_comments`]: add lint for checking
empty lines after rustdoc comments.

Fixes: #10395
---
 CHANGELOG.md                                  |   1 +
 clippy_lints/src/attrs.rs                     |  76 ++++++++--
 clippy_lints/src/declared_lints.rs            |   1 +
 tests/ui/empty_line_after_doc_comments.rs     | 132 ++++++++++++++++++
 tests/ui/empty_line_after_doc_comments.stderr |  36 +++++
 5 files changed, 238 insertions(+), 8 deletions(-)
 create mode 100644 tests/ui/empty_line_after_doc_comments.rs
 create mode 100644 tests/ui/empty_line_after_doc_comments.stderr

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10dd28a8f6a..83aaeee8c18 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4619,6 +4619,7 @@ Released 2018-09-13
 [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
 [`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop
 [`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum
+[`empty_line_after_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_doc_comments
 [`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr
 [`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop
 [`empty_structs_with_brackets`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_structs_with_brackets
diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index 751c262673b..93d88391a79 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -176,6 +176,52 @@ declare_clippy_lint! {
     "empty line after outer attribute"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for empty lines after documenation comments.
+    ///
+    /// ### Why is this bad?
+    /// The documentation comment was most likely meant to be an inner attribute or regular comment.
+    /// If it was intended to be a documentation comment, then the empty line should be removed to
+    /// be more idiomatic.
+    ///
+    /// ### Known problems
+    /// Only detects empty lines immediately following the documentation. If the doc comment is followed
+    /// by an attribute and then an empty line, this lint will not trigger. Use `empty_line_after_outer_attr`
+    /// in combination with this lint to detect both cases.
+    ///
+    /// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`).
+    ///
+    /// ### Example
+    /// ```rust
+    /// /// Some doc comment with a blank line after it.
+    ///
+    /// fn not_quite_good_code() { }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// /// Good (no blank line)
+    /// fn this_is_fine() { }
+    /// ```
+    ///
+    /// ```rust
+    /// // Good (convert to a regular comment)
+    ///
+    /// fn this_is_fine_too() { }
+    /// ```
+    ///
+    /// ```rust
+    /// //! Good (convert to a comment on an inner attribute)
+    ///
+    /// fn this_is_fine_as_well() { }
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub EMPTY_LINE_AFTER_DOC_COMMENTS,
+    nursery,
+    "empty line after documentation comments"
+}
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
@@ -604,6 +650,7 @@ impl_lint_pass!(EarlyAttributes => [
     DEPRECATED_CFG_ATTR,
     MISMATCHED_TARGET_OS,
     EMPTY_LINE_AFTER_OUTER_ATTR,
+    EMPTY_LINE_AFTER_DOC_COMMENTS,
 ]);
 
 impl EarlyLintPass for EarlyAttributes {
@@ -619,10 +666,16 @@ impl EarlyLintPass for EarlyAttributes {
     extract_msrv_attr!(EarlyContext);
 }
 
+/// Check for empty lines after outer attributes.
+///
+/// Attributes and documenation comments are both considered outer attributes
+/// by the AST. However, the average user likely considers them to be different.
+/// Checking for empty lines after each of these attributes is split into two different
+/// lints but can share the same logic.
 fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
     let mut iter = item.attrs.iter().peekable();
     while let Some(attr) = iter.next() {
-        if matches!(attr.kind, AttrKind::Normal(..))
+        if (matches!(attr.kind, AttrKind::Normal(..)) || matches!(attr.kind, AttrKind::DocComment(..)))
             && attr.style == AttrStyle::Outer
             && is_present_in_source(cx, attr.span)
         {
@@ -639,13 +692,20 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
                 let lines = without_block_comments(lines);
 
                 if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 {
-                    span_lint(
-                        cx,
-                        EMPTY_LINE_AFTER_OUTER_ATTR,
-                        begin_of_attr_to_item,
-                        "found an empty line after an outer attribute. \
-                        Perhaps you forgot to add a `!` to make it an inner attribute?",
-                    );
+                    let (lint_msg, lint_type) = match attr.kind {
+                        AttrKind::DocComment(..) => (
+                            "found an empty line after a doc comment. \
+                            Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?",
+                            EMPTY_LINE_AFTER_DOC_COMMENTS,
+                        ),
+                        AttrKind::Normal(..) => (
+                            "found an empty line after an outer attribute. \
+                            Perhaps you forgot to add a `!` to make it an inner attribute?",
+                            EMPTY_LINE_AFTER_OUTER_ATTR,
+                        ),
+                    };
+
+                    span_lint(cx, lint_type, begin_of_attr_to_item, lint_msg);
                 }
             }
         }
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index f24dab62780..260be34a795 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -48,6 +48,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::attrs::BLANKET_CLIPPY_RESTRICTION_LINTS_INFO,
     crate::attrs::DEPRECATED_CFG_ATTR_INFO,
     crate::attrs::DEPRECATED_SEMVER_INFO,
+    crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
     crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
     crate::attrs::INLINE_ALWAYS_INFO,
     crate::attrs::MISMATCHED_TARGET_OS_INFO,
diff --git a/tests/ui/empty_line_after_doc_comments.rs b/tests/ui/empty_line_after_doc_comments.rs
new file mode 100644
index 00000000000..e843770f578
--- /dev/null
+++ b/tests/ui/empty_line_after_doc_comments.rs
@@ -0,0 +1,132 @@
+//@aux-build:proc_macro_attr.rs
+#![warn(clippy::empty_line_after_doc_comments)]
+#![allow(clippy::assertions_on_constants)]
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
+
+#[macro_use]
+extern crate proc_macro_attr;
+
+mod some_mod {
+    //! This doc comment should *NOT* produce a warning
+
+    mod some_inner_mod {
+        fn some_noop() {}
+    }
+}
+
+/// This should produce a warning
+
+fn with_doc_and_newline() { assert!(true)}
+
+// This should *NOT* produce a warning
+#[crate_type = "lib"]
+
+/// some comment
+fn with_one_newline_and_comment() { assert!(true) }
+
+// This should *NOT* produce a warning
+#[crate_type = "lib"]
+/// some comment
+fn with_no_newline_and_comment() { assert!(true) }
+
+
+// This should *NOT* produce a warning
+#[crate_type = "lib"]
+
+fn with_one_newline() { assert!(true) }
+
+// This should *NOT* produce a warning
+#[crate_type = "lib"]
+
+
+fn with_two_newlines() { assert!(true) }
+
+
+// This should *NOT* produce a warning
+#[crate_type = "lib"]
+
+enum Baz {
+    One,
+    Two
+}
+
+// This should *NOT* produce a warning
+#[crate_type = "lib"]
+
+struct Foo {
+    one: isize,
+    two: isize
+}
+
+// This should *NOT* produce a warning
+#[crate_type = "lib"]
+
+mod foo {
+}
+
+/// This doc comment should produce a warning
+
+/** This is also a doc comment and should produce a warning
+ */
+
+// This should *NOT* produce a warning
+#[allow(non_camel_case_types)]
+#[allow(missing_docs)]
+#[allow(missing_docs)]
+fn three_attributes() { assert!(true) }
+
+// This should *NOT* produce a warning
+#[doc = "
+Returns the escaped value of the textual representation of
+
+"]
+pub fn function() -> bool {
+    true
+}
+
+// This should *NOT* produce a warning
+#[derive(Clone, Copy)]
+pub enum FooFighter {
+    Bar1,
+
+    Bar2,
+
+    Bar3,
+
+    Bar4
+}
+
+// This should *NOT* produce a warning because the empty line is inside a block comment
+#[crate_type = "lib"]
+/*
+
+*/
+pub struct S;
+
+// This should *NOT* produce a warning
+#[crate_type = "lib"]
+/* test */
+pub struct T;
+
+// This should *NOT* produce a warning
+// See https://github.com/rust-lang/rust-clippy/issues/5567
+#[fake_async_trait]
+pub trait Bazz {
+    fn foo() -> Vec<u8> {
+        let _i = "";
+
+
+
+        vec![]
+    }
+}
+
+#[derive(Clone, Copy)]
+#[dummy(string = "first line
+
+second line
+")]
+pub struct Args;
+
+fn main() {}
diff --git a/tests/ui/empty_line_after_doc_comments.stderr b/tests/ui/empty_line_after_doc_comments.stderr
new file mode 100644
index 00000000000..2ca1b51679e
--- /dev/null
+++ b/tests/ui/empty_line_after_doc_comments.stderr
@@ -0,0 +1,36 @@
+error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?
+  --> $DIR/empty_line_after_doc_comments.rs:18:1
+   |
+LL | / /// This should produce a warning
+LL | |
+LL | | fn with_doc_and_newline() { assert!(true)}
+   | |_
+   |
+   = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings`
+
+error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?
+  --> $DIR/empty_line_after_doc_comments.rs:68:1
+   |
+LL | / /// This doc comment should produce a warning
+LL | |
+LL | | /** This is also a doc comment and should produce a warning
+LL | |  */
+...  |
+LL | | #[allow(missing_docs)]
+LL | | fn three_attributes() { assert!(true) }
+   | |_
+
+error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?
+  --> $DIR/empty_line_after_doc_comments.rs:70:1
+   |
+LL | / /** This is also a doc comment and should produce a warning
+LL | |  */
+LL | |
+LL | | // This should *NOT* produce a warning
+...  |
+LL | | #[allow(missing_docs)]
+LL | | fn three_attributes() { assert!(true) }
+   | |_
+
+error: aborting due to 3 previous errors
+

From 3991dd10b524637a113824ac3272620bd9a1c409 Mon Sep 17 00:00:00 2001
From: disco07 <koneenok@outlook.fr>
Date: Thu, 11 May 2023 07:07:10 +0200
Subject: [PATCH 48/78] fix reviewer comments: tests results

---
 .../redundant_pattern_matching_result.fixed   | 24 +++++++----
 tests/ui/redundant_pattern_matching_result.rs | 32 ++++++++++-----
 .../redundant_pattern_matching_result.stderr  | 40 +++++++++----------
 3 files changed, 58 insertions(+), 38 deletions(-)

diff --git a/tests/ui/redundant_pattern_matching_result.fixed b/tests/ui/redundant_pattern_matching_result.fixed
index a242c38e833..e4032ae44b7 100644
--- a/tests/ui/redundant_pattern_matching_result.fixed
+++ b/tests/ui/redundant_pattern_matching_result.fixed
@@ -110,16 +110,26 @@ const fn issue6067() {
 }
 
 fn issue10726() {
-    Ok::<i32, i32>(42).is_ok();
+    // This is optional, but it makes the examples easier
+    let x: Result<i32, i32> = Ok(42);
 
-    Ok::<i32, i32>(42).is_err();
+    x.is_ok();
 
-    Err::<i32, i32>(42).is_ok();
+    x.is_err();
 
-    Err::<i32, i32>(42).is_err();
+    x.is_err();
 
-    match Ok::<i32, i32>(42) {
-        Ok(21) => true,
-        _ => false,
+    x.is_ok();
+
+    // Don't lint
+    match x {
+        Err(16) => false,
+        _ => true,
+    };
+
+    // Don't lint
+    match x {
+        Ok(16) => false,
+        _ => true,
     };
 }
diff --git a/tests/ui/redundant_pattern_matching_result.rs b/tests/ui/redundant_pattern_matching_result.rs
index a4b0673ae5b..39eb10df878 100644
--- a/tests/ui/redundant_pattern_matching_result.rs
+++ b/tests/ui/redundant_pattern_matching_result.rs
@@ -128,28 +128,38 @@ const fn issue6067() {
 }
 
 fn issue10726() {
-    match Ok::<i32, i32>(42) {
+    // This is optional, but it makes the examples easier
+    let x: Result<i32, i32> = Ok(42);
+
+    match x {
         Ok(_) => true,
         _ => false,
     };
 
-    match Ok::<i32, i32>(42) {
+    match x {
+        Ok(_) => false,
+        _ => true,
+    };
+
+    match x {
         Err(_) => true,
         _ => false,
     };
 
-    match Err::<i32, i32>(42) {
-        Ok(_) => true,
-        _ => false,
+    match x {
+        Err(_) => false,
+        _ => true,
     };
 
-    match Err::<i32, i32>(42) {
-        Err(_) => true,
-        _ => false,
+    // Don't lint
+    match x {
+        Err(16) => false,
+        _ => true,
     };
 
-    match Ok::<i32, i32>(42) {
-        Ok(21) => true,
-        _ => false,
+    // Don't lint
+    match x {
+        Ok(16) => false,
+        _ => true,
     };
 }
diff --git a/tests/ui/redundant_pattern_matching_result.stderr b/tests/ui/redundant_pattern_matching_result.stderr
index 151a7440251..5893ae4dcc4 100644
--- a/tests/ui/redundant_pattern_matching_result.stderr
+++ b/tests/ui/redundant_pattern_matching_result.stderr
@@ -151,40 +151,40 @@ LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:131:5
+  --> $DIR/redundant_pattern_matching_result.rs:134:5
    |
-LL | /     match Ok::<i32, i32>(42) {
+LL | /     match x {
 LL | |         Ok(_) => true,
 LL | |         _ => false,
 LL | |     };
-   | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
+   | |_____^ help: try this: `x.is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:136:5
+  --> $DIR/redundant_pattern_matching_result.rs:139:5
    |
-LL | /     match Ok::<i32, i32>(42) {
+LL | /     match x {
+LL | |         Ok(_) => false,
+LL | |         _ => true,
+LL | |     };
+   | |_____^ help: try this: `x.is_err()`
+
+error: redundant pattern matching, consider using `is_err()`
+  --> $DIR/redundant_pattern_matching_result.rs:144:5
+   |
+LL | /     match x {
 LL | |         Err(_) => true,
 LL | |         _ => false,
 LL | |     };
-   | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
+   | |_____^ help: try this: `x.is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching_result.rs:141:5
+  --> $DIR/redundant_pattern_matching_result.rs:149:5
    |
-LL | /     match Err::<i32, i32>(42) {
-LL | |         Ok(_) => true,
-LL | |         _ => false,
+LL | /     match x {
+LL | |         Err(_) => false,
+LL | |         _ => true,
 LL | |     };
-   | |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
-
-error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching_result.rs:146:5
-   |
-LL | /     match Err::<i32, i32>(42) {
-LL | |         Err(_) => true,
-LL | |         _ => false,
-LL | |     };
-   | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
+   | |_____^ help: try this: `x.is_ok()`
 
 error: aborting due to 26 previous errors
 

From c53ceba56f0b0ec5d3ee20a19f0f6aace6d26228 Mon Sep 17 00:00:00 2001
From: disco07 <koneenok@outlook.fr>
Date: Thu, 11 May 2023 07:20:02 +0200
Subject: [PATCH 49/78] update tests

---
 .../redundant_pattern_matching_option.fixed   | 14 +++++++----
 tests/ui/redundant_pattern_matching_option.rs | 14 +++++++----
 .../redundant_pattern_matching_option.stderr  | 24 +++++++++----------
 3 files changed, 30 insertions(+), 22 deletions(-)

diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed
index 2f907f7ae3d..94c89049189 100644
--- a/tests/ui/redundant_pattern_matching_option.fixed
+++ b/tests/ui/redundant_pattern_matching_option.fixed
@@ -91,15 +91,19 @@ fn issue7921() {
 }
 
 fn issue10726() {
-    Some(42).is_some();
+    let x = Some(42);
+    let y = None::<()>;
 
-    Some(42).is_none();
+    x.is_some();
 
-    None::<()>.is_some();
+    x.is_none();
 
-    None::<()>.is_none();
+    y.is_some();
 
-    match Some(42) {
+    y.is_none();
+
+    // Don't lint
+    match x {
         Some(21) => true,
         _ => false,
     };
diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs
index 5e80a2b384b..303a0280e9d 100644
--- a/tests/ui/redundant_pattern_matching_option.rs
+++ b/tests/ui/redundant_pattern_matching_option.rs
@@ -106,27 +106,31 @@ fn issue7921() {
 }
 
 fn issue10726() {
-    match Some(42) {
+    let x = Some(42);
+    let y = None::<()>;
+
+    match x {
         Some(_) => true,
         _ => false,
     };
 
-    match Some(42) {
+    match x {
         None => true,
         _ => false,
     };
 
-    match None::<()> {
+    match y {
         Some(_) => true,
         _ => false,
     };
 
-    match None::<()> {
+    match y {
         None => true,
         _ => false,
     };
 
-    match Some(42) {
+    // Don't lint
+    match x {
         Some(21) => true,
         _ => false,
     };
diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr
index 97de2f1c86f..eb4d87ba2b5 100644
--- a/tests/ui/redundant_pattern_matching_option.stderr
+++ b/tests/ui/redundant_pattern_matching_option.stderr
@@ -149,40 +149,40 @@ LL |     if let None = *&None::<()> {}
    |     -------^^^^--------------- help: try this: `if (&None::<()>).is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:109:5
+  --> $DIR/redundant_pattern_matching_option.rs:112:5
    |
-LL | /     match Some(42) {
+LL | /     match x {
 LL | |         Some(_) => true,
 LL | |         _ => false,
 LL | |     };
-   | |_____^ help: try this: `Some(42).is_some()`
+   | |_____^ help: try this: `x.is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:114:5
+  --> $DIR/redundant_pattern_matching_option.rs:117:5
    |
-LL | /     match Some(42) {
+LL | /     match x {
 LL | |         None => true,
 LL | |         _ => false,
 LL | |     };
-   | |_____^ help: try this: `Some(42).is_none()`
+   | |_____^ help: try this: `x.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:119:5
+  --> $DIR/redundant_pattern_matching_option.rs:122:5
    |
-LL | /     match None::<()> {
+LL | /     match y {
 LL | |         Some(_) => true,
 LL | |         _ => false,
 LL | |     };
-   | |_____^ help: try this: `None::<()>.is_some()`
+   | |_____^ help: try this: `y.is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:124:5
+  --> $DIR/redundant_pattern_matching_option.rs:127:5
    |
-LL | /     match None::<()> {
+LL | /     match y {
 LL | |         None => true,
 LL | |         _ => false,
 LL | |     };
-   | |_____^ help: try this: `None::<()>.is_none()`
+   | |_____^ help: try this: `y.is_none()`
 
 error: aborting due to 26 previous errors
 

From a8834bc46ab948c8978b5fcbe0a7aa4760783338 Mon Sep 17 00:00:00 2001
From: Icxolu <10486322+Icxolu@users.noreply.github.com>
Date: Thu, 4 May 2023 22:44:35 +0200
Subject: [PATCH 50/78] add lint `manual_next_back`

checks for manual reverse iteration (`.rev().next()`) of a
`DoubleEndedIterator`
---
 CHANGELOG.md                                 |  1 +
 clippy_lints/src/declared_lints.rs           |  1 +
 clippy_lints/src/methods/manual_next_back.rs | 38 ++++++++++++++++++++
 clippy_lints/src/methods/mod.rs              | 26 ++++++++++++++
 tests/ui/manual_next_back.fixed              | 36 +++++++++++++++++++
 tests/ui/manual_next_back.rs                 | 36 +++++++++++++++++++
 tests/ui/manual_next_back.stderr             | 16 +++++++++
 7 files changed, 154 insertions(+)
 create mode 100644 clippy_lints/src/methods/manual_next_back.rs
 create mode 100644 tests/ui/manual_next_back.fixed
 create mode 100644 tests/ui/manual_next_back.rs
 create mode 100644 tests/ui/manual_next_back.stderr

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 85d451a87d0..4cb937e8766 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4785,6 +4785,7 @@ Released 2018-09-13
 [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str
 [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
 [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
+[`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back
 [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
 [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
 [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 6614b99713a..982d5a802f5 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -351,6 +351,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::ITER_WITH_DRAIN_INFO,
     crate::methods::MANUAL_FILTER_MAP_INFO,
     crate::methods::MANUAL_FIND_MAP_INFO,
+    crate::methods::MANUAL_NEXT_BACK_INFO,
     crate::methods::MANUAL_OK_OR_INFO,
     crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO,
     crate::methods::MANUAL_SPLIT_ONCE_INFO,
diff --git a/clippy_lints/src/methods/manual_next_back.rs b/clippy_lints/src/methods/manual_next_back.rs
new file mode 100644
index 00000000000..5f3fec53827
--- /dev/null
+++ b/clippy_lints/src/methods/manual_next_back.rs
@@ -0,0 +1,38 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_trait_method;
+use clippy_utils::ty::implements_trait;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    rev_call: &'tcx Expr<'_>,
+    rev_recv: &'tcx Expr<'_>,
+) {
+    let rev_recv_ty = cx.typeck_results().expr_ty(rev_recv);
+
+    // check that the receiver of `rev` implements `DoubleEndedIterator` and
+    // that `rev` and `next` come from `Iterator`
+    if cx
+        .tcx
+        .get_diagnostic_item(sym::DoubleEndedIterator)
+        .map_or(false, |double_ended_iterator| {
+            implements_trait(cx, rev_recv_ty, double_ended_iterator, &[])
+        })
+        && is_trait_method(cx, rev_call, sym::Iterator)
+        && is_trait_method(cx, expr, sym::Iterator)
+    {
+        span_lint_and_sugg(
+            cx,
+            super::MANUAL_NEXT_BACK,
+            expr.span.with_lo(rev_recv.span.hi()),
+            "manual backwards iteration",
+            "use",
+            String::from(".next_back()"),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 06b88e34d24..cb86917464b 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -45,6 +45,7 @@ mod iter_overeager_cloned;
 mod iter_skip_next;
 mod iter_with_drain;
 mod iterator_step_by_zero;
+mod manual_next_back;
 mod manual_ok_or;
 mod manual_saturating_arithmetic;
 mod manual_str_repeat;
@@ -3193,6 +3194,29 @@ declare_clippy_lint! {
     "calling `drain` in order to `clear` a container"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `.rev().next()` on a `DoubleEndedIterator`
+    ///
+    /// ### Why is this bad?
+    /// `.next_back()` is cleaner.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let foo = [0; 10];
+    /// foo.iter().rev().next();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # let foo = [0; 10];
+    /// foo.iter().next_back();
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub MANUAL_NEXT_BACK,
+    style,
+    "manual reverse iteration of `DoubleEndedIterator`"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -3321,6 +3345,7 @@ impl_lint_pass!(Methods => [
     NEEDLESS_COLLECT,
     SUSPICIOUS_COMMAND_ARG_SPACE,
     CLEAR_WITH_DRAIN,
+    MANUAL_NEXT_BACK,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -3677,6 +3702,7 @@ impl Methods {
                             ("iter", []) => iter_next_slice::check(cx, expr, recv2),
                             ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
                             ("skip_while", [_]) => skip_while_next::check(cx, expr),
+                            ("rev", [])=> manual_next_back::check(cx, expr, recv, recv2),
                             _ => {},
                         }
                     }
diff --git a/tests/ui/manual_next_back.fixed b/tests/ui/manual_next_back.fixed
new file mode 100644
index 00000000000..e8a47063ad6
--- /dev/null
+++ b/tests/ui/manual_next_back.fixed
@@ -0,0 +1,36 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::manual_next_back)]
+
+struct FakeIter(std::ops::Range<i32>);
+
+impl FakeIter {
+    fn rev(self) -> Self {
+        self
+    }
+
+    fn next(&self) {}
+}
+
+impl DoubleEndedIterator for FakeIter {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        self.0.next_back()
+    }
+}
+
+impl Iterator for FakeIter {
+    type Item = i32;
+    fn next(&mut self) -> Option<Self::Item> {
+        self.0.next()
+    }
+}
+
+fn main() {
+    // should not lint
+    FakeIter(0..10).rev().next();
+
+    // should lint
+    let _ = (0..10).next_back().unwrap();
+    let _ = "something".bytes().next_back();
+}
diff --git a/tests/ui/manual_next_back.rs b/tests/ui/manual_next_back.rs
new file mode 100644
index 00000000000..9ec89242241
--- /dev/null
+++ b/tests/ui/manual_next_back.rs
@@ -0,0 +1,36 @@
+//@run-rustfix
+
+#![allow(unused)]
+#![warn(clippy::manual_next_back)]
+
+struct FakeIter(std::ops::Range<i32>);
+
+impl FakeIter {
+    fn rev(self) -> Self {
+        self
+    }
+
+    fn next(&self) {}
+}
+
+impl DoubleEndedIterator for FakeIter {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        self.0.next_back()
+    }
+}
+
+impl Iterator for FakeIter {
+    type Item = i32;
+    fn next(&mut self) -> Option<Self::Item> {
+        self.0.next()
+    }
+}
+
+fn main() {
+    // should not lint
+    FakeIter(0..10).rev().next();
+
+    // should lint
+    let _ = (0..10).rev().next().unwrap();
+    let _ = "something".bytes().rev().next();
+}
diff --git a/tests/ui/manual_next_back.stderr b/tests/ui/manual_next_back.stderr
new file mode 100644
index 00000000000..94ccaa9e4cc
--- /dev/null
+++ b/tests/ui/manual_next_back.stderr
@@ -0,0 +1,16 @@
+error: manual backwards iteration
+  --> $DIR/manual_next_back.rs:34:20
+   |
+LL |     let _ = (0..10).rev().next().unwrap();
+   |                    ^^^^^^^^^^^^^ help: use: `.next_back()`
+   |
+   = note: `-D clippy::manual-next-back` implied by `-D warnings`
+
+error: manual backwards iteration
+  --> $DIR/manual_next_back.rs:35:32
+   |
+LL |     let _ = "something".bytes().rev().next();
+   |                                ^^^^^^^^^^^^^ help: use: `.next_back()`
+
+error: aborting due to 2 previous errors
+

From 8100a8843bf0e1708ad97cbfb3f4a657b718df73 Mon Sep 17 00:00:00 2001
From: Takayuki Nakata <f.seasons017@gmail.com>
Date: Fri, 12 May 2023 22:39:33 +0900
Subject: [PATCH 51/78] Update actions/checkout

---
 .github/workflows/clippy.yml      |  2 +-
 .github/workflows/clippy_bors.yml | 10 +++++-----
 .github/workflows/clippy_dev.yml  |  2 +-
 .github/workflows/deploy.yml      |  4 ++--
 .github/workflows/remark.yml      |  2 +-
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml
index b9921301197..a9d42159c4b 100644
--- a/.github/workflows/clippy.yml
+++ b/.github/workflows/clippy.yml
@@ -39,7 +39,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v3.0.2
+      uses: actions/checkout@v3
 
     - name: Install toolchain
       run: rustup show active-toolchain
diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml
index 93198aabdb5..30a156c925b 100644
--- a/.github/workflows/clippy_bors.yml
+++ b/.github/workflows/clippy_bors.yml
@@ -27,7 +27,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v3.0.2
+      uses: actions/checkout@v3
       with:
         ref: ${{ github.ref }}
 
@@ -83,7 +83,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v3.0.2
+      uses: actions/checkout@v3
 
     - name: Install toolchain
       run: rustup show active-toolchain
@@ -149,7 +149,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v3.0.2
+      uses: actions/checkout@v3
 
     - name: Install toolchain
       run: rustup show active-toolchain
@@ -173,7 +173,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v3.0.2
+      uses: actions/checkout@v3
 
     - name: Install toolchain
       run: rustup show active-toolchain
@@ -233,7 +233,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v3.0.2
+      uses: actions/checkout@v3
 
     - name: Install toolchain
       run: rustup show active-toolchain
diff --git a/.github/workflows/clippy_dev.yml b/.github/workflows/clippy_dev.yml
index 14f20212add..514706d64c8 100644
--- a/.github/workflows/clippy_dev.yml
+++ b/.github/workflows/clippy_dev.yml
@@ -25,7 +25,7 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v3.0.2
+      uses: actions/checkout@v3
 
     # Run
     - name: Build
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 71d71d10359..f42928c2cd1 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -21,10 +21,10 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v3.0.2
+      uses: actions/checkout@v3
 
     - name: Checkout
-      uses: actions/checkout@v3.0.2
+      uses: actions/checkout@v3
       with:
         ref: ${{ env.TARGET_BRANCH }}
         path: 'out'
diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml
index 0bc2f49f5e9..69be130804d 100644
--- a/.github/workflows/remark.yml
+++ b/.github/workflows/remark.yml
@@ -16,7 +16,7 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v3.0.2
+      uses: actions/checkout@v3
 
     - name: Setup Node.js
       uses: actions/setup-node@v1.4.4

From fce41cef7f6ef241c78c967033924cb0b08552a8 Mon Sep 17 00:00:00 2001
From: Takayuki Nakata <f.seasons017@gmail.com>
Date: Fri, 12 May 2023 23:05:20 +0900
Subject: [PATCH 52/78] Update actions/setup-node

---
 .github/workflows/remark.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml
index 69be130804d..7d25b6a2b79 100644
--- a/.github/workflows/remark.yml
+++ b/.github/workflows/remark.yml
@@ -19,7 +19,7 @@ jobs:
       uses: actions/checkout@v3
 
     - name: Setup Node.js
-      uses: actions/setup-node@v1.4.4
+      uses: actions/setup-node@v3
       with:
         node-version: '14.x'
 

From 891fffef0ced6a62406db1b9c7742cc064af96ba Mon Sep 17 00:00:00 2001
From: Caio <c410.f3r@gmail.com>
Date: Sat, 13 May 2023 23:24:33 -0300
Subject: [PATCH 53/78] Consider referenced allowed or hard-coded types

---
 clippy_lints/src/operators/arithmetic_side_effects.rs | 10 +++++-----
 tests/ui/arithmetic_side_effects.rs                   |  8 ++++++++
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs
index f72595987ee..c80e2ff7057 100644
--- a/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -21,7 +21,7 @@ const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[
     ["f64", "f64"],
     ["std::num::Saturating", "std::num::Saturating"],
     ["std::num::Wrapping", "std::num::Wrapping"],
-    ["std::string::String", "&str"],
+    ["std::string::String", "str"],
 ];
 const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"];
 const INTEGER_METHODS: &[&str] = &["saturating_div", "wrapping_div", "wrapping_rem", "wrapping_rem_euclid"];
@@ -144,8 +144,10 @@ impl ArithmeticSideEffects {
         ) {
             return;
         };
-        let lhs_ty = cx.typeck_results().expr_ty(lhs);
-        let rhs_ty = cx.typeck_results().expr_ty(rhs);
+        let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
+        let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
+        let lhs_ty = cx.typeck_results().expr_ty(actual_lhs).peel_refs();
+        let rhs_ty = cx.typeck_results().expr_ty(actual_rhs).peel_refs();
         if self.has_allowed_binary(lhs_ty, rhs_ty) {
             return;
         }
@@ -154,8 +156,6 @@ impl ArithmeticSideEffects {
                 // At least for integers, shifts are already handled by the CTFE
                 return;
             }
-            let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
-            let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
             match (
                 Self::literal_integer(cx, actual_lhs),
                 Self::literal_integer(cx, actual_rhs),
diff --git a/tests/ui/arithmetic_side_effects.rs b/tests/ui/arithmetic_side_effects.rs
index ab408bdf261..f95af1017bc 100644
--- a/tests/ui/arithmetic_side_effects.rs
+++ b/tests/ui/arithmetic_side_effects.rs
@@ -458,4 +458,12 @@ pub fn issue_10583(a: u16) -> u16 {
     10 / a
 }
 
+pub fn issue_10767() {
+    let n = &1.0;
+    n + n;
+    3.1_f32 + &1.2_f32;
+    &3.4_f32 + 1.5_f32;
+    &3.5_f32 + &1.3_f32;
+}
+
 fn main() {}

From e234dfa63ea36ac2d9ecf245e681b1dbac644140 Mon Sep 17 00:00:00 2001
From: Renato Lochetti <renato.lochetti@gmail.com>
Date: Sun, 14 May 2023 10:26:48 +0100
Subject: [PATCH 54/78] Ignoring `let_underscore_untyped` warnings in code from
 proc macros

---
 clippy_lints/src/let_underscore.rs     | 26 ++++++++++++++++----------
 tests/ui/let_underscore_untyped.rs     | 14 ++++++++++++++
 tests/ui/let_underscore_untyped.stderr | 20 ++++++++++----------
 3 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs
index 16772a9d598..20a675d053e 100644
--- a/clippy_lints/src/let_underscore.rs
+++ b/clippy_lints/src/let_underscore.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
 use clippy_utils::{is_must_use_func_call, paths};
 use rustc_hir::{ExprKind, Local, PatKind};
@@ -138,7 +139,7 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [
 ];
 
 impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &Local<'tcx>) {
         if !in_external_macro(cx.tcx.sess, local.span)
             && let PatKind::Wild = local.pat.kind
             && let Some(init) = local.init
@@ -191,15 +192,20 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
             if local.pat.default_binding_modes && local.ty.is_none() {
                 // When `default_binding_modes` is true, the `let` keyword is present.
 
-				// Ignore function calls that return impl traits...
-				if let Some(init) = local.init &&
-				matches!(init.kind, ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _)) {
-					let expr_ty = cx.typeck_results().expr_ty(init);
-					if expr_ty.is_impl_trait() {
-						return;
-					}
-				}
-
+				if let Some(init) = local.init {
+                    // Ignore function calls that return impl traits...
+                    if matches!(init.kind, ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _)) {
+                        let expr_ty = cx.typeck_results().expr_ty(init);
+                        if expr_ty.is_impl_trait() {
+                            return;
+                        }
+                    }
+    
+                    // Ignore if it is from a procedural macro...
+                    if is_from_proc_macro(cx, init) {
+                        return;
+                    }
+                }
 
 				span_lint_and_help(
                     cx,
diff --git a/tests/ui/let_underscore_untyped.rs b/tests/ui/let_underscore_untyped.rs
index 8486137d3a6..05ecd9b281a 100644
--- a/tests/ui/let_underscore_untyped.rs
+++ b/tests/ui/let_underscore_untyped.rs
@@ -1,6 +1,12 @@
+//@aux-build: proc_macros.rs
+
 #![allow(unused)]
 #![warn(clippy::let_underscore_untyped)]
 
+extern crate proc_macros;
+use proc_macros::with_span;
+
+use clippy_utils::is_from_proc_macro;
 use std::future::Future;
 use std::{boxed::Box, fmt::Display};
 
@@ -32,6 +38,14 @@ fn g() -> impl Fn() {
     || {}
 }
 
+with_span!(
+    span
+
+    fn dont_lint_proc_macro() {
+        let _ = a();
+    }
+);
+
 fn main() {
     let _ = a();
     let _ = b(1);
diff --git a/tests/ui/let_underscore_untyped.stderr b/tests/ui/let_underscore_untyped.stderr
index 6844cb998f7..bbf2508af10 100644
--- a/tests/ui/let_underscore_untyped.stderr
+++ b/tests/ui/let_underscore_untyped.stderr
@@ -1,60 +1,60 @@
 error: non-binding `let` without a type annotation
-  --> $DIR/let_underscore_untyped.rs:36:5
+  --> $DIR/let_underscore_untyped.rs:50:5
    |
 LL |     let _ = a();
    |     ^^^^^^^^^^^^
    |
 help: consider adding a type annotation
-  --> $DIR/let_underscore_untyped.rs:36:10
+  --> $DIR/let_underscore_untyped.rs:50:10
    |
 LL |     let _ = a();
    |          ^
    = note: `-D clippy::let-underscore-untyped` implied by `-D warnings`
 
 error: non-binding `let` without a type annotation
-  --> $DIR/let_underscore_untyped.rs:37:5
+  --> $DIR/let_underscore_untyped.rs:51:5
    |
 LL |     let _ = b(1);
    |     ^^^^^^^^^^^^^
    |
 help: consider adding a type annotation
-  --> $DIR/let_underscore_untyped.rs:37:10
+  --> $DIR/let_underscore_untyped.rs:51:10
    |
 LL |     let _ = b(1);
    |          ^
 
 error: non-binding `let` without a type annotation
-  --> $DIR/let_underscore_untyped.rs:39:5
+  --> $DIR/let_underscore_untyped.rs:53:5
    |
 LL |     let _ = d(&1);
    |     ^^^^^^^^^^^^^^
    |
 help: consider adding a type annotation
-  --> $DIR/let_underscore_untyped.rs:39:10
+  --> $DIR/let_underscore_untyped.rs:53:10
    |
 LL |     let _ = d(&1);
    |          ^
 
 error: non-binding `let` without a type annotation
-  --> $DIR/let_underscore_untyped.rs:40:5
+  --> $DIR/let_underscore_untyped.rs:54:5
    |
 LL |     let _ = e();
    |     ^^^^^^^^^^^^
    |
 help: consider adding a type annotation
-  --> $DIR/let_underscore_untyped.rs:40:10
+  --> $DIR/let_underscore_untyped.rs:54:10
    |
 LL |     let _ = e();
    |          ^
 
 error: non-binding `let` without a type annotation
-  --> $DIR/let_underscore_untyped.rs:41:5
+  --> $DIR/let_underscore_untyped.rs:55:5
    |
 LL |     let _ = f();
    |     ^^^^^^^^^^^^
    |
 help: consider adding a type annotation
-  --> $DIR/let_underscore_untyped.rs:41:10
+  --> $DIR/let_underscore_untyped.rs:55:10
    |
 LL |     let _ = f();
    |          ^

From df200aaf39184258ad2fb5d2d9a4682fb069bbd5 Mon Sep 17 00:00:00 2001
From: Renato Lochetti <renato.lochetti@gmail.com>
Date: Sun, 14 May 2023 10:38:32 +0100
Subject: [PATCH 55/78] fixing fmt

---
 clippy_lints/src/let_underscore.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs
index 20a675d053e..0596ea732f3 100644
--- a/clippy_lints/src/let_underscore.rs
+++ b/clippy_lints/src/let_underscore.rs
@@ -200,7 +200,6 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                             return;
                         }
                     }
-    
                     // Ignore if it is from a procedural macro...
                     if is_from_proc_macro(cx, init) {
                         return;

From 493b2ae8dc8f077a4a54fa5f9aca095dedb15e73 Mon Sep 17 00:00:00 2001
From: Caio <c410.f3r@gmail.com>
Date: Sun, 14 May 2023 08:37:12 -0300
Subject: [PATCH 56/78] Rename integer_arithmetic

---
 clippy_lints/src/declared_lints.rs            |   1 -
 clippy_lints/src/operators/mod.rs             |  27 ---
 .../src/operators/numeric_arithmetic.rs       |  45 +----
 clippy_lints/src/renamed_lints.rs             |   1 +
 tests/ui/float_arithmetic.rs                  |   2 +-
 tests/ui/integer_arithmetic.rs                | 109 -----------
 tests/ui/integer_arithmetic.stderr            | 169 ------------------
 tests/ui/needless_return.fixed                |   5 +-
 tests/ui/needless_return.rs                   |   5 +-
 tests/ui/needless_return.stderr               |  26 +--
 tests/ui/rename.fixed                         |   2 +
 tests/ui/rename.rs                            |   2 +
 tests/ui/rename.stderr                        |  94 +++++-----
 13 files changed, 81 insertions(+), 407 deletions(-)
 delete mode 100644 tests/ui/integer_arithmetic.rs
 delete mode 100644 tests/ui/integer_arithmetic.stderr

diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index a3a6f1746bc..40c64efaa37 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -491,7 +491,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::operators::FLOAT_EQUALITY_WITHOUT_ABS_INFO,
     crate::operators::IDENTITY_OP_INFO,
     crate::operators::INEFFECTIVE_BIT_MASK_INFO,
-    crate::operators::INTEGER_ARITHMETIC_INFO,
     crate::operators::INTEGER_DIVISION_INFO,
     crate::operators::MISREFACTORED_ASSIGN_OP_INFO,
     crate::operators::MODULO_ARITHMETIC_INFO,
diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs
index 19599731bd6..d63a836e73d 100644
--- a/clippy_lints/src/operators/mod.rs
+++ b/clippy_lints/src/operators/mod.rs
@@ -96,32 +96,6 @@ declare_clippy_lint! {
     "any arithmetic expression that can cause side effects like overflows or panics"
 }
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for integer arithmetic operations which could overflow or panic.
-    ///
-    /// Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable
-    /// of overflowing according to the [Rust
-    /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
-    /// or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is
-    /// attempted.
-    ///
-    /// ### Why is this bad?
-    /// Integer overflow will trigger a panic in debug builds or will wrap in
-    /// release mode. Division by zero will cause a panic in either mode. In some applications one
-    /// wants explicitly checked, wrapping or saturating arithmetic.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # let a = 0;
-    /// a + 1;
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub INTEGER_ARITHMETIC,
-    restriction,
-    "any integer arithmetic expression which could overflow or panic"
-}
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for float arithmetic.
@@ -787,7 +761,6 @@ pub struct Operators {
 impl_lint_pass!(Operators => [
     ABSURD_EXTREME_COMPARISONS,
     ARITHMETIC_SIDE_EFFECTS,
-    INTEGER_ARITHMETIC,
     FLOAT_ARITHMETIC,
     ASSIGN_OP_PATTERN,
     MISREFACTORED_ASSIGN_OP,
diff --git a/clippy_lints/src/operators/numeric_arithmetic.rs b/clippy_lints/src/operators/numeric_arithmetic.rs
index 77fd45b199a..102845ceed0 100644
--- a/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -1,8 +1,6 @@
-use super::{FLOAT_ARITHMETIC, INTEGER_ARITHMETIC};
+use super::FLOAT_ARITHMETIC;
 use clippy_utils::consts::constant_simple;
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_from_proc_macro;
-use clippy_utils::is_integer_literal;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::source_map::Span;
@@ -45,31 +43,8 @@ impl Context {
             _ => (),
         }
 
-        let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r));
-        if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() {
-            if is_from_proc_macro(cx, expr) {
-                return;
-            }
-            match op {
-                hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind {
-                    hir::ExprKind::Lit(_lit) => (),
-                    hir::ExprKind::Unary(hir::UnOp::Neg, expr) => {
-                        if is_integer_literal(expr, 1) {
-                            span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
-                            self.expr_id = Some(expr.hir_id);
-                        }
-                    },
-                    _ => {
-                        span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
-                        self.expr_id = Some(expr.hir_id);
-                    },
-                },
-                _ => {
-                    span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
-                    self.expr_id = Some(expr.hir_id);
-                },
-            }
-        } else if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() {
+        let (_, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r));
+        if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() {
             span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
             self.expr_id = Some(expr.hir_id);
         }
@@ -80,17 +55,9 @@ impl Context {
             return;
         }
         let ty = cx.typeck_results().expr_ty(arg);
-        if constant_simple(cx, cx.typeck_results(), expr).is_none() {
-            if ty.is_integral() {
-                if is_from_proc_macro(cx, expr) {
-                    return;
-                }
-                span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
-                self.expr_id = Some(expr.hir_id);
-            } else if ty.is_floating_point() {
-                span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
-                self.expr_id = Some(expr.hir_id);
-            }
+        if constant_simple(cx, cx.typeck_results(), expr).is_none() && ty.is_floating_point() {
+            span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected");
+            self.expr_id = Some(expr.hir_id);
         }
     }
 
diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs
index 5e81a01a461..79d2ca15988 100644
--- a/clippy_lints/src/renamed_lints.rs
+++ b/clippy_lints/src/renamed_lints.rs
@@ -15,6 +15,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
     ("clippy::identity_conversion", "clippy::useless_conversion"),
     ("clippy::if_let_some_result", "clippy::match_result_ok"),
+    ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"),
     ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
     ("clippy::new_without_default_derive", "clippy::new_without_default"),
     ("clippy::option_and_then_some", "clippy::bind_instead_of_map"),
diff --git a/tests/ui/float_arithmetic.rs b/tests/ui/float_arithmetic.rs
index 60fa7569eb9..a928c35e8bc 100644
--- a/tests/ui/float_arithmetic.rs
+++ b/tests/ui/float_arithmetic.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::integer_arithmetic, clippy::float_arithmetic)]
+#![warn(clippy::arithmetic_side_effects, clippy::float_arithmetic)]
 #![allow(
     unused,
     clippy::shadow_reuse,
diff --git a/tests/ui/integer_arithmetic.rs b/tests/ui/integer_arithmetic.rs
deleted file mode 100644
index ab9b6094c2c..00000000000
--- a/tests/ui/integer_arithmetic.rs
+++ /dev/null
@@ -1,109 +0,0 @@
-//@aux-build:proc_macro_derive.rs
-
-#![warn(clippy::integer_arithmetic, clippy::float_arithmetic)]
-#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::op_ref)]
-
-extern crate proc_macro_derive;
-
-#[derive(proc_macro_derive::ShadowDerive)]
-pub struct Nothing;
-
-#[rustfmt::skip]
-fn main() {
-    let mut i = 1i32;
-    let mut var1 = 13i32;
-    let mut var2 = -1i32;
-    1 + i;
-    i * 2;
-    1 %
-    i / 2; // no error, this is part of the expression in the preceding line
-    i - 2 + 2 - i;
-    -i;
-    i >> 1;
-    i << 1;
-
-    // no error, overflows are checked by `overflowing_literals`
-    -1;
-    -(-1);
-
-    i & 1; // no wrapping
-    i | 1;
-    i ^ 1;
-
-    i += 1;
-    i -= 1;
-    i *= 2;
-    i /= 2;
-    i /= 0;
-    i /= -1;
-    i /= var1;
-    i /= var2;
-    i %= 2;
-    i %= 0;
-    i %= -1;
-    i %= var1;
-    i %= var2;
-    i <<= 3;
-    i >>= 2;
-
-    // no errors
-    i |= 1;
-    i &= 1;
-    i ^= i;
-
-    // No errors for the following items because they are constant expressions
-    enum Foo {
-        Bar = -2,
-    }
-    struct Baz([i32; 1 + 1]);
-    union Qux {
-        field: [i32; 1 + 1],
-    }
-    type Alias = [i32; 1 + 1];
-
-    const FOO: i32 = -2;
-    static BAR: i32 = -2;
-
-    let _: [i32; 1 + 1] = [0, 0];
-
-    let _: [i32; 1 + 1] = {
-        let a: [i32; 1 + 1] = [0, 0];
-        a
-    };
-
-    trait Trait {
-        const ASSOC: i32 = 1 + 1;
-    }
-
-    impl Trait for Foo {
-        const ASSOC: i32 = {
-            let _: [i32; 1 + 1];
-            fn foo() {}
-            1 + 1
-        };
-    }
-}
-
-// warn on references as well! (#5328)
-pub fn int_arith_ref() {
-    3 + &1;
-    &3 + 1;
-    &3 + &1;
-}
-
-pub fn foo(x: &i32) -> i32 {
-    let a = 5;
-    a + x
-}
-
-pub fn bar(x: &i32, y: &i32) -> i32 {
-    x + y
-}
-
-pub fn baz(x: i32, y: &i32) -> i32 {
-    x + y
-}
-
-pub fn qux(x: i32, y: i32) -> i32 {
-    (&x + &y)
-}
diff --git a/tests/ui/integer_arithmetic.stderr b/tests/ui/integer_arithmetic.stderr
deleted file mode 100644
index add3b6b90fa..00000000000
--- a/tests/ui/integer_arithmetic.stderr
+++ /dev/null
@@ -1,169 +0,0 @@
-error: this operation will panic at runtime
-  --> $DIR/integer_arithmetic.rs:37:5
-   |
-LL |     i /= 0;
-   |     ^^^^^^ attempt to divide `_` by zero
-   |
-   = note: `#[deny(unconditional_panic)]` on by default
-
-error: this operation will panic at runtime
-  --> $DIR/integer_arithmetic.rs:42:5
-   |
-LL |     i %= 0;
-   |     ^^^^^^ attempt to calculate the remainder of `_` with a divisor of zero
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:16:5
-   |
-LL |     1 + i;
-   |     ^^^^^
-   |
-   = note: `-D clippy::integer-arithmetic` implied by `-D warnings`
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:17:5
-   |
-LL |     i * 2;
-   |     ^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:18:5
-   |
-LL | /     1 %
-LL | |     i / 2; // no error, this is part of the expression in the preceding line
-   | |_____^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:20:5
-   |
-LL |     i - 2 + 2 - i;
-   |     ^^^^^^^^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:21:5
-   |
-LL |     -i;
-   |     ^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:22:5
-   |
-LL |     i >> 1;
-   |     ^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:23:5
-   |
-LL |     i << 1;
-   |     ^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:33:5
-   |
-LL |     i += 1;
-   |     ^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:34:5
-   |
-LL |     i -= 1;
-   |     ^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:35:5
-   |
-LL |     i *= 2;
-   |     ^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:38:11
-   |
-LL |     i /= -1;
-   |           ^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:39:5
-   |
-LL |     i /= var1;
-   |     ^^^^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:40:5
-   |
-LL |     i /= var2;
-   |     ^^^^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:43:11
-   |
-LL |     i %= -1;
-   |           ^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:44:5
-   |
-LL |     i %= var1;
-   |     ^^^^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:45:5
-   |
-LL |     i %= var2;
-   |     ^^^^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:46:5
-   |
-LL |     i <<= 3;
-   |     ^^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:47:5
-   |
-LL |     i >>= 2;
-   |     ^^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:89:5
-   |
-LL |     3 + &1;
-   |     ^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:90:5
-   |
-LL |     &3 + 1;
-   |     ^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:91:5
-   |
-LL |     &3 + &1;
-   |     ^^^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:96:5
-   |
-LL |     a + x
-   |     ^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:100:5
-   |
-LL |     x + y
-   |     ^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:104:5
-   |
-LL |     x + y
-   |     ^^^^^
-
-error: integer arithmetic detected
-  --> $DIR/integer_arithmetic.rs:108:5
-   |
-LL |     (&x + &y)
-   |     ^^^^^^^^^
-
-error: aborting due to 27 previous errors
-
diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed
index ee4e5007dc5..d49ae5d8636 100644
--- a/tests/ui/needless_return.fixed
+++ b/tests/ui/needless_return.fixed
@@ -231,8 +231,9 @@ fn needless_return_macro() -> String {
 }
 
 fn issue_9361() -> i32 {
-    #[allow(clippy::integer_arithmetic)]
-    return 1 + 2;
+    let n = 1;
+    #[allow(clippy::arithmetic_side_effects)]
+    return n + n;
 }
 
 fn issue8336(x: i32) -> bool {
diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs
index cd999db4f40..36763826174 100644
--- a/tests/ui/needless_return.rs
+++ b/tests/ui/needless_return.rs
@@ -239,8 +239,9 @@ fn needless_return_macro() -> String {
 }
 
 fn issue_9361() -> i32 {
-    #[allow(clippy::integer_arithmetic)]
-    return 1 + 2;
+    let n = 1;
+    #[allow(clippy::arithmetic_side_effects)]
+    return n + n;
 }
 
 fn issue8336(x: i32) -> bool {
diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr
index 87d0cd3e14c..05f6038cd25 100644
--- a/tests/ui/needless_return.stderr
+++ b/tests/ui/needless_return.stderr
@@ -328,7 +328,7 @@ LL |     return format!("Hello {}", "world!");
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:249:9
+  --> $DIR/needless_return.rs:250:9
    |
 LL |         return true;
    |         ^^^^^^^^^^^
@@ -336,7 +336,7 @@ LL |         return true;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:251:9
+  --> $DIR/needless_return.rs:252:9
    |
 LL |         return false;
    |         ^^^^^^^^^^^^
@@ -344,7 +344,7 @@ LL |         return false;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:258:13
+  --> $DIR/needless_return.rs:259:13
    |
 LL |             return 10;
    |             ^^^^^^^^^
@@ -352,7 +352,7 @@ LL |             return 10;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:261:13
+  --> $DIR/needless_return.rs:262:13
    |
 LL |             return 100;
    |             ^^^^^^^^^^
@@ -360,7 +360,7 @@ LL |             return 100;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:269:9
+  --> $DIR/needless_return.rs:270:9
    |
 LL |         return 0;
    |         ^^^^^^^^
@@ -368,7 +368,7 @@ LL |         return 0;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:276:13
+  --> $DIR/needless_return.rs:277:13
    |
 LL |             return *(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -376,7 +376,7 @@ LL |             return *(x as *const isize);
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:278:13
+  --> $DIR/needless_return.rs:279:13
    |
 LL |             return !*(x as *const isize);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -384,7 +384,7 @@ LL |             return !*(x as *const isize);
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:285:20
+  --> $DIR/needless_return.rs:286:20
    |
 LL |           let _ = 42;
    |  ____________________^
@@ -395,7 +395,7 @@ LL | |         return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:292:20
+  --> $DIR/needless_return.rs:293:20
    |
 LL |         let _ = 42; return;
    |                    ^^^^^^^
@@ -403,7 +403,7 @@ LL |         let _ = 42; return;
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:304:9
+  --> $DIR/needless_return.rs:305:9
    |
 LL |         return Ok(format!("ok!"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -411,7 +411,7 @@ LL |         return Ok(format!("ok!"));
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:306:9
+  --> $DIR/needless_return.rs:307:9
    |
 LL |         return Err(format!("err!"));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -419,7 +419,7 @@ LL |         return Err(format!("err!"));
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:312:9
+  --> $DIR/needless_return.rs:313:9
    |
 LL |         return if true { 1 } else { 2 };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -427,7 +427,7 @@ LL |         return if true { 1 } else { 2 };
    = help: remove `return`
 
 error: unneeded `return` statement
-  --> $DIR/needless_return.rs:316:9
+  --> $DIR/needless_return.rs:317:9
    |
 LL |         return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 };
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed
index aa3b4f53d72..104c8191712 100644
--- a/tests/ui/rename.fixed
+++ b/tests/ui/rename.fixed
@@ -16,6 +16,7 @@
 #![allow(clippy::mixed_read_write_in_expression)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::match_result_ok)]
+#![allow(clippy::arithmetic_side_effects)]
 #![allow(clippy::overly_complex_bool_expr)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::bind_instead_of_map)]
@@ -53,6 +54,7 @@
 #![warn(clippy::mixed_read_write_in_expression)]
 #![warn(clippy::useless_conversion)]
 #![warn(clippy::match_result_ok)]
+#![warn(clippy::arithmetic_side_effects)]
 #![warn(clippy::overly_complex_bool_expr)]
 #![warn(clippy::new_without_default)]
 #![warn(clippy::bind_instead_of_map)]
diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs
index 600ec79fcbf..c7fc7a47a4a 100644
--- a/tests/ui/rename.rs
+++ b/tests/ui/rename.rs
@@ -16,6 +16,7 @@
 #![allow(clippy::mixed_read_write_in_expression)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::match_result_ok)]
+#![allow(clippy::arithmetic_side_effects)]
 #![allow(clippy::overly_complex_bool_expr)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::bind_instead_of_map)]
@@ -53,6 +54,7 @@
 #![warn(clippy::eval_order_dependence)]
 #![warn(clippy::identity_conversion)]
 #![warn(clippy::if_let_some_result)]
+#![warn(clippy::integer_arithmetic)]
 #![warn(clippy::logic_bug)]
 #![warn(clippy::new_without_default_derive)]
 #![warn(clippy::option_and_then_some)]
diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr
index 70d15408b9f..d44bd9c4d2a 100644
--- a/tests/ui/rename.stderr
+++ b/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:43:9
+  --> $DIR/rename.rs:44:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,256 +7,262 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:44:9
+  --> $DIR/rename.rs:45:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:45:9
+  --> $DIR/rename.rs:46:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:46:9
+  --> $DIR/rename.rs:47:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:47:9
+  --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:48:9
+  --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> $DIR/rename.rs:50:9
+  --> $DIR/rename.rs:51:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:53:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
+error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
+  --> $DIR/rename.rs:57:9
+   |
+LL | #![warn(clippy::integer_arithmetic)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
+
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:78:9
+  --> $DIR/rename.rs:80:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:80:9
+  --> $DIR/rename.rs:82:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:81:9
+  --> $DIR/rename.rs:83:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:84:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:83:9
+  --> $DIR/rename.rs:85:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:84:9
+  --> $DIR/rename.rs:86:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:85:9
+  --> $DIR/rename.rs:87:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 43 previous errors
+error: aborting due to 44 previous errors
 

From fcb132765cdd7e1a08f7767b3434333ad91a0ea9 Mon Sep 17 00:00:00 2001
From: David Tolnay <dtolnay@gmail.com>
Date: Sun, 14 May 2023 07:58:06 -0700
Subject: [PATCH 57/78] Exposes false negative in clippy's
 diverging_sub_expression

---
 tests/ui/diverging_sub_expression.stderr | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/tests/ui/diverging_sub_expression.stderr b/tests/ui/diverging_sub_expression.stderr
index 9c91d935716..51a3b0d972e 100644
--- a/tests/ui/diverging_sub_expression.stderr
+++ b/tests/ui/diverging_sub_expression.stderr
@@ -30,19 +30,11 @@ error: sub-expression diverges
 LL |             3 => true || diverge(),
    |                          ^^^^^^^^^
 
-error: sub-expression diverges
-  --> $DIR/diverging_sub_expression.rs:36:30
-   |
-LL |                 _ => true || panic!("boo"),
-   |                              ^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
-
 error: sub-expression diverges
   --> $DIR/diverging_sub_expression.rs:38:26
    |
 LL |             _ => true || break,
    |                          ^^^^^
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 

From 84f89f30ebda5485badac09b34d666fbab243a19 Mon Sep 17 00:00:00 2001
From: Icxolu <10486322+Icxolu@users.noreply.github.com>
Date: Sat, 13 May 2023 11:47:05 +0200
Subject: [PATCH 58/78] enhance `needless_collect`

Updates `needless_collect` to lint for collecting into a method or
function argument thats taking an `IntoIterator` (for example `extend`).
Every `Iterator` trivially implements `IntoIterator` and colleting it
only causes an unnecessary allocation.
---
 clippy_lints/src/methods/needless_collect.rs | 68 +++++++++++++++++++-
 tests/ui/needless_collect.fixed              | 12 ++++
 tests/ui/needless_collect.rs                 | 12 ++++
 tests/ui/needless_collect.stderr             | 26 +++++++-
 4 files changed, 115 insertions(+), 3 deletions(-)

diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs
index 0b0c6adc504..6841aaf626c 100644
--- a/clippy_lints/src/methods/needless_collect.rs
+++ b/clippy_lints/src/methods/needless_collect.rs
@@ -1,6 +1,5 @@
 use super::NEEDLESS_COLLECT;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
-use clippy_utils::higher;
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection};
@@ -8,6 +7,7 @@ use clippy_utils::{
     can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id,
     CaptureKind,
 };
+use clippy_utils::{fn_def_id, higher};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
@@ -16,7 +16,7 @@ use rustc_hir::{
 };
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{self, AssocKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
+use rustc_middle::ty::{self, AssocKind, Clause, EarlyBinder, GenericArg, GenericArgKind, PredicateKind, Ty};
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, Symbol};
 
@@ -32,6 +32,8 @@ pub(super) fn check<'tcx>(
     if let Some(parent) = get_parent_node(cx.tcx, collect_expr.hir_id) {
         match parent {
             Node::Expr(parent) => {
+                check_collect_into_intoiterator(cx, parent, collect_expr, call_span, iter_expr);
+
                 if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind {
                     let mut app = Applicability::MachineApplicable;
                     let name = name.ident.as_str();
@@ -134,6 +136,68 @@ pub(super) fn check<'tcx>(
     }
 }
 
+/// checks for for collecting into a (generic) method or function argument
+/// taking an `IntoIterator`
+fn check_collect_into_intoiterator<'tcx>(
+    cx: &LateContext<'tcx>,
+    parent: &'tcx Expr<'tcx>,
+    collect_expr: &'tcx Expr<'tcx>,
+    call_span: Span,
+    iter_expr: &'tcx Expr<'tcx>,
+) {
+    if let Some(id) = fn_def_id(cx, parent) {
+        let args = match parent.kind {
+            ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => args,
+            _ => &[],
+        };
+        // find the argument index of the `collect_expr` in the
+        // function / method call
+        if let Some(arg_idx) = args.iter().position(|e| e.hir_id == collect_expr.hir_id).map(|i| {
+            if matches!(parent.kind, ExprKind::MethodCall(_, _, _, _)) {
+                i + 1
+            } else {
+                i
+            }
+        }) {
+            // extract the input types of the function/method call
+            // that contains `collect_expr`
+            let inputs = cx
+                .tcx
+                .liberate_late_bound_regions(id, cx.tcx.fn_sig(id).subst_identity())
+                .inputs();
+
+            // map IntoIterator generic bounds to their signature
+            // types and check whether the argument type is an
+            // `IntoIterator`
+            if cx
+                .tcx
+                .param_env(id)
+                .caller_bounds()
+                .into_iter()
+                .filter_map(|p| {
+                    if let PredicateKind::Clause(Clause::Trait(t)) = p.kind().skip_binder()
+                            && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) {
+                                Some(t.self_ty())
+                            } else {
+                                None
+                            }
+                })
+                .any(|ty| ty == inputs[arg_idx])
+            {
+                span_lint_and_sugg(
+                    cx,
+                    NEEDLESS_COLLECT,
+                    call_span.with_lo(iter_expr.span.hi()),
+                    NEEDLESS_COLLECT_MSG,
+                    "remove this call",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
+
 /// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool`
 fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool {
     cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| {
diff --git a/tests/ui/needless_collect.fixed b/tests/ui/needless_collect.fixed
index 024c22de225..b7e80af5015 100644
--- a/tests/ui/needless_collect.fixed
+++ b/tests/ui/needless_collect.fixed
@@ -62,4 +62,16 @@ fn main() {
 
     let _ = sample.iter().next().is_none();
     let _ = sample.iter().any(|x| x == &0);
+
+    #[allow(clippy::double_parens)]
+    {
+        Vec::<u8>::new().extend((0..10));
+        foo((0..10));
+        bar((0..10).collect::<Vec<_>>(), (0..10));
+        baz((0..10), (), ('a'..='z'))
+    }
 }
+
+fn foo(_: impl IntoIterator<Item = usize>) {}
+fn bar<I: IntoIterator<Item = usize>>(_: Vec<usize>, _: I) {}
+fn baz<I: IntoIterator<Item = usize>>(_: I, _: (), _: impl IntoIterator<Item = char>) {}
diff --git a/tests/ui/needless_collect.rs b/tests/ui/needless_collect.rs
index 7ed7babec30..680b6fa5b55 100644
--- a/tests/ui/needless_collect.rs
+++ b/tests/ui/needless_collect.rs
@@ -62,4 +62,16 @@ fn main() {
 
     let _ = sample.iter().collect::<VecWrapper<_>>().is_empty();
     let _ = sample.iter().collect::<VecWrapper<_>>().contains(&&0);
+
+    #[allow(clippy::double_parens)]
+    {
+        Vec::<u8>::new().extend((0..10).collect::<Vec<_>>());
+        foo((0..10).collect::<Vec<_>>());
+        bar((0..10).collect::<Vec<_>>(), (0..10).collect::<Vec<_>>());
+        baz((0..10), (), ('a'..='z').collect::<Vec<_>>())
+    }
 }
+
+fn foo(_: impl IntoIterator<Item = usize>) {}
+fn bar<I: IntoIterator<Item = usize>>(_: Vec<usize>, _: I) {}
+fn baz<I: IntoIterator<Item = usize>>(_: I, _: (), _: impl IntoIterator<Item = char>) {}
diff --git a/tests/ui/needless_collect.stderr b/tests/ui/needless_collect.stderr
index 584d2a1d835..ad22a7b057e 100644
--- a/tests/ui/needless_collect.stderr
+++ b/tests/ui/needless_collect.stderr
@@ -90,5 +90,29 @@ error: avoid using `collect()` when not needed
 LL |     let _ = sample.iter().collect::<VecWrapper<_>>().contains(&&0);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &0)`
 
-error: aborting due to 15 previous errors
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:68:40
+   |
+LL |         Vec::<u8>::new().extend((0..10).collect::<Vec<_>>());
+   |                                        ^^^^^^^^^^^^^^^^^^^^ help: remove this call
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:69:20
+   |
+LL |         foo((0..10).collect::<Vec<_>>());
+   |                    ^^^^^^^^^^^^^^^^^^^^ help: remove this call
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:70:49
+   |
+LL |         bar((0..10).collect::<Vec<_>>(), (0..10).collect::<Vec<_>>());
+   |                                                 ^^^^^^^^^^^^^^^^^^^^ help: remove this call
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:71:37
+   |
+LL |         baz((0..10), (), ('a'..='z').collect::<Vec<_>>())
+   |                                     ^^^^^^^^^^^^^^^^^^^^ help: remove this call
+
+error: aborting due to 19 previous errors
 

From 1190c02bb89c8e127b449ec3cf7fcb51f0cfe0fd Mon Sep 17 00:00:00 2001
From: Centri3 <114838443+Centri3@users.noreply.github.com>
Date: Sun, 14 May 2023 12:21:23 -0500
Subject: [PATCH 59/78] fix #10773

---
 clippy_lints/src/useless_conversion.rs | 13 ++++++++++-
 tests/ui/useless_conversion.fixed      |  6 +++++
 tests/ui/useless_conversion.rs         |  6 +++++
 tests/ui/useless_conversion.stderr     | 32 +++++++++++++-------------
 4 files changed, 40 insertions(+), 17 deletions(-)

diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs
index ddbe6b2c790..3d5c0514b58 100644
--- a/clippy_lints/src/useless_conversion.rs
+++ b/clippy_lints/src/useless_conversion.rs
@@ -5,7 +5,8 @@ use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
 use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -138,6 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                 if_chain! {
                     if let ExprKind::Path(ref qpath) = path.kind;
                     if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
+                    if !is_ty_alias(qpath);
                     then {
                         let a = cx.typeck_results().expr_ty(e);
                         let b = cx.typeck_results().expr_ty(arg);
@@ -195,3 +197,12 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
         }
     }
 }
+
+/// `cx.qpath_res` seems to return `AssocFn` so we do this instead
+fn is_ty_alias(qpath: &QPath<'_>) -> bool {
+    match *qpath {
+        QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias, ..)),
+        QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => is_ty_alias(&qpath),
+        _ => false,
+    }
+}
diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed
index 01eb6c5b080..c16caa38fe9 100644
--- a/tests/ui/useless_conversion.fixed
+++ b/tests/ui/useless_conversion.fixed
@@ -33,6 +33,11 @@ fn test_issue_3913() -> Result<(), std::io::Error> {
     Ok(())
 }
 
+fn dont_lint_on_type_alias() {
+    type A = i32;
+    _ = A::from(0i32);
+}
+
 fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() {
     let text = "foo\r\nbar\n\nbaz\n";
     let lines = text.lines();
@@ -106,6 +111,7 @@ fn main() {
     test_questionmark().unwrap();
     test_issue_3913().unwrap();
 
+    dont_lint_on_type_alias();
     dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr();
     lint_into_iter_on_mutable_local_implementing_iterator_in_expr();
     lint_into_iter_on_expr_implementing_iterator();
diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs
index 34b43a6299b..c75a2bce4ca 100644
--- a/tests/ui/useless_conversion.rs
+++ b/tests/ui/useless_conversion.rs
@@ -33,6 +33,11 @@ fn test_issue_3913() -> Result<(), std::io::Error> {
     Ok(())
 }
 
+fn dont_lint_on_type_alias() {
+    type A = i32;
+    _ = A::from(0i32);
+}
+
 fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() {
     let text = "foo\r\nbar\n\nbaz\n";
     let lines = text.lines();
@@ -106,6 +111,7 @@ fn main() {
     test_questionmark().unwrap();
     test_issue_3913().unwrap();
 
+    dont_lint_on_type_alias();
     dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr();
     lint_into_iter_on_mutable_local_implementing_iterator_in_expr();
     lint_into_iter_on_expr_implementing_iterator();
diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr
index be067c6843a..4dca3aac533 100644
--- a/tests/ui/useless_conversion.stderr
+++ b/tests/ui/useless_conversion.stderr
@@ -23,97 +23,97 @@ LL |         let _: i32 = 0i32.into();
    |                      ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
 
 error: useless conversion to the same type: `std::str::Lines<'_>`
-  --> $DIR/useless_conversion.rs:45:22
+  --> $DIR/useless_conversion.rs:50:22
    |
 LL |     if Some("ok") == lines.into_iter().next() {}
    |                      ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines`
 
 error: useless conversion to the same type: `std::str::Lines<'_>`
-  --> $DIR/useless_conversion.rs:50:21
+  --> $DIR/useless_conversion.rs:55:21
    |
 LL |     let mut lines = text.lines().into_iter();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()`
 
 error: useless conversion to the same type: `std::str::Lines<'_>`
-  --> $DIR/useless_conversion.rs:56:22
+  --> $DIR/useless_conversion.rs:61:22
    |
 LL |     if Some("ok") == text.lines().into_iter().next() {}
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()`
 
 error: useless conversion to the same type: `std::ops::Range<i32>`
-  --> $DIR/useless_conversion.rs:62:13
+  --> $DIR/useless_conversion.rs:67:13
    |
 LL |     let _ = NUMBERS.into_iter().next();
    |             ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS`
 
 error: useless conversion to the same type: `std::ops::Range<i32>`
-  --> $DIR/useless_conversion.rs:67:17
+  --> $DIR/useless_conversion.rs:72:17
    |
 LL |     let mut n = NUMBERS.into_iter();
    |                 ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:128:21
+  --> $DIR/useless_conversion.rs:134:21
    |
 LL |     let _: String = "foo".to_string().into();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:129:21
+  --> $DIR/useless_conversion.rs:135:21
    |
 LL |     let _: String = From::from("foo".to_string());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:130:13
+  --> $DIR/useless_conversion.rs:136:13
    |
 LL |     let _ = String::from("foo".to_string());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:131:13
+  --> $DIR/useless_conversion.rs:137:13
    |
 LL |     let _ = String::from(format!("A: {:04}", 123));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
 
 error: useless conversion to the same type: `std::str::Lines<'_>`
-  --> $DIR/useless_conversion.rs:132:13
+  --> $DIR/useless_conversion.rs:138:13
    |
 LL |     let _ = "".lines().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
 
 error: useless conversion to the same type: `std::vec::IntoIter<i32>`
-  --> $DIR/useless_conversion.rs:133:13
+  --> $DIR/useless_conversion.rs:139:13
    |
 LL |     let _ = vec![1, 2, 3].into_iter().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
 
 error: useless conversion to the same type: `std::string::String`
-  --> $DIR/useless_conversion.rs:134:21
+  --> $DIR/useless_conversion.rs:140:21
    |
 LL |     let _: String = format!("Hello {}", "world").into();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
 
 error: useless conversion to the same type: `i32`
-  --> $DIR/useless_conversion.rs:139:13
+  --> $DIR/useless_conversion.rs:145:13
    |
 LL |     let _ = i32::from(a + b) * 3;
    |             ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)`
 
 error: useless conversion to the same type: `Foo<'a'>`
-  --> $DIR/useless_conversion.rs:145:23
+  --> $DIR/useless_conversion.rs:151:23
    |
 LL |     let _: Foo<'a'> = s2.into();
    |                       ^^^^^^^^^ help: consider removing `.into()`: `s2`
 
 error: useless conversion to the same type: `Foo<'a'>`
-  --> $DIR/useless_conversion.rs:147:13
+  --> $DIR/useless_conversion.rs:153:13
    |
 LL |     let _ = Foo::<'a'>::from(s3);
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3`
 
 error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>`
-  --> $DIR/useless_conversion.rs:149:13
+  --> $DIR/useless_conversion.rs:155:13
    |
 LL |     let _ = vec![s4, s4, s4].into_iter().into_iter();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()`

From a36d9a7820be9040de8e56ec1852e2920377b935 Mon Sep 17 00:00:00 2001
From: Centri3 <114838443+Centri3@users.noreply.github.com>
Date: Sun, 14 May 2023 12:39:08 -0500
Subject: [PATCH 60/78] move `is_ty_alias` to `clippy_utils`

---
 clippy_lints/src/useless_conversion.rs | 13 ++-----------
 clippy_utils/src/lib.rs                | 10 ++++++++++
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs
index 3d5c0514b58..28c3fc859e3 100644
--- a/clippy_lints/src/useless_conversion.rs
+++ b/clippy_lints/src/useless_conversion.rs
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::is_ty_alias;
 use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
 use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind, QPath, TyKind};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -197,12 +197,3 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
         }
     }
 }
-
-/// `cx.qpath_res` seems to return `AssocFn` so we do this instead
-fn is_ty_alias(qpath: &QPath<'_>) -> bool {
-    match *qpath {
-        QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias, ..)),
-        QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => is_ty_alias(&qpath),
-        _ => false,
-    }
-}
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 964104fc31d..2e27c260f74 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -1,5 +1,6 @@
 #![feature(array_chunks)]
 #![feature(box_patterns)]
+#![feature(if_let_guard)]
 #![feature(let_chains)]
 #![feature(lint_reasons)]
 #![feature(never_type)]
@@ -282,6 +283,15 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
     matches!(pat.kind, PatKind::Wild)
 }
 
+/// Checks if the given `QPath` belongs to a type alias.
+pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
+    match *qpath {
+        QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias, ..)),
+        QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) },
+        _ => false,
+    }
+}
+
 /// Checks if the method call given in `expr` belongs to the given trait.
 /// This is a deprecated function, consider using [`is_trait_method`].
 pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {

From 9c6350b19c420cd731922689a17f4f14ef345eaf Mon Sep 17 00:00:00 2001
From: Philipp Krones <hello@philkrones.com>
Date: Mon, 15 May 2023 09:58:10 +0200
Subject: [PATCH 61/78] flip1995: Stepping down from the reviewer rotation

A step I was trying to avoid for way too long, but sadly necessary now. I hope I
can come back stronger in a few months.
---
 triagebot.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/triagebot.toml b/triagebot.toml
index 3f8f6a7b98c..c40b71f6ca7 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -17,9 +17,9 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB
 
 [assign.owners]
 "/.github" = ["@flip1995"]
+"/book" = ["@flip1995"]
 "/util/gh-pages" = ["@xFrednet"]
 "*" = [
-    "@flip1995",
     "@Manishearth",
     "@llogiq",
     "@giraffate",

From 79a8867addbaad8c2d15adc2accf4c9d7194136a Mon Sep 17 00:00:00 2001
From: disco07 <koneenok@outlook.fr>
Date: Mon, 15 May 2023 19:43:22 +0200
Subject: [PATCH 62/78] update test option

---
 .../redundant_pattern_matching_option.fixed   |  5 ++-
 tests/ui/redundant_pattern_matching_option.rs | 13 ++++----
 .../redundant_pattern_matching_option.stderr  | 32 +++++++++----------
 3 files changed, 24 insertions(+), 26 deletions(-)

diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed
index 94c89049189..accdf1da9dd 100644
--- a/tests/ui/redundant_pattern_matching_option.fixed
+++ b/tests/ui/redundant_pattern_matching_option.fixed
@@ -92,15 +92,14 @@ fn issue7921() {
 
 fn issue10726() {
     let x = Some(42);
-    let y = None::<()>;
 
     x.is_some();
 
     x.is_none();
 
-    y.is_some();
+    x.is_none();
 
-    y.is_none();
+    x.is_some();
 
     // Don't lint
     match x {
diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs
index 303a0280e9d..ec684bdf71c 100644
--- a/tests/ui/redundant_pattern_matching_option.rs
+++ b/tests/ui/redundant_pattern_matching_option.rs
@@ -107,7 +107,6 @@ fn issue7921() {
 
 fn issue10726() {
     let x = Some(42);
-    let y = None::<()>;
 
     match x {
         Some(_) => true,
@@ -119,14 +118,14 @@ fn issue10726() {
         _ => false,
     };
 
-    match y {
-        Some(_) => true,
-        _ => false,
+    match x {
+        Some(_) => false,
+        _ => true,
     };
 
-    match y {
-        None => true,
-        _ => false,
+    match x {
+        None => false,
+        _ => true,
     };
 
     // Don't lint
diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr
index eb4d87ba2b5..a69eb390520 100644
--- a/tests/ui/redundant_pattern_matching_option.stderr
+++ b/tests/ui/redundant_pattern_matching_option.stderr
@@ -149,7 +149,7 @@ LL |     if let None = *&None::<()> {}
    |     -------^^^^--------------- help: try this: `if (&None::<()>).is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:112:5
+  --> $DIR/redundant_pattern_matching_option.rs:111:5
    |
 LL | /     match x {
 LL | |         Some(_) => true,
@@ -158,7 +158,7 @@ LL | |     };
    | |_____^ help: try this: `x.is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:117:5
+  --> $DIR/redundant_pattern_matching_option.rs:116:5
    |
 LL | /     match x {
 LL | |         None => true,
@@ -166,23 +166,23 @@ LL | |         _ => false,
 LL | |     };
    | |_____^ help: try this: `x.is_none()`
 
-error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:122:5
-   |
-LL | /     match y {
-LL | |         Some(_) => true,
-LL | |         _ => false,
-LL | |     };
-   | |_____^ help: try this: `y.is_some()`
-
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:127:5
+  --> $DIR/redundant_pattern_matching_option.rs:121:5
    |
-LL | /     match y {
-LL | |         None => true,
-LL | |         _ => false,
+LL | /     match x {
+LL | |         Some(_) => false,
+LL | |         _ => true,
 LL | |     };
-   | |_____^ help: try this: `y.is_none()`
+   | |_____^ help: try this: `x.is_none()`
+
+error: redundant pattern matching, consider using `is_some()`
+  --> $DIR/redundant_pattern_matching_option.rs:126:5
+   |
+LL | /     match x {
+LL | |         None => false,
+LL | |         _ => true,
+LL | |     };
+   | |_____^ help: try this: `x.is_some()`
 
 error: aborting due to 26 previous errors
 

From f0be0ee1aa5314f6c7bb6949a8afe19e84ead35a Mon Sep 17 00:00:00 2001
From: y21 <30553356+y21@users.noreply.github.com>
Date: Mon, 15 May 2023 21:33:56 +0200
Subject: [PATCH 63/78] handle nested macros and add tests for them

---
 clippy_lints/src/dbg_macro.rs | 51 ++++++++++++++++++++++++-----------
 tests/ui/dbg_macro.rs         | 19 +++++++++++++
 tests/ui/dbg_macro.stderr     | 38 ++++++++++++++++++++------
 3 files changed, 85 insertions(+), 23 deletions(-)

diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs
index cea712f2fee..ea17e7a6071 100644
--- a/clippy_lints/src/dbg_macro.rs
+++ b/clippy_lints/src/dbg_macro.rs
@@ -3,10 +3,10 @@ use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind};
+use rustc_hir::{Expr, ExprKind, Node};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{sym, Span};
+use rustc_span::{sym, BytePos, Pos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -31,9 +31,29 @@ declare_clippy_lint! {
     "`dbg!` macro is intended as a debugging tool"
 }
 
-fn span_including_semi(cx: &LateContext<'_>, span: Span) -> Span {
-    let span = cx.sess().source_map().span_extend_to_next_char(span, ';', true);
-    span.with_hi(span.hi() + rustc_span::BytePos(1))
+/// Gets the span of the statement up to the next semicolon, if and only if the next
+/// non-whitespace character actually is a semicolon.
+/// E.g.
+/// ```rust,ignore
+/// 
+///    dbg!();
+///    ^^^^^^^  this span is returned
+///
+///   foo!(dbg!());
+///             no span is returned
+/// ```
+fn span_including_semi(cx: &LateContext<'_>, span: Span) -> Option<Span> {
+    let sm = cx.sess().source_map();
+    let sf = sm.lookup_source_file(span.hi());
+    let src = sf.src.as_ref()?.get(span.hi().to_usize()..)?;
+    let first_non_whitespace = src.find(|c: char| !c.is_whitespace())?;
+
+    if src.as_bytes()[first_non_whitespace] == b';' {
+        let hi = span.hi() + BytePos::from_usize(first_non_whitespace + 1);
+        Some(span.with_hi(hi))
+    } else {
+        None
+    }
 }
 
 #[derive(Copy, Clone)]
@@ -62,16 +82,17 @@ impl LateLintPass<'_> for DbgMacro {
             let mut applicability = Applicability::MachineApplicable;
 
             let (sugg_span, suggestion) = match expr.peel_drop_temps().kind {
-                ExprKind::Block(..) => match cx.tcx.hir().find_parent(expr.hir_id) {
-                    // dbg!() as a standalone statement, suggest removing the whole statement entirely
-                    Some(Node::Stmt(
-                        stmt @ Stmt {
-                            kind: StmtKind::Semi(_),
-                            ..
-                        },
-                    )) => (span_including_semi(cx, stmt.span.source_callsite()), String::new()),
-                    // empty dbg!() in arbitrary position (e.g. `foo(dbg!())`), suggest replacing with `foo(())`
-                    _ => (macro_call.span, String::from("()")),
+                // dbg!()
+                ExprKind::Block(..) => {
+                    // If the `dbg!` macro is a "free" statement and not contained within other expressions,
+                    // remove the whole statement.
+                    if let Some(Node::Stmt(stmt)) = cx.tcx.hir().find_parent(expr.hir_id)
+                        && let Some(span) = span_including_semi(cx, stmt.span.source_callsite())
+                    {
+                        (span, String::new())
+                    } else {
+                        (macro_call.span, String::from("()"))
+                    }
                 },
                 // dbg!(1)
                 ExprKind::Match(val, ..) => (
diff --git a/tests/ui/dbg_macro.rs b/tests/ui/dbg_macro.rs
index ae2075e7dad..10788d40481 100644
--- a/tests/ui/dbg_macro.rs
+++ b/tests/ui/dbg_macro.rs
@@ -23,10 +23,29 @@ fn main() {
 }
 
 fn issue9914() {
+    macro_rules! foo {
+        ($x:expr) => {
+            $x;
+        };
+    }
+    macro_rules! foo2 {
+        ($x:expr) => {
+            $x;
+        };
+    }
+    macro_rules! expand_to_dbg {
+        () => {
+            dbg!();
+        };
+    }
+
     dbg!();
     #[allow(clippy::let_unit_value)]
     let _ = dbg!();
     bar(dbg!());
+    foo!(dbg!());
+    foo2!(foo!(dbg!()));
+    expand_to_dbg!();
 }
 
 mod issue7274 {
diff --git a/tests/ui/dbg_macro.stderr b/tests/ui/dbg_macro.stderr
index 34329a06b97..530e7663317 100644
--- a/tests/ui/dbg_macro.stderr
+++ b/tests/ui/dbg_macro.stderr
@@ -99,7 +99,7 @@ LL |     (1, 2, 3, 4, 5);
    |     ~~~~~~~~~~~~~~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:26:5
+  --> $DIR/dbg_macro.rs:42:5
    |
 LL |     dbg!();
    |     ^^^^^^^
@@ -111,7 +111,7 @@ LL +
    |
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:28:13
+  --> $DIR/dbg_macro.rs:44:13
    |
 LL |     let _ = dbg!();
    |             ^^^^^^
@@ -122,7 +122,7 @@ LL |     let _ = ();
    |             ~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:29:9
+  --> $DIR/dbg_macro.rs:45:9
    |
 LL |     bar(dbg!());
    |         ^^^^^^
@@ -133,7 +133,29 @@ LL |     bar(());
    |         ~~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:49:9
+  --> $DIR/dbg_macro.rs:46:10
+   |
+LL |     foo!(dbg!());
+   |          ^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL |     foo!(());
+   |          ~~
+
+error: the `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:47:16
+   |
+LL |     foo2!(foo!(dbg!()));
+   |                ^^^^^^
+   |
+help: remove the invocation before committing it to a version control system
+   |
+LL |     foo2!(foo!(()));
+   |                ~~
+
+error: the `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:68:9
    |
 LL |         dbg!(2);
    |         ^^^^^^^
@@ -144,7 +166,7 @@ LL |         2;
    |         ~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:55:5
+  --> $DIR/dbg_macro.rs:74:5
    |
 LL |     dbg!(1);
    |     ^^^^^^^
@@ -155,7 +177,7 @@ LL |     1;
    |     ~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:60:5
+  --> $DIR/dbg_macro.rs:79:5
    |
 LL |     dbg!(1);
    |     ^^^^^^^
@@ -166,7 +188,7 @@ LL |     1;
    |     ~
 
 error: the `dbg!` macro is intended as a debugging tool
-  --> $DIR/dbg_macro.rs:66:9
+  --> $DIR/dbg_macro.rs:85:9
    |
 LL |         dbg!(1);
    |         ^^^^^^^
@@ -176,5 +198,5 @@ help: remove the invocation before committing it to a version control system
 LL |         1;
    |         ~
 
-error: aborting due to 16 previous errors
+error: aborting due to 18 previous errors
 

From 79eb06c6ec8838f6929ee54681de346f1b6bbde4 Mon Sep 17 00:00:00 2001
From: Mick van Gelderen <mickvangelderen@gmail.com>
Date: Mon, 15 May 2023 22:24:37 +0200
Subject: [PATCH 64/78] Remove unnecessary  from  example

---
 clippy_lints/src/methods/mod.rs | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index cb86917464b..02d4a9aa08f 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -3133,8 +3133,11 @@ declare_clippy_lint! {
     /// ### Example
     /// ```rust
     /// # let iterator = vec![1].into_iter();
-    /// let len = iterator.clone().collect::<Vec<_>>().len();
-    /// // should be
+    /// let len = iterator.collect::<Vec<_>>().len();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # let iterator = vec![1].into_iter();
     /// let len = iterator.count();
     /// ```
     #[clippy::version = "1.30.0"]

From 2d9d81fc1e881f4ccf84c0509ffc23c8086cdcc6 Mon Sep 17 00:00:00 2001
From: Renato Lochetti <renato.lochetti@gmail.com>
Date: Tue, 16 May 2023 09:34:20 +0100
Subject: [PATCH 65/78] Checking for proc_macro not only when local.init is
 Some

---
 clippy_lints/src/let_underscore.rs | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs
index 0596ea732f3..34a9d217606 100644
--- a/clippy_lints/src/let_underscore.rs
+++ b/clippy_lints/src/let_underscore.rs
@@ -192,18 +192,18 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
             if local.pat.default_binding_modes && local.ty.is_none() {
                 // When `default_binding_modes` is true, the `let` keyword is present.
 
-				if let Some(init) = local.init {
-                    // Ignore function calls that return impl traits...
-                    if matches!(init.kind, ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _)) {
-                        let expr_ty = cx.typeck_results().expr_ty(init);
-                        if expr_ty.is_impl_trait() {
-                            return;
-                        }
-                    }
-                    // Ignore if it is from a procedural macro...
-                    if is_from_proc_macro(cx, init) {
-                        return;
-                    }
+				// Ignore function calls that return impl traits...
+				if let Some(init) = local.init &&
+				matches!(init.kind, ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _)) {
+					let expr_ty = cx.typeck_results().expr_ty(init);
+					if expr_ty.is_impl_trait() {
+						return;
+					}
+				}
+
+                // Ignore if it is from a procedural macro...
+                if is_from_proc_macro(cx, init) {
+                    return;
                 }
 
 				span_lint_and_help(

From fc126379be1063b5ceb4d07ad492ba2f780c8039 Mon Sep 17 00:00:00 2001
From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com>
Date: Tue, 16 May 2023 19:23:38 +0200
Subject: [PATCH 66/78] Remove `LangItems::require`

It's just a short wrapper used by `tcx.require_lang_item`. Deleting it
gives us a negative diff.
---
 clippy_lints/src/matches/redundant_pattern_match.rs | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index af121f317cd..0809837d1fd 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -289,10 +289,11 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte
     let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false };
 
     match expected_item {
-        Item::Lang(expected_lang_item) => {
-            let expected_id = cx.tcx.lang_items().require(expected_lang_item).unwrap();
-            cx.tcx.parent(id) == expected_id
-        },
+        Item::Lang(expected_lang_item) => cx
+            .tcx
+            .lang_items()
+            .get(expected_lang_item)
+            .map_or(false, |expected_id| cx.tcx.parent(id) == expected_id),
         Item::Diag(expected_ty, expected_variant) => {
             let ty = cx.typeck_results().pat_ty(pat);
 

From ae40b7f8cc261832862b407b7772c2798236db95 Mon Sep 17 00:00:00 2001
From: Catherine <114838443+Centri3@users.noreply.github.com>
Date: Tue, 16 May 2023 18:11:20 -0500
Subject: [PATCH 67/78] fix example heading in `string_slice`

---
 clippy_lints/src/strings.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index 5b588e914fd..483f860a8b5 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -132,7 +132,7 @@ declare_clippy_lint! {
     /// Probably lots of false positives. If an index comes from a known valid position (e.g.
     /// obtained via `char_indices` over the same string), it is totally OK.
     ///
-    /// # Example
+    /// ### Example
     /// ```rust,should_panic
     /// &"Ölkanne"[1..];
     /// ```

From 591f5f7ea906149fb99f0a80fbca9965ca429f37 Mon Sep 17 00:00:00 2001
From: adrianEffe <adrian.iosdev@gmail.com>
Date: Wed, 17 May 2023 22:37:38 +0300
Subject: [PATCH 68/78] Update urls in Type Checking

---
 book/src/development/type_checking.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/book/src/development/type_checking.md b/book/src/development/type_checking.md
index 225de849566..d7c2775b896 100644
--- a/book/src/development/type_checking.md
+++ b/book/src/development/type_checking.md
@@ -133,7 +133,7 @@ in this chapter:
 - [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html)
 - [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html)
 
-[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html#variant.Adt
+[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html#variant.Adt
 [AdtDef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html
 [expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty
 [node_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.node_type
@@ -142,9 +142,9 @@ in this chapter:
 [kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.kind
 [LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html
 [LateLintPass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
-[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty
+[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/typeck_results/struct.TypeckResults.html#method.pat_ty
 [Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html
-[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html
+[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html
 [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html
 [middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html
 [hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html

From 0eb364b8d6f6b77f0c43467d81867f7a196a1794 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= <me@fmease.dev>
Date: Wed, 17 May 2023 19:47:23 +0200
Subject: [PATCH 69/78] Exclude inherent projections from some alias ty matches

---
 tests/ui/issue-111399.rs | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 tests/ui/issue-111399.rs

diff --git a/tests/ui/issue-111399.rs b/tests/ui/issue-111399.rs
new file mode 100644
index 00000000000..b65e6c7261a
--- /dev/null
+++ b/tests/ui/issue-111399.rs
@@ -0,0 +1,13 @@
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+// Check that rustc doesn't crash on the trait bound `Self::Ty: std::marker::Freeze`.
+
+pub struct Struct;
+
+impl Struct {
+    pub type Ty = usize;
+    pub const CT: Self::Ty = 42;
+}
+
+fn main() {}

From cfa5aa2aad8e11508c4d57ee3113c8d0620a88d5 Mon Sep 17 00:00:00 2001
From: Alex Macleod <alex@macleod.io>
Date: Thu, 18 May 2023 12:33:52 +0000
Subject: [PATCH 70/78] Don't suggest unnameable types in box_default,
 let_underscore_untyped

---
 clippy_lints/src/box_default.rs    |  9 ++++++---
 clippy_lints/src/let_underscore.rs | 17 ++++++++---------
 tests/ui/box_default.fixed         |  9 ++++++++-
 tests/ui/box_default.rs            |  9 ++++++++-
 tests/ui/box_default.stderr        |  8 ++++----
 tests/ui/let_underscore_untyped.rs |  1 +
 6 files changed, 35 insertions(+), 18 deletions(-)

diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs
index dfa949d1af2..e42c3fe2432 100644
--- a/clippy_lints/src/box_default.rs
+++ b/clippy_lints/src/box_default.rs
@@ -8,7 +8,9 @@ use rustc_hir::{
     Block, Expr, ExprKind, Local, Node, QPath, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::{lint::in_external_macro, ty::print::with_forced_trimmed_paths};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::print::with_forced_trimmed_paths;
+use rustc_middle::ty::IsSuggestable;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
 
@@ -49,7 +51,6 @@ impl LateLintPass<'_> for BoxDefault {
             && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box())
             && is_default_equivalent(cx, arg)
         {
-            let arg_ty = cx.typeck_results().expr_ty(arg);
             span_lint_and_sugg(
                 cx,
                 BOX_DEFAULT,
@@ -58,8 +59,10 @@ impl LateLintPass<'_> for BoxDefault {
                 "try",
                 if is_plain_default(arg_path) || given_type(cx, expr) {
                     "Box::default()".into()
-                } else {
+                } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) {
                     with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()"))
+                } else {
+                    return
                 },
                 Applicability::MachineApplicable
             );
diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs
index 34a9d217606..e6614180920 100644
--- a/clippy_lints/src/let_underscore.rs
+++ b/clippy_lints/src/let_underscore.rs
@@ -2,10 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::is_from_proc_macro;
 use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
 use clippy_utils::{is_must_use_func_call, paths};
-use rustc_hir::{ExprKind, Local, PatKind};
+use rustc_hir::{Local, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::IsSuggestable;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{BytePos, Span};
 
@@ -192,14 +193,12 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
             if local.pat.default_binding_modes && local.ty.is_none() {
                 // When `default_binding_modes` is true, the `let` keyword is present.
 
-				// Ignore function calls that return impl traits...
-				if let Some(init) = local.init &&
-				matches!(init.kind, ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _)) {
-					let expr_ty = cx.typeck_results().expr_ty(init);
-					if expr_ty.is_impl_trait() {
-						return;
-					}
-				}
+                // Ignore unnameable types
+                if let Some(init) = local.init
+                    && !cx.typeck_results().expr_ty(init).is_suggestable(cx.tcx, true)
+                {
+                    return;
+                }
 
                 // Ignore if it is from a procedural macro...
                 if is_from_proc_macro(cx, init) {
diff --git a/tests/ui/box_default.fixed b/tests/ui/box_default.fixed
index e6331290420..fb066d8982e 100644
--- a/tests/ui/box_default.fixed
+++ b/tests/ui/box_default.fixed
@@ -1,6 +1,6 @@
 //@run-rustfix
 #![warn(clippy::box_default)]
-#![allow(clippy::default_constructed_unit_structs)]
+#![allow(unused, clippy::default_constructed_unit_structs)]
 
 #[derive(Default)]
 struct ImplementsDefault;
@@ -35,6 +35,13 @@ fn main() {
     let _more = ret_ty_fn();
     call_ty_fn(Box::default());
     issue_10381();
+
+    // `Box::<Option<_>>::default()` would be valid here, but not `Box::default()` or
+    // `Box::<Option<[closure@...]>::default()`
+    //
+    // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563
+    let mut unnameable = Box::new(Option::default());
+    let _ = unnameable.insert(|| {});
 }
 
 fn ret_ty_fn() -> Box<bool> {
diff --git a/tests/ui/box_default.rs b/tests/ui/box_default.rs
index 34a05a29c5a..2882170492c 100644
--- a/tests/ui/box_default.rs
+++ b/tests/ui/box_default.rs
@@ -1,6 +1,6 @@
 //@run-rustfix
 #![warn(clippy::box_default)]
-#![allow(clippy::default_constructed_unit_structs)]
+#![allow(unused, clippy::default_constructed_unit_structs)]
 
 #[derive(Default)]
 struct ImplementsDefault;
@@ -35,6 +35,13 @@ fn main() {
     let _more = ret_ty_fn();
     call_ty_fn(Box::new(u8::default()));
     issue_10381();
+
+    // `Box::<Option<_>>::default()` would be valid here, but not `Box::default()` or
+    // `Box::<Option<[closure@...]>::default()`
+    //
+    // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563
+    let mut unnameable = Box::new(Option::default());
+    let _ = unnameable.insert(|| {});
 }
 
 fn ret_ty_fn() -> Box<bool> {
diff --git a/tests/ui/box_default.stderr b/tests/ui/box_default.stderr
index c9834863601..13dfc5ae48a 100644
--- a/tests/ui/box_default.stderr
+++ b/tests/ui/box_default.stderr
@@ -73,25 +73,25 @@ LL |     call_ty_fn(Box::new(u8::default()));
    |                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:41:5
+  --> $DIR/box_default.rs:48:5
    |
 LL |     Box::new(bool::default())
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:58:28
+  --> $DIR/box_default.rs:65:28
    |
 LL |     let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:67:17
+  --> $DIR/box_default.rs:74:17
    |
 LL |         let _ = Box::new(WeirdPathed::default());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:79:18
+  --> $DIR/box_default.rs:86:18
    |
 LL |             Some(Box::new(Foo::default()))
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Foo>::default()`
diff --git a/tests/ui/let_underscore_untyped.rs b/tests/ui/let_underscore_untyped.rs
index 05ecd9b281a..2c313ff35d5 100644
--- a/tests/ui/let_underscore_untyped.rs
+++ b/tests/ui/let_underscore_untyped.rs
@@ -54,6 +54,7 @@ fn main() {
     let _ = e();
     let _ = f();
     let _ = g();
+    let closure = || {};
 
     _ = a();
     _ = b(1);

From 0b3c2ed81152a927c91c02d9d94762d2c65254a2 Mon Sep 17 00:00:00 2001
From: Jason Newcomb <jsnewcomb@pm.me>
Date: Tue, 7 Mar 2023 22:51:35 -0500
Subject: [PATCH 71/78] Search for inactive `cfg` attributes and empty macro
 expansion through the entire block

---
 clippy_lints/src/matches/mod.rs |  13 +--
 clippy_utils/src/hir_utils.rs   | 156 ++++++++++++++++++++++----------
 clippy_utils/src/lib.rs         |  34 +++----
 clippy_utils/src/source.rs      |  52 ++++++++++-
 tests/ui/match_same_arms.rs     |  48 +++++++++-
 5 files changed, 229 insertions(+), 74 deletions(-)

diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs
index 87b63eead25..55ec9d4474f 100644
--- a/clippy_lints/src/matches/mod.rs
+++ b/clippy_lints/src/matches/mod.rs
@@ -25,9 +25,9 @@ mod wild_in_or_pats;
 
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet_opt, walk_span_to_context};
-use clippy_utils::{higher, in_constant, is_span_match};
+use clippy_utils::{higher, in_constant, is_span_match, tokenize_with_text};
 use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
-use rustc_lexer::{tokenize, TokenKind};
+use rustc_lexer::TokenKind;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -1147,12 +1147,7 @@ fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool {
         // Assume true. This would require either an invalid span, or one which crosses file boundaries.
         return true;
     };
-    let mut pos = 0usize;
-    let mut iter = tokenize(&snip).map(|t| {
-        let start = pos;
-        pos += t.len as usize;
-        (t.kind, start..pos)
-    });
+    let mut iter = tokenize_with_text(&snip);
 
     // Search for the token sequence [`#`, `[`, `cfg`]
     while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) {
@@ -1163,7 +1158,7 @@ fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool {
             )
         });
         if matches!(iter.next(), Some((TokenKind::OpenBracket, _)))
-            && matches!(iter.next(), Some((TokenKind::Ident, range)) if &snip[range.clone()] == "cfg")
+            && matches!(iter.next(), Some((TokenKind::Ident, "cfg")))
         {
             return true;
         }
diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs
index 9b7408d5133..3561e760ac9 100644
--- a/clippy_utils/src/hir_utils.rs
+++ b/clippy_utils/src/hir_utils.rs
@@ -1,6 +1,7 @@
 use crate::consts::constant_simple;
 use crate::macros::macro_backtrace;
-use crate::source::snippet_opt;
+use crate::source::{get_source_text, snippet_opt, walk_span_to_context, SpanRange};
+use crate::tokenize_with_text;
 use rustc_ast::ast::InlineAsmTemplatePiece;
 use rustc_data_structures::fx::FxHasher;
 use rustc_hir::def::Res;
@@ -13,8 +14,9 @@ use rustc_hir::{
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::TypeckResults;
-use rustc_span::{sym, Symbol};
+use rustc_span::{sym, BytePos, Symbol, SyntaxContext};
 use std::hash::{Hash, Hasher};
+use std::ops::Range;
 
 /// Callback that is called when two expressions are not equal in the sense of `SpanlessEq`, but
 /// other conditions would make them equal.
@@ -127,51 +129,83 @@ impl HirEqInterExpr<'_, '_, '_> {
 
     /// Checks whether two blocks are the same.
     fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
-        match (left.stmts, left.expr, right.stmts, right.expr) {
-            ([], None, [], None) => {
-                // For empty blocks, check to see if the tokens are equal. This will catch the case where a macro
-                // expanded to nothing, or the cfg attribute was used.
-                let (Some(left), Some(right)) = (
-                    snippet_opt(self.inner.cx, left.span),
-                    snippet_opt(self.inner.cx, right.span),
-                ) else { return true };
-                let mut left_pos = 0;
-                let left = tokenize(&left)
-                    .map(|t| {
-                        let end = left_pos + t.len as usize;
-                        let s = &left[left_pos..end];
-                        left_pos = end;
-                        (t, s)
-                    })
-                    .filter(|(t, _)| {
-                        !matches!(
-                            t.kind,
-                            TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace
-                        )
-                    })
-                    .map(|(_, s)| s);
-                let mut right_pos = 0;
-                let right = tokenize(&right)
-                    .map(|t| {
-                        let end = right_pos + t.len as usize;
-                        let s = &right[right_pos..end];
-                        right_pos = end;
-                        (t, s)
-                    })
-                    .filter(|(t, _)| {
-                        !matches!(
-                            t.kind,
-                            TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace
-                        )
-                    })
-                    .map(|(_, s)| s);
-                left.eq(right)
-            },
-            _ => {
-                over(left.stmts, right.stmts, |l, r| self.eq_stmt(l, r))
-                    && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
-            },
+        use TokenKind::{BlockComment, LineComment, Semi, Whitespace};
+        if left.stmts.len() != right.stmts.len() {
+            return false;
         }
+        let lspan = left.span.data();
+        let rspan = right.span.data();
+        if lspan.ctxt != SyntaxContext::root() && rspan.ctxt != SyntaxContext::root() {
+            // Don't try to check in between statements inside macros.
+            return over(left.stmts, right.stmts, |left, right| self.eq_stmt(left, right))
+                && both(&left.expr, &right.expr, |left, right| self.eq_expr(left, right));
+        }
+        if lspan.ctxt != rspan.ctxt {
+            return false;
+        }
+
+        let mut lstart = lspan.lo;
+        let mut rstart = rspan.lo;
+
+        for (left, right) in left.stmts.iter().zip(right.stmts) {
+            if !self.eq_stmt(left, right) {
+                return false;
+            }
+            let Some(lstmt_span) = walk_span_to_context(left.span, lspan.ctxt) else {
+                return false;
+            };
+            let Some(rstmt_span) = walk_span_to_context(right.span, rspan.ctxt) else {
+                return false;
+            };
+            let lstmt_span = lstmt_span.data();
+            let rstmt_span = rstmt_span.data();
+
+            if lstmt_span.lo < lstart && rstmt_span.lo < rstart {
+                // Can happen when macros expand to multiple statements, or rearrange statements.
+                // Nothing in between the statements to check in this case.
+                continue;
+            } else if lstmt_span.lo < lstart || rstmt_span.lo < rstart {
+                // Only one of the blocks had a weird macro.
+                return false;
+            }
+            if !eq_span_tokens(self.inner.cx, lstart..lstmt_span.lo, rstart..rstmt_span.lo, |t| {
+                !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi)
+            }) {
+                return false;
+            }
+
+            lstart = lstmt_span.hi;
+            rstart = rstmt_span.hi;
+        }
+
+        let (lend, rend) = match (left.expr, right.expr) {
+            (Some(left), Some(right)) => {
+                if !self.eq_expr(left, right) {
+                    return false;
+                }
+                let Some(lexpr_span) = walk_span_to_context(left.span, lspan.ctxt) else {
+                    return false;
+                };
+                let Some(rexpr_span) = walk_span_to_context(right.span, rspan.ctxt) else {
+                    return false;
+                };
+                (lexpr_span.lo(), rexpr_span.lo())
+            },
+            (None, None) => (lspan.hi, rspan.hi),
+            (Some(_), None) | (None, Some(_)) => return false,
+        };
+
+        if lend < lstart && rend < rstart {
+            // Can happen when macros rearrange the input.
+            // Nothing in between the statements to check in this case.
+            return true;
+        } else if lend < lstart || rend < rstart {
+            // Only one of the blocks had a weird macro
+            return false;
+        }
+        eq_span_tokens(self.inner.cx, lstart..lend, rstart..rend, |t| {
+            !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi)
+        })
     }
 
     fn should_ignore(&mut self, expr: &Expr<'_>) -> bool {
@@ -1038,3 +1072,33 @@ pub fn hash_expr(cx: &LateContext<'_>, e: &Expr<'_>) -> u64 {
     h.hash_expr(e);
     h.finish()
 }
+
+fn eq_span_tokens(
+    cx: &LateContext<'_>,
+    left: impl SpanRange,
+    right: impl SpanRange,
+    pred: impl Fn(TokenKind) -> bool,
+) -> bool {
+    fn f(cx: &LateContext<'_>, left: Range<BytePos>, right: Range<BytePos>, pred: impl Fn(TokenKind) -> bool) -> bool {
+        if let Some(lsrc) = get_source_text(cx, left)
+            && let Some(lsrc) = lsrc.as_str()
+            && let Some(rsrc) = get_source_text(cx, right)
+            && let Some(rsrc) = rsrc.as_str()
+        {
+            let pred = |t: &(_, _)| pred(t.0);
+            let map = |(_, x)| x;
+
+            let ltok = tokenize_with_text(lsrc)
+                .filter(pred)
+                .map(map);
+            let rtok = tokenize_with_text(rsrc)
+                .filter(pred)
+                .map(map);
+            ltok.eq(rtok)
+        } else {
+            // Unable to access the source. Conservatively assume the blocks aren't equal.
+            false
+        }
+    }
+    f(cx, left.into_range(), right.into_range(), pred)
+}
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 2e27c260f74..2ddd2ade6ae 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -77,6 +77,7 @@ use std::sync::OnceLock;
 use std::sync::{Mutex, MutexGuard};
 
 use if_chain::if_chain;
+use itertools::Itertools;
 use rustc_ast::ast::{self, LitKind, RangeLimits};
 use rustc_ast::Attribute;
 use rustc_data_structures::fx::FxHashMap;
@@ -2490,6 +2491,17 @@ pub fn walk_to_expr_usage<'tcx, T>(
     None
 }
 
+/// Tokenizes the input while keeping the text associated with each token.
+pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str)> {
+    let mut pos = 0;
+    tokenize(s).map(move |t| {
+        let end = pos + t.len;
+        let range = pos as usize..end as usize;
+        pos = end;
+        (t.kind, s.get(range).unwrap_or_default())
+    })
+}
+
 /// Checks whether a given span has any comment token
 /// This checks for all types of comment: line "//", block "/**", doc "///" "//!"
 pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
@@ -2506,23 +2518,11 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool {
 /// Comments are returned wrapped with their relevant delimiters
 pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String {
     let snippet = sm.span_to_snippet(span).unwrap_or_default();
-    let mut comments_buf: Vec<String> = Vec::new();
-    let mut index: usize = 0;
-
-    for token in tokenize(&snippet) {
-        let token_range = index..(index + token.len as usize);
-        index += token.len as usize;
-        match token.kind {
-            TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => {
-                if let Some(comment) = snippet.get(token_range) {
-                    comments_buf.push(comment.to_string());
-                }
-            },
-            _ => (),
-        }
-    }
-
-    comments_buf.join("\n")
+    let res = tokenize_with_text(&snippet)
+        .filter(|(t, _)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }))
+        .map(|(_, s)| s)
+        .join("\n");
+    res
 }
 
 pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span {
diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs
index 62fa37660fa..0f60290644a 100644
--- a/clippy_utils/src/source.rs
+++ b/clippy_utils/src/source.rs
@@ -2,14 +2,64 @@
 
 #![allow(clippy::module_name_repetitions)]
 
+use rustc_data_structures::sync::Lrc;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_session::Session;
-use rustc_span::hygiene;
 use rustc_span::source_map::{original_sp, SourceMap};
+use rustc_span::{hygiene, SourceFile};
 use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP};
 use std::borrow::Cow;
+use std::ops::Range;
+
+/// A type which can be converted to the range portion of a `Span`.
+pub trait SpanRange {
+    fn into_range(self) -> Range<BytePos>;
+}
+impl SpanRange for Span {
+    fn into_range(self) -> Range<BytePos> {
+        let data = self.data();
+        data.lo..data.hi
+    }
+}
+impl SpanRange for SpanData {
+    fn into_range(self) -> Range<BytePos> {
+        self.lo..self.hi
+    }
+}
+impl SpanRange for Range<BytePos> {
+    fn into_range(self) -> Range<BytePos> {
+        self
+    }
+}
+
+pub struct SourceFileRange {
+    pub sf: Lrc<SourceFile>,
+    pub range: Range<usize>,
+}
+impl SourceFileRange {
+    /// Attempts to get the text from the source file. This can fail if the source text isn't
+    /// loaded.
+    pub fn as_str(&self) -> Option<&str> {
+        self.sf.src.as_ref().and_then(|x| x.get(self.range.clone()))
+    }
+}
+
+/// Gets the source file, and range in the file, of the given span. Returns `None` if the span
+/// extends through multiple files, or is malformed.
+pub fn get_source_text(cx: &impl LintContext, sp: impl SpanRange) -> Option<SourceFileRange> {
+    fn f(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> {
+        let start = sm.lookup_byte_offset(sp.start);
+        let end = sm.lookup_byte_offset(sp.end);
+        if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos {
+            return None;
+        }
+        let range = start.pos.to_usize()..end.pos.to_usize();
+        Some(SourceFileRange { sf: start.sf, range })
+    }
+    f(cx.sess().source_map(), sp.into_range())
+}
 
 /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
 pub fn expr_block<T: LintContext>(
diff --git a/tests/ui/match_same_arms.rs b/tests/ui/match_same_arms.rs
index 0b9342c9c42..15410734dec 100644
--- a/tests/ui/match_same_arms.rs
+++ b/tests/ui/match_same_arms.rs
@@ -53,4 +53,50 @@ mod issue4244 {
     }
 }
 
-fn main() {}
+macro_rules! m {
+    (foo) => {};
+    (bar) => {};
+}
+
+fn main() {
+    let x = 0;
+    let _ = match 0 {
+        0 => {
+            m!(foo);
+            x
+        },
+        1 => {
+            m!(bar);
+            x
+        },
+        _ => 1,
+    };
+
+    let _ = match 0 {
+        0 => {
+            let mut x = 0;
+            #[cfg(not_enabled)]
+            {
+                x = 5;
+            }
+            #[cfg(not(not_enabled))]
+            {
+                x = 6;
+            }
+            x
+        },
+        1 => {
+            let mut x = 0;
+            #[cfg(also_not_enabled)]
+            {
+                x = 5;
+            }
+            #[cfg(not(also_not_enabled))]
+            {
+                x = 6;
+            }
+            x
+        },
+        _ => 0,
+    };
+}

From 5351170744bdc6dfca0f57908cd072cfa84a3f30 Mon Sep 17 00:00:00 2001
From: Jason Newcomb <jsnewcomb@pm.me>
Date: Thu, 9 Mar 2023 15:46:46 -0500
Subject: [PATCH 72/78] Slightly refactor constant evaluation and add detection
 for empty macro expansion and `cfg`ed statements.

---
 clippy_lints/src/assertions_on_constants.rs   |   2 +-
 clippy_lints/src/casts/cast_nan_to_int.rs     |   4 +-
 .../src/casts/cast_possible_truncation.rs     |   2 +-
 clippy_lints/src/casts/cast_sign_loss.rs      |   2 +-
 clippy_lints/src/floating_point_arithmetic.rs |  22 ++--
 clippy_lints/src/fn_null_check.rs             |   6 +-
 clippy_lints/src/implicit_saturating_add.rs   |   4 +-
 clippy_lints/src/index_refutable_slice.rs     |   2 +-
 clippy_lints/src/indexing_slicing.rs          |   8 +-
 clippy_lints/src/manual_strip.rs              |   2 +-
 clippy_lints/src/matches/overlapping_arms.rs  |   4 +-
 clippy_lints/src/methods/iter_nth_zero.rs     |   2 +-
 .../src/methods/iterator_step_by_zero.rs      |   2 +-
 clippy_lints/src/methods/mod.rs               |   4 +-
 clippy_lints/src/methods/repeat_once.rs       |   4 +-
 clippy_lints/src/methods/str_splitn.rs        |   2 +-
 .../operators/absurd_extreme_comparisons.rs   |   2 +-
 .../src/operators/arithmetic_side_effects.rs  |   2 +-
 clippy_lints/src/operators/bit_mask.rs        |   2 +-
 clippy_lints/src/operators/cmp_nan.rs         |   2 +-
 clippy_lints/src/operators/duration_subsec.rs |   2 +-
 clippy_lints/src/operators/float_cmp.rs       |  61 +++++-----
 .../src/operators/modulo_arithmetic.rs        |   6 +-
 clippy_lints/src/ranges.rs                    |   8 +-
 clippy_lints/src/regex.rs                     |   2 +-
 .../src/transmute/transmute_null_to_fn.rs     |   4 +-
 .../src/transmute/transmuting_null.rs         |   5 +-
 clippy_lints/src/vec.rs                       |   2 +-
 clippy_utils/src/consts.rs                    | 107 ++++++++++++------
 clippy_utils/src/hir_utils.rs                 |   2 +
 clippy_utils/src/lib.rs                       |   2 +-
 tests/ui/match_same_arms.rs                   |  12 ++
 32 files changed, 165 insertions(+), 128 deletions(-)

diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs
index a36df55d0bd..a8dc0cb3b58 100644
--- a/clippy_lints/src/assertions_on_constants.rs
+++ b/clippy_lints/src/assertions_on_constants.rs
@@ -38,7 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
             _ => return,
         };
         let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return };
-        let Some((Constant::Bool(val), _)) = constant(cx, cx.typeck_results(), condition) else { return };
+        let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else { return };
         if val {
             span_lint_and_help(
                 cx,
diff --git a/clippy_lints/src/casts/cast_nan_to_int.rs b/clippy_lints/src/casts/cast_nan_to_int.rs
index 322dc41b3a1..da756129db3 100644
--- a/clippy_lints/src/casts/cast_nan_to_int.rs
+++ b/clippy_lints/src/casts/cast_nan_to_int.rs
@@ -21,8 +21,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
 
 fn is_known_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     match constant(cx, cx.typeck_results(), e) {
-        Some((Constant::F64(n), _)) => n.is_nan(),
-        Some((Constant::F32(n), _)) => n.is_nan(),
+        Some(Constant::F64(n)) => n.is_nan(),
+        Some(Constant::F32(n)) => n.is_nan(),
         _ => false,
     }
 }
diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs
index 95c2ecbf791..84b99ad5c24 100644
--- a/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -15,7 +15,7 @@ use rustc_target::abi::IntegerType;
 use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION};
 
 fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
-    if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) {
+    if let Some(Constant::Int(c)) = constant(cx, cx.typeck_results(), expr) {
         Some(c)
     } else {
         None
diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs
index a20a97d4e56..a83dfd94dc2 100644
--- a/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/clippy_lints/src/casts/cast_sign_loss.rs
@@ -29,7 +29,7 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
             // Don't lint for positive constants.
             let const_val = constant(cx, cx.typeck_results(), cast_op);
             if_chain! {
-                if let Some((Constant::Int(n), _)) = const_val;
+                if let Some(Constant::Int(n)) = const_val;
                 if let ty::Int(ity) = *cast_from.kind();
                 if sext(cx.tcx, n, ity) >= 0;
                 then {
diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs
index a1a2c398a8a..3c55a563af4 100644
--- a/clippy_lints/src/floating_point_arithmetic.rs
+++ b/clippy_lints/src/floating_point_arithmetic.rs
@@ -114,7 +114,7 @@ declare_lint_pass!(FloatingPointArithmetic => [
 // Returns the specialized log method for a given base if base is constant
 // and is one of 2, 10 and e
 fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>) -> Option<&'static str> {
-    if let Some((value, _)) = constant(cx, cx.typeck_results(), base) {
+    if let Some(value) = constant(cx, cx.typeck_results(), base) {
         if F32(2.0) == value || F64(2.0) == value {
             return Some("log2");
         } else if F32(10.0) == value || F64(10.0) == value {
@@ -193,8 +193,8 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
             constant(cx, cx.typeck_results(), lhs),
             constant(cx, cx.typeck_results(), rhs),
         ) {
-            (Some((value, _)), _) if F32(1.0) == value || F64(1.0) == value => rhs,
-            (_, Some((value, _))) if F32(1.0) == value || F64(1.0) == value => lhs,
+            (Some(value), _) if F32(1.0) == value || F64(1.0) == value => rhs,
+            (_, Some(value)) if F32(1.0) == value || F64(1.0) == value => lhs,
             _ => return,
         };
 
@@ -237,7 +237,7 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
 
 fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
     // Check receiver
-    if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) {
+    if let Some(value) = constant(cx, cx.typeck_results(), receiver) {
         if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
             Some("exp")
         } else if F32(2.0) == value || F64(2.0) == value {
@@ -258,7 +258,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
     }
 
     // Check argument
-    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
+    if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) {
         let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value {
             (
                 SUBOPTIMAL_FLOPS,
@@ -298,7 +298,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
 }
 
 fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
-    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
+    if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) {
         if value == Int(2) {
             if let Some(parent) = get_parent_expr(cx, expr) {
                 if let Some(grandparent) = get_parent_expr(cx, parent) {
@@ -384,8 +384,8 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
                 _
             ) = &add_rhs.kind;
             if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
-            if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), largs_1);
-            if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), rargs_1);
+            if let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1);
+            if let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1);
             if Int(2) == lvalue && Int(2) == rvalue;
             then {
                 return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, "..")));
@@ -416,7 +416,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
         if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind;
         if cx.typeck_results().expr_ty(lhs).is_floating_point();
-        if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs);
+        if let Some(value) = constant(cx, cx.typeck_results(), rhs);
         if F32(1.0) == value || F64(1.0) == value;
         if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind;
         if cx.typeck_results().expr_ty(self_arg).is_floating_point();
@@ -669,8 +669,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             mul_lhs,
             mul_rhs,
         ) = &div_lhs.kind;
-        if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), div_rhs);
-        if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), mul_rhs);
+        if let Some(rvalue) = constant(cx, cx.typeck_results(), div_rhs);
+        if let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs);
         then {
             // TODO: also check for constant values near PI/180 or 180/PI
             if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) &&
diff --git a/clippy_lints/src/fn_null_check.rs b/clippy_lints/src/fn_null_check.rs
index d8f4a5fe221..521045a9fed 100644
--- a/clippy_lints/src/fn_null_check.rs
+++ b/clippy_lints/src/fn_null_check.rs
@@ -89,11 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for FnNullCheck {
 
                     // Catching:
                     // (fn_ptr as *<const/mut> <ty>) == <const that evaluates to null_ptr>
-                    _ if matches!(
-                        constant(cx, cx.typeck_results(), to_check),
-                        Some((Constant::RawPtr(0), _))
-                    ) =>
-                    {
+                    _ if matches!(constant(cx, cx.typeck_results(), to_check), Some(Constant::RawPtr(0))) => {
                         lint_expr(cx, expr);
                     },
 
diff --git a/clippy_lints/src/implicit_saturating_add.rs b/clippy_lints/src/implicit_saturating_add.rs
index 012aa5a1d1d..ee7973b82ab 100644
--- a/clippy_lints/src/implicit_saturating_add.rs
+++ b/clippy_lints/src/implicit_saturating_add.rs
@@ -101,10 +101,10 @@ fn get_int_max(ty: Ty<'_>) -> Option<u128> {
 fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, BinOpKind, &'tcx Expr<'tcx>)> {
     if let ExprKind::Binary(op, l, r) = expr.kind {
         let tr = cx.typeck_results();
-        if let Some((Constant::Int(c), _)) = constant(cx, tr, r) {
+        if let Some(Constant::Int(c)) = constant(cx, tr, r) {
             return Some((c, op.node, l));
         };
-        if let Some((Constant::Int(c), _)) = constant(cx, tr, l) {
+        if let Some(Constant::Int(c)) = constant(cx, tr, l) {
             return Some((c, invert_op(op.node)?, r));
         }
     }
diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs
index bdeddf44df7..7a269e98ff1 100644
--- a/clippy_lints/src/index_refutable_slice.rs
+++ b/clippy_lints/src/index_refutable_slice.rs
@@ -254,7 +254,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
                 let parent_id = map.parent_id(expr.hir_id);
                 if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id);
                 if let hir::ExprKind::Index(_, index_expr) = parent_expr.kind;
-                if let Some((Constant::Int(index_value), _)) = constant(cx, cx.typeck_results(), index_expr);
+                if let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr);
                 if let Ok(index_value) = index_value.try_into();
                 if index_value < max_suggested_slice;
 
diff --git a/clippy_lints/src/indexing_slicing.rs b/clippy_lints/src/indexing_slicing.rs
index 924a361c0f6..22c14d9b04d 100644
--- a/clippy_lints/src/indexing_slicing.rs
+++ b/clippy_lints/src/indexing_slicing.rs
@@ -191,18 +191,14 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing {
 /// Returns a tuple of options with the start and end (exclusive) values of
 /// the range. If the start or end is not constant, None is returned.
 fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u128) -> (Option<u128>, Option<u128>) {
-    let s = range
-        .start
-        .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c));
+    let s = range.start.map(|expr| constant(cx, cx.typeck_results(), expr));
     let start = match s {
         Some(Some(Constant::Int(x))) => Some(x),
         Some(_) => None,
         None => Some(0),
     };
 
-    let e = range
-        .end
-        .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c));
+    let e = range.end.map(|expr| constant(cx, cx.typeck_results(), expr));
     let end = match e {
         Some(Some(Constant::Int(x))) => {
             if range.limits == RangeLimits::Closed {
diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs
index 7d28c111624..93d977a5c96 100644
--- a/clippy_lints/src/manual_strip.rs
+++ b/clippy_lints/src/manual_strip.rs
@@ -144,7 +144,7 @@ fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx E
 
 // Returns the length of the `expr` if it's a constant string or char.
 fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
-    let (value, _) = constant(cx, cx.typeck_results(), expr)?;
+    let value = constant(cx, cx.typeck_results(), expr)?;
     match value {
         Constant::Str(value) => Some(value.len() as u128),
         Constant::Char(value) => Some(value.len_utf8() as u128),
diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs
index ae69ca8a339..abf2525a61c 100644
--- a/clippy_lints/src/matches/overlapping_arms.rs
+++ b/clippy_lints/src/matches/overlapping_arms.rs
@@ -34,7 +34,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
             if let Arm { pat, guard: None, .. } = *arm {
                 if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
                     let lhs_const = match lhs {
-                        Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
+                        Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
                         None => {
                             let min_val_const = ty.numeric_min_val(cx.tcx)?;
                             let min_constant = mir::ConstantKind::from_value(
@@ -45,7 +45,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                         },
                     };
                     let rhs_const = match rhs {
-                        Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
+                        Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
                         None => {
                             let max_val_const = ty.numeric_max_val(cx.tcx)?;
                             let max_constant = mir::ConstantKind::from_value(
diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs
index c830958d5c8..d1609eebfdc 100644
--- a/clippy_lints/src/methods/iter_nth_zero.rs
+++ b/clippy_lints/src/methods/iter_nth_zero.rs
@@ -13,7 +13,7 @@ use super::ITER_NTH_ZERO;
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
     if_chain! {
         if is_trait_method(cx, expr, sym::Iterator);
-        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg);
+        if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg);
         then {
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
diff --git a/clippy_lints/src/methods/iterator_step_by_zero.rs b/clippy_lints/src/methods/iterator_step_by_zero.rs
index 64c09214a76..b631cd00cda 100644
--- a/clippy_lints/src/methods/iterator_step_by_zero.rs
+++ b/clippy_lints/src/methods/iterator_step_by_zero.rs
@@ -9,7 +9,7 @@ use super::ITERATOR_STEP_BY_ZERO;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
     if is_trait_method(cx, expr, sym::Iterator) {
-        if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg) {
+        if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg) {
             span_lint(
                 cx,
                 ITERATOR_STEP_BY_ZERO,
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 02d4a9aa08f..9a594d964ab 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -3770,13 +3770,13 @@ impl Methods {
                     unnecessary_sort_by::check(cx, expr, recv, arg, true);
                 },
                 ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
-                    if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
+                    if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
                         str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv);
                     }
                 },
                 ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
-                    if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
+                    if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
                     }
                 },
diff --git a/clippy_lints/src/methods/repeat_once.rs b/clippy_lints/src/methods/repeat_once.rs
index a345ec813ff..bb4cdd2a6fa 100644
--- a/clippy_lints/src/methods/repeat_once.rs
+++ b/clippy_lints/src/methods/repeat_once.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_context, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_lang_item;
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(
     recv: &'tcx Expr<'_>,
     repeat_arg: &'tcx Expr<'_>,
 ) {
-    if constant_context(cx, cx.typeck_results()).expr(repeat_arg) == Some(Constant::Int(1)) {
+    if constant(cx, cx.typeck_results(), repeat_arg) == Some(Constant::Int(1)) {
         let ty = cx.typeck_results().expr_ty(recv).peel_refs();
         if ty.is_str() {
             span_lint_and_sugg(
diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs
index 91f7ce1dbe5..5ea12c44184 100644
--- a/clippy_lints/src/methods/str_splitn.rs
+++ b/clippy_lints/src/methods/str_splitn.rs
@@ -316,7 +316,7 @@ fn parse_iter_usage<'tcx>(
                     };
                 },
                 ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
-                    if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) {
+                    if let Some(Constant::Int(idx)) = constant(cx, cx.typeck_results(), idx_expr) {
                         let span = if name.ident.as_str() == "nth" {
                             e.span
                         } else {
diff --git a/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/clippy_lints/src/operators/absurd_extreme_comparisons.rs
index d29ca37eaeb..f4863600ccc 100644
--- a/clippy_lints/src/operators/absurd_extreme_comparisons.rs
+++ b/clippy_lints/src/operators/absurd_extreme_comparisons.rs
@@ -121,7 +121,7 @@ fn detect_absurd_comparison<'tcx>(
 fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> {
     let ty = cx.typeck_results().expr_ty(expr);
 
-    let cv = constant(cx, cx.typeck_results(), expr)?.0;
+    let cv = constant(cx, cx.typeck_results(), expr)?;
 
     let which = match (ty.kind(), cv) {
         (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => ExtremeType::Minimum,
diff --git a/clippy_lints/src/operators/arithmetic_side_effects.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs
index c80e2ff7057..5c240276b76 100644
--- a/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -113,7 +113,7 @@ impl ArithmeticSideEffects {
         if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
             return Some(n)
         }
-        if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) {
+        if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) {
             return Some(n);
         }
         None
diff --git a/clippy_lints/src/operators/bit_mask.rs b/clippy_lints/src/operators/bit_mask.rs
index 1369b3e7462..1fddf0f50e3 100644
--- a/clippy_lints/src/operators/bit_mask.rs
+++ b/clippy_lints/src/operators/bit_mask.rs
@@ -166,7 +166,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op:
 }
 
 fn fetch_int_literal(cx: &LateContext<'_>, lit: &Expr<'_>) -> Option<u128> {
-    match constant(cx, cx.typeck_results(), lit)?.0 {
+    match constant(cx, cx.typeck_results(), lit)? {
         Constant::Int(n) => Some(n),
         _ => None,
     }
diff --git a/clippy_lints/src/operators/cmp_nan.rs b/clippy_lints/src/operators/cmp_nan.rs
index 786ae1552ad..e18064b7061 100644
--- a/clippy_lints/src/operators/cmp_nan.rs
+++ b/clippy_lints/src/operators/cmp_nan.rs
@@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp
 }
 
 fn is_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    if let Some((value, _)) = constant(cx, cx.typeck_results(), e) {
+    if let Some(value) = constant(cx, cx.typeck_results(), e) {
         match value {
             Constant::F32(num) => num.is_nan(),
             Constant::F64(num) => num.is_nan(),
diff --git a/clippy_lints/src/operators/duration_subsec.rs b/clippy_lints/src/operators/duration_subsec.rs
index 49e662cacb0..f120be13836 100644
--- a/clippy_lints/src/operators/duration_subsec.rs
+++ b/clippy_lints/src/operators/duration_subsec.rs
@@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(
     if op == BinOpKind::Div
         && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind
         && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration)
-        && let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right)
+        && let Some(Constant::Int(divisor)) = constant(cx, cx.typeck_results(), right)
     {
         let suggested_fn = match (method_path.ident.as_str(), divisor) {
             ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis",
diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs
index 97ddcdb2479..15dff126be7 100644
--- a/clippy_lints/src/operators/float_cmp.rs
+++ b/clippy_lints/src/operators/float_cmp.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{constant_with_source, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::get_item_name;
 use clippy_utils::sugg::Sugg;
@@ -18,9 +18,16 @@ pub(crate) fn check<'tcx>(
     right: &'tcx Expr<'_>,
 ) {
     if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) {
-        if is_allowed(cx, left) || is_allowed(cx, right) {
-            return;
-        }
+        let left_is_local = match constant_with_source(cx, cx.typeck_results(), left) {
+            Some((c, s)) if !is_allowed(&c) => s.is_local(),
+            Some(_) => return,
+            None => true,
+        };
+        let right_is_local = match constant_with_source(cx, cx.typeck_results(), right) {
+            Some((c, s)) if !is_allowed(&c) => s.is_local(),
+            Some(_) => return,
+            None => true,
+        };
 
         // Allow comparing the results of signum()
         if is_signum(cx, left) && is_signum(cx, right) {
@@ -34,10 +41,7 @@ pub(crate) fn check<'tcx>(
             }
         }
         let is_comparing_arrays = is_array(cx, left) || is_array(cx, right);
-        let (lint, msg) = get_lint_and_message(
-            is_named_constant(cx, left) || is_named_constant(cx, right),
-            is_comparing_arrays,
-        );
+        let (lint, msg) = get_lint_and_message(left_is_local && right_is_local, is_comparing_arrays);
         span_lint_and_then(cx, lint, expr.span, msg, |diag| {
             let lhs = Sugg::hir(cx, left, "..");
             let rhs = Sugg::hir(cx, right, "..");
@@ -59,20 +63,8 @@ pub(crate) fn check<'tcx>(
     }
 }
 
-fn get_lint_and_message(
-    is_comparing_constants: bool,
-    is_comparing_arrays: bool,
-) -> (&'static rustc_lint::Lint, &'static str) {
-    if is_comparing_constants {
-        (
-            FLOAT_CMP_CONST,
-            if is_comparing_arrays {
-                "strict comparison of `f32` or `f64` constant arrays"
-            } else {
-                "strict comparison of `f32` or `f64` constant"
-            },
-        )
-    } else {
+fn get_lint_and_message(is_local: bool, is_comparing_arrays: bool) -> (&'static rustc_lint::Lint, &'static str) {
+    if is_local {
         (
             FLOAT_CMP,
             if is_comparing_arrays {
@@ -81,22 +73,23 @@ fn get_lint_and_message(
                 "strict comparison of `f32` or `f64`"
             },
         )
-    }
-}
-
-fn is_named_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
-    if let Some((_, res)) = constant(cx, cx.typeck_results(), expr) {
-        res
     } else {
-        false
+        (
+            FLOAT_CMP_CONST,
+            if is_comparing_arrays {
+                "strict comparison of `f32` or `f64` constant arrays"
+            } else {
+                "strict comparison of `f32` or `f64` constant"
+            },
+        )
     }
 }
 
-fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
-    match constant(cx, cx.typeck_results(), expr) {
-        Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(),
-        Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(),
-        Some((Constant::Vec(vec), _)) => vec.iter().all(|f| match f {
+fn is_allowed(val: &Constant) -> bool {
+    match val {
+        &Constant::F32(f) => f == 0.0 || f.is_infinite(),
+        &Constant::F64(f) => f == 0.0 || f.is_infinite(),
+        Constant::Vec(vec) => vec.iter().all(|f| match f {
             Constant::F32(f) => *f == 0.0 || (*f).is_infinite(),
             Constant::F64(f) => *f == 0.0 || (*f).is_infinite(),
             _ => false,
diff --git a/clippy_lints/src/operators/modulo_arithmetic.rs b/clippy_lints/src/operators/modulo_arithmetic.rs
index af4e74947f4..a2c3a4d8ba7 100644
--- a/clippy_lints/src/operators/modulo_arithmetic.rs
+++ b/clippy_lints/src/operators/modulo_arithmetic.rs
@@ -40,7 +40,7 @@ struct OperandInfo {
 
 fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OperandInfo> {
     match constant(cx, cx.typeck_results(), operand) {
-        Some((Constant::Int(v), _)) => match *cx.typeck_results().expr_ty(expr).kind() {
+        Some(Constant::Int(v)) => match *cx.typeck_results().expr_ty(expr).kind() {
             ty::Int(ity) => {
                 let value = sext(cx.tcx, v, ity);
                 return Some(OperandInfo {
@@ -58,10 +58,10 @@ fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) ->
             },
             _ => {},
         },
-        Some((Constant::F32(f), _)) => {
+        Some(Constant::F32(f)) => {
             return Some(floating_point_operand_info(&f));
         },
-        Some((Constant::F64(f), _)) => {
+        Some(Constant::F64(f)) => {
             return Some(floating_point_operand_info(&f));
         },
         _ => {},
diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs
index fc655fe2d0b..dd7ded491e7 100644
--- a/clippy_lints/src/ranges.rs
+++ b/clippy_lints/src/ranges.rs
@@ -319,7 +319,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R
             _ => return None,
         };
         if let Some(id) = path_to_local(l) {
-            if let Some((c, _)) = constant(cx, cx.typeck_results(), r) {
+            if let Some(c) = constant(cx, cx.typeck_results(), r) {
                 return Some(RangeBounds {
                     val: c,
                     expr: r,
@@ -331,7 +331,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R
                 });
             }
         } else if let Some(id) = path_to_local(r) {
-            if let Some((c, _)) = constant(cx, cx.typeck_results(), l) {
+            if let Some(c) = constant(cx, cx.typeck_results(), l) {
                 return Some(RangeBounds {
                     val: c,
                     expr: l,
@@ -451,8 +451,8 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::Range::hir(expr);
         let ty = cx.typeck_results().expr_ty(start);
         if let ty::Int(_) | ty::Uint(_) = ty.kind();
-        if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start);
-        if let Some((end_idx, _)) = constant(cx, cx.typeck_results(), end);
+        if let Some(start_idx) = constant(cx, cx.typeck_results(), start);
+        if let Some(end_idx) = constant(cx, cx.typeck_results(), end);
         if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx);
         if is_empty_range(limits, ordering);
         then {
diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs
index fe5be248700..ef19c6f4617 100644
--- a/clippy_lints/src/regex.rs
+++ b/clippy_lints/src/regex.rs
@@ -122,7 +122,7 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: &regex_syntax::Error, unescape
 }
 
 fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String> {
-    constant(cx, cx.typeck_results(), e).and_then(|(c, _)| match c {
+    constant(cx, cx.typeck_results(), e).and_then(|c| match c {
         Constant::Str(s) => Some(s),
         _ => None,
     })
diff --git a/clippy_lints/src/transmute/transmute_null_to_fn.rs b/clippy_lints/src/transmute/transmute_null_to_fn.rs
index e75d7f6bf1d..4944381da24 100644
--- a/clippy_lints/src/transmute/transmute_null_to_fn.rs
+++ b/clippy_lints/src/transmute/transmute_null_to_fn.rs
@@ -31,9 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
     match arg.kind {
         // Catching:
         // transmute over constants that resolve to `null`.
-        ExprKind::Path(ref _qpath)
-            if matches!(constant(cx, cx.typeck_results(), arg), Some((Constant::RawPtr(0), _))) =>
-        {
+        ExprKind::Path(ref _qpath) if matches!(constant(cx, cx.typeck_results(), arg), Some(Constant::RawPtr(0))) => {
             lint_expr(cx, expr);
             true
         },
diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs
index 1e407fc4138..770914e99e1 100644
--- a/clippy_lints/src/transmute/transmuting_null.rs
+++ b/clippy_lints/src/transmute/transmuting_null.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant_context, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{is_integer_literal, is_path_diagnostic_item};
 use rustc_hir::{Expr, ExprKind};
@@ -16,9 +16,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
     }
 
     // Catching transmute over constants that resolve to `null`.
-    let mut const_eval_context = constant_context(cx, cx.typeck_results());
     if let ExprKind::Path(ref _qpath) = arg.kind &&
-        let Some(Constant::RawPtr(0)) = const_eval_context.expr(arg)
+        let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg)
     {
         span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
         return true;
diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs
index 297a80e5767..7329e508106 100644
--- a/clippy_lints/src/vec.rs
+++ b/clippy_lints/src/vec.rs
@@ -84,7 +84,7 @@ impl UselessVec {
         let mut applicability = Applicability::MachineApplicable;
         let snippet = match *vec_args {
             higher::VecArgs::Repeat(elem, len) => {
-                if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) {
+                if let Some(Constant::Int(len_constant)) = constant(cx, cx.typeck_results(), len) {
                     #[expect(clippy::cast_possible_truncation)]
                     if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack {
                         return;
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index b52caf6e405..34ca9b2d67e 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -1,18 +1,21 @@
 #![allow(clippy::float_cmp)]
 
+use crate::source::{span_source_range, walk_span_to_context};
 use crate::{clip, is_direct_expn_of, sext, unsext};
 use if_chain::if_chain;
 use rustc_ast::ast::{self, LitFloatType, LitKind};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
+use rustc_lexer::tokenize;
 use rustc_lint::LateContext;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::ty::SubstsRef;
 use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt};
+use rustc_middle::ty::{List, SubstsRef};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Symbol;
+use rustc_span::SyntaxContext;
 use std::cmp::Ordering::{self, Equal};
 use std::hash::{Hash, Hasher};
 use std::iter;
@@ -227,27 +230,46 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
     }
 }
 
+/// The source of a constant value.
+pub enum ConstantSource {
+    /// The value is determined solely from the expression.
+    Local,
+    /// The value is dependent on a defined constant.
+    Constant,
+}
+impl ConstantSource {
+    pub fn is_local(&self) -> bool {
+        matches!(self, Self::Local)
+    }
+}
+
+/// Attempts to evaluate the expression as a constant.
 pub fn constant<'tcx>(
     lcx: &LateContext<'tcx>,
     typeck_results: &ty::TypeckResults<'tcx>,
     e: &Expr<'_>,
-) -> Option<(Constant, bool)> {
-    let mut cx = ConstEvalLateContext {
-        lcx,
-        typeck_results,
-        param_env: lcx.param_env,
-        needed_resolution: false,
-        substs: ty::List::empty(),
-    };
-    cx.expr(e).map(|cst| (cst, cx.needed_resolution))
+) -> Option<Constant> {
+    ConstEvalLateContext::new(lcx, typeck_results).expr(e)
 }
 
+/// Attempts to evaluate the expression as a constant.
+pub fn constant_with_source<'tcx>(
+    lcx: &LateContext<'tcx>,
+    typeck_results: &ty::TypeckResults<'tcx>,
+    e: &Expr<'_>,
+) -> Option<(Constant, ConstantSource)> {
+    let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results);
+    let res = ctxt.expr(e);
+    res.map(|x| (x, ctxt.source))
+}
+
+/// Attempts to evaluate an expression only if it's value is not dependent on other items.
 pub fn constant_simple<'tcx>(
     lcx: &LateContext<'tcx>,
     typeck_results: &ty::TypeckResults<'tcx>,
     e: &Expr<'_>,
 ) -> Option<Constant> {
-    constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
+    constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c))
 }
 
 pub fn constant_full_int<'tcx>(
@@ -296,29 +318,25 @@ impl Ord for FullInt {
     }
 }
 
-/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
-pub fn constant_context<'a, 'tcx>(
-    lcx: &'a LateContext<'tcx>,
-    typeck_results: &'a ty::TypeckResults<'tcx>,
-) -> ConstEvalLateContext<'a, 'tcx> {
-    ConstEvalLateContext {
-        lcx,
-        typeck_results,
-        param_env: lcx.param_env,
-        needed_resolution: false,
-        substs: ty::List::empty(),
-    }
-}
-
 pub struct ConstEvalLateContext<'a, 'tcx> {
     lcx: &'a LateContext<'tcx>,
     typeck_results: &'a ty::TypeckResults<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    needed_resolution: bool,
+    source: ConstantSource,
     substs: SubstsRef<'tcx>,
 }
 
 impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
+    fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self {
+        Self {
+            lcx,
+            typeck_results,
+            param_env: lcx.param_env,
+            source: ConstantSource::Local,
+            substs: List::empty(),
+        }
+    }
+
     /// Simple constant folding: Insert an expression, get a constant or none.
     pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
         match e.kind {
@@ -453,11 +471,9 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                     .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None)
                     .ok()
                     .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?;
-                let result = miri_to_const(self.lcx.tcx, result);
-                if result.is_some() {
-                    self.needed_resolution = true;
-                }
-                result
+                let result = miri_to_const(self.lcx.tcx, result)?;
+                self.source = ConstantSource::Constant;
+                Some(result)
             },
             // FIXME: cover all usable cases.
             _ => None,
@@ -491,8 +507,33 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
 
     /// A block can only yield a constant if it only has one constant expression.
     fn block(&mut self, block: &Block<'_>) -> Option<Constant> {
-        if block.stmts.is_empty() {
-            block.expr.as_ref().and_then(|b| self.expr(b))
+        if block.stmts.is_empty()
+            && let Some(expr) = block.expr
+        {
+            // Try to detect any `cfg`ed statements or empty macro expansions.
+            let span = block.span.data();
+            if span.ctxt == SyntaxContext::root() {
+                if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt)
+                    && let expr_lo = expr_span.lo()
+                    && expr_lo >= span.lo
+                    && let Some(src) = span_source_range(self.lcx, span.lo..expr_lo)
+                    && let Some(src) = src.as_str()
+                {
+                    use rustc_lexer::TokenKind::{Whitespace, LineComment, BlockComment, Semi, OpenBrace};
+                    if !tokenize(src)
+                        .map(|t| t.kind)
+                        .filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi))
+                        .eq([OpenBrace])
+                    {
+                        self.source = ConstantSource::Constant;
+                    }
+                } else {
+                    // Unable to access the source. Assume a non-local dependency.
+                    self.source = ConstantSource::Constant;
+                }
+            }
+
+            self.expr(expr)
         } else {
             None
         }
diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs
index 3561e760ac9..2aec5a10e5d 100644
--- a/clippy_utils/src/hir_utils.rs
+++ b/clippy_utils/src/hir_utils.rs
@@ -151,6 +151,8 @@ impl HirEqInterExpr<'_, '_, '_> {
             if !self.eq_stmt(left, right) {
                 return false;
             }
+
+            // Try to detect any `cfg`ed statements or empty macro expansions.
             let Some(lstmt_span) = walk_span_to_context(left.span, lspan.ctxt) else {
                 return false;
             };
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 2ddd2ade6ae..c857595b844 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -1547,7 +1547,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
         return true;
     }
     let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id);
-    if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
+    if let Some(Constant::Int(v)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
         return value == v;
     }
     false
diff --git a/tests/ui/match_same_arms.rs b/tests/ui/match_same_arms.rs
index 15410734dec..26e2ca86758 100644
--- a/tests/ui/match_same_arms.rs
+++ b/tests/ui/match_same_arms.rs
@@ -72,6 +72,18 @@ fn main() {
         _ => 1,
     };
 
+    let _ = match 0 {
+        0 => {
+            m!(foo);
+            0
+        },
+        1 => {
+            m!(bar);
+            0
+        },
+        _ => 1,
+    };
+
     let _ = match 0 {
         0 => {
             let mut x = 0;

From 58132cb3b0ddadc2004a121f0bd85d12bf089ff6 Mon Sep 17 00:00:00 2001
From: Jason Newcomb <jsnewcomb@pm.me>
Date: Fri, 10 Mar 2023 10:43:04 -0500
Subject: [PATCH 73/78] Improve `SpanlessEq` * Don't consider expansions of
 different macros to be the same, even if they expand to the same tokens *
 Don't consider `cfg!` expansions to be equal if they check different configs.

---
 clippy_utils/src/consts.rs        |  4 +--
 clippy_utils/src/hir_utils.rs     | 52 +++++++++++++++++++++++++++++--
 clippy_utils/src/lib.rs           |  4 +--
 tests/ui/collapsible_if.fixed     |  7 ++++-
 tests/ui/collapsible_if.rs        |  7 ++++-
 tests/ui/collapsible_if.stderr    | 18 +++++------
 tests/ui/match_same_arms.rs       | 22 +++++++++++++
 tests/ui/match_same_arms2.rs      |  6 ++++
 tests/ui/match_same_arms2.stderr  | 17 +++++++++-
 tests/ui/partialeq_to_none.fixed  |  1 +
 tests/ui/partialeq_to_none.rs     |  1 +
 tests/ui/partialeq_to_none.stderr | 30 +++++++++---------
 12 files changed, 135 insertions(+), 34 deletions(-)

diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index 34ca9b2d67e..992d41bc378 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -1,6 +1,6 @@
 #![allow(clippy::float_cmp)]
 
-use crate::source::{span_source_range, walk_span_to_context};
+use crate::source::{get_source_text, walk_span_to_context};
 use crate::{clip, is_direct_expn_of, sext, unsext};
 use if_chain::if_chain;
 use rustc_ast::ast::{self, LitFloatType, LitKind};
@@ -516,7 +516,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                 if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt)
                     && let expr_lo = expr_span.lo()
                     && expr_lo >= span.lo
-                    && let Some(src) = span_source_range(self.lcx, span.lo..expr_lo)
+                    && let Some(src) = get_source_text(self.lcx, span.lo..expr_lo)
                     && let Some(src) = src.as_str()
                 {
                     use rustc_lexer::TokenKind::{Whitespace, LineComment, BlockComment, Semi, OpenBrace};
diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs
index 2aec5a10e5d..a49246a7832 100644
--- a/clippy_utils/src/hir_utils.rs
+++ b/clippy_utils/src/hir_utils.rs
@@ -14,7 +14,7 @@ use rustc_hir::{
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::TypeckResults;
-use rustc_span::{sym, BytePos, Symbol, SyntaxContext};
+use rustc_span::{sym, BytePos, ExpnKind, MacroKind, Symbol, SyntaxContext};
 use std::hash::{Hash, Hasher};
 use std::ops::Range;
 
@@ -67,6 +67,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
     pub fn inter_expr(&mut self) -> HirEqInterExpr<'_, 'a, 'tcx> {
         HirEqInterExpr {
             inner: self,
+            left_ctxt: SyntaxContext::root(),
+            right_ctxt: SyntaxContext::root(),
             locals: HirIdMap::default(),
         }
     }
@@ -94,6 +96,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
 
 pub struct HirEqInterExpr<'a, 'b, 'tcx> {
     inner: &'a mut SpanlessEq<'b, 'tcx>,
+    left_ctxt: SyntaxContext,
+    right_ctxt: SyntaxContext,
 
     // When binding are declared, the binding ID in the left expression is mapped to the one on the
     // right. For example, when comparing `{ let x = 1; x + 2 }` and `{ let y = 1; y + 2 }`,
@@ -128,6 +132,7 @@ impl HirEqInterExpr<'_, '_, '_> {
     }
 
     /// Checks whether two blocks are the same.
+    #[expect(clippy::similar_names)]
     fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
         use TokenKind::{BlockComment, LineComment, Semi, Whitespace};
         if left.stmts.len() != right.stmts.len() {
@@ -166,7 +171,8 @@ impl HirEqInterExpr<'_, '_, '_> {
                 // Can happen when macros expand to multiple statements, or rearrange statements.
                 // Nothing in between the statements to check in this case.
                 continue;
-            } else if lstmt_span.lo < lstart || rstmt_span.lo < rstart {
+            }
+            if lstmt_span.lo < lstart || rstmt_span.lo < rstart {
                 // Only one of the blocks had a weird macro.
                 return false;
             }
@@ -243,7 +249,7 @@ impl HirEqInterExpr<'_, '_, '_> {
 
     #[expect(clippy::similar_names)]
     pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
-        if !self.inner.allow_side_effects && left.span.ctxt() != right.span.ctxt() {
+        if !self.check_ctxt(left.span.ctxt(), right.span.ctxt()) {
             return false;
         }
 
@@ -476,6 +482,45 @@ impl HirEqInterExpr<'_, '_, '_> {
     fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool {
         left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty())
     }
+
+    fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool {
+        if self.left_ctxt == left && self.right_ctxt == right {
+            return true;
+        } else if self.left_ctxt == left || self.right_ctxt == right {
+            // Only one context has changed. This can only happen if the two nodes are written differently.
+            return false;
+        } else if left != SyntaxContext::root() {
+            let mut left_data = left.outer_expn_data();
+            let mut right_data = right.outer_expn_data();
+            loop {
+                use TokenKind::{BlockComment, LineComment, Whitespace};
+                if left_data.macro_def_id != right_data.macro_def_id
+                    || (matches!(left_data.kind, ExpnKind::Macro(MacroKind::Bang, name) if name == sym::cfg)
+                        && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| {
+                            !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. })
+                        }))
+                {
+                    // Either a different chain of macro calls, or different arguments to the `cfg` macro.
+                    return false;
+                }
+                let left_ctxt = left_data.call_site.ctxt();
+                let right_ctxt = right_data.call_site.ctxt();
+                if left_ctxt == SyntaxContext::root() && right_ctxt == SyntaxContext::root() {
+                    break;
+                }
+                if left_ctxt == SyntaxContext::root() || right_ctxt == SyntaxContext::root() {
+                    // Different lengths for the expansion stack. This can only happen if nodes are written differently,
+                    // or shouldn't be compared to start with.
+                    return false;
+                }
+                left_data = left_ctxt.outer_expn_data();
+                right_data = right_ctxt.outer_expn_data();
+            }
+        }
+        self.left_ctxt = left;
+        self.right_ctxt = right;
+        true
+    }
 }
 
 /// Some simple reductions like `{ return }` => `return`
@@ -1075,6 +1120,7 @@ pub fn hash_expr(cx: &LateContext<'_>, e: &Expr<'_>) -> u64 {
     h.finish()
 }
 
+#[expect(clippy::similar_names)]
 fn eq_span_tokens(
     cx: &LateContext<'_>,
     left: impl SpanRange,
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index c857595b844..575c29a6b6f 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -1499,7 +1499,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
                 && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree()))
                 && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty)
                 && let Some(min_const) = miri_to_const(cx.tcx, min_const_kind)
-                && let Some((start_const, _)) = constant(cx, cx.typeck_results(), start)
+                && let Some(start_const) = constant(cx, cx.typeck_results(), start)
             {
                 start_const == min_const
             } else {
@@ -1515,7 +1515,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
                         && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree()))
                         && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty)
                         && let Some(max_const) = miri_to_const(cx.tcx, max_const_kind)
-                        && let Some((end_const, _)) = constant(cx, cx.typeck_results(), end)
+                        && let Some(end_const) = constant(cx, cx.typeck_results(), end)
                     {
                         end_const == max_const
                     } else {
diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed
index d2aba2ac59b..c6514a55934 100644
--- a/tests/ui/collapsible_if.fixed
+++ b/tests/ui/collapsible_if.fixed
@@ -1,5 +1,10 @@
 //@run-rustfix
-#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)]
+#![allow(
+    clippy::assertions_on_constants,
+    clippy::equatable_if_let,
+    clippy::nonminimal_bool,
+    clippy::eq_op
+)]
 
 #[rustfmt::skip]
 #[warn(clippy::collapsible_if)]
diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs
index e0bef7f9c97..2c85b68df63 100644
--- a/tests/ui/collapsible_if.rs
+++ b/tests/ui/collapsible_if.rs
@@ -1,5 +1,10 @@
 //@run-rustfix
-#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)]
+#![allow(
+    clippy::assertions_on_constants,
+    clippy::equatable_if_let,
+    clippy::nonminimal_bool,
+    clippy::eq_op
+)]
 
 #[rustfmt::skip]
 #[warn(clippy::collapsible_if)]
diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr
index 6327444df21..c687bae1acc 100644
--- a/tests/ui/collapsible_if.stderr
+++ b/tests/ui/collapsible_if.stderr
@@ -1,5 +1,5 @@
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:9:5
+  --> $DIR/collapsible_if.rs:14:5
    |
 LL | /     if x == "hello" {
 LL | |         if y == "world" {
@@ -17,7 +17,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:15:5
+  --> $DIR/collapsible_if.rs:20:5
    |
 LL | /     if x == "hello" || x == "world" {
 LL | |         if y == "world" || y == "hello" {
@@ -34,7 +34,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:21:5
+  --> $DIR/collapsible_if.rs:26:5
    |
 LL | /     if x == "hello" && x == "world" {
 LL | |         if y == "world" || y == "hello" {
@@ -51,7 +51,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:27:5
+  --> $DIR/collapsible_if.rs:32:5
    |
 LL | /     if x == "hello" || x == "world" {
 LL | |         if y == "world" && y == "hello" {
@@ -68,7 +68,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:33:5
+  --> $DIR/collapsible_if.rs:38:5
    |
 LL | /     if x == "hello" && x == "world" {
 LL | |         if y == "world" && y == "hello" {
@@ -85,7 +85,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:39:5
+  --> $DIR/collapsible_if.rs:44:5
    |
 LL | /     if 42 == 1337 {
 LL | |         if 'a' != 'A' {
@@ -102,7 +102,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:95:5
+  --> $DIR/collapsible_if.rs:100:5
    |
 LL | /     if x == "hello" {
 LL | |         if y == "world" { // Collapsible
@@ -119,7 +119,7 @@ LL +     }
    |
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:154:5
+  --> $DIR/collapsible_if.rs:159:5
    |
 LL | /     if matches!(true, true) {
 LL | |         if matches!(true, true) {}
@@ -127,7 +127,7 @@ LL | |     }
    | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}`
 
 error: this `if` statement can be collapsed
-  --> $DIR/collapsible_if.rs:159:5
+  --> $DIR/collapsible_if.rs:164:5
    |
 LL | /     if matches!(true, true) && truth() {
 LL | |         if matches!(true, true) {}
diff --git a/tests/ui/match_same_arms.rs b/tests/ui/match_same_arms.rs
index 26e2ca86758..3914b45464c 100644
--- a/tests/ui/match_same_arms.rs
+++ b/tests/ui/match_same_arms.rs
@@ -57,6 +57,16 @@ macro_rules! m {
     (foo) => {};
     (bar) => {};
 }
+macro_rules! foo {
+    () => {
+        1
+    };
+}
+macro_rules! bar {
+    () => {
+        1
+    };
+}
 
 fn main() {
     let x = 0;
@@ -111,4 +121,16 @@ fn main() {
         },
         _ => 0,
     };
+
+    let _ = match 0 {
+        0 => foo!(),
+        1 => bar!(),
+        _ => 1,
+    };
+
+    let _ = match 0 {
+        0 => cfg!(not_enabled),
+        1 => cfg!(also_not_enabled),
+        _ => false,
+    };
 }
diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs
index 82b2c433d99..60b2975be04 100644
--- a/tests/ui/match_same_arms2.rs
+++ b/tests/ui/match_same_arms2.rs
@@ -239,4 +239,10 @@ fn main() {
         3 => core::convert::identity::<u32>(todo!()),
         _ => 5,
     };
+
+    let _ = match 0 {
+        0 => cfg!(not_enable),
+        1 => cfg!(not_enable),
+        _ => false,
+    };
 }
diff --git a/tests/ui/match_same_arms2.stderr b/tests/ui/match_same_arms2.stderr
index 06cd4300054..8fb461bd286 100644
--- a/tests/ui/match_same_arms2.stderr
+++ b/tests/ui/match_same_arms2.stderr
@@ -192,5 +192,20 @@ note: other arm here
 LL |         Some(Bar { x: 0, y: 5, .. }) => 1,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 12 previous errors
+error: this match arm has an identical body to another arm
+  --> $DIR/match_same_arms2.rs:245:9
+   |
+LL |         1 => cfg!(not_enable),
+   |         -^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         help: try merging the arm patterns: `1 | 0`
+   |
+   = help: or try changing either arm body
+note: other arm here
+  --> $DIR/match_same_arms2.rs:244:9
+   |
+LL |         0 => cfg!(not_enable),
+   |         ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/partialeq_to_none.fixed b/tests/ui/partialeq_to_none.fixed
index 81a716bd276..2df87a26d6d 100644
--- a/tests/ui/partialeq_to_none.fixed
+++ b/tests/ui/partialeq_to_none.fixed
@@ -1,5 +1,6 @@
 //@run-rustfix
 #![warn(clippy::partialeq_to_none)]
+#![allow(clippy::eq_op)]
 
 struct Foobar;
 
diff --git a/tests/ui/partialeq_to_none.rs b/tests/ui/partialeq_to_none.rs
index f454715fa30..df6233b9afd 100644
--- a/tests/ui/partialeq_to_none.rs
+++ b/tests/ui/partialeq_to_none.rs
@@ -1,5 +1,6 @@
 //@run-rustfix
 #![warn(clippy::partialeq_to_none)]
+#![allow(clippy::eq_op)]
 
 struct Foobar;
 
diff --git a/tests/ui/partialeq_to_none.stderr b/tests/ui/partialeq_to_none.stderr
index d06ab7aee55..4f84862a22b 100644
--- a/tests/ui/partialeq_to_none.stderr
+++ b/tests/ui/partialeq_to_none.stderr
@@ -1,5 +1,5 @@
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:14:8
+  --> $DIR/partialeq_to_none.rs:15:8
    |
 LL |     if f != None { "yay" } else { "nay" }
    |        ^^^^^^^^^ help: use `Option::is_some()` instead: `f.is_some()`
@@ -7,55 +7,55 @@ LL |     if f != None { "yay" } else { "nay" }
    = note: `-D clippy::partialeq-to-none` implied by `-D warnings`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:44:13
+  --> $DIR/partialeq_to_none.rs:45:13
    |
 LL |     let _ = x == None;
    |             ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:45:13
+  --> $DIR/partialeq_to_none.rs:46:13
    |
 LL |     let _ = x != None;
    |             ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:46:13
+  --> $DIR/partialeq_to_none.rs:47:13
    |
 LL |     let _ = None == x;
    |             ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:47:13
+  --> $DIR/partialeq_to_none.rs:48:13
    |
 LL |     let _ = None != x;
    |             ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:49:8
+  --> $DIR/partialeq_to_none.rs:50:8
    |
 LL |     if foobar() == None {}
    |        ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:51:8
+  --> $DIR/partialeq_to_none.rs:52:8
    |
 LL |     if bar().ok() != None {}
    |        ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:53:13
+  --> $DIR/partialeq_to_none.rs:54:13
    |
 LL |     let _ = Some(1 + 2) != None;
    |             ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:55:13
+  --> $DIR/partialeq_to_none.rs:56:13
    |
 LL |     let _ = { Some(0) } == None;
    |             ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:57:13
+  --> $DIR/partialeq_to_none.rs:58:13
    |
 LL |       let _ = {
    |  _____________^
@@ -77,31 +77,31 @@ LL ~     }.is_some();
    |
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:67:13
+  --> $DIR/partialeq_to_none.rs:68:13
    |
 LL |     let _ = optref() == &&None;
    |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:68:13
+  --> $DIR/partialeq_to_none.rs:69:13
    |
 LL |     let _ = &&None != optref();
    |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:69:13
+  --> $DIR/partialeq_to_none.rs:70:13
    |
 LL |     let _ = **optref() == None;
    |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:70:13
+  --> $DIR/partialeq_to_none.rs:71:13
    |
 LL |     let _ = &None != *optref();
    |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()`
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:73:13
+  --> $DIR/partialeq_to_none.rs:74:13
    |
 LL |     let _ = None != *x;
    |             ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()`

From ab66a86815a2bb562edef92ef8c308b6958ea734 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Tue, 9 May 2023 11:51:36 +0200
Subject: [PATCH 74/78] Add new `UNIQUE_CFG_CONDITION` lint

---
 clippy_lints/src/attrs.rs          | 60 ++++++++++++++++++++++++++++++
 clippy_lints/src/declared_lints.rs |  1 +
 2 files changed, 61 insertions(+)

diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index 93d88391a79..6678002820a 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -338,6 +338,30 @@ declare_clippy_lint! {
     "ensures that all `allow` and `expect` attributes have a reason"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `any` and `all` combinators in `cfg` with only one condition.
+    ///
+    /// ### Why is this bad?
+    /// If there is only one condition, no need to wrap it into `any` or `all` combinators.
+    ///
+    /// ### Example
+    /// ```rust
+    /// #[cfg(any(unix))]
+    /// pub struct Bar;
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// #[cfg(unix)]
+    /// pub struct Bar;
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub NON_MINIMAL_CFG,
+    style,
+    "ensure that all `cfg(any())` and `cfg(all())` have more than one condition"
+}
+
 declare_lint_pass!(Attributes => [
     ALLOW_ATTRIBUTES_WITHOUT_REASON,
     INLINE_ALWAYS,
@@ -651,6 +675,7 @@ impl_lint_pass!(EarlyAttributes => [
     MISMATCHED_TARGET_OS,
     EMPTY_LINE_AFTER_OUTER_ATTR,
     EMPTY_LINE_AFTER_DOC_COMMENTS,
+    NON_MINIMAL_CFG,
 ]);
 
 impl EarlyLintPass for EarlyAttributes {
@@ -661,6 +686,7 @@ impl EarlyLintPass for EarlyAttributes {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
         check_deprecated_cfg_attr(cx, attr, &self.msrv);
         check_mismatched_target_os(cx, attr);
+        check_minimal_cfg_condition(cx, attr);
     }
 
     extract_msrv_attr!(EarlyContext);
@@ -750,6 +776,40 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msr
     }
 }
 
+fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
+    for item in items.iter() {
+        if let NestedMetaItem::MetaItem(meta) = item {
+            if !meta.has_name(sym::any) && !meta.has_name(sym::all) {
+                continue;
+            }
+            if let MetaItemKind::List(list) = &meta.kind {
+                check_nested_cfg(cx, list);
+                if list.len() == 1 {
+                    span_lint_and_then(
+                        cx,
+                        NON_MINIMAL_CFG,
+                        meta.span,
+                        "unneeded sub `cfg` when there is only one condition",
+                        |diag| {
+                            if let Some(snippet) = snippet_opt(cx, list[0].span()) {
+                                diag.span_suggestion(meta.span, "try", snippet, Applicability::MaybeIncorrect);
+                            }
+                        },
+                    );
+                }
+            }
+        }
+    }
+}
+
+fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) {
+    if attr.has_name(sym::cfg) &&
+        let Some(items) = attr.meta_item_list()
+    {
+        check_nested_cfg(cx, &items);
+    }
+}
+
 fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
     fn find_os(name: &str) -> Option<&'static str> {
         UNIX_SYSTEMS
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 40c64efaa37..aee43edc478 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -52,6 +52,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
     crate::attrs::INLINE_ALWAYS_INFO,
     crate::attrs::MISMATCHED_TARGET_OS_INFO,
+    crate::attrs::NON_MINIMAL_CFG_INFO,
     crate::attrs::USELESS_ATTRIBUTE_INFO,
     crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO,
     crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO,

From fcf19481aa17ea7bfaabc0bfae07aebc40248146 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Tue, 9 May 2023 12:13:49 +0200
Subject: [PATCH 75/78] Add UI test for UNIQUE_CFG_CONDITION

---
 tests/ui/non_minimal_cfg.fixed  | 14 ++++++++++++++
 tests/ui/non_minimal_cfg.rs     | 14 ++++++++++++++
 tests/ui/non_minimal_cfg.stderr | 28 ++++++++++++++++++++++++++++
 3 files changed, 56 insertions(+)
 create mode 100644 tests/ui/non_minimal_cfg.fixed
 create mode 100644 tests/ui/non_minimal_cfg.rs
 create mode 100644 tests/ui/non_minimal_cfg.stderr

diff --git a/tests/ui/non_minimal_cfg.fixed b/tests/ui/non_minimal_cfg.fixed
new file mode 100644
index 00000000000..ca9a48a3e37
--- /dev/null
+++ b/tests/ui/non_minimal_cfg.fixed
@@ -0,0 +1,14 @@
+//@run-rustfix
+
+#![allow(unused)]
+
+#[cfg(windows)]
+fn hermit() {}
+
+#[cfg(windows)]
+fn wasi() {}
+
+#[cfg(all(unix, not(windows)))]
+fn the_end() {}
+
+fn main() {}
diff --git a/tests/ui/non_minimal_cfg.rs b/tests/ui/non_minimal_cfg.rs
new file mode 100644
index 00000000000..bf322236fef
--- /dev/null
+++ b/tests/ui/non_minimal_cfg.rs
@@ -0,0 +1,14 @@
+//@run-rustfix
+
+#![allow(unused)]
+
+#[cfg(all(windows))]
+fn hermit() {}
+
+#[cfg(any(windows))]
+fn wasi() {}
+
+#[cfg(all(any(unix), all(not(windows))))]
+fn the_end() {}
+
+fn main() {}
diff --git a/tests/ui/non_minimal_cfg.stderr b/tests/ui/non_minimal_cfg.stderr
new file mode 100644
index 00000000000..cdfd728aa61
--- /dev/null
+++ b/tests/ui/non_minimal_cfg.stderr
@@ -0,0 +1,28 @@
+error: unneeded sub `cfg` when there is only one condition
+  --> $DIR/non_minimal_cfg.rs:5:7
+   |
+LL | #[cfg(all(windows))]
+   |       ^^^^^^^^^^^^ help: try: `windows`
+   |
+   = note: `-D clippy::non-minimal-cfg` implied by `-D warnings`
+
+error: unneeded sub `cfg` when there is only one condition
+  --> $DIR/non_minimal_cfg.rs:8:7
+   |
+LL | #[cfg(any(windows))]
+   |       ^^^^^^^^^^^^ help: try: `windows`
+
+error: unneeded sub `cfg` when there is only one condition
+  --> $DIR/non_minimal_cfg.rs:11:11
+   |
+LL | #[cfg(all(any(unix), all(not(windows))))]
+   |           ^^^^^^^^^ help: try: `unix`
+
+error: unneeded sub `cfg` when there is only one condition
+  --> $DIR/non_minimal_cfg.rs:11:22
+   |
+LL | #[cfg(all(any(unix), all(not(windows))))]
+   |                      ^^^^^^^^^^^^^^^^^ help: try: `not(windows)`
+
+error: aborting due to 4 previous errors
+

From 5328852ad7d6801acd03eefc8bc88c3ee70929b5 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Tue, 9 May 2023 12:14:04 +0200
Subject: [PATCH 76/78] Update CHANGELOG

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index dafa3f3a139..79f2a47110b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4899,6 +4899,7 @@ Released 2018-09-13
 [`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
 [`no_mangle_with_rust_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_mangle_with_rust_abi
 [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
+[`non_minimal_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_minimal_cfg
 [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
 [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
 [`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool

From dbc76a766333bf510de601111f31e3eb42fb0434 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Fri, 19 May 2023 16:23:17 +0200
Subject: [PATCH 77/78] Add check for empty cfg `all` condition

---
 clippy_lints/src/attrs.rs        |  8 ++++++++
 tests/ui/non_minimal_cfg.fixed   |  3 +++
 tests/ui/non_minimal_cfg.rs      |  3 +++
 tests/ui/non_minimal_cfg2.rs     |  6 ++++++
 tests/ui/non_minimal_cfg2.stderr | 10 ++++++++++
 5 files changed, 30 insertions(+)
 create mode 100644 tests/ui/non_minimal_cfg2.rs
 create mode 100644 tests/ui/non_minimal_cfg2.stderr

diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index 6678002820a..897495ba108 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -796,6 +796,14 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
                             }
                         },
                     );
+                } else if list.is_empty() && meta.has_name(sym::all) {
+                    span_lint_and_then(
+                        cx,
+                        NON_MINIMAL_CFG,
+                        meta.span,
+                        "unneeded sub `cfg` when there is no condition",
+                        |_| {},
+                    );
                 }
             }
         }
diff --git a/tests/ui/non_minimal_cfg.fixed b/tests/ui/non_minimal_cfg.fixed
index ca9a48a3e37..430caafb33e 100644
--- a/tests/ui/non_minimal_cfg.fixed
+++ b/tests/ui/non_minimal_cfg.fixed
@@ -11,4 +11,7 @@ fn wasi() {}
 #[cfg(all(unix, not(windows)))]
 fn the_end() {}
 
+#[cfg(any())]
+fn any() {}
+
 fn main() {}
diff --git a/tests/ui/non_minimal_cfg.rs b/tests/ui/non_minimal_cfg.rs
index bf322236fef..a38ce1c21d6 100644
--- a/tests/ui/non_minimal_cfg.rs
+++ b/tests/ui/non_minimal_cfg.rs
@@ -11,4 +11,7 @@ fn wasi() {}
 #[cfg(all(any(unix), all(not(windows))))]
 fn the_end() {}
 
+#[cfg(any())]
+fn any() {}
+
 fn main() {}
diff --git a/tests/ui/non_minimal_cfg2.rs b/tests/ui/non_minimal_cfg2.rs
new file mode 100644
index 00000000000..a4c6abce387
--- /dev/null
+++ b/tests/ui/non_minimal_cfg2.rs
@@ -0,0 +1,6 @@
+#![allow(unused)]
+
+#[cfg(all())]
+fn all() {}
+
+fn main() {}
diff --git a/tests/ui/non_minimal_cfg2.stderr b/tests/ui/non_minimal_cfg2.stderr
new file mode 100644
index 00000000000..2a9a36fbcef
--- /dev/null
+++ b/tests/ui/non_minimal_cfg2.stderr
@@ -0,0 +1,10 @@
+error: unneeded sub `cfg` when there is no condition
+  --> $DIR/non_minimal_cfg2.rs:3:7
+   |
+LL | #[cfg(all())]
+   |       ^^^^^
+   |
+   = note: `-D clippy::non-minimal-cfg` implied by `-D warnings`
+
+error: aborting due to previous error
+

From 2e95a4fd4c78e9145ff8ed07e7ded566d53b8e91 Mon Sep 17 00:00:00 2001
From: Philipp Krones <hello@philkrones.com>
Date: Sat, 20 May 2023 15:32:32 +0200
Subject: [PATCH 78/78] Bump nightly version -> 2023-05-20

---
 rust-toolchain | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/rust-toolchain b/rust-toolchain
index 60b8a5ac071..bc7fb711ed8 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-05-05"
+channel = "nightly-2023-05-20"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]