From e4eddc611afef1d68432022f7dd1a9dbebf40772 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= <tomasz.miasko@gmail.com>
Date: Tue, 5 Jul 2022 00:00:00 +0000
Subject: [PATCH 01/34] Replace `Body::basic_blocks()` with field access

---
 clippy_lints/src/redundant_clone.rs      | 6 +++---
 clippy_utils/src/qualify_min_const_fn.rs | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs
index eddca604575..9fd86331ec7 100644
--- a/clippy_lints/src/redundant_clone.rs
+++ b/clippy_lints/src/redundant_clone.rs
@@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
             vis.into_map(cx, maybe_storage_live_result)
         };
 
-        for (bb, bbdata) in mir.basic_blocks().iter_enumerated() {
+        for (bb, bbdata) in mir.basic_blocks.iter_enumerated() {
             let terminator = bbdata.terminator();
 
             if terminator.source_info.span.from_expansion() {
@@ -186,7 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                     unwrap_or_continue!(find_stmt_assigns_to(cx, mir, pred_arg, true, ps[0]));
                 let loc = mir::Location {
                     block: bb,
-                    statement_index: mir.basic_blocks()[bb].statements.len(),
+                    statement_index: mir.basic_blocks[bb].statements.len(),
                 };
 
                 // This can be turned into `res = move local` if `arg` and `cloned` are not borrowed
@@ -310,7 +310,7 @@ fn find_stmt_assigns_to<'tcx>(
     by_ref: bool,
     bb: mir::BasicBlock,
 ) -> Option<(mir::Local, CannotMoveOut)> {
-    let rvalue = mir.basic_blocks()[bb].statements.iter().rev().find_map(|stmt| {
+    let rvalue = mir.basic_blocks[bb].statements.iter().rev().find_map(|stmt| {
         if let mir::StatementKind::Assign(box (mir::Place { local, .. }, v)) = &stmt.kind {
             return if *local == to_local { Some(v) } else { None };
         }
diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs
index 3bf75bcbee8..74c222bbcbe 100644
--- a/clippy_utils/src/qualify_min_const_fn.rs
+++ b/clippy_utils/src/qualify_min_const_fn.rs
@@ -55,7 +55,7 @@ pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv:
         body.local_decls.iter().next().unwrap().source_info.span,
     )?;
 
-    for bb in body.basic_blocks() {
+    for bb in body.basic_blocks.iter() {
         check_terminator(tcx, body, bb.terminator(), msrv)?;
         for stmt in &bb.statements {
             check_statement(tcx, body, def_id, stmt)?;

From 3b80e994d5ada5d22bbe186aad0de28719b2d5b7 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Fri, 26 Aug 2022 15:43:00 +1000
Subject: [PATCH 02/34] Use `&'hir Expr` everywhere.

For consistency, and because it makes HIR measurement simpler and more
accurate.
---
 clippy_lints/src/loops/never_loop.rs | 4 ++--
 clippy_lints/src/utils/author.rs     | 2 +-
 clippy_utils/src/lib.rs              | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs
index 32de20f6531..5448360049d 100644
--- a/clippy_lints/src/loops/never_loop.rs
+++ b/clippy_lints/src/loops/never_loop.rs
@@ -178,9 +178,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
                 InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
                     never_loop_expr(expr, main_loop_id)
                 },
-                InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter(), main_loop_id),
+                InlineAsmOperand::Out { expr, .. } => never_loop_expr_all(&mut expr.iter().copied(), main_loop_id),
                 InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
-                    never_loop_expr_all(&mut once(in_expr).chain(out_expr.iter()), main_loop_id)
+                    never_loop_expr_all(&mut once(*in_expr).chain(out_expr.iter().copied()), main_loop_id)
                 },
                 InlineAsmOperand::Const { .. }
                 | InlineAsmOperand::SymFn { .. }
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index 429c64ac156..3ffcaa90af3 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -595,7 +595,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
     }
 
     fn body(&self, body_id: &Binding<hir::BodyId>) {
-        let expr = &self.cx.tcx.hir().body(body_id.value).value;
+        let expr = self.cx.tcx.hir().body(body_id.value).value;
         bind!(self, expr);
         out!("let {expr} = &cx.tcx.hir().body({body_id}).value;");
         self.expr(expr);
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index f716f009ff3..dd1ceb6a4dc 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -1804,7 +1804,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool
             }
         };
 
-        let mut expr = &func.value;
+        let mut expr = func.value;
         loop {
             match expr.kind {
                 #[rustfmt::skip]

From 3ce109e12da7f4ee9392be7feef56e158f72914b Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Fri, 26 Aug 2022 15:57:44 +1000
Subject: [PATCH 03/34] Use `&'hir Ty` everywhere.

For consistency, and because it makes HIR measurement simpler and more
accurate.
---
 clippy_lints/src/manual_bits.rs | 2 +-
 clippy_utils/src/lib.rs         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs
index 60bbcde4f1d..940601a44fb 100644
--- a/clippy_lints/src/manual_bits.rs
+++ b/clippy_lints/src/manual_bits.rs
@@ -105,7 +105,7 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
         if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
         if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id);
         then {
-            cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (real_ty, resolved_ty))
+            cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (*real_ty, resolved_ty))
         } else {
             None
         }
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index dd1ceb6a4dc..42ce3b6bf0f 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -333,7 +333,7 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tc
         .map_or(&[][..], |a| a.args)
         .iter()
         .filter_map(|a| match a {
-            hir::GenericArg::Type(ty) => Some(ty),
+            hir::GenericArg::Type(ty) => Some(*ty),
             _ => None,
         })
 }

From ce847beb4794a5149a714b21b68347daf27a380c Mon Sep 17 00:00:00 2001
From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com>
Date: Sat, 20 Aug 2022 20:40:08 +0200
Subject: [PATCH 04/34] Revert let_chains stabilization

This reverts commit 326646074940222d602f3683d0559088690830f4.

This is the revert against master, the beta revert was already done in #100538.
---
 clippy_dev/src/lib.rs              |  1 +
 clippy_lints/src/lib.rs            |  1 +
 clippy_utils/src/lib.rs            |  1 +
 tests/ui/needless_late_init.fixed  |  1 +
 tests/ui/needless_late_init.rs     |  1 +
 tests/ui/needless_late_init.stderr | 32 +++++++++++++++---------------
 6 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs
index 8a6bd1cbdf5..82574a8e64b 100644
--- a/clippy_dev/src/lib.rs
+++ b/clippy_dev/src/lib.rs
@@ -1,3 +1,4 @@
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(once_cell)]
 #![feature(rustc_private)]
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index e6a405f8170..ec5c73c1357 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -4,6 +4,7 @@
 #![feature(control_flow_enum)]
 #![feature(drain_filter)]
 #![feature(iter_intersperse)]
+#![feature(let_chains)]
 #![feature(let_else)]
 #![feature(lint_reasons)]
 #![feature(never_type)]
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index f716f009ff3..313f1f1d9a6 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -2,6 +2,7 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(let_else)]
+#![feature(let_chains)]
 #![feature(lint_reasons)]
 #![feature(once_cell)]
 #![feature(rustc_private)]
diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed
index 4c98e1827bd..fee8e3030b8 100644
--- a/tests/ui/needless_late_init.fixed
+++ b/tests/ui/needless_late_init.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+#![feature(let_chains)]
 #![allow(
     unused,
     clippy::assign_op_pattern,
diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs
index 25e1e0214fb..402d9f9ef7f 100644
--- a/tests/ui/needless_late_init.rs
+++ b/tests/ui/needless_late_init.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+#![feature(let_chains)]
 #![allow(
     unused,
     clippy::assign_op_pattern,
diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr
index 97f0f7019a9..313cdbbeba1 100644
--- a/tests/ui/needless_late_init.stderr
+++ b/tests/ui/needless_late_init.stderr
@@ -1,5 +1,5 @@
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:22:5
+  --> $DIR/needless_late_init.rs:23:5
    |
 LL |     let a;
    |     ^^^^^^ created here
@@ -13,7 +13,7 @@ LL |     let a = "zero";
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:25:5
+  --> $DIR/needless_late_init.rs:26:5
    |
 LL |     let b;
    |     ^^^^^^ created here
@@ -27,7 +27,7 @@ LL |     let b = 1;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:26:5
+  --> $DIR/needless_late_init.rs:27:5
    |
 LL |     let c;
    |     ^^^^^^ created here
@@ -41,7 +41,7 @@ LL |     let c = 2;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:30:5
+  --> $DIR/needless_late_init.rs:31:5
    |
 LL |     let d: usize;
    |     ^^^^^^^^^^^^^ created here
@@ -54,7 +54,7 @@ LL |     let d: usize = 1;
    |     ~~~~~~~~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:33:5
+  --> $DIR/needless_late_init.rs:34:5
    |
 LL |     let e;
    |     ^^^^^^ created here
@@ -67,7 +67,7 @@ LL |     let e = format!("{}", d);
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:38:5
+  --> $DIR/needless_late_init.rs:39:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -88,7 +88,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:47:5
+  --> $DIR/needless_late_init.rs:48:5
    |
 LL |     let b;
    |     ^^^^^^
@@ -109,7 +109,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:54:5
+  --> $DIR/needless_late_init.rs:55:5
    |
 LL |     let d;
    |     ^^^^^^
@@ -130,7 +130,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:62:5
+  --> $DIR/needless_late_init.rs:63:5
    |
 LL |     let e;
    |     ^^^^^^
@@ -151,7 +151,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:69:5
+  --> $DIR/needless_late_init.rs:70:5
    |
 LL |     let f;
    |     ^^^^^^
@@ -167,7 +167,7 @@ LL +         1 => "three",
    |
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:75:5
+  --> $DIR/needless_late_init.rs:76:5
    |
 LL |     let g: usize;
    |     ^^^^^^^^^^^^^
@@ -187,7 +187,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:83:5
+  --> $DIR/needless_late_init.rs:84:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -201,7 +201,7 @@ LL |     let x = 1;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:87:5
+  --> $DIR/needless_late_init.rs:88:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -215,7 +215,7 @@ LL |     let x = SignificantDrop;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:91:5
+  --> $DIR/needless_late_init.rs:92:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -229,7 +229,7 @@ LL |     let x = SignificantDrop;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:110:5
+  --> $DIR/needless_late_init.rs:111:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -250,7 +250,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:127:5
+  --> $DIR/needless_late_init.rs:128:5
    |
 LL |     let a;
    |     ^^^^^^

From 98fe5f7c7d8c2b8b4559fadc7e58844bc4262728 Mon Sep 17 00:00:00 2001
From: 5225225 <5225225@mailbox.org>
Date: Mon, 29 Aug 2022 21:28:35 +0100
Subject: [PATCH 05/34] Fix tests due to stricter invalid_value

---
 tests/ui/uninit.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/ui/uninit.rs b/tests/ui/uninit.rs
index dac5ce272c0..21131731708 100644
--- a/tests/ui/uninit.rs
+++ b/tests/ui/uninit.rs
@@ -1,5 +1,5 @@
 #![feature(stmt_expr_attributes)]
-#![allow(clippy::let_unit_value)]
+#![allow(clippy::let_unit_value, invalid_value)]
 
 use std::mem::{self, MaybeUninit};
 

From 28a055dceacd61d1a0faad075d69f71dfd439678 Mon Sep 17 00:00:00 2001
From: Tim Siegel <siegeltr@gmail.com>
Date: Wed, 31 Aug 2022 09:09:11 -0400
Subject: [PATCH 06/34] match_wild_err_arm: Fix typo in note text

---
 clippy_lints/src/matches/match_wild_err_arm.rs | 2 +-
 tests/ui/match_wild_err_arm.edition2018.stderr | 8 ++++----
 tests/ui/match_wild_err_arm.edition2021.stderr | 8 ++++----
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs
index bc16f17b619..a3aa2e4b389 100644
--- a/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -40,7 +40,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
                                 arm.pat.span,
                                 &format!("`Err({})` matches all errors", ident_bind_name),
                                 None,
-                                "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
+                                "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable",
                             );
                         }
                     }
diff --git a/tests/ui/match_wild_err_arm.edition2018.stderr b/tests/ui/match_wild_err_arm.edition2018.stderr
index 2a4012039ba..2d66daea804 100644
--- a/tests/ui/match_wild_err_arm.edition2018.stderr
+++ b/tests/ui/match_wild_err_arm.edition2018.stderr
@@ -5,7 +5,7 @@ LL |         Err(_) => panic!("err"),
    |         ^^^^^^
    |
    = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_)` matches all errors
   --> $DIR/match_wild_err_arm.rs:20:9
@@ -13,7 +13,7 @@ error: `Err(_)` matches all errors
 LL |         Err(_) => panic!(),
    |         ^^^^^^
    |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_)` matches all errors
   --> $DIR/match_wild_err_arm.rs:26:9
@@ -21,7 +21,7 @@ error: `Err(_)` matches all errors
 LL |         Err(_) => {
    |         ^^^^^^
    |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_e)` matches all errors
   --> $DIR/match_wild_err_arm.rs:34:9
@@ -29,7 +29,7 @@ error: `Err(_e)` matches all errors
 LL |         Err(_e) => panic!(),
    |         ^^^^^^^
    |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/match_wild_err_arm.edition2021.stderr b/tests/ui/match_wild_err_arm.edition2021.stderr
index 2a4012039ba..2d66daea804 100644
--- a/tests/ui/match_wild_err_arm.edition2021.stderr
+++ b/tests/ui/match_wild_err_arm.edition2021.stderr
@@ -5,7 +5,7 @@ LL |         Err(_) => panic!("err"),
    |         ^^^^^^
    |
    = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_)` matches all errors
   --> $DIR/match_wild_err_arm.rs:20:9
@@ -13,7 +13,7 @@ error: `Err(_)` matches all errors
 LL |         Err(_) => panic!(),
    |         ^^^^^^
    |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_)` matches all errors
   --> $DIR/match_wild_err_arm.rs:26:9
@@ -21,7 +21,7 @@ error: `Err(_)` matches all errors
 LL |         Err(_) => {
    |         ^^^^^^
    |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_e)` matches all errors
   --> $DIR/match_wild_err_arm.rs:34:9
@@ -29,7 +29,7 @@ error: `Err(_e)` matches all errors
 LL |         Err(_e) => panic!(),
    |         ^^^^^^^
    |
-   = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: aborting due to 4 previous errors
 

From 7298de256850e2e7480844f6300c0ecc297276b6 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Wed, 31 Aug 2022 15:24:40 +0200
Subject: [PATCH 07/34] fix a clippy test

---
 tests/ui/indexing_slicing_index.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/ui/indexing_slicing_index.rs b/tests/ui/indexing_slicing_index.rs
index 45a430edcb5..7ebf6ee993c 100644
--- a/tests/ui/indexing_slicing_index.rs
+++ b/tests/ui/indexing_slicing_index.rs
@@ -3,7 +3,7 @@
 // We also check the out_of_bounds_indexing lint here, because it lints similar things and
 // we want to avoid false positives.
 #![warn(clippy::out_of_bounds_indexing)]
-#![allow(const_err, clippy::no_effect, clippy::unnecessary_operation)]
+#![allow(const_err, unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)]
 
 const ARR: [i32; 2] = [1, 2];
 const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr.

From fb41bfa77405233da5ddd324091380e018e3d956 Mon Sep 17 00:00:00 2001
From: Jason Newcomb <jsnewcomb@pm.me>
Date: Wed, 31 Aug 2022 09:24:45 -0400
Subject: [PATCH 08/34] Merge commit 'f51aade56f93175dde89177a92e3669ebd8e7592'
 into clippyup

---
 .github/workflows/clippy.yml                  |   1 +
 .github/workflows/clippy_bors.yml             |   1 +
 CHANGELOG.md                                  | 160 +++-
 clippy_dev/src/bless.rs                       |   2 +-
 clippy_dev/src/fmt.rs                         |   8 +-
 clippy_dev/src/new_lint.rs                    |   2 +-
 clippy_dev/src/update_lints.rs                |   4 +-
 clippy_lints/src/as_underscore.rs             |  74 --
 clippy_lints/src/borrow_as_ptr.rs             |  99 --
 clippy_lints/src/borrow_deref_ref.rs          |   7 +-
 clippy_lints/src/bytecount.rs                 | 103 --
 clippy_lints/src/bytes_count_to_len.rs        |  70 --
 ...se_sensitive_file_extension_comparisons.rs |  86 --
 clippy_lints/src/casts/as_underscore.rs       |  25 +
 clippy_lints/src/casts/borrow_as_ptr.rs       |  37 +
 .../src/casts/cast_slice_from_raw_parts.rs    |  63 ++
 clippy_lints/src/casts/mod.rs                 | 109 ++-
 clippy_lints/src/casts/unnecessary_cast.rs    |   9 +-
 clippy_lints/src/dereference.rs               | 312 ++++++-
 clippy_lints/src/derive.rs                    |   5 +-
 clippy_lints/src/doc_link_with_quotes.rs      |   2 +-
 clippy_lints/src/duplicate_mod.rs             |   2 +-
 clippy_lints/src/escape.rs                    |  13 +-
 clippy_lints/src/floating_point_arithmetic.rs |  22 +-
 clippy_lints/src/format.rs                    |  24 +-
 clippy_lints/src/format_args.rs               |  94 +-
 clippy_lints/src/format_impl.rs               |  11 +-
 clippy_lints/src/functions/mod.rs             |  56 +-
 clippy_lints/src/functions/result.rs          | 100 ++
 clippy_lints/src/functions/result_unit_err.rs |  66 --
 clippy_lints/src/get_first.rs                 |  68 --
 clippy_lints/src/if_let_mutex.rs              |  50 +-
 clippy_lints/src/if_then_some_else_none.rs    |  90 +-
 clippy_lints/src/lib.register_all.rs          |  30 +-
 clippy_lints/src/lib.register_complexity.rs   |   9 +-
 clippy_lints/src/lib.register_correctness.rs  |   8 +-
 clippy_lints/src/lib.register_lints.rs        |  50 +-
 clippy_lints/src/lib.register_nursery.rs      |   5 +-
 clippy_lints/src/lib.register_pedantic.rs     |  11 +-
 clippy_lints/src/lib.register_perf.rs         |   2 +
 clippy_lints/src/lib.register_restriction.rs  |   6 +-
 clippy_lints/src/lib.register_style.rs        |   6 +-
 clippy_lints/src/lib.register_suspicious.rs   |   5 +
 clippy_lints/src/lib.rs                       |  53 +-
 clippy_lints/src/loops/needless_collect.rs    |  34 +-
 clippy_lints/src/manual_async_fn.rs           |   2 +-
 clippy_lints/src/manual_ok_or.rs              |  95 --
 clippy_lints/src/manual_string_new.rs         | 140 +++
 clippy_lints/src/map_clone.rs                 | 167 ----
 clippy_lints/src/map_err_ignore.rs            | 154 ---
 .../src/matches/match_like_matches.rs         |   4 +-
 clippy_lints/src/matches/needless_match.rs    |  22 +-
 clippy_lints/src/methods/bytecount.rs         |  70 ++
 .../src/methods/bytes_count_to_len.rs         |  37 +
 ...se_sensitive_file_extension_comparisons.rs |  41 +
 .../src/methods/collapsible_str_replace.rs    |  96 ++
 clippy_lints/src/methods/expect_used.rs       |  18 +-
 clippy_lints/src/methods/get_first.rs         |  39 +
 .../iter_on_single_or_empty_collections.rs    | 107 +++
 clippy_lints/src/methods/manual_ok_or.rs      |  64 ++
 clippy_lints/src/methods/map_clone.rs         | 122 +++
 clippy_lints/src/methods/map_err_ignore.rs    |  34 +
 clippy_lints/src/methods/mod.rs               | 857 ++++++++++++++++-
 clippy_lints/src/methods/mut_mutex_lock.rs    |  30 +
 .../src/{ => methods}/open_options.rs         |  44 +-
 .../src/methods/option_map_unwrap_or.rs       |   2 +-
 .../src/methods/path_buf_push_overwrite.rs    |  37 +
 .../src/methods/range_zip_with_len.rs         |  34 +
 clippy_lints/src/methods/repeat_once.rs       |  52 ++
 .../src/methods/stable_sort_primitive.rs      |  31 +
 .../src/methods/suspicious_to_owned.rs        |  36 +
 .../src/methods/uninit_assumed_init.rs        |   4 +-
 clippy_lints/src/methods/unit_hash.rs         |  29 +
 .../src/{ => methods}/unnecessary_sort_by.rs  | 156 ++--
 .../src/methods/unnecessary_to_owned.rs       |  37 +-
 clippy_lints/src/methods/unwrap_used.rs       |  20 +-
 .../src/methods/vec_resize_to_zero.rs         |  45 +
 .../src/methods/verbose_file_reads.rs         |  28 +
 .../misc_early/unneeded_wildcard_pattern.rs   |   2 +-
 .../src/mismatching_type_param_order.rs       |   2 +-
 clippy_lints/src/multi_assignments.rs         |  65 ++
 clippy_lints/src/mut_mutex_lock.rs            |  70 --
 clippy_lints/src/only_used_in_recursion.rs    | 880 +++++++-----------
 clippy_lints/src/option_if_let_else.rs        | 167 +++-
 clippy_lints/src/partialeq_to_none.rs         |   3 +-
 clippy_lints/src/path_buf_push_overwrite.rs   |  72 --
 clippy_lints/src/question_mark.rs             |   2 +-
 clippy_lints/src/ranges.rs                    |  73 +-
 clippy_lints/src/rc_clone_in_vec_init.rs      |   2 +-
 clippy_lints/src/redundant_slicing.rs         |   4 +-
 .../src/redundant_static_lifetimes.rs         |  12 +-
 clippy_lints/src/repeat_once.rs               |  89 --
 clippy_lints/src/returns.rs                   |  10 +-
 clippy_lints/src/self_named_constructors.rs   |   4 +-
 clippy_lints/src/stable_sort_primitive.rs     | 144 ---
 clippy_lints/src/trait_bounds.rs              | 106 ++-
 clippy_lints/src/transmute/mod.rs             |  25 +
 .../src/transmute/transmute_undefined_repr.rs | 400 ++++----
 .../src/transmute/transmuting_null.rs         |  61 ++
 clippy_lints/src/transmuting_null.rs          |  89 --
 clippy_lints/src/unicode.rs                   |   7 +
 clippy_lints/src/uninit_vec.rs                |   2 +-
 clippy_lints/src/unit_hash.rs                 |  78 --
 clippy_lints/src/unnecessary_wraps.rs         |   2 +-
 clippy_lints/src/unused_peekable.rs           | 225 +++++
 clippy_lints/src/unused_rounding.rs           |   2 +-
 clippy_lints/src/utils/conf.rs                |   6 +-
 clippy_lints/src/utils/internal_lints.rs      |   4 +-
 .../internal_lints/metadata_collector.rs      |   2 +-
 clippy_lints/src/vec_resize_to_zero.rs        |  64 --
 clippy_lints/src/verbose_file_reads.rs        |  88 --
 clippy_lints/src/write.rs                     | 129 ++-
 clippy_utils/Cargo.toml                       |   1 +
 clippy_utils/src/lib.rs                       |  29 +-
 clippy_utils/src/macros.rs                    | 678 ++++++++++----
 clippy_utils/src/msrvs.rs                     |   4 +-
 clippy_utils/src/paths.rs                     |   2 +-
 clippy_utils/src/ty.rs                        |  60 +-
 rust-toolchain                                |   2 +-
 rustc_tools_util/src/lib.rs                   |   4 +-
 tests/check-fmt.rs                            |   2 +-
 tests/compile-test.rs                         |  19 +-
 tests/dogfood.rs                              |   4 +-
 tests/integration.rs                          |   4 +-
 tests/lint_message_convention.rs              |   4 +-
 .../toml_unknown_key/conf_unknown_key.stderr  |   1 +
 ...se_sensitive_file_extension_comparisons.rs |  10 +-
 ...ensitive_file_extension_comparisons.stderr |  12 +-
 tests/ui/cast_raw_slice_pointer_cast.fixed    |  24 +
 tests/ui/cast_raw_slice_pointer_cast.rs       |  24 +
 tests/ui/cast_raw_slice_pointer_cast.stderr   |  46 +
 tests/ui/collapsible_str_replace.fixed        |  73 ++
 tests/ui/collapsible_str_replace.rs           |  76 ++
 tests/ui/collapsible_str_replace.stderr       |  86 ++
 tests/ui/expect.rs                            |   3 +-
 tests/ui/expect.stderr                        |  10 +-
 tests/ui/floating_point_exp.fixed             |   1 +
 tests/ui/floating_point_exp.rs                |   1 +
 tests/ui/floating_point_exp.stderr            |  12 +-
 tests/ui/floating_point_log.fixed             |   1 +
 tests/ui/floating_point_log.rs                |   1 +
 tests/ui/floating_point_log.stderr            |  54 +-
 tests/ui/floating_point_logbase.fixed         |   1 +
 tests/ui/floating_point_logbase.rs            |   1 +
 tests/ui/floating_point_logbase.stderr        |  12 +-
 tests/ui/floating_point_powf.fixed            |   3 +
 tests/ui/floating_point_powf.rs               |   3 +
 tests/ui/floating_point_powf.stderr           |  52 +-
 tests/ui/floating_point_powi.fixed            |   1 +
 tests/ui/floating_point_powi.rs               |   1 +
 tests/ui/floating_point_powi.stderr           |  12 +-
 tests/ui/floating_point_rad.fixed             |   5 +
 tests/ui/floating_point_rad.rs                |   5 +
 tests/ui/floating_point_rad.stderr            |  32 +-
 tests/ui/format.fixed                         |   2 +-
 tests/ui/format.rs                            |   2 +-
 tests/ui/format_args.fixed                    |  51 +-
 tests/ui/format_args.rs                       |  51 +-
 tests/ui/format_args.stderr                   |  56 +-
 tests/ui/identity_op.fixed                    |   2 +-
 tests/ui/identity_op.rs                       |   2 +-
 tests/ui/if_let_mutex.rs                      |   8 +
 tests/ui/if_let_mutex.stderr                  |  30 +-
 tests/ui/if_then_some_else_none.stderr        |   8 +-
 tests/ui/iter_on_empty_collections.fixed      |  63 ++
 tests/ui/iter_on_empty_collections.rs         |  63 ++
 tests/ui/iter_on_empty_collections.stderr     |  40 +
 tests/ui/iter_on_single_items.fixed           |  63 ++
 tests/ui/iter_on_single_items.rs              |  63 ++
 tests/ui/iter_on_single_items.stderr          |  40 +
 tests/ui/manual_string_new.fixed              |  63 ++
 tests/ui/manual_string_new.rs                 |  63 ++
 tests/ui/manual_string_new.stderr             |  58 ++
 tests/ui/match_expr_like_matches_macro.fixed  |  25 +
 tests/ui/match_expr_like_matches_macro.rs     |  25 +
 tests/ui/multi_assignments.rs                 |   9 +
 tests/ui/multi_assignments.stderr             |  40 +
 tests/ui/needless_borrow.fixed                | 117 ++-
 tests/ui/needless_borrow.rs                   | 117 ++-
 tests/ui/needless_borrow.stderr               |  48 +-
 tests/ui/needless_collect_indirect.rs         | 189 ++++
 tests/ui/needless_collect_indirect.stderr     | 119 ++-
 tests/ui/needless_match.fixed                 |  39 +
 tests/ui/needless_match.rs                    |  46 +
 tests/ui/needless_match.stderr                |  23 +-
 tests/ui/needless_return.fixed                |  10 +-
 tests/ui/needless_return.rs                   |  10 +-
 tests/ui/only_used_in_recursion.rs            | 143 ++-
 tests/ui/only_used_in_recursion.stderr        | 193 +++-
 tests/ui/only_used_in_recursion2.rs           |  91 ++
 tests/ui/only_used_in_recursion2.stderr       |  63 ++
 tests/ui/option_if_let_else.fixed             |   9 +
 tests/ui/option_if_let_else.rs                |  21 +
 tests/ui/option_if_let_else.stderr            |  48 +-
 tests/ui/or_fun_call.fixed                    |   4 +-
 tests/ui/or_fun_call.rs                       |   4 +-
 tests/ui/or_fun_call.stderr                   |   6 +-
 tests/ui/partialeq_to_none.fixed              |  12 +
 tests/ui/partialeq_to_none.rs                 |  12 +
 tests/ui/partialeq_to_none.stderr             |  28 +-
 .../positional_named_format_parameters.fixed  |  56 ++
 .../ui/positional_named_format_parameters.rs  |  56 ++
 .../positional_named_format_parameters.stderr | 418 +++++++++
 tests/ui/question_mark.fixed                  |  15 +
 tests/ui/question_mark.rs                     |  15 +
 tests/ui/regex.rs                             |   2 +-
 tests/ui/result_large_err.rs                  |  98 ++
 tests/ui/result_large_err.stderr              |  91 ++
 tests/ui/same_item_push.rs                    |   1 +
 tests/ui/string_add.rs                        |   4 +-
 tests/ui/string_add_assign.fixed              |   4 +-
 tests/ui/string_add_assign.rs                 |   4 +-
 tests/ui/suspicious_to_owned.rs               |  62 ++
 tests/ui/suspicious_to_owned.stderr           |  42 +
 tests/ui/trait_duplication_in_bounds.fixed    | 112 +++
 tests/ui/trait_duplication_in_bounds.rs       | 230 ++---
 tests/ui/trait_duplication_in_bounds.stderr   | 185 +---
 .../trait_duplication_in_bounds_unfixable.rs  | 166 ++++
 ...ait_duplication_in_bounds_unfixable.stderr |  71 ++
 tests/ui/transmute_undefined_repr.rs          |  12 +
 tests/ui/transmute_undefined_repr.stderr      |  38 +-
 tests/ui/unicode.fixed                        |  48 +-
 tests/ui/unicode.rs                           |  48 +-
 tests/ui/unicode.stderr                       |  46 +-
 tests/ui/unnecessary_cast.fixed               |   9 +
 tests/ui/unnecessary_cast.rs                  |   9 +
 tests/ui/unnecessary_cast.stderr              |  14 +-
 .../ui/unnecessary_owned_empty_strings.fixed  |   1 +
 tests/ui/unnecessary_owned_empty_strings.rs   |   1 +
 .../ui/unnecessary_owned_empty_strings.stderr |   2 +-
 tests/ui/unnecessary_to_owned.fixed           |  28 +
 tests/ui/unnecessary_to_owned.rs              |  28 +
 tests/ui/unused_peekable.rs                   | 144 +++
 tests/ui/unused_peekable.stderr               |  67 ++
 tests/ui/unwrap.rs                            |   3 +-
 tests/ui/unwrap.stderr                        |  10 +-
 tests/ui/unwrap_expect_used.rs                |  25 +
 tests/ui/unwrap_expect_used.stderr            |  26 +-
 tests/ui/useless_conversion_try.rs            |   4 +-
 tests/ui/useless_conversion_try.stderr        |   2 +-
 tests/ui/vec_resize_to_zero.rs                |  12 +-
 tests/ui/vec_resize_to_zero.stderr            |  10 +-
 tests/ui/verbose_file_reads.rs                |   2 +-
 tests/workspace.rs                            |  14 +-
 244 files changed, 9305 insertions(+), 4024 deletions(-)
 delete mode 100644 clippy_lints/src/as_underscore.rs
 delete mode 100644 clippy_lints/src/borrow_as_ptr.rs
 delete mode 100644 clippy_lints/src/bytecount.rs
 delete mode 100644 clippy_lints/src/bytes_count_to_len.rs
 delete mode 100644 clippy_lints/src/case_sensitive_file_extension_comparisons.rs
 create mode 100644 clippy_lints/src/casts/as_underscore.rs
 create mode 100644 clippy_lints/src/casts/borrow_as_ptr.rs
 create mode 100644 clippy_lints/src/casts/cast_slice_from_raw_parts.rs
 create mode 100644 clippy_lints/src/functions/result.rs
 delete mode 100644 clippy_lints/src/functions/result_unit_err.rs
 delete mode 100644 clippy_lints/src/get_first.rs
 delete mode 100644 clippy_lints/src/manual_ok_or.rs
 create mode 100644 clippy_lints/src/manual_string_new.rs
 delete mode 100644 clippy_lints/src/map_clone.rs
 delete mode 100644 clippy_lints/src/map_err_ignore.rs
 create mode 100644 clippy_lints/src/methods/bytecount.rs
 create mode 100644 clippy_lints/src/methods/bytes_count_to_len.rs
 create mode 100644 clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
 create mode 100644 clippy_lints/src/methods/collapsible_str_replace.rs
 create mode 100644 clippy_lints/src/methods/get_first.rs
 create mode 100644 clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
 create mode 100644 clippy_lints/src/methods/manual_ok_or.rs
 create mode 100644 clippy_lints/src/methods/map_clone.rs
 create mode 100644 clippy_lints/src/methods/map_err_ignore.rs
 create mode 100644 clippy_lints/src/methods/mut_mutex_lock.rs
 rename clippy_lints/src/{ => methods}/open_options.rs (80%)
 create mode 100644 clippy_lints/src/methods/path_buf_push_overwrite.rs
 create mode 100644 clippy_lints/src/methods/range_zip_with_len.rs
 create mode 100644 clippy_lints/src/methods/repeat_once.rs
 create mode 100644 clippy_lints/src/methods/stable_sort_primitive.rs
 create mode 100644 clippy_lints/src/methods/suspicious_to_owned.rs
 create mode 100644 clippy_lints/src/methods/unit_hash.rs
 rename clippy_lints/src/{ => methods}/unnecessary_sort_by.rs (63%)
 create mode 100644 clippy_lints/src/methods/vec_resize_to_zero.rs
 create mode 100644 clippy_lints/src/methods/verbose_file_reads.rs
 create mode 100644 clippy_lints/src/multi_assignments.rs
 delete mode 100644 clippy_lints/src/mut_mutex_lock.rs
 delete mode 100644 clippy_lints/src/path_buf_push_overwrite.rs
 delete mode 100644 clippy_lints/src/repeat_once.rs
 delete mode 100644 clippy_lints/src/stable_sort_primitive.rs
 create mode 100644 clippy_lints/src/transmute/transmuting_null.rs
 delete mode 100644 clippy_lints/src/transmuting_null.rs
 delete mode 100644 clippy_lints/src/unit_hash.rs
 create mode 100644 clippy_lints/src/unused_peekable.rs
 delete mode 100644 clippy_lints/src/vec_resize_to_zero.rs
 delete mode 100644 clippy_lints/src/verbose_file_reads.rs
 create mode 100644 tests/ui/cast_raw_slice_pointer_cast.fixed
 create mode 100644 tests/ui/cast_raw_slice_pointer_cast.rs
 create mode 100644 tests/ui/cast_raw_slice_pointer_cast.stderr
 create mode 100644 tests/ui/collapsible_str_replace.fixed
 create mode 100644 tests/ui/collapsible_str_replace.rs
 create mode 100644 tests/ui/collapsible_str_replace.stderr
 create mode 100644 tests/ui/iter_on_empty_collections.fixed
 create mode 100644 tests/ui/iter_on_empty_collections.rs
 create mode 100644 tests/ui/iter_on_empty_collections.stderr
 create mode 100644 tests/ui/iter_on_single_items.fixed
 create mode 100644 tests/ui/iter_on_single_items.rs
 create mode 100644 tests/ui/iter_on_single_items.stderr
 create mode 100644 tests/ui/manual_string_new.fixed
 create mode 100644 tests/ui/manual_string_new.rs
 create mode 100644 tests/ui/manual_string_new.stderr
 create mode 100644 tests/ui/multi_assignments.rs
 create mode 100644 tests/ui/multi_assignments.stderr
 create mode 100644 tests/ui/only_used_in_recursion2.rs
 create mode 100644 tests/ui/only_used_in_recursion2.stderr
 create mode 100644 tests/ui/positional_named_format_parameters.fixed
 create mode 100644 tests/ui/positional_named_format_parameters.rs
 create mode 100644 tests/ui/positional_named_format_parameters.stderr
 create mode 100644 tests/ui/result_large_err.rs
 create mode 100644 tests/ui/result_large_err.stderr
 create mode 100644 tests/ui/suspicious_to_owned.rs
 create mode 100644 tests/ui/suspicious_to_owned.stderr
 create mode 100644 tests/ui/trait_duplication_in_bounds.fixed
 create mode 100644 tests/ui/trait_duplication_in_bounds_unfixable.rs
 create mode 100644 tests/ui/trait_duplication_in_bounds_unfixable.stderr
 create mode 100644 tests/ui/unused_peekable.rs
 create mode 100644 tests/ui/unused_peekable.stderr

diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml
index 0e27cc927ac..fac2c99714d 100644
--- a/.github/workflows/clippy.yml
+++ b/.github/workflows/clippy.yml
@@ -24,6 +24,7 @@ env:
   RUST_BACKTRACE: 1
   CARGO_TARGET_DIR: '${{ github.workspace }}/target'
   NO_FMT_TEST: 1
+  CARGO_INCREMENTAL: 0
 
 jobs:
   base:
diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml
index 97453303cd6..30607af4901 100644
--- a/.github/workflows/clippy_bors.yml
+++ b/.github/workflows/clippy_bors.yml
@@ -10,6 +10,7 @@ env:
   RUST_BACKTRACE: 1
   CARGO_TARGET_DIR: '${{ github.workspace }}/target'
   NO_FMT_TEST: 1
+  CARGO_INCREMENTAL: 0
 
 defaults:
   run:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 380cd451987..c488c142e46 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,11 +6,157 @@ document.
 
 ## Unreleased / In Rust Nightly
 
-[7c21f91b...master](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...master)
+[d7b5cbf0...master](https://github.com/rust-lang/rust-clippy/compare/d7b5cbf0...master)
+
+## Rust 1.63
+
+Current stable, released 2022-08-11
+
+[7c21f91b...d7b5cbf0](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...d7b5cbf0)
+
+### New Lints
+
+* [`borrow_deref_ref`]
+  [#7930](https://github.com/rust-lang/rust-clippy/pull/7930)
+* [`doc_link_with_quotes`]
+  [#8385](https://github.com/rust-lang/rust-clippy/pull/8385)
+* [`no_effect_replace`]
+  [#8754](https://github.com/rust-lang/rust-clippy/pull/8754)
+* [`rc_clone_in_vec_init`]
+  [#8769](https://github.com/rust-lang/rust-clippy/pull/8769)
+* [`derive_partial_eq_without_eq`]
+  [#8796](https://github.com/rust-lang/rust-clippy/pull/8796)
+* [`mismatching_type_param_order`]
+  [#8831](https://github.com/rust-lang/rust-clippy/pull/8831)
+* [`duplicate_mod`] [#8832](https://github.com/rust-lang/rust-clippy/pull/8832)
+* [`unused_rounding`]
+  [#8866](https://github.com/rust-lang/rust-clippy/pull/8866)
+* [`get_first`] [#8882](https://github.com/rust-lang/rust-clippy/pull/8882)
+* [`swap_ptr_to_ref`]
+  [#8916](https://github.com/rust-lang/rust-clippy/pull/8916)
+* [`almost_complete_letter_range`]
+  [#8918](https://github.com/rust-lang/rust-clippy/pull/8918)
+* [`needless_parens_on_range_literals`]
+  [#8933](https://github.com/rust-lang/rust-clippy/pull/8933)
+* [`as_underscore`] [#8934](https://github.com/rust-lang/rust-clippy/pull/8934)
+
+### Moves and Deprecations
+
+* Rename `eval_order_dependence` to [`mixed_read_write_in_expression`], move to
+  `nursery` [#8621](https://github.com/rust-lang/rust-clippy/pull/8621)
+
+### Enhancements
+
+* [`undocumented_unsafe_blocks`]: Now also lints on unsafe trait implementations
+  [#8761](https://github.com/rust-lang/rust-clippy/pull/8761)
+* [`empty_line_after_outer_attr`]: Now also lints on argumentless macros
+  [#8790](https://github.com/rust-lang/rust-clippy/pull/8790)
+* [`expect_used`]: Now can be disabled in tests with the `allow-expect-in-tests`
+  option [#8802](https://github.com/rust-lang/rust-clippy/pull/8802)
+* [`unwrap_used`]: Now can be disabled in tests with the `allow-unwrap-in-tests`
+  option [#8802](https://github.com/rust-lang/rust-clippy/pull/8802)
+* [`disallowed_methods`]: Now also lints indirect usages
+  [#8852](https://github.com/rust-lang/rust-clippy/pull/8852)
+* [`get_last_with_len`]: Now also lints `VecDeque` and any deref to slice
+  [#8862](https://github.com/rust-lang/rust-clippy/pull/8862)
+* [`manual_range_contains`]: Now also lints on chains of `&&` and `||`
+  [#8884](https://github.com/rust-lang/rust-clippy/pull/8884)
+* [`rc_clone_in_vec_init`]: Now also lints on `Weak`
+  [#8885](https://github.com/rust-lang/rust-clippy/pull/8885)
+* [`dbg_macro`]: Introduce `allow-dbg-in-tests` config option
+  [#8897](https://github.com/rust-lang/rust-clippy/pull/8897)
+* [`use_self`]: Now also lints on `TupleStruct` and `Struct` patterns
+  [#8899](https://github.com/rust-lang/rust-clippy/pull/8899)
+* [`manual_find_map`] and [`manual_filter_map`]: Now also lints on more complex
+  method chains inside `map`
+  [#8930](https://github.com/rust-lang/rust-clippy/pull/8930)
+* [`needless_return`]: Now also lints on macro expressions in return statements
+  [#8932](https://github.com/rust-lang/rust-clippy/pull/8932)
+* [`doc_markdown`]: Users can now indicate, that the `doc-valid-idents` config
+  should extend the default and not replace it
+  [#8944](https://github.com/rust-lang/rust-clippy/pull/8944)
+* [`disallowed_names`]: Users can now indicate, that the `disallowed-names`
+  config should extend the default and not replace it
+  [#8944](https://github.com/rust-lang/rust-clippy/pull/8944)
+* [`never_loop`]: Now checks for `continue` in struct expression
+  [#9002](https://github.com/rust-lang/rust-clippy/pull/9002)
+
+### False Positive Fixes
+
+* [`useless_transmute`]: No longer lints on types with erased regions
+  [#8564](https://github.com/rust-lang/rust-clippy/pull/8564)
+* [`vec_init_then_push`]: No longer lints when further extended
+  [#8699](https://github.com/rust-lang/rust-clippy/pull/8699)
+* [`cmp_owned`]: No longer lints on `From::from` for `Copy` types
+  [#8807](https://github.com/rust-lang/rust-clippy/pull/8807)
+* [`redundant_allocation`]: No longer lints on fat pointers that would become
+  thin pointers [#8813](https://github.com/rust-lang/rust-clippy/pull/8813)
+* [`derive_partial_eq_without_eq`]:
+    * Handle differing predicates applied by `#[derive(PartialEq)]` and
+      `#[derive(Eq)]`
+      [#8869](https://github.com/rust-lang/rust-clippy/pull/8869)
+    * No longer lints on non-public types and better handles generics
+      [#8950](https://github.com/rust-lang/rust-clippy/pull/8950)
+* [`empty_line_after_outer_attr`]: No longer lints empty lines in inner
+  string values [#8892](https://github.com/rust-lang/rust-clippy/pull/8892)
+* [`branches_sharing_code`]: No longer lints when using different binding names
+  [#8901](https://github.com/rust-lang/rust-clippy/pull/8901)
+* [`significant_drop_in_scrutinee`]: No longer lints on Try `?` and `await`
+  desugared expressions [#8902](https://github.com/rust-lang/rust-clippy/pull/8902)
+* [`checked_conversions`]: No longer lints in `const` contexts
+  [#8907](https://github.com/rust-lang/rust-clippy/pull/8907)
+* [`iter_overeager_cloned`]: No longer lints on `.cloned().flatten()` when
+  `T::Item` doesn't implement `IntoIterator`
+  [#8960](https://github.com/rust-lang/rust-clippy/pull/8960)
+
+### Suggestion Fixes/Improvements
+
+* [`vec_init_then_push`]: Suggest to remove `mut` binding when possible
+  [#8699](https://github.com/rust-lang/rust-clippy/pull/8699)
+* [`manual_range_contains`]: Fix suggestion for integers with different signs
+  [#8763](https://github.com/rust-lang/rust-clippy/pull/8763)
+* [`identity_op`]: Add parenthesis to suggestions where required
+  [#8786](https://github.com/rust-lang/rust-clippy/pull/8786)
+* [`cast_lossless`]: No longer gives wrong suggestion on `usize`/`isize`->`f64`
+  [#8778](https://github.com/rust-lang/rust-clippy/pull/8778)
+* [`rc_clone_in_vec_init`]: Add suggestion
+  [#8814](https://github.com/rust-lang/rust-clippy/pull/8814)
+* The "unknown field" error messages for config files now wraps the field names
+  [#8823](https://github.com/rust-lang/rust-clippy/pull/8823)
+* [`cast_abs_to_unsigned`]: Do not remove cast if it's required
+  [#8876](https://github.com/rust-lang/rust-clippy/pull/8876)
+* [`significant_drop_in_scrutinee`]: Improve lint message for types that are not
+  references and not trivially clone-able
+  [#8902](https://github.com/rust-lang/rust-clippy/pull/8902)
+* [`for_loops_over_fallibles`]: Now suggests the correct variant of `iter()`,
+  `iter_mut()` or `into_iter()`
+  [#8941](https://github.com/rust-lang/rust-clippy/pull/8941)
+
+### ICE Fixes
+
+* Fix ICE in [`let_unit_value`] when calling a `static`/`const` callable type
+  [#8835](https://github.com/rust-lang/rust-clippy/pull/8835)
+* Fix ICEs on callable `static`/`const`s
+  [#8896](https://github.com/rust-lang/rust-clippy/pull/8896)
+* [`needless_late_init`]
+  [#8912](https://github.com/rust-lang/rust-clippy/pull/8912)
+* Fix ICE in shadow lints
+  [#8913](https://github.com/rust-lang/rust-clippy/pull/8913)
+
+### Documentation Improvements
+
+* Clippy has a [Book](https://doc.rust-lang.org/nightly/clippy/) now!
+  [#7359](https://github.com/rust-lang/rust-clippy/pull/7359)
+* Add a *copy lint name*-button to Clippy's lint list
+  [#8839](https://github.com/rust-lang/rust-clippy/pull/8839)
+* Display past names of renamed lints on Clippy's lint list
+  [#8843](https://github.com/rust-lang/rust-clippy/pull/8843)
+* Add the ability to show the lint output in the lint list
+  [#8947](https://github.com/rust-lang/rust-clippy/pull/8947)
 
 ## Rust 1.62
 
-Current stable, released 2022-06-30
+Released 2022-06-30
 
 [d0cf3481...7c21f91b](https://github.com/rust-lang/rust-clippy/compare/d0cf3481...7c21f91b)
 
@@ -3481,6 +3627,7 @@ Released 2018-09-13
 [`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut
 [`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
 [`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes
+[`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts
 [`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
 [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
@@ -3496,6 +3643,7 @@ Released 2018-09-13
 [`collapsible_else_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if
 [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
 [`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match
+[`collapsible_str_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace
 [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
 [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
 [`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
@@ -3656,6 +3804,8 @@ Released 2018-09-13
 [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator
 [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
 [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
+[`iter_on_empty_collections`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_empty_collections
+[`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items
 [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
 [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
 [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
@@ -3697,6 +3847,7 @@ Released 2018-09-13
 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
 [`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once
 [`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
+[`manual_string_new`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_string_new
 [`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
@@ -3747,6 +3898,7 @@ Released 2018-09-13
 [`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions
 [`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic
 [`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one
+[`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments
 [`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions
 [`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl
 [`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate
@@ -3827,6 +3979,7 @@ Released 2018-09-13
 [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
 [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
 [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
+[`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
 [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
 [`print_in_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_in_format_impl
@@ -3872,6 +4025,7 @@ Released 2018-09-13
 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
 [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs
 [`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used
+[`result_large_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err
 [`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option
 [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
 [`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
@@ -3930,6 +4084,7 @@ Released 2018-09-13
 [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
 [`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings
 [`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
+[`suspicious_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_to_owned
 [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
 [`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref
 [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
@@ -4002,6 +4157,7 @@ Released 2018-09-13
 [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
 [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 [`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
+[`unused_peekable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_peekable
 [`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding
 [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
 [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
diff --git a/clippy_dev/src/bless.rs b/clippy_dev/src/bless.rs
index f5c51b9474f..92b2771f3fe 100644
--- a/clippy_dev/src/bless.rs
+++ b/clippy_dev/src/bless.rs
@@ -37,7 +37,7 @@ fn update_reference_file(test_output_entry: &DirEntry, ignore_timestamp: bool) {
         return;
     }
 
-    let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file");
+    let test_output_file = fs::read(test_output_path).expect("Unable to read test output file");
     let reference_file = fs::read(&reference_file_path).unwrap_or_default();
 
     if test_output_file != reference_file {
diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs
index 3b27f061eb0..357cf6fc43a 100644
--- a/clippy_dev/src/fmt.rs
+++ b/clippy_dev/src/fmt.rs
@@ -46,7 +46,7 @@ pub fn run(check: bool, verbose: bool) {
         // dependency
         if fs::read_to_string(project_root.join("Cargo.toml"))
             .expect("Failed to read clippy Cargo.toml")
-            .contains(&"[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
+            .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]")
         {
             return Err(CliError::IntellijSetupActive);
         }
@@ -193,10 +193,10 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
     let args = &["--version"];
 
     if context.verbose {
-        println!("{}", format_command(&program, &dir, args));
+        println!("{}", format_command(program, &dir, args));
     }
 
-    let output = Command::new(&program).current_dir(&dir).args(args.iter()).output()?;
+    let output = Command::new(program).current_dir(&dir).args(args.iter()).output()?;
 
     if output.status.success() {
         Ok(())
@@ -207,7 +207,7 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> {
         Err(CliError::RustfmtNotInstalled)
     } else {
         Err(CliError::CommandFailed(
-            format_command(&program, &dir, args),
+            format_command(program, &dir, args),
             std::str::from_utf8(&output.stderr).unwrap_or("").to_string(),
         ))
     }
diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs
index 10a8f31f457..be05e67d724 100644
--- a/clippy_dev/src/new_lint.rs
+++ b/clippy_dev/src/new_lint.rs
@@ -155,7 +155,7 @@ fn to_camel_case(name: &str) -> String {
     name.split('_')
         .map(|s| {
             if s.is_empty() {
-                String::from("")
+                String::new()
             } else {
                 [&s[0..1].to_uppercase(), &s[1..]].concat()
             }
diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs
index 05e79a24188..c503142e5e4 100644
--- a/clippy_dev/src/update_lints.rs
+++ b/clippy_dev/src/update_lints.rs
@@ -418,7 +418,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
             .expect("failed to find `impl_lint_pass` terminator");
 
         impl_lint_pass_end += impl_lint_pass_start;
-        if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(&lint_name_upper) {
+        if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) {
             let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len());
             for c in content[lint_name_end..impl_lint_pass_end].chars() {
                 // Remove trailing whitespace
@@ -451,7 +451,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec<Lint>) -> io
                 }
 
                 let mut content =
-                    fs::read_to_string(&path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
+                    fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
 
                 eprintln!(
                     "warn: you will have to manually remove any code related to `{}` from `{}`",
diff --git a/clippy_lints/src/as_underscore.rs b/clippy_lints/src/as_underscore.rs
deleted file mode 100644
index 0bdef9d0a7e..00000000000
--- a/clippy_lints/src/as_underscore.rs
+++ /dev/null
@@ -1,74 +0,0 @@
-use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, TyKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Check for the usage of `as _` conversion using inferred type.
-    ///
-    /// ### Why is this bad?
-    /// The conversion might include lossy conversion and dangerous cast that might go
-    /// undetected du to the type being inferred.
-    ///
-    /// The lint is allowed by default as using `_` is less wordy than always specifying the type.
-    ///
-    /// ### Example
-    /// ```rust
-    /// fn foo(n: usize) {}
-    /// let n: u16 = 256;
-    /// foo(n as _);
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// fn foo(n: usize) {}
-    /// let n: u16 = 256;
-    /// foo(n as usize);
-    /// ```
-    #[clippy::version = "1.63.0"]
-    pub AS_UNDERSCORE,
-    restriction,
-    "detects `as _` conversion"
-}
-declare_lint_pass!(AsUnderscore => [AS_UNDERSCORE]);
-
-impl<'tcx> LateLintPass<'tcx> for AsUnderscore {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        if let ExprKind::Cast(_, ty) = expr.kind && let TyKind::Infer = ty.kind {
-
-            let ty_resolved = cx.typeck_results().expr_ty(expr);
-            if let ty::Error(_) = ty_resolved.kind() {
-                span_lint_and_help(
-                    cx,
-                AS_UNDERSCORE,
-                expr.span,
-                "using `as _` conversion",
-                None,
-                "consider giving the type explicitly",
-                );
-            } else {
-            span_lint_and_then(
-                cx,
-                AS_UNDERSCORE,
-                expr.span,
-                "using `as _` conversion",
-                |diag| {
-                    diag.span_suggestion(
-                        ty.span,
-                        "consider giving the type explicitly",
-                        ty_resolved,
-                        Applicability::MachineApplicable,
-                    );
-            }
-            );
-        }
-        }
-    }
-}
diff --git a/clippy_lints/src/borrow_as_ptr.rs b/clippy_lints/src/borrow_as_ptr.rs
deleted file mode 100644
index 0993adbae2e..00000000000
--- a/clippy_lints/src/borrow_as_ptr.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_no_std_crate;
-use clippy_utils::source::snippet_opt;
-use clippy_utils::{meets_msrv, msrvs};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, TyKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_semver::RustcVersion;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for the usage of `&expr as *const T` or
-    /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or
-    /// `ptr::addr_of_mut` instead.
-    ///
-    /// ### Why is this bad?
-    /// This would improve readability and avoid creating a reference
-    /// that points to an uninitialized value or unaligned place.
-    /// Read the `ptr::addr_of` docs for more information.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let val = 1;
-    /// let p = &val as *const i32;
-    ///
-    /// let mut val_mut = 1;
-    /// let p_mut = &mut val_mut as *mut i32;
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// let val = 1;
-    /// let p = std::ptr::addr_of!(val);
-    ///
-    /// let mut val_mut = 1;
-    /// let p_mut = std::ptr::addr_of_mut!(val_mut);
-    /// ```
-    #[clippy::version = "1.60.0"]
-    pub BORROW_AS_PTR,
-    pedantic,
-    "borrowing just to cast to a raw pointer"
-}
-
-impl_lint_pass!(BorrowAsPtr => [BORROW_AS_PTR]);
-
-pub struct BorrowAsPtr {
-    msrv: Option<RustcVersion>,
-}
-
-impl BorrowAsPtr {
-    #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
-        Self { msrv }
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) {
-            return;
-        }
-
-        if expr.span.from_expansion() {
-            return;
-        }
-
-        if_chain! {
-            if let ExprKind::Cast(left_expr, ty) = &expr.kind;
-            if let TyKind::Ptr(_) = ty.kind;
-            if let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = &left_expr.kind;
-
-            then {
-                let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
-                let macro_name = match mutability {
-                    Mutability::Not => "addr_of",
-                    Mutability::Mut => "addr_of_mut",
-                };
-
-                span_lint_and_sugg(
-                    cx,
-                    BORROW_AS_PTR,
-                    expr.span,
-                    "borrow as raw pointer",
-                    "try",
-                    format!(
-                        "{}::ptr::{}!({})",
-                        core_or_std,
-                        macro_name,
-                        snippet_opt(cx, e.span).unwrap()
-                    ),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-    }
-
-    extract_msrv_attr!(LateContext);
-}
diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs
index 937765b6614..c4520d00392 100644
--- a/clippy_lints/src/borrow_deref_ref.rs
+++ b/clippy_lints/src/borrow_deref_ref.rs
@@ -29,22 +29,17 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```rust
-    /// fn foo(_x: &str) {}
-    ///
     /// let s = &String::new();
     ///
     /// let a: &String = &* s;
-    /// foo(&*s);
     /// ```
     ///
     /// Use instead:
     /// ```rust
-    /// # fn foo(_x: &str) {}
     /// # let s = &String::new();
     /// let a: &String = s;
-    /// foo(&**s);
     /// ```
-    #[clippy::version = "1.59.0"]
+    #[clippy::version = "1.63.0"]
     pub BORROW_DEREF_REF,
     complexity,
     "deref on an immutable reference returns the same type as itself"
diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs
deleted file mode 100644
index 326ce34082a..00000000000
--- a/clippy_lints/src/bytecount.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::match_type;
-use clippy_utils::visitors::is_local_used;
-use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, UintTy};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for naive byte counts
-    ///
-    /// ### Why is this bad?
-    /// The [`bytecount`](https://crates.io/crates/bytecount)
-    /// crate has methods to count your bytes faster, especially for large slices.
-    ///
-    /// ### Known problems
-    /// If you have predominantly small slices, the
-    /// `bytecount::count(..)` method may actually be slower. However, if you can
-    /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
-    /// faster in those cases.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # let vec = vec![1_u8];
-    /// let count = vec.iter().filter(|x| **x == 0u8).count();
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// # let vec = vec![1_u8];
-    /// let count = bytecount::count(&vec, 0u8);
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub NAIVE_BYTECOUNT,
-    pedantic,
-    "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values"
-}
-
-declare_lint_pass!(ByteCount => [NAIVE_BYTECOUNT]);
-
-impl<'tcx> LateLintPass<'tcx> for ByteCount {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if_chain! {
-            if let ExprKind::MethodCall(count, [count_recv], _) = expr.kind;
-            if count.ident.name == sym::count;
-            if let ExprKind::MethodCall(filter, [filter_recv, filter_arg], _) = count_recv.kind;
-            if filter.ident.name == sym!(filter);
-            if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind;
-            let body = cx.tcx.hir().body(body);
-            if let [param] = body.params;
-            if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
-            if let ExprKind::Binary(ref op, l, r) = body.value.kind;
-            if op.node == BinOpKind::Eq;
-            if match_type(cx,
-                       cx.typeck_results().expr_ty(filter_recv).peel_refs(),
-                       &paths::SLICE_ITER);
-            let operand_is_arg = |expr| {
-                let expr = peel_ref_operators(cx, peel_blocks(expr));
-                path_to_local_id(expr, arg_id)
-            };
-            let needle = if operand_is_arg(l) {
-                r
-            } else if operand_is_arg(r) {
-                l
-            } else {
-                return;
-            };
-            if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
-            if !is_local_used(cx, needle, arg_id);
-            then {
-                let haystack = if let ExprKind::MethodCall(path, args, _) =
-                        filter_recv.kind {
-                    let p = path.ident.name;
-                    if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
-                        &args[0]
-                    } else {
-                        filter_recv
-                    }
-                } else {
-                    filter_recv
-                };
-                let mut applicability = Applicability::MaybeIncorrect;
-                span_lint_and_sugg(
-                    cx,
-                    NAIVE_BYTECOUNT,
-                    expr.span,
-                    "you appear to be counting bytes the naive way",
-                    "consider using the bytecount crate",
-                    format!("bytecount::count({}, {})",
-                            snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
-                            snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
-                    applicability,
-                );
-            }
-        };
-    }
-}
diff --git a/clippy_lints/src/bytes_count_to_len.rs b/clippy_lints/src/bytes_count_to_len.rs
deleted file mode 100644
index d70dbf5b239..00000000000
--- a/clippy_lints/src/bytes_count_to_len.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{match_def_path, paths};
-use if_chain::if_chain;
-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};
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// It checks for `str::bytes().count()` and suggests replacing it with
-    /// `str::len()`.
-    ///
-    /// ### Why is this bad?
-    /// `str::bytes().count()` is longer and may not be as performant as using
-    /// `str::len()`.
-    ///
-    /// ### Example
-    /// ```rust
-    /// "hello".bytes().count();
-    /// String::from("hello").bytes().count();
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// "hello".len();
-    /// String::from("hello").len();
-    /// ```
-    #[clippy::version = "1.62.0"]
-    pub BYTES_COUNT_TO_LEN,
-    complexity,
-    "Using `bytes().count()` when `len()` performs the same functionality"
-}
-
-declare_lint_pass!(BytesCountToLen => [BYTES_COUNT_TO_LEN]);
-
-impl<'tcx> LateLintPass<'tcx> for BytesCountToLen {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if_chain! {
-            if let hir::ExprKind::MethodCall(_, expr_args, _) = &expr.kind;
-            if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
-            if match_def_path(cx, expr_def_id, &paths::ITER_COUNT);
-
-            if let [bytes_expr] = &**expr_args;
-            if let hir::ExprKind::MethodCall(_, bytes_args, _) = &bytes_expr.kind;
-            if let Some(bytes_def_id) = cx.typeck_results().type_dependent_def_id(bytes_expr.hir_id);
-            if match_def_path(cx, bytes_def_id, &paths::STR_BYTES);
-
-            if let [str_expr] = &**bytes_args;
-            let ty = cx.typeck_results().expr_ty(str_expr).peel_refs();
-
-            if is_type_diagnostic_item(cx, ty, sym::String) || ty.kind() == &ty::Str;
-            then {
-                let mut applicability = Applicability::MachineApplicable;
-                span_lint_and_sugg(
-                    cx,
-                    BYTES_COUNT_TO_LEN,
-                    expr.span,
-                    "using long and hard to read `.bytes().count()`",
-                    "consider calling `.len()` instead",
-                    format!("{}.len()", snippet_with_applicability(cx, str_expr.span, "..", &mut applicability)),
-                    applicability
-                );
-            }
-        };
-    }
-}
diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
deleted file mode 100644
index 7eff71d5007..00000000000
--- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
-use rustc_hir::{Expr, ExprKind, PathSegment};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{source_map::Spanned, symbol::sym, Span};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for calls to `ends_with` with possible file extensions
-    /// and suggests to use a case-insensitive approach instead.
-    ///
-    /// ### Why is this bad?
-    /// `ends_with` is case-sensitive and may not detect files with a valid extension.
-    ///
-    /// ### Example
-    /// ```rust
-    /// fn is_rust_file(filename: &str) -> bool {
-    ///     filename.ends_with(".rs")
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// fn is_rust_file(filename: &str) -> bool {
-    ///     let filename = std::path::Path::new(filename);
-    ///     filename.extension()
-    ///         .map(|ext| ext.eq_ignore_ascii_case("rs"))
-    ///         .unwrap_or(false)
-    /// }
-    /// ```
-    #[clippy::version = "1.51.0"]
-    pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
-    pedantic,
-    "Checks for calls to ends_with with case-sensitive file extensions"
-}
-
-declare_lint_pass!(CaseSensitiveFileExtensionComparisons => [CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS]);
-
-fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Span> {
-    if_chain! {
-        if let ExprKind::MethodCall(PathSegment { ident, .. }, [obj, extension, ..], span) = expr.kind;
-        if ident.as_str() == "ends_with";
-        if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = extension.kind;
-        if (2..=6).contains(&ext_literal.as_str().len());
-        if ext_literal.as_str().starts_with('.');
-        if ext_literal.as_str().chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit())
-            || ext_literal.as_str().chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit());
-        then {
-            let mut ty = ctx.typeck_results().expr_ty(obj);
-            ty = match ty.kind() {
-                ty::Ref(_, ty, ..) => *ty,
-                _ => ty
-            };
-
-            match ty.kind() {
-                ty::Str => {
-                    return Some(span);
-                },
-                ty::Adt(def, _) => {
-                    if ctx.tcx.is_diagnostic_item(sym::String, def.did()) {
-                        return Some(span);
-                    }
-                },
-                _ => { return None; }
-            }
-        }
-    }
-    None
-}
-
-impl<'tcx> LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons {
-    fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if let Some(span) = check_case_sensitive_file_extension_comparison(ctx, expr) {
-            span_lint_and_help(
-                ctx,
-                CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
-                span,
-                "case-sensitive file extension comparison",
-                None,
-                "consider using a case-insensitive comparison instead",
-            );
-        }
-    }
-}
diff --git a/clippy_lints/src/casts/as_underscore.rs b/clippy_lints/src/casts/as_underscore.rs
new file mode 100644
index 00000000000..56e894c6261
--- /dev/null
+++ b/clippy_lints/src/casts/as_underscore.rs
@@ -0,0 +1,25 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, Ty, TyKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+
+use super::AS_UNDERSCORE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ty: &'tcx Ty<'_>) {
+    if matches!(ty.kind, TyKind::Infer) {
+        span_lint_and_then(cx, AS_UNDERSCORE, expr.span, "using `as _` conversion", |diag| {
+            let ty_resolved = cx.typeck_results().expr_ty(expr);
+            if let ty::Error(_) = ty_resolved.kind() {
+                diag.help("consider giving the type explicitly");
+            } else {
+                diag.span_suggestion(
+                    ty.span,
+                    "consider giving the type explicitly",
+                    ty_resolved,
+                    Applicability::MachineApplicable,
+                );
+            }
+        });
+    }
+}
diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs
new file mode 100644
index 00000000000..6e1f8cd64f0
--- /dev/null
+++ b/clippy_lints/src/casts/borrow_as_ptr.rs
@@ -0,0 +1,37 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_no_std_crate;
+use clippy_utils::source::snippet_with_context;
+use rustc_errors::Applicability;
+use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind};
+use rustc_lint::LateContext;
+
+use super::BORROW_AS_PTR;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    cast_expr: &'tcx Expr<'_>,
+    cast_to: &'tcx Ty<'_>,
+) {
+    if matches!(cast_to.kind, TyKind::Ptr(_))
+        && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind
+    {
+        let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
+        let macro_name = match mutability {
+            Mutability::Not => "addr_of",
+            Mutability::Mut => "addr_of_mut",
+        };
+        let mut app = Applicability::MachineApplicable;
+        let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0;
+
+        span_lint_and_sugg(
+            cx,
+            BORROW_AS_PTR,
+            expr.span,
+            "borrow as raw pointer",
+            "try",
+            format!("{}::ptr::{}!({})", core_or_std, macro_name, snip),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
new file mode 100644
index 00000000000..284ef165998
--- /dev/null
+++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
@@ -0,0 +1,63 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{match_def_path, meets_msrv, msrvs, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{def_id::DefId, Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+use rustc_semver::RustcVersion;
+
+use super::CAST_SLICE_FROM_RAW_PARTS;
+
+enum RawPartsKind {
+    Immutable,
+    Mutable,
+}
+
+fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option<RawPartsKind> {
+    if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS) {
+        Some(RawPartsKind::Immutable)
+    } else if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS_MUT) {
+        Some(RawPartsKind::Mutable)
+    } else {
+        None
+    }
+}
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    cast_expr: &Expr<'_>,
+    cast_to: Ty<'_>,
+    msrv: Option<RustcVersion>,
+) {
+    if_chain! {
+        if meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS);
+        if let ty::RawPtr(ptrty) = cast_to.kind();
+        if let ty::Slice(_) = ptrty.ty.kind();
+        if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind;
+        if let ExprKind::Path(ref qpath) = fun.kind;
+        if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
+        if let Some(rpk) = raw_parts_kind(cx, fun_def_id);
+        then {
+            let func = match rpk {
+                RawPartsKind::Immutable => "from_raw_parts",
+                RawPartsKind::Mutable => "from_raw_parts_mut"
+            };
+            let span = expr.span;
+            let mut applicability = Applicability::MachineApplicable;
+            let ptr = snippet_with_applicability(cx, ptr_arg.span, "ptr", &mut applicability);
+            let len = snippet_with_applicability(cx, len_arg.span, "len", &mut applicability);
+            span_lint_and_sugg(
+                cx,
+                CAST_SLICE_FROM_RAW_PARTS,
+                span,
+                &format!("casting the result of `{func}` to {cast_to}"),
+                "replace with",
+                format!("core::ptr::slice_{func}({ptr}, {len})"),
+                applicability
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index af3798a0cc8..cc5d346b954 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -1,3 +1,5 @@
+mod as_underscore;
+mod borrow_as_ptr;
 mod cast_abs_to_unsigned;
 mod cast_enum_constructor;
 mod cast_lossless;
@@ -8,6 +10,7 @@ mod cast_ptr_alignment;
 mod cast_ref_to_mut;
 mod cast_sign_loss;
 mod cast_slice_different_sizes;
+mod cast_slice_from_raw_parts;
 mod char_lit_as_u8;
 mod fn_to_numeric_cast;
 mod fn_to_numeric_cast_any;
@@ -16,7 +19,7 @@ mod ptr_as_ptr;
 mod unnecessary_cast;
 mod utils;
 
-use clippy_utils::is_hir_ty_cfg_dependant;
+use clippy_utils::{is_hir_ty_cfg_dependant, meets_msrv, msrvs};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -506,6 +509,93 @@ declare_clippy_lint! {
     "casting the result of `abs()` to an unsigned integer can panic"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Check for the usage of `as _` conversion using inferred type.
+    ///
+    /// ### Why is this bad?
+    /// The conversion might include lossy conversion and dangerous cast that might go
+    /// undetected due to the type being inferred.
+    ///
+    /// The lint is allowed by default as using `_` is less wordy than always specifying the type.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn foo(n: usize) {}
+    /// let n: u16 = 256;
+    /// foo(n as _);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn foo(n: usize) {}
+    /// let n: u16 = 256;
+    /// foo(n as usize);
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub AS_UNDERSCORE,
+    restriction,
+    "detects `as _` conversion"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for the usage of `&expr as *const T` or
+    /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or
+    /// `ptr::addr_of_mut` instead.
+    ///
+    /// ### Why is this bad?
+    /// This would improve readability and avoid creating a reference
+    /// that points to an uninitialized value or unaligned place.
+    /// Read the `ptr::addr_of` docs for more information.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let val = 1;
+    /// let p = &val as *const i32;
+    ///
+    /// let mut val_mut = 1;
+    /// let p_mut = &mut val_mut as *mut i32;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let val = 1;
+    /// let p = std::ptr::addr_of!(val);
+    ///
+    /// let mut val_mut = 1;
+    /// let p_mut = std::ptr::addr_of_mut!(val_mut);
+    /// ```
+    #[clippy::version = "1.60.0"]
+    pub BORROW_AS_PTR,
+    pedantic,
+    "borrowing just to cast to a raw pointer"
+}
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for a raw slice being cast to a slice pointer
+    ///
+    /// ### Why is this bad?
+    /// This can result in multiple `&mut` references to the same location when only a pointer is
+    /// required.
+    /// `ptr::slice_from_raw_parts` is a safe alternative that doesn't require
+    /// the same [safety requirements] to be upheld.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _;
+    /// let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _;
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len);
+    /// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
+    /// ```
+    /// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety
+    #[clippy::version = "1.64.0"]
+    pub CAST_SLICE_FROM_RAW_PARTS,
+    suspicious,
+    "casting a slice created from a pointer and length to a slice pointer"
+}
+
 pub struct Casts {
     msrv: Option<RustcVersion>,
 }
@@ -534,7 +624,10 @@ impl_lint_pass!(Casts => [
     PTR_AS_PTR,
     CAST_ENUM_TRUNCATION,
     CAST_ENUM_CONSTRUCTOR,
-    CAST_ABS_TO_UNSIGNED
+    CAST_ABS_TO_UNSIGNED,
+    AS_UNDERSCORE,
+    BORROW_AS_PTR,
+    CAST_SLICE_FROM_RAW_PARTS
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -547,8 +640,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             return;
         }
 
-        if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
-            if is_hir_ty_cfg_dependant(cx, cast_to) {
+        if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind {
+            if is_hir_ty_cfg_dependant(cx, cast_to_hir) {
                 return;
             }
             let (cast_from, cast_to) = (
@@ -559,7 +652,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
                 return;
             }
-
+            cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, self.msrv);
             fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
             fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
             fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
@@ -575,6 +668,12 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
                 cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
                 cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
             }
+
+            as_underscore::check(cx, expr, cast_to_hir);
+
+            if meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) {
+                borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
+            }
         }
 
         cast_ref_to_mut::check(cx, expr);
diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs
index fff7da8e33f..19d2e6e1d12 100644
--- a/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/clippy_lints/src/casts/unnecessary_cast.rs
@@ -90,13 +90,20 @@ pub(super) fn check<'tcx>(
 
 fn lint_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &str, cast_from: Ty<'_>, cast_to: Ty<'_>) {
     let literal_kind_name = if cast_from.is_integral() { "integer" } else { "float" };
+    let replaced_literal;
+    let matchless = if literal_str.contains(['(', ')']) {
+        replaced_literal = literal_str.replace(['(', ')'], "");
+        &replaced_literal
+    } else {
+        literal_str
+    };
     span_lint_and_sugg(
         cx,
         UNNECESSARY_CAST,
         expr.span,
         &format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to),
         "try",
-        format!("{}_{}", literal_str.trim_end_matches('.'), cast_to),
+        format!("{}_{}", matchless.trim_end_matches('.'), cast_to),
         Applicability::MachineApplicable,
     );
 }
diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index 59f10247a11..1506ea604f0 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -1,24 +1,34 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res};
-use clippy_utils::{get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage};
+use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res};
+use clippy_utils::{
+    fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, meets_msrv, msrvs, path_to_local,
+    walk_to_expr_usage,
+};
 use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{
-    self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId,
-    ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem,
-    TraitItemKind, TyKind, UnOp,
+    self as hir, def_id::DefId, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy,
+    GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind,
+    Path, QPath, TraitItem, TraitItemKind, TyKind, UnOp,
 };
+use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
-use rustc_middle::ty::{self, Binder, BoundVariableKind, List, Ty, TyCtxt, TypeVisitable, TypeckResults};
+use rustc_middle::ty::{
+    self, subst::Subst, Binder, BoundVariableKind, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind,
+    ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults,
+};
+use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
-use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
+use std::collections::VecDeque;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -151,6 +161,7 @@ pub struct Dereferencing {
     /// been finished. Note we can't lint at the end of every body as they can be nested within each
     /// other.
     current_body: Option<BodyId>,
+
     /// The list of locals currently being checked by the lint.
     /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
     /// This is needed for or patterns where one of the branches can be linted, but another can not
@@ -158,6 +169,19 @@ pub struct Dereferencing {
     ///
     /// e.g. `m!(x) | Foo::Bar(ref x)`
     ref_locals: FxIndexMap<HirId, Option<RefPat>>,
+
+    // `IntoIterator` for arrays requires Rust 1.53.
+    msrv: Option<RustcVersion>,
+}
+
+impl Dereferencing {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self {
+            msrv,
+            ..Dereferencing::default()
+        }
+    }
 }
 
 struct StateData {
@@ -170,6 +194,7 @@ struct StateData {
 struct DerefedBorrow {
     count: usize,
     msg: &'static str,
+    snip_expr: Option<HirId>,
 }
 
 enum State {
@@ -250,7 +275,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
         match (self.state.take(), kind) {
             (None, kind) => {
                 let expr_ty = typeck.expr_ty(expr);
-                let (position, adjustments) = walk_parents(cx, expr);
+                let (position, adjustments) = walk_parents(cx, expr, self.msrv);
 
                 match kind {
                     RefOp::Deref => {
@@ -331,20 +356,23 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
                         let deref_msg =
                             "this expression creates a reference which is immediately dereferenced by the compiler";
                         let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
+                        let impl_msg = "the borrowed expression implements the required traits";
 
-                        let (required_refs, msg) = if position.can_auto_borrow() {
-                            (1, if deref_count == 1 { borrow_msg } else { deref_msg })
+                        let (required_refs, msg, snip_expr) = if position.can_auto_borrow() {
+                            (1, if deref_count == 1 { borrow_msg } else { deref_msg }, None)
+                        } else if let Position::ImplArg(hir_id) = position {
+                            (0, impl_msg, Some(hir_id))
                         } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) =
                             next_adjust.map(|a| &a.kind)
                         {
                             if matches!(mutability, AutoBorrowMutability::Mut { .. }) && !position.is_reborrow_stable()
                             {
-                                (3, deref_msg)
+                                (3, deref_msg, None)
                             } else {
-                                (2, deref_msg)
+                                (2, deref_msg, None)
                             }
                         } else {
-                            (2, deref_msg)
+                            (2, deref_msg, None)
                         };
 
                         if deref_count >= required_refs {
@@ -354,6 +382,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
                                     // can't be removed without breaking the code. See earlier comment.
                                     count: deref_count - required_refs,
                                     msg,
+                                    snip_expr,
                                 }),
                                 StateData { span: expr.span, hir_id: expr.hir_id, position },
                             ));
@@ -510,7 +539,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
                             spans: vec![pat.span],
                             app,
                             replacements: vec![(pat.span, snip.into())],
-                            hir_id: pat.hir_id
+                            hir_id: pat.hir_id,
                         }),
                     );
                 }
@@ -542,6 +571,8 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
             self.current_body = None;
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 fn try_parse_ref_op<'tcx>(
@@ -594,6 +625,7 @@ enum Position {
     /// The method is defined on a reference type. e.g. `impl Foo for &T`
     MethodReceiverRefImpl,
     Callee,
+    ImplArg(HirId),
     FieldAccess(Symbol),
     Postfix,
     Deref,
@@ -630,7 +662,7 @@ impl Position {
             | Self::Callee
             | Self::FieldAccess(_)
             | Self::Postfix => PREC_POSTFIX,
-            Self::Deref => PREC_PREFIX,
+            Self::ImplArg(_) | Self::Deref => PREC_PREFIX,
             Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
         }
     }
@@ -639,8 +671,12 @@ impl Position {
 /// Walks up the parent expressions attempting to determine both how stable the auto-deref result
 /// is, and which adjustments will be applied to it. Note this will not consider auto-borrow
 /// locations as those follow different rules.
-#[allow(clippy::too_many_lines)]
-fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &'tcx [Adjustment<'tcx>]) {
+#[expect(clippy::too_many_lines)]
+fn walk_parents<'tcx>(
+    cx: &LateContext<'tcx>,
+    e: &'tcx Expr<'_>,
+    msrv: Option<RustcVersion>,
+) -> (Position, &'tcx [Adjustment<'tcx>]) {
     let mut adjustments = [].as_slice();
     let mut precedence = 0i8;
     let ctxt = e.span.ctxt();
@@ -745,13 +781,20 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                     .iter()
                     .position(|arg| arg.hir_id == child_id)
                     .zip(expr_sig(cx, func))
-                    .and_then(|(i, sig)| sig.input_with_hir(i))
-                    .map(|(hir_ty, ty)| match hir_ty {
-                        // Type inference for closures can depend on how they're called. Only go by the explicit
-                        // types here.
-                        Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()),
-                        None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
-                            .position_for_arg(),
+                    .and_then(|(i, sig)| {
+                        sig.input_with_hir(i).map(|(hir_ty, ty)| match hir_ty {
+                            // Type inference for closures can depend on how they're called. Only go by the explicit
+                            // types here.
+                            Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()),
+                            None => {
+                                if let ty::Param(param_ty) = ty.skip_binder().kind() {
+                                    needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv)
+                                } else {
+                                    ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
+                                        .position_for_arg()
+                                }
+                            },
+                        })
                     }),
                 ExprKind::MethodCall(_, args, _) => {
                     let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
@@ -773,7 +816,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                                     .and_then(|subs| subs.get(1..))
                                 {
                                     Some(subs) => cx.tcx.mk_substs(subs.iter().copied()),
-                                    None => cx.tcx.mk_substs([].iter()),
+                                    None => cx.tcx.mk_substs(std::iter::empty::<ty::subst::GenericArg<'_>>()),
                                 } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
                                     // Trait methods taking `&self`
                                     sub_ty
@@ -792,12 +835,17 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                                 Position::MethodReceiver
                             }
                         } else {
-                            ty_auto_deref_stability(
-                                cx,
-                                cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
-                                precedence,
-                            )
-                            .position_for_arg()
+                            let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
+                            if let ty::Param(param_ty) = ty.kind() {
+                                needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv)
+                            } else {
+                                ty_auto_deref_stability(
+                                    cx,
+                                    cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
+                                    precedence,
+                                )
+                                .position_for_arg()
+                            }
                         }
                     })
                 },
@@ -948,6 +996,205 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
     v.0
 }
 
+// Checks whether:
+// * child is an expression of the form `&e` in an argument position requiring an `impl Trait`
+// * `e`'s type implements `Trait` and is copyable
+// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`.
+//   The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to
+// be moved, but it cannot be.
+fn needless_borrow_impl_arg_position<'tcx>(
+    cx: &LateContext<'tcx>,
+    parent: &Expr<'tcx>,
+    arg_index: usize,
+    param_ty: ParamTy,
+    mut expr: &Expr<'tcx>,
+    precedence: i8,
+    msrv: Option<RustcVersion>,
+) -> Position {
+    let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
+    let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
+
+    let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) };
+    let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+    let substs_with_expr_ty = cx
+        .typeck_results()
+        .node_substs(if let ExprKind::Call(callee, _) = parent.kind {
+            callee.hir_id
+        } else {
+            parent.hir_id
+        });
+
+    let predicates = cx.tcx.param_env(callee_def_id).caller_bounds();
+    let projection_predicates = predicates
+        .iter()
+        .filter_map(|predicate| {
+            if let PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
+                Some(projection_predicate)
+            } else {
+                None
+            }
+        })
+        .collect::<Vec<_>>();
+
+    let mut trait_with_ref_mut_self_method = false;
+
+    // If no traits were found, or only the `Destruct`, `Sized`, or `Any` traits were found, return.
+    if predicates
+        .iter()
+        .filter_map(|predicate| {
+            if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder()
+                && trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx)
+            {
+                Some(trait_predicate.trait_ref.def_id)
+            } else {
+                None
+            }
+        })
+        .inspect(|trait_def_id| {
+            trait_with_ref_mut_self_method |= has_ref_mut_self_method(cx, *trait_def_id);
+        })
+        .all(|trait_def_id| {
+            Some(trait_def_id) == destruct_trait_def_id
+                || Some(trait_def_id) == sized_trait_def_id
+                || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id)
+        })
+    {
+        return Position::Other(precedence);
+    }
+
+    // `substs_with_referent_ty` can be constructed outside of `check_referent` because the same
+    // elements are modified each time `check_referent` is called.
+    let mut substs_with_referent_ty = substs_with_expr_ty.to_vec();
+
+    let mut check_referent = |referent| {
+        let referent_ty = cx.typeck_results().expr_ty(referent);
+
+        if !is_copy(cx, referent_ty) {
+            return false;
+        }
+
+        // https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
+        if trait_with_ref_mut_self_method && !matches!(referent_ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
+            return false;
+        }
+
+        if !replace_types(
+            cx,
+            param_ty,
+            referent_ty,
+            fn_sig,
+            arg_index,
+            &projection_predicates,
+            &mut substs_with_referent_ty,
+        ) {
+            return false;
+        }
+
+        predicates.iter().all(|predicate| {
+            if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder()
+                && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id)
+                && let ty::Param(param_ty) = trait_predicate.self_ty().kind()
+                && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack()
+                && ty.is_array()
+                && !meets_msrv(msrv, msrvs::ARRAY_INTO_ITERATOR)
+            {
+                return false;
+            }
+
+            let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty);
+            let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
+            cx.tcx
+                .infer_ctxt()
+                .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
+        })
+    };
+
+    let mut needless_borrow = false;
+    while let ExprKind::AddrOf(_, _, referent) = expr.kind {
+        if !check_referent(referent) {
+            break;
+        }
+        expr = referent;
+        needless_borrow = true;
+    }
+
+    if needless_borrow {
+        Position::ImplArg(expr.hir_id)
+    } else {
+        Position::Other(precedence)
+    }
+}
+
+fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
+    cx.tcx
+        .associated_items(trait_def_id)
+        .in_definition_order()
+        .any(|assoc_item| {
+            if assoc_item.fn_has_self_parameter {
+                let self_ty = cx.tcx.fn_sig(assoc_item.def_id).skip_binder().inputs()[0];
+                matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut))
+            } else {
+                false
+            }
+        })
+}
+
+// Iteratively replaces `param_ty` with `new_ty` in `substs`, and similarly for each resulting
+// projected type that is a type parameter. Returns `false` if replacing the types would have an
+// effect on the function signature beyond substituting `new_ty` for `param_ty`.
+// See: https://github.com/rust-lang/rust-clippy/pull/9136#discussion_r927212757
+fn replace_types<'tcx>(
+    cx: &LateContext<'tcx>,
+    param_ty: ParamTy,
+    new_ty: Ty<'tcx>,
+    fn_sig: FnSig<'tcx>,
+    arg_index: usize,
+    projection_predicates: &[ProjectionPredicate<'tcx>],
+    substs: &mut [ty::GenericArg<'tcx>],
+) -> bool {
+    let mut replaced = BitSet::new_empty(substs.len());
+
+    let mut deque = VecDeque::with_capacity(substs.len());
+    deque.push_back((param_ty, new_ty));
+
+    while let Some((param_ty, new_ty)) = deque.pop_front() {
+        // If `replaced.is_empty()`, then `param_ty` and `new_ty` are those initially passed in.
+        if !fn_sig
+            .inputs_and_output
+            .iter()
+            .enumerate()
+            .all(|(i, ty)| (replaced.is_empty() && i == arg_index) || !ty.contains(param_ty.to_ty(cx.tcx)))
+        {
+            return false;
+        }
+
+        substs[param_ty.index as usize] = ty::GenericArg::from(new_ty);
+
+        // The `replaced.insert(...)` check provides some protection against infinite loops.
+        if replaced.insert(param_ty.index) {
+            for projection_predicate in projection_predicates {
+                if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx)
+                    && let ty::Term::Ty(term_ty) = projection_predicate.term
+                    && let ty::Param(term_param_ty) = term_ty.kind()
+                {
+                    let item_def_id = projection_predicate.projection_ty.item_def_id;
+                    let assoc_item = cx.tcx.associated_item(item_def_id);
+                    let projection = cx.tcx
+                        .mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, &[]));
+
+                    if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
+                        && substs[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty)
+                    {
+                        deque.push_back((*term_param_ty, projected_ty));
+                    }
+                }
+            }
+        }
+    }
+
+    true
+}
+
 struct TyPosition<'tcx> {
     position: Position,
     ty: Option<Ty<'tcx>>,
@@ -1086,7 +1333,8 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
         },
         State::DerefedBorrow(state) => {
             let mut app = Applicability::MachineApplicable;
-            let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
+            let snip_expr = state.snip_expr.map_or(expr, |hir_id| cx.tcx.hir().expect_expr(hir_id));
+            let (snip, snip_is_macro) = snippet_with_context(cx, snip_expr.span, data.span.ctxt(), "..", &mut app);
             span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| {
                 let calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee);
                 let sugg = if !snip_is_macro
diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs
index a982990e418..9ca443b7dff 100644
--- a/clippy_lints/src/derive.rs
+++ b/clippy_lints/src/derive.rs
@@ -516,7 +516,10 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
         tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain(
             params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
                 tcx.mk_predicate(Binder::dummy(PredicateKind::Trait(TraitPredicate {
-                    trait_ref: TraitRef::new(eq_trait_id, tcx.mk_substs([tcx.mk_param_from_def(param)].into_iter())),
+                    trait_ref: TraitRef::new(
+                        eq_trait_id,
+                        tcx.mk_substs(std::iter::once(tcx.mk_param_from_def(param))),
+                    ),
                     constness: BoundConstness::NotConst,
                     polarity: ImplPolarity::Positive,
                 })))
diff --git a/clippy_lints/src/doc_link_with_quotes.rs b/clippy_lints/src/doc_link_with_quotes.rs
index cb07f57e870..0ff1d2755da 100644
--- a/clippy_lints/src/doc_link_with_quotes.rs
+++ b/clippy_lints/src/doc_link_with_quotes.rs
@@ -21,7 +21,7 @@ declare_clippy_lint! {
     /// /// See also: [`foo`]
     /// fn bar() {}
     /// ```
-    #[clippy::version = "1.60.0"]
+    #[clippy::version = "1.63.0"]
     pub DOC_LINK_WITH_QUOTES,
     pedantic,
     "possible typo for an intra-doc link"
diff --git a/clippy_lints/src/duplicate_mod.rs b/clippy_lints/src/duplicate_mod.rs
index e1eb3b6324c..7ff7068f0b0 100644
--- a/clippy_lints/src/duplicate_mod.rs
+++ b/clippy_lints/src/duplicate_mod.rs
@@ -39,7 +39,7 @@ declare_clippy_lint! {
     /// // a.rs
     /// use crate::b;
     /// ```
-    #[clippy::version = "1.62.0"]
+    #[clippy::version = "1.63.0"]
     pub DUPLICATE_MOD,
     suspicious,
     "file loaded as module multiple times"
diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs
index 1ac7bfba06b..327865e4c85 100644
--- a/clippy_lints/src/escape.rs
+++ b/clippy_lints/src/escape.rs
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_hir;
-use clippy_utils::ty::contains_ty;
 use rustc_hir::intravisit;
 use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
 use rustc_infer::infer::TyCtxtInferExt;
@@ -30,18 +29,12 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```rust
-    /// # fn foo(bar: usize) {}
-    /// let x = Box::new(1);
-    /// foo(*x);
-    /// println!("{}", *x);
+    /// fn foo(x: Box<u32>) {}
     /// ```
     ///
     /// Use instead:
     /// ```rust
-    /// # fn foo(bar: usize) {}
-    /// let x = 1;
-    /// foo(x);
-    /// println!("{}", x);
+    /// fn foo(x: u32) {}
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub BOXED_LOCAL,
@@ -172,7 +165,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
                 // skip if there is a `self` parameter binding to a type
                 // that contains `Self` (i.e.: `self: Box<Self>`), see #4804
                 if let Some(trait_self_ty) = self.trait_self_ty {
-                    if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(cmt.place.ty(), trait_self_ty) {
+                    if map.name(cmt.hir_id) == kw::SelfLower && cmt.place.ty().contains(trait_self_ty) {
                         return;
                     }
                 }
diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs
index df9b41d2c98..bb50e8fcabb 100644
--- a/clippy_lints/src/floating_point_arithmetic.rs
+++ b/clippy_lints/src/floating_point_arithmetic.rs
@@ -172,7 +172,7 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
             expr.span,
             "logarithm for bases 2, 10 and e can be computed more accurately",
             "consider using",
-            format!("{}.{}()", Sugg::hir(cx, &args[0], ".."), method),
+            format!("{}.{}()", Sugg::hir(cx, &args[0], "..").maybe_par(), method),
             Applicability::MachineApplicable,
         );
     }
@@ -263,13 +263,13 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
             (
                 SUBOPTIMAL_FLOPS,
                 "square-root of a number can be computed more efficiently and accurately",
-                format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")),
+                format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
             )
         } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
             (
                 IMPRECISE_FLOPS,
                 "cube-root of a number can be computed more accurately",
-                format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")),
+                format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
             )
         } else if let Some(exponent) = get_integer_from_float_constant(&value) {
             (
@@ -277,7 +277,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                 "exponentiation with integer powers can be computed more efficiently",
                 format!(
                     "{}.powi({})",
-                    Sugg::hir(cx, &args[0], ".."),
+                    Sugg::hir(cx, &args[0], "..").maybe_par(),
                     numeric_literal::format(&exponent.to_string(), None, false)
                 ),
             )
@@ -327,7 +327,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                         "consider using",
                         format!(
                             "{}.mul_add({}, {})",
-                            Sugg::hir(cx, &args[0], ".."),
+                            Sugg::hir(cx, &args[0], "..").maybe_par(),
                             Sugg::hir(cx, &args[0], ".."),
                             Sugg::hir(cx, other_addend, ".."),
                         ),
@@ -418,7 +418,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
                 "consider using",
                 format!(
                     "{}.exp_m1()",
-                    Sugg::hir(cx, self_arg, "..")
+                    Sugg::hir(cx, self_arg, "..").maybe_par()
                 ),
                 Applicability::MachineApplicable,
             );
@@ -550,11 +550,11 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
         then {
             let positive_abs_sugg = (
                 "manual implementation of `abs` method",
-                format!("{}.abs()", Sugg::hir(cx, body, "..")),
+                format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_par()),
             );
             let negative_abs_sugg = (
                 "manual implementation of negation of `abs` method",
-                format!("-{}.abs()", Sugg::hir(cx, body, "..")),
+                format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_par()),
             );
             let sugg = if is_testing_positive(cx, cond, body) {
                 if if_expr_positive {
@@ -621,7 +621,7 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
                 expr.span,
                 "log base can be expressed more clearly",
                 "consider using",
-                format!("{}.log({})", Sugg::hir(cx, largs_self, ".."), Sugg::hir(cx, rargs_self, ".."),),
+                format!("{}.log({})", Sugg::hir(cx, largs_self, "..").maybe_par(), Sugg::hir(cx, rargs_self, ".."),),
                 Applicability::MachineApplicable,
             );
         }
@@ -651,7 +651,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
             if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) &&
                (F32(180_f32) == lvalue || F64(180_f64) == lvalue)
             {
-                let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, ".."));
+                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 ast::LitKind::Float(ref value, float_type) = literal.node;
@@ -677,7 +677,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
                 (F32(180_f32) == rvalue || F64(180_f64) == rvalue) &&
                 (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
             {
-                let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, ".."));
+                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 ast::LitKind::Float(ref value, float_type) = literal.node;
diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs
index 925a8cb8dee..0c5851cdbed 100644
--- a/clippy_lints/src/format.rs
+++ b/clippy_lints/src/format.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
-use clippy_utils::source::{snippet_opt, snippet_with_applicability};
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -56,29 +56,27 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
         };
 
         let mut applicability = Applicability::MachineApplicable;
-        if format_args.value_args.is_empty() {
-            match *format_args.format_string_parts {
+        if format_args.args.is_empty() {
+            match *format_args.format_string.parts {
                 [] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
                 [_] => {
-                    if let Some(s_src) = snippet_opt(cx, format_args.format_string_span) {
-                        // Simulate macro expansion, converting {{ and }} to { and }.
-                        let s_expand = s_src.replace("{{", "{").replace("}}", "}");
-                        let sugg = format!("{}.to_string()", s_expand);
-                        span_useless_format(cx, call_site, sugg, applicability);
-                    }
+                    // Simulate macro expansion, converting {{ and }} to { and }.
+                    let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}");
+                    let sugg = format!("{}.to_string()", s_expand);
+                    span_useless_format(cx, call_site, sugg, applicability);
                 },
                 [..] => {},
             }
-        } else if let [value] = *format_args.value_args {
+        } else if let [arg] = &*format_args.args {
+            let value = arg.param.value;
             if_chain! {
-                if format_args.format_string_parts == [kw::Empty];
+                if format_args.format_string.parts == [kw::Empty];
                 if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
                     ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()),
                     ty::Str => true,
                     _ => false,
                 };
-                if let Some(args) = format_args.args();
-                if args.iter().all(|arg| arg.format_trait == sym::Display && !arg.has_string_formatting());
+                if !arg.format.has_string_formatting();
                 then {
                     let is_new_string = match value.kind {
                         ExprKind::Binary(..) => true,
diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs
index 1e6feaac26c..9fb9fd99748 100644
--- a/clippy_lints/src/format_args.rs
+++ b/clippy_lints/src/format_args.rs
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::is_diag_trait_item;
-use clippy_utils::macros::{is_format_macro, FormatArgsArg, FormatArgsExpn};
+use clippy_utils::macros::{is_format_macro, FormatArgsExpn};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::implements_trait;
 use if_chain::if_chain;
+use itertools::Itertools;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_middle::ty::Ty;
@@ -74,20 +75,16 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
             if let Some(macro_def_id) = outermost_expn_data.macro_def_id;
             if is_format_macro(cx, macro_def_id);
             if let ExpnKind::Macro(_, name) = outermost_expn_data.kind;
-            if let Some(args) = format_args.args();
             then {
-                for (i, arg) in args.iter().enumerate() {
-                    if arg.format_trait != sym::Display {
+                for arg in &format_args.args {
+                    if arg.format.has_string_formatting() {
                         continue;
                     }
-                    if arg.has_string_formatting() {
+                    if is_aliased(&format_args, arg.param.value.hir_id) {
                         continue;
                     }
-                    if is_aliased(&args, i) {
-                        continue;
-                    }
-                    check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.value);
-                    check_to_string_in_format_args(cx, name, arg.value);
+                    check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value);
+                    check_to_string_in_format_args(cx, name, arg.param.value);
                 }
             }
         }
@@ -134,45 +131,56 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex
         if is_diag_trait_item(cx, method_def_id, sym::ToString);
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
         if let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display);
+        let (n_needed_derefs, target) =
+            count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter());
+        if implements_trait(cx, target, display_trait_id, &[]);
+        if let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait();
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
-            let (n_needed_derefs, target) = count_needed_derefs(
-                receiver_ty,
-                cx.typeck_results().expr_adjustments(receiver).iter(),
-            );
-            if implements_trait(cx, target, display_trait_id, &[]) {
-                if n_needed_derefs == 0 {
-                    span_lint_and_sugg(
-                        cx,
-                        TO_STRING_IN_FORMAT_ARGS,
-                        value.span.with_lo(receiver.span.hi()),
-                        &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
-                        "remove this",
-                        String::new(),
-                        Applicability::MachineApplicable,
-                    );
-                } else {
-                    span_lint_and_sugg(
-                        cx,
-                        TO_STRING_IN_FORMAT_ARGS,
-                        value.span,
-                        &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
-                        "use this",
-                        format!("{:*>width$}{}", "", receiver_snippet, width = n_needed_derefs),
-                        Applicability::MachineApplicable,
-                    );
-                }
+            let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]);
+            if n_needed_derefs == 0 && !needs_ref {
+                span_lint_and_sugg(
+                    cx,
+                    TO_STRING_IN_FORMAT_ARGS,
+                    value.span.with_lo(receiver.span.hi()),
+                    &format!(
+                        "`to_string` applied to a type that implements `Display` in `{}!` args",
+                        name
+                    ),
+                    "remove this",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                span_lint_and_sugg(
+                    cx,
+                    TO_STRING_IN_FORMAT_ARGS,
+                    value.span,
+                    &format!(
+                        "`to_string` applied to a type that implements `Display` in `{}!` args",
+                        name
+                    ),
+                    "use this",
+                    format!(
+                        "{}{:*>width$}{}",
+                        if needs_ref { "&" } else { "" },
+                        "",
+                        receiver_snippet,
+                        width = n_needed_derefs
+                    ),
+                    Applicability::MachineApplicable,
+                );
             }
         }
     }
 }
 
-// Returns true if `args[i]` "refers to" or "is referred to by" another argument.
-fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool {
-    let value = args[i].value;
-    args.iter()
-        .enumerate()
-        .any(|(j, arg)| i != j && std::ptr::eq(value, arg.value))
+// Returns true if `hir_id` is referred to by multiple format params
+fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool {
+    args.params()
+        .filter(|param| param.value.hir_id == hir_id)
+        .at_most_one()
+        .is_err()
 }
 
 fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs
index 04b5be6c80e..d8bc0bf08f2 100644
--- a/clippy_lints/src/format_impl.rs
+++ b/clippy_lints/src/format_impl.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArgsArg, FormatArgsExpn};
+use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArg, FormatArgsExpn};
 use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -168,10 +168,9 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>,
         if let macro_def_id = outer_macro.def_id;
         if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, outer_macro.expn);
         if is_format_macro(cx, macro_def_id);
-        if let Some(args) = format_args.args();
         then {
-            for arg in args {
-                if arg.format_trait != impl_trait.name {
+            for arg in format_args.args {
+                if arg.format.r#trait != impl_trait.name {
                     continue;
                 }
                 check_format_arg_self(cx, expr, &arg, impl_trait);
@@ -180,11 +179,11 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>,
     }
 }
 
-fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArgsArg<'_>, impl_trait: FormatTrait) {
+fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArg<'_>, impl_trait: FormatTrait) {
     // Handle multiple dereferencing of references e.g. &&self
     // Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl)
     // Since the argument to fmt is itself a reference: &self
-    let reference = peel_ref_operators(cx, arg.value);
+    let reference = peel_ref_operators(cx, arg.param.value);
     let map = cx.tcx.hir();
     // Is the reference self?
     if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) {
diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs
index 73261fb8a44..90911e0bf25 100644
--- a/clippy_lints/src/functions/mod.rs
+++ b/clippy_lints/src/functions/mod.rs
@@ -1,6 +1,6 @@
 mod must_use;
 mod not_unsafe_ptr_arg_deref;
-mod result_unit_err;
+mod result;
 mod too_many_arguments;
 mod too_many_lines;
 
@@ -217,17 +217,62 @@ declare_clippy_lint! {
     "public function returning `Result` with an `Err` type of `()`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for functions that return `Result` with an unusually large
+    /// `Err`-variant.
+    ///
+    /// ### Why is this bad?
+    /// 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.
+    ///
+    /// ### Known problems
+    /// The size determined by Clippy is platform-dependent.
+    ///
+    /// ### Examples
+    /// ```rust
+    /// pub enum ParseError {
+    ///     UnparsedBytes([u8; 512]),
+    ///     UnexpectedEof,
+    /// }
+    ///
+    /// // The `Result` has at least 512 bytes, even in the `Ok`-case
+    /// pub fn parse() -> Result<(), ParseError> {
+    ///     Ok(())
+    /// }
+    /// ```
+    /// should be
+    /// ```
+    /// pub enum ParseError {
+    ///     UnparsedBytes(Box<[u8; 512]>),
+    ///     UnexpectedEof,
+    /// }
+    ///
+    /// // The `Result` is slightly larger than a pointer
+    /// pub fn parse() -> Result<(), ParseError> {
+    ///     Ok(())
+    /// }
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub RESULT_LARGE_ERR,
+    perf,
+    "function returning `Result` with large `Err` type"
+}
+
 #[derive(Copy, Clone)]
 pub struct Functions {
     too_many_arguments_threshold: u64,
     too_many_lines_threshold: u64,
+    large_error_threshold: u64,
 }
 
 impl Functions {
-    pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64) -> Self {
+    pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64) -> Self {
         Self {
             too_many_arguments_threshold,
             too_many_lines_threshold,
+            large_error_threshold,
         }
     }
 }
@@ -240,6 +285,7 @@ impl_lint_pass!(Functions => [
     DOUBLE_MUST_USE,
     MUST_USE_CANDIDATE,
     RESULT_UNIT_ERR,
+    RESULT_LARGE_ERR,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Functions {
@@ -259,18 +305,18 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
         must_use::check_item(cx, item);
-        result_unit_err::check_item(cx, item);
+        result::check_item(cx, item, self.large_error_threshold);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
         must_use::check_impl_item(cx, item);
-        result_unit_err::check_impl_item(cx, item);
+        result::check_impl_item(cx, item, self.large_error_threshold);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
         too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold);
         not_unsafe_ptr_arg_deref::check_trait_item(cx, item);
         must_use::check_trait_item(cx, item);
-        result_unit_err::check_trait_item(cx, item);
+        result::check_trait_item(cx, item, self.large_error_threshold);
     }
 }
diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs
new file mode 100644
index 00000000000..af520a493ed
--- /dev/null
+++ b/clippy_lints/src/functions/result.rs
@@ -0,0 +1,100 @@
+use rustc_errors::Diagnostic;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{sym, Span};
+use rustc_typeck::hir_ty_to_ty;
+
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
+use clippy_utils::trait_ref_of_method;
+use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item};
+
+use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR};
+
+/// The type of the `Err`-variant in a `std::result::Result` returned by the
+/// given `FnDecl`
+fn result_err_ty<'tcx>(
+    cx: &LateContext<'tcx>,
+    decl: &hir::FnDecl<'tcx>,
+    item_span: Span,
+) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
+    if !in_external_macro(cx.sess(), item_span)
+        && let hir::FnRetTy::Return(hir_ty) = decl.output
+        && let ty = hir_ty_to_ty(cx.tcx, hir_ty)
+        && is_type_diagnostic_item(cx, ty, sym::Result)
+        && let ty::Adt(_, substs) = ty.kind()
+    {
+        let err_ty = substs.type_at(1);
+        Some((hir_ty, err_ty))
+    } else {
+        None
+    }
+}
+
+pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) {
+    if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind
+        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span)
+    {
+        if cx.access_levels.is_exported(item.def_id) {
+            let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+            check_result_unit_err(cx, err_ty, fn_header_span);
+        }
+        check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold);
+    }
+}
+
+pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) {
+    // Don't lint if method is a trait's implementation, we can't do anything about those
+    if let hir::ImplItemKind::Fn(ref sig, _) = item.kind
+        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span)
+        && trait_ref_of_method(cx, item.def_id).is_none()
+    {
+        if cx.access_levels.is_exported(item.def_id) {
+            let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+            check_result_unit_err(cx, err_ty, fn_header_span);
+        }
+        check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold);
+    }
+}
+
+pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) {
+    if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
+        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
+        if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) {
+            if cx.access_levels.is_exported(item.def_id) {
+                check_result_unit_err(cx, err_ty, fn_header_span);
+            }
+            check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold);
+        }
+    }
+}
+
+fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: Span) {
+    if err_ty.is_unit() {
+        span_lint_and_help(
+            cx,
+            RESULT_UNIT_ERR,
+            fn_header_span,
+            "this returns a `Result<_, ()>`",
+            None,
+            "use a custom `Error` type instead",
+        );
+    }
+}
+
+fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) {
+    let ty_size = approx_ty_size(cx, err_ty);
+    if ty_size >= large_err_threshold {
+        span_lint_and_then(
+            cx,
+            RESULT_LARGE_ERR,
+            hir_ty_span,
+            "the `Err`-variant returned from this function is very large",
+            |diag: &mut Diagnostic| {
+                diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes"));
+                diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`"));
+            },
+        );
+    }
+}
diff --git a/clippy_lints/src/functions/result_unit_err.rs b/clippy_lints/src/functions/result_unit_err.rs
deleted file mode 100644
index 2e63a1f920d..00000000000
--- a/clippy_lints/src/functions/result_unit_err.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty;
-use rustc_span::{sym, Span};
-use rustc_typeck::hir_ty_to_ty;
-
-use if_chain::if_chain;
-
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::trait_ref_of_method;
-use clippy_utils::ty::is_type_diagnostic_item;
-
-use super::RESULT_UNIT_ERR;
-
-pub(super) fn check_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
-    if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.def_id);
-        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if is_public {
-            check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
-        }
-    }
-}
-
-pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &hir::ImplItem<'_>) {
-    if let hir::ImplItemKind::Fn(ref sig, _) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.def_id);
-        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if is_public && trait_ref_of_method(cx, item.def_id).is_none() {
-            check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
-        }
-    }
-}
-
-pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>) {
-    if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
-        let is_public = cx.access_levels.is_exported(item.def_id);
-        let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if is_public {
-            check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
-        }
-    }
-}
-
-fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span: Span, fn_header_span: Span) {
-    if_chain! {
-        if !in_external_macro(cx.sess(), item_span);
-        if let hir::FnRetTy::Return(ty) = decl.output;
-        let ty = hir_ty_to_ty(cx.tcx, ty);
-        if is_type_diagnostic_item(cx, ty, sym::Result);
-        if let ty::Adt(_, substs) = ty.kind();
-        let err_ty = substs.type_at(1);
-        if err_ty.is_unit();
-        then {
-            span_lint_and_help(
-                cx,
-                RESULT_UNIT_ERR,
-                fn_header_span,
-                "this returns a `Result<_, ()>`",
-                None,
-                "use a custom `Error` type instead",
-            );
-        }
-    }
-}
diff --git a/clippy_lints/src/get_first.rs b/clippy_lints/src/get_first.rs
deleted file mode 100644
index 529f7babaa5..00000000000
--- a/clippy_lints/src/get_first.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_slice_of_primitives, match_def_path, paths};
-use if_chain::if_chain;
-use rustc_ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Spanned;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for using `x.get(0)` instead of
-    /// `x.first()`.
-    ///
-    /// ### Why is this bad?
-    /// Using `x.first()` is easier to read and has the same
-    /// result.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let x = vec![2, 3, 5];
-    /// let first_element = x.get(0);
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust
-    /// let x = vec![2, 3, 5];
-    /// let first_element = x.first();
-    /// ```
-    #[clippy::version = "1.63.0"]
-    pub GET_FIRST,
-    style,
-    "Using `x.get(0)` when `x.first()` is simpler"
-}
-declare_lint_pass!(GetFirst => [GET_FIRST]);
-
-impl<'tcx> LateLintPass<'tcx> for GetFirst {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if_chain! {
-            if let hir::ExprKind::MethodCall(_, [struct_calling_on, method_arg], _) = &expr.kind;
-            if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
-            if match_def_path(cx, expr_def_id, &paths::SLICE_GET);
-
-            if let Some(_) = is_slice_of_primitives(cx, struct_calling_on);
-            if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = method_arg.kind;
-
-            then {
-                let mut applicability = Applicability::MachineApplicable;
-                let slice_name = snippet_with_applicability(
-                    cx,
-                    struct_calling_on.span, "..",
-                    &mut applicability,
-                );
-                span_lint_and_sugg(
-                    cx,
-                    GET_FIRST,
-                    expr.span,
-                    &format!("accessing first element with `{0}.get(0)`", slice_name),
-                    "try",
-                    format!("{}.first()", slice_name),
-                    applicability,
-                );
-            }
-        }
-    }
-}
diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs
index e9501700784..4d703d691ac 100644
--- a/clippy_lints/src/if_let_mutex.rs
+++ b/clippy_lints/src/if_let_mutex.rs
@@ -1,8 +1,9 @@
-use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::SpanlessEq;
 use if_chain::if_chain;
+use rustc_errors::Diagnostic;
 use rustc_hir::intravisit::{self as visit, Visitor};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -45,16 +46,8 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]);
 
 impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        let mut arm_visit = ArmVisitor {
-            mutex_lock_called: false,
-            found_mutex: None,
-            cx,
-        };
-        let mut op_visit = OppVisitor {
-            mutex_lock_called: false,
-            found_mutex: None,
-            cx,
-        };
+        let mut arm_visit = ArmVisitor { found_mutex: None, cx };
+        let mut op_visit = OppVisitor { found_mutex: None, cx };
         if let Some(higher::IfLet {
             let_expr,
             if_then,
@@ -63,18 +56,28 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
         }) = higher::IfLet::hir(cx, expr)
         {
             op_visit.visit_expr(let_expr);
-            if op_visit.mutex_lock_called {
+            if let Some(op_mutex) = op_visit.found_mutex {
                 arm_visit.visit_expr(if_then);
                 arm_visit.visit_expr(if_else);
 
-                if arm_visit.mutex_lock_called && arm_visit.same_mutex(cx, op_visit.found_mutex.unwrap()) {
-                    span_lint_and_help(
+                if let Some(arm_mutex) = arm_visit.found_mutex_if_same_as(op_mutex) {
+                    let diag = |diag: &mut Diagnostic| {
+                        diag.span_label(
+                            op_mutex.span,
+                            "this Mutex will remain locked for the entire `if let`-block...",
+                        );
+                        diag.span_label(
+                            arm_mutex.span,
+                            "... and is tried to lock again here, which will always deadlock.",
+                        );
+                        diag.help("move the lock call outside of the `if let ...` expression");
+                    };
+                    span_lint_and_then(
                         cx,
                         IF_LET_MUTEX,
                         expr.span,
                         "calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock",
-                        None,
-                        "move the lock call outside of the `if let ...` expression",
+                        diag,
                     );
                 }
             }
@@ -84,7 +87,6 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex {
 
 /// Checks if `Mutex::lock` is called in the `if let` expr.
 pub struct OppVisitor<'a, 'tcx> {
-    mutex_lock_called: bool,
     found_mutex: Option<&'tcx Expr<'tcx>>,
     cx: &'a LateContext<'tcx>,
 }
@@ -93,7 +95,6 @@ impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
             self.found_mutex = Some(mutex);
-            self.mutex_lock_called = true;
             return;
         }
         visit::walk_expr(self, expr);
@@ -102,7 +103,6 @@ impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> {
 
 /// Checks if `Mutex::lock` is called in any of the branches.
 pub struct ArmVisitor<'a, 'tcx> {
-    mutex_lock_called: bool,
     found_mutex: Option<&'tcx Expr<'tcx>>,
     cx: &'a LateContext<'tcx>,
 }
@@ -111,7 +111,6 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
             self.found_mutex = Some(mutex);
-            self.mutex_lock_called = true;
             return;
         }
         visit::walk_expr(self, expr);
@@ -119,9 +118,12 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> {
 }
 
 impl<'tcx, 'l> ArmVisitor<'tcx, 'l> {
-    fn same_mutex(&self, cx: &LateContext<'_>, op_mutex: &Expr<'_>) -> bool {
-        self.found_mutex
-            .map_or(false, |arm_mutex| SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex))
+    fn found_mutex_if_same_as(&self, op_mutex: &Expr<'_>) -> Option<&Expr<'_>> {
+        self.found_mutex.and_then(|arm_mutex| {
+            SpanlessEq::new(self.cx)
+                .eq_expr(op_mutex, arm_mutex)
+                .then_some(arm_mutex)
+        })
     }
 }
 
@@ -129,7 +131,7 @@ fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Opt
     if_chain! {
         if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
         if path.ident.as_str() == "lock";
-        let ty = cx.typeck_results().expr_ty(self_arg);
+        let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
         if is_type_diagnostic_item(cx, ty, sym::Mutex);
         then {
             Some(self_arg)
diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs
index b8d227855d9..11c43247868 100644
--- a/clippy_lints/src/if_then_some_else_none.rs
+++ b/clippy_lints/src/if_then_some_else_none.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::source::snippet_with_macro_callsite;
 use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs, peel_blocks};
-use if_chain::if_chain;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -11,10 +11,12 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for if-else that could be written to `bool::then`.
+    /// Checks for if-else that could be written using either `bool::then` or `bool::then_some`.
     ///
     /// ### Why is this bad?
-    /// Looks a little redundant. Using `bool::then` helps it have less lines of code.
+    /// Looks a little redundant. Using `bool::then` is more concise and incurs no loss of clarity.
+    /// For simple calculations and known values, use `bool::then_some`, which is eagerly evaluated
+    /// in comparison to `bool::then`.
     ///
     /// ### Example
     /// ```rust
@@ -39,7 +41,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.53.0"]
     pub IF_THEN_SOME_ELSE_NONE,
     restriction,
-    "Finds if-else that could be written using `bool::then`"
+    "Finds if-else that could be written using either `bool::then` or `bool::then_some`"
 }
 
 pub struct IfThenSomeElseNone {
@@ -56,7 +58,7 @@ impl IfThenSomeElseNone {
 impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
 
 impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if !meets_msrv(self.msrv, msrvs::BOOL_THEN) {
             return;
         }
@@ -70,43 +72,47 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
             return;
         }
 
-        if_chain! {
-            if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr);
-            if let ExprKind::Block(then_block, _) = then.kind;
-            if let Some(then_expr) = then_block.expr;
-            if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind;
-            if let ExprKind::Path(ref then_call_qpath) = then_call.kind;
-            if is_lang_ctor(cx, then_call_qpath, OptionSome);
-            if let ExprKind::Path(ref qpath) = peel_blocks(els).kind;
-            if is_lang_ctor(cx, qpath, OptionNone);
-            if !stmts_contains_early_return(then_block.stmts);
-            then {
-                let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]");
-                let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) {
-                    format!("({})", cond_snip)
-                } else {
-                    cond_snip.into_owned()
-                };
-                let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, "");
-                let closure_body = if then_block.stmts.is_empty() {
-                    arg_snip.into_owned()
-                } else {
-                    format!("{{ /* snippet */ {} }}", arg_snip)
-                };
-                let help = format!(
-                    "consider using `bool::then` like: `{}.then(|| {})`",
-                    cond_snip,
-                    closure_body,
-                );
-                span_lint_and_help(
-                    cx,
-                    IF_THEN_SOME_ELSE_NONE,
-                    expr.span,
-                    "this could be simplified with `bool::then`",
-                    None,
-                    &help,
-                );
-            }
+        if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr)
+            && let ExprKind::Block(then_block, _) = then.kind
+            && let Some(then_expr) = then_block.expr
+            && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
+            && let ExprKind::Path(ref then_call_qpath) = then_call.kind
+            && is_lang_ctor(cx, then_call_qpath, OptionSome)
+            && let ExprKind::Path(ref qpath) = peel_blocks(els).kind
+            && is_lang_ctor(cx, qpath, OptionNone)
+            && !stmts_contains_early_return(then_block.stmts)
+        {
+            let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]");
+            let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) {
+                format!("({})", cond_snip)
+            } else {
+                cond_snip.into_owned()
+            };
+            let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, "");
+            let mut method_body = if then_block.stmts.is_empty() {
+                arg_snip.into_owned()
+            } else {
+                format!("{{ /* snippet */ {} }}", arg_snip)
+            };
+            let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) {
+                "then_some"
+            } else {
+                method_body.insert_str(0, "|| ");
+                "then"
+            };
+
+            let help = format!(
+                "consider using `bool::{}` like: `{}.{}({})`",
+                method_name, cond_snip, method_name, method_body,
+            );
+            span_lint_and_help(
+                cx,
+                IF_THEN_SOME_ELSE_NONE,
+                expr.span,
+                &format!("this could be simplified with `bool::{}`", method_name),
+                None,
+                &help,
+            );
         }
     }
 
diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs
index 01082cc8eeb..134cbbf7b5c 100644
--- a/clippy_lints/src/lib.register_all.rs
+++ b/clippy_lints/src/lib.register_all.rs
@@ -20,12 +20,12 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(booleans::NONMINIMAL_BOOL),
     LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
     LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
-    LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
     LintId::of(casts::CAST_ABS_TO_UNSIGNED),
     LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
     LintId::of(casts::CAST_ENUM_TRUNCATION),
     LintId::of(casts::CAST_REF_TO_MUT),
     LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
+    LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
     LintId::of(casts::CHAR_LIT_AS_U8),
     LintId::of(casts::FN_TO_NUMERIC_CAST),
     LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
@@ -80,9 +80,9 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(functions::DOUBLE_MUST_USE),
     LintId::of(functions::MUST_USE_UNIT),
     LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
+    LintId::of(functions::RESULT_LARGE_ERR),
     LintId::of(functions::RESULT_UNIT_ERR),
     LintId::of(functions::TOO_MANY_ARGUMENTS),
-    LintId::of(get_first::GET_FIRST),
     LintId::of(if_let_mutex::IF_LET_MUTEX),
     LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
     LintId::of(infinite_iter::INFINITE_ITER),
@@ -128,7 +128,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID),
     LintId::of(manual_retain::MANUAL_RETAIN),
     LintId::of(manual_strip::MANUAL_STRIP),
-    LintId::of(map_clone::MAP_CLONE),
     LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
     LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
     LintId::of(match_result_ok::MATCH_RESULT_OK),
@@ -150,17 +149,20 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
     LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
     LintId::of(methods::BIND_INSTEAD_OF_MAP),
+    LintId::of(methods::BYTES_COUNT_TO_LEN),
     LintId::of(methods::BYTES_NTH),
     LintId::of(methods::CHARS_LAST_CMP),
     LintId::of(methods::CHARS_NEXT_CMP),
     LintId::of(methods::CLONE_DOUBLE_REF),
     LintId::of(methods::CLONE_ON_COPY),
+    LintId::of(methods::COLLAPSIBLE_STR_REPLACE),
     LintId::of(methods::ERR_EXPECT),
     LintId::of(methods::EXPECT_FUN_CALL),
     LintId::of(methods::EXTEND_WITH_DRAIN),
     LintId::of(methods::FILTER_MAP_IDENTITY),
     LintId::of(methods::FILTER_NEXT),
     LintId::of(methods::FLAT_MAP_IDENTITY),
+    LintId::of(methods::GET_FIRST),
     LintId::of(methods::GET_LAST_WITH_LEN),
     LintId::of(methods::INSPECT_FOR_EACH),
     LintId::of(methods::INTO_ITER_ON_REF),
@@ -178,13 +180,16 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
     LintId::of(methods::MANUAL_SPLIT_ONCE),
     LintId::of(methods::MANUAL_STR_REPEAT),
+    LintId::of(methods::MAP_CLONE),
     LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
     LintId::of(methods::MAP_FLATTEN),
     LintId::of(methods::MAP_IDENTITY),
+    LintId::of(methods::MUT_MUTEX_LOCK),
     LintId::of(methods::NEEDLESS_OPTION_AS_DEREF),
     LintId::of(methods::NEEDLESS_OPTION_TAKE),
     LintId::of(methods::NEEDLESS_SPLITN),
     LintId::of(methods::NEW_RET_NO_SELF),
+    LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
     LintId::of(methods::NO_EFFECT_REPLACE),
     LintId::of(methods::OBFUSCATED_IF_ELSE),
     LintId::of(methods::OK_EXPECT),
@@ -193,6 +198,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(methods::OPTION_MAP_OR_NONE),
     LintId::of(methods::OR_FUN_CALL),
     LintId::of(methods::OR_THEN_UNWRAP),
+    LintId::of(methods::RANGE_ZIP_WITH_LEN),
+    LintId::of(methods::REPEAT_ONCE),
     LintId::of(methods::RESULT_MAP_OR_INTO_OPTION),
     LintId::of(methods::SEARCH_IS_SOME),
     LintId::of(methods::SHOULD_IMPLEMENT_TRAIT),
@@ -202,14 +209,18 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(methods::STRING_EXTEND_CHARS),
     LintId::of(methods::SUSPICIOUS_MAP),
     LintId::of(methods::SUSPICIOUS_SPLITN),
+    LintId::of(methods::SUSPICIOUS_TO_OWNED),
     LintId::of(methods::UNINIT_ASSUMED_INIT),
+    LintId::of(methods::UNIT_HASH),
     LintId::of(methods::UNNECESSARY_FILTER_MAP),
     LintId::of(methods::UNNECESSARY_FIND_MAP),
     LintId::of(methods::UNNECESSARY_FOLD),
     LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS),
+    LintId::of(methods::UNNECESSARY_SORT_BY),
     LintId::of(methods::UNNECESSARY_TO_OWNED),
     LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT),
     LintId::of(methods::USELESS_ASREF),
+    LintId::of(methods::VEC_RESIZE_TO_ZERO),
     LintId::of(methods::WRONG_SELF_CONVENTION),
     LintId::of(methods::ZST_OFFSET),
     LintId::of(minmax::MIN_MAX),
@@ -224,8 +235,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
     LintId::of(misc_early::ZERO_PREFIXED_LITERAL),
     LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION),
+    LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
-    LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
     LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
     LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
     LintId::of(needless_bool::BOOL_COMPARISON),
@@ -245,7 +256,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
     LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
     LintId::of(octal_escapes::OCTAL_ESCAPES),
-    LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
+    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
     LintId::of(operators::ABSURD_EXTREME_COMPARISONS),
     LintId::of(operators::ASSIGN_OP_PATTERN),
     LintId::of(operators::BAD_BIT_MASK),
@@ -275,7 +286,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
     LintId::of(question_mark::QUESTION_MARK),
     LintId::of(ranges::MANUAL_RANGE_CONTAINS),
-    LintId::of(ranges::RANGE_ZIP_WITH_LEN),
     LintId::of(ranges::REVERSED_EMPTY_RANGES),
     LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
     LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC),
@@ -286,7 +296,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
     LintId::of(reference::DEREF_ADDROF),
     LintId::of(regex::INVALID_REGEX),
-    LintId::of(repeat_once::REPEAT_ONCE),
     LintId::of(returns::LET_AND_RETURN),
     LintId::of(returns::NEEDLESS_RETURN),
     LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
@@ -314,10 +323,10 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
     LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
     LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
+    LintId::of(transmute::TRANSMUTING_NULL),
     LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
     LintId::of(transmute::USELESS_TRANSMUTE),
     LintId::of(transmute::WRONG_TRANSMUTE),
-    LintId::of(transmuting_null::TRANSMUTING_NULL),
     LintId::of(types::BORROWED_BOX),
     LintId::of(types::BOX_COLLECTION),
     LintId::of(types::REDUNDANT_ALLOCATION),
@@ -325,7 +334,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(types::VEC_BOX),
     LintId::of(unicode::INVISIBLE_CHARACTERS),
     LintId::of(uninit_vec::UNINIT_VEC),
-    LintId::of(unit_hash::UNIT_HASH),
     LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
     LintId::of(unit_types::LET_UNIT_VALUE),
     LintId::of(unit_types::UNIT_ARG),
@@ -333,9 +341,9 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
     LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
     LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS),
-    LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
     LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
     LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
+    LintId::of(unused_peekable::UNUSED_PEEKABLE),
     LintId::of(unused_unit::UNUSED_UNIT),
     LintId::of(unwrap::PANICKING_UNWRAP),
     LintId::of(unwrap::UNNECESSARY_UNWRAP),
@@ -343,7 +351,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(useless_conversion::USELESS_CONVERSION),
     LintId::of(vec::USELESS_VEC),
     LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
-    LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
+    LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS),
     LintId::of(write::PRINTLN_EMPTY_STRING),
     LintId::of(write::PRINT_LITERAL),
     LintId::of(write::PRINT_WITH_NEWLINE),
diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs
index 3784d3c68dc..aa247352f88 100644
--- a/clippy_lints/src/lib.register_complexity.rs
+++ b/clippy_lints/src/lib.register_complexity.rs
@@ -6,7 +6,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(attrs::DEPRECATED_CFG_ATTR),
     LintId::of(booleans::NONMINIMAL_BOOL),
     LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
-    LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
     LintId::of(casts::CHAR_LIT_AS_U8),
     LintId::of(casts::UNNECESSARY_CAST),
     LintId::of(dereference::EXPLICIT_AUTO_DEREF),
@@ -33,6 +32,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(matches::NEEDLESS_MATCH),
     LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
     LintId::of(methods::BIND_INSTEAD_OF_MAP),
+    LintId::of(methods::BYTES_COUNT_TO_LEN),
     LintId::of(methods::CLONE_ON_COPY),
     LintId::of(methods::FILTER_MAP_IDENTITY),
     LintId::of(methods::FILTER_NEXT),
@@ -51,10 +51,13 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(methods::OPTION_AS_REF_DEREF),
     LintId::of(methods::OPTION_FILTER_MAP),
     LintId::of(methods::OR_THEN_UNWRAP),
+    LintId::of(methods::RANGE_ZIP_WITH_LEN),
+    LintId::of(methods::REPEAT_ONCE),
     LintId::of(methods::SEARCH_IS_SOME),
     LintId::of(methods::SKIP_WHILE_NEXT),
     LintId::of(methods::UNNECESSARY_FILTER_MAP),
     LintId::of(methods::UNNECESSARY_FIND_MAP),
+    LintId::of(methods::UNNECESSARY_SORT_BY),
     LintId::of(methods::USELESS_ASREF),
     LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
     LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN),
@@ -69,6 +72,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD),
     LintId::of(no_effect::NO_EFFECT),
     LintId::of(no_effect::UNNECESSARY_OPERATION),
+    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
     LintId::of(operators::DOUBLE_COMPARISONS),
     LintId::of(operators::DURATION_SUBSEC),
     LintId::of(operators::IDENTITY_OP),
@@ -76,11 +80,9 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
     LintId::of(precedence::PRECEDENCE),
     LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
-    LintId::of(ranges::RANGE_ZIP_WITH_LEN),
     LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
     LintId::of(redundant_slicing::REDUNDANT_SLICING),
     LintId::of(reference::DEREF_ADDROF),
-    LintId::of(repeat_once::REPEAT_ONCE),
     LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
     LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
     LintId::of(swap::MANUAL_SWAP),
@@ -99,7 +101,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(types::TYPE_COMPLEXITY),
     LintId::of(types::VEC_BOX),
     LintId::of(unit_types::UNIT_ARG),
-    LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY),
     LintId::of(unwrap::UNNECESSARY_UNWRAP),
     LintId::of(useless_conversion::USELESS_CONVERSION),
     LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO),
diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs
index 006275d1383..bb94037ec2e 100644
--- a/clippy_lints/src/lib.register_correctness.rs
+++ b/clippy_lints/src/lib.register_correctness.rs
@@ -39,12 +39,14 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
     LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
     LintId::of(methods::CLONE_DOUBLE_REF),
     LintId::of(methods::ITERATOR_STEP_BY_ZERO),
+    LintId::of(methods::NONSENSICAL_OPEN_OPTIONS),
     LintId::of(methods::SUSPICIOUS_SPLITN),
     LintId::of(methods::UNINIT_ASSUMED_INIT),
+    LintId::of(methods::UNIT_HASH),
+    LintId::of(methods::VEC_RESIZE_TO_ZERO),
     LintId::of(methods::ZST_OFFSET),
     LintId::of(minmax::MIN_MAX),
     LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
-    LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
     LintId::of(operators::ABSURD_EXTREME_COMPARISONS),
     LintId::of(operators::BAD_BIT_MASK),
     LintId::of(operators::CMP_NAN),
@@ -62,17 +64,15 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
     LintId::of(serde_api::SERDE_API_MISUSE),
     LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
     LintId::of(swap::ALMOST_SWAPPED),
+    LintId::of(transmute::TRANSMUTING_NULL),
     LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
     LintId::of(transmute::WRONG_TRANSMUTE),
-    LintId::of(transmuting_null::TRANSMUTING_NULL),
     LintId::of(unicode::INVISIBLE_CHARACTERS),
     LintId::of(uninit_vec::UNINIT_VEC),
-    LintId::of(unit_hash::UNIT_HASH),
     LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
     LintId::of(unit_types::UNIT_CMP),
     LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
     LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS),
     LintId::of(unused_io_amount::UNUSED_IO_AMOUNT),
     LintId::of(unwrap::PANICKING_UNWRAP),
-    LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
 ])
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index c540573b802..fd20e016578 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -38,7 +38,6 @@ store.register_lints(&[
     almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE,
     approx_const::APPROX_CONSTANT,
     as_conversions::AS_CONVERSIONS,
-    as_underscore::AS_UNDERSCORE,
     asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
     asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
     assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
@@ -59,16 +58,14 @@ store.register_lints(&[
     bool_assert_comparison::BOOL_ASSERT_COMPARISON,
     booleans::NONMINIMAL_BOOL,
     booleans::OVERLY_COMPLEX_BOOL_EXPR,
-    borrow_as_ptr::BORROW_AS_PTR,
     borrow_deref_ref::BORROW_DEREF_REF,
-    bytecount::NAIVE_BYTECOUNT,
-    bytes_count_to_len::BYTES_COUNT_TO_LEN,
     cargo::CARGO_COMMON_METADATA,
     cargo::MULTIPLE_CRATE_VERSIONS,
     cargo::NEGATIVE_FEATURE_NAMES,
     cargo::REDUNDANT_FEATURE_NAMES,
     cargo::WILDCARD_DEPENDENCIES,
-    case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+    casts::AS_UNDERSCORE,
+    casts::BORROW_AS_PTR,
     casts::CAST_ABS_TO_UNSIGNED,
     casts::CAST_ENUM_CONSTRUCTOR,
     casts::CAST_ENUM_TRUNCATION,
@@ -80,6 +77,7 @@ store.register_lints(&[
     casts::CAST_REF_TO_MUT,
     casts::CAST_SIGN_LOSS,
     casts::CAST_SLICE_DIFFERENT_SIZES,
+    casts::CAST_SLICE_FROM_RAW_PARTS,
     casts::CHAR_LIT_AS_U8,
     casts::FN_TO_NUMERIC_CAST,
     casts::FN_TO_NUMERIC_CAST_ANY,
@@ -173,11 +171,11 @@ store.register_lints(&[
     functions::MUST_USE_CANDIDATE,
     functions::MUST_USE_UNIT,
     functions::NOT_UNSAFE_PTR_ARG_DEREF,
+    functions::RESULT_LARGE_ERR,
     functions::RESULT_UNIT_ERR,
     functions::TOO_MANY_ARGUMENTS,
     functions::TOO_MANY_LINES,
     future_not_send::FUTURE_NOT_SEND,
-    get_first::GET_FIRST,
     if_let_mutex::IF_LET_MUTEX,
     if_not_else::IF_NOT_ELSE,
     if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
@@ -246,12 +244,10 @@ store.register_lints(&[
     manual_bits::MANUAL_BITS,
     manual_instant_elapsed::MANUAL_INSTANT_ELAPSED,
     manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
-    manual_ok_or::MANUAL_OK_OR,
     manual_rem_euclid::MANUAL_REM_EUCLID,
     manual_retain::MANUAL_RETAIN,
+    manual_string_new::MANUAL_STRING_NEW,
     manual_strip::MANUAL_STRIP,
-    map_clone::MAP_CLONE,
-    map_err_ignore::MAP_ERR_IGNORE,
     map_unit_fn::OPTION_MAP_UNIT_FN,
     map_unit_fn::RESULT_MAP_UNIT_FN,
     match_result_ok::MATCH_RESULT_OK,
@@ -284,13 +280,16 @@ store.register_lints(&[
     mem_replace::MEM_REPLACE_WITH_DEFAULT,
     mem_replace::MEM_REPLACE_WITH_UNINIT,
     methods::BIND_INSTEAD_OF_MAP,
+    methods::BYTES_COUNT_TO_LEN,
     methods::BYTES_NTH,
+    methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
     methods::CHARS_LAST_CMP,
     methods::CHARS_NEXT_CMP,
     methods::CLONED_INSTEAD_OF_COPIED,
     methods::CLONE_DOUBLE_REF,
     methods::CLONE_ON_COPY,
     methods::CLONE_ON_REF_PTR,
+    methods::COLLAPSIBLE_STR_REPLACE,
     methods::ERR_EXPECT,
     methods::EXPECT_FUN_CALL,
     methods::EXPECT_USED,
@@ -302,6 +301,7 @@ store.register_lints(&[
     methods::FLAT_MAP_IDENTITY,
     methods::FLAT_MAP_OPTION,
     methods::FROM_ITER_INSTEAD_OF_COLLECT,
+    methods::GET_FIRST,
     methods::GET_LAST_WITH_LEN,
     methods::GET_UNWRAP,
     methods::IMPLICIT_CLONE,
@@ -315,22 +315,30 @@ store.register_lints(&[
     methods::ITER_NEXT_SLICE,
     methods::ITER_NTH,
     methods::ITER_NTH_ZERO,
+    methods::ITER_ON_EMPTY_COLLECTIONS,
+    methods::ITER_ON_SINGLE_ITEMS,
     methods::ITER_OVEREAGER_CLONED,
     methods::ITER_SKIP_NEXT,
     methods::ITER_WITH_DRAIN,
     methods::MANUAL_FILTER_MAP,
     methods::MANUAL_FIND_MAP,
+    methods::MANUAL_OK_OR,
     methods::MANUAL_SATURATING_ARITHMETIC,
     methods::MANUAL_SPLIT_ONCE,
     methods::MANUAL_STR_REPEAT,
+    methods::MAP_CLONE,
     methods::MAP_COLLECT_RESULT_UNIT,
+    methods::MAP_ERR_IGNORE,
     methods::MAP_FLATTEN,
     methods::MAP_IDENTITY,
     methods::MAP_UNWRAP_OR,
+    methods::MUT_MUTEX_LOCK,
+    methods::NAIVE_BYTECOUNT,
     methods::NEEDLESS_OPTION_AS_DEREF,
     methods::NEEDLESS_OPTION_TAKE,
     methods::NEEDLESS_SPLITN,
     methods::NEW_RET_NO_SELF,
+    methods::NONSENSICAL_OPEN_OPTIONS,
     methods::NO_EFFECT_REPLACE,
     methods::OBFUSCATED_IF_ELSE,
     methods::OK_EXPECT,
@@ -339,25 +347,34 @@ store.register_lints(&[
     methods::OPTION_MAP_OR_NONE,
     methods::OR_FUN_CALL,
     methods::OR_THEN_UNWRAP,
+    methods::PATH_BUF_PUSH_OVERWRITE,
+    methods::RANGE_ZIP_WITH_LEN,
+    methods::REPEAT_ONCE,
     methods::RESULT_MAP_OR_INTO_OPTION,
     methods::SEARCH_IS_SOME,
     methods::SHOULD_IMPLEMENT_TRAIT,
     methods::SINGLE_CHAR_ADD_STR,
     methods::SINGLE_CHAR_PATTERN,
     methods::SKIP_WHILE_NEXT,
+    methods::STABLE_SORT_PRIMITIVE,
     methods::STRING_EXTEND_CHARS,
     methods::SUSPICIOUS_MAP,
     methods::SUSPICIOUS_SPLITN,
+    methods::SUSPICIOUS_TO_OWNED,
     methods::UNINIT_ASSUMED_INIT,
+    methods::UNIT_HASH,
     methods::UNNECESSARY_FILTER_MAP,
     methods::UNNECESSARY_FIND_MAP,
     methods::UNNECESSARY_FOLD,
     methods::UNNECESSARY_JOIN,
     methods::UNNECESSARY_LAZY_EVALUATIONS,
+    methods::UNNECESSARY_SORT_BY,
     methods::UNNECESSARY_TO_OWNED,
     methods::UNWRAP_OR_ELSE_DEFAULT,
     methods::UNWRAP_USED,
     methods::USELESS_ASREF,
+    methods::VEC_RESIZE_TO_ZERO,
+    methods::VERBOSE_FILE_READS,
     methods::WRONG_SELF_CONVENTION,
     methods::ZST_OFFSET,
     minmax::MIN_MAX,
@@ -384,9 +401,9 @@ store.register_lints(&[
     mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION,
     module_style::MOD_MODULE_FILES,
     module_style::SELF_NAMED_MODULE_FILES,
+    multi_assignments::MULTI_ASSIGNMENTS,
     mut_key::MUTABLE_KEY_TYPE,
     mut_mut::MUT_MUT,
-    mut_mutex_lock::MUT_MUTEX_LOCK,
     mut_reference::UNNECESSARY_MUT_PASSED,
     mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
     mutex_atomic::MUTEX_ATOMIC,
@@ -418,7 +435,6 @@ store.register_lints(&[
     nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
     octal_escapes::OCTAL_ESCAPES,
     only_used_in_recursion::ONLY_USED_IN_RECURSION,
-    open_options::NONSENSICAL_OPEN_OPTIONS,
     operators::ABSURD_EXTREME_COMPARISONS,
     operators::ARITHMETIC,
     operators::ASSIGN_OP_PATTERN,
@@ -457,7 +473,6 @@ store.register_lints(&[
     partialeq_to_none::PARTIALEQ_TO_NONE,
     pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
     pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
-    path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
     pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
     precedence::PRECEDENCE,
     ptr::CMP_NULL,
@@ -470,7 +485,6 @@ store.register_lints(&[
     ranges::MANUAL_RANGE_CONTAINS,
     ranges::RANGE_MINUS_ONE,
     ranges::RANGE_PLUS_ONE,
-    ranges::RANGE_ZIP_WITH_LEN,
     ranges::REVERSED_EMPTY_RANGES,
     rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT,
     read_zero_byte_vec::READ_ZERO_BYTE_VEC,
@@ -486,7 +500,6 @@ store.register_lints(&[
     reference::DEREF_ADDROF,
     regex::INVALID_REGEX,
     regex::TRIVIAL_REGEX,
-    repeat_once::REPEAT_ONCE,
     return_self_not_must_use::RETURN_SELF_NOT_MUST_USE,
     returns::LET_AND_RETURN,
     returns::NEEDLESS_RETURN,
@@ -501,7 +514,6 @@ store.register_lints(&[
     single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
     size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
     slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
-    stable_sort_primitive::STABLE_SORT_PRIMITIVE,
     std_instead_of_core::ALLOC_INSTEAD_OF_CORE,
     std_instead_of_core::STD_INSTEAD_OF_ALLOC,
     std_instead_of_core::STD_INSTEAD_OF_CORE,
@@ -537,10 +549,10 @@ store.register_lints(&[
     transmute::TRANSMUTE_PTR_TO_PTR,
     transmute::TRANSMUTE_PTR_TO_REF,
     transmute::TRANSMUTE_UNDEFINED_REPR,
+    transmute::TRANSMUTING_NULL,
     transmute::UNSOUND_COLLECTION_TRANSMUTE,
     transmute::USELESS_TRANSMUTE,
     transmute::WRONG_TRANSMUTE,
-    transmuting_null::TRANSMUTING_NULL,
     types::BORROWED_BOX,
     types::BOX_COLLECTION,
     types::LINKEDLIST,
@@ -555,7 +567,6 @@ store.register_lints(&[
     unicode::NON_ASCII_LITERAL,
     unicode::UNICODE_NOT_NFC,
     uninit_vec::UNINIT_VEC,
-    unit_hash::UNIT_HASH,
     unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
     unit_types::LET_UNIT_VALUE,
     unit_types::UNIT_ARG,
@@ -564,12 +575,12 @@ store.register_lints(&[
     unnamed_address::VTABLE_ADDRESS_COMPARISONS,
     unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS,
     unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS,
-    unnecessary_sort_by::UNNECESSARY_SORT_BY,
     unnecessary_wraps::UNNECESSARY_WRAPS,
     unnested_or_patterns::UNNESTED_OR_PATTERNS,
     unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
     unused_async::UNUSED_ASYNC,
     unused_io_amount::UNUSED_IO_AMOUNT,
+    unused_peekable::UNUSED_PEEKABLE,
     unused_rounding::UNUSED_ROUNDING,
     unused_self::UNUSED_SELF,
     unused_unit::UNUSED_UNIT,
@@ -581,10 +592,9 @@ store.register_lints(&[
     useless_conversion::USELESS_CONVERSION,
     vec::USELESS_VEC,
     vec_init_then_push::VEC_INIT_THEN_PUSH,
-    vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
-    verbose_file_reads::VERBOSE_FILE_READS,
     wildcard_imports::ENUM_GLOB_USE,
     wildcard_imports::WILDCARD_IMPORTS,
+    write::POSITIONAL_NAMED_FORMAT_PARAMETERS,
     write::PRINTLN_EMPTY_STRING,
     write::PRINT_LITERAL,
     write::PRINT_STDERR,
diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs
index 91210b23afe..e319e7ee72c 100644
--- a/clippy_lints/src/lib.register_nursery.rs
+++ b/clippy_lints/src/lib.register_nursery.rs
@@ -14,16 +14,17 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
     LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE),
     LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
     LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
+    LintId::of(methods::ITER_ON_EMPTY_COLLECTIONS),
+    LintId::of(methods::ITER_ON_SINGLE_ITEMS),
     LintId::of(methods::ITER_WITH_DRAIN),
+    LintId::of(methods::PATH_BUF_PUSH_OVERWRITE),
     LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
     LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
     LintId::of(mutex_atomic::MUTEX_ATOMIC),
     LintId::of(mutex_atomic::MUTEX_INTEGER),
     LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
     LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
-    LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION),
     LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
-    LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
     LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
     LintId::of(regex::TRIVIAL_REGEX),
     LintId::of(strings::STRING_LIT_AS_BYTES),
diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs
index bd7d1a15ab4..584ccf55e51 100644
--- a/clippy_lints/src/lib.register_pedantic.rs
+++ b/clippy_lints/src/lib.register_pedantic.rs
@@ -4,9 +4,7 @@
 
 store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(attrs::INLINE_ALWAYS),
-    LintId::of(borrow_as_ptr::BORROW_AS_PTR),
-    LintId::of(bytecount::NAIVE_BYTECOUNT),
-    LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
+    LintId::of(casts::BORROW_AS_PTR),
     LintId::of(casts::CAST_LOSSLESS),
     LintId::of(casts::CAST_POSSIBLE_TRUNCATION),
     LintId::of(casts::CAST_POSSIBLE_WRAP),
@@ -50,20 +48,24 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(macro_use::MACRO_USE_IMPORTS),
     LintId::of(manual_assert::MANUAL_ASSERT),
     LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED),
-    LintId::of(manual_ok_or::MANUAL_OK_OR),
+    LintId::of(manual_string_new::MANUAL_STRING_NEW),
     LintId::of(matches::MATCH_BOOL),
     LintId::of(matches::MATCH_ON_VEC_ITEMS),
     LintId::of(matches::MATCH_SAME_ARMS),
     LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
     LintId::of(matches::MATCH_WILD_ERR_ARM),
     LintId::of(matches::SINGLE_MATCH_ELSE),
+    LintId::of(methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
     LintId::of(methods::CLONED_INSTEAD_OF_COPIED),
     LintId::of(methods::FILTER_MAP_NEXT),
     LintId::of(methods::FLAT_MAP_OPTION),
     LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT),
     LintId::of(methods::IMPLICIT_CLONE),
     LintId::of(methods::INEFFICIENT_TO_STRING),
+    LintId::of(methods::MANUAL_OK_OR),
     LintId::of(methods::MAP_UNWRAP_OR),
+    LintId::of(methods::NAIVE_BYTECOUNT),
+    LintId::of(methods::STABLE_SORT_PRIMITIVE),
     LintId::of(methods::UNNECESSARY_JOIN),
     LintId::of(misc::USED_UNDERSCORE_BINDING),
     LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER),
@@ -85,7 +87,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(ref_option_ref::REF_OPTION_REF),
     LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
     LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
-    LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
     LintId::of(strings::STRING_ADD_ASSIGN),
     LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
     LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
diff --git a/clippy_lints/src/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs
index e1b90acb93c..195ce41e31e 100644
--- a/clippy_lints/src/lib.register_perf.rs
+++ b/clippy_lints/src/lib.register_perf.rs
@@ -7,12 +7,14 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
     LintId::of(escape::BOXED_LOCAL),
     LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
     LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
+    LintId::of(functions::RESULT_LARGE_ERR),
     LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
     LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
     LintId::of(loops::MANUAL_MEMCPY),
     LintId::of(loops::MISSING_SPIN_LOOP),
     LintId::of(loops::NEEDLESS_COLLECT),
     LintId::of(manual_retain::MANUAL_RETAIN),
+    LintId::of(methods::COLLAPSIBLE_STR_REPLACE),
     LintId::of(methods::EXPECT_FUN_CALL),
     LintId::of(methods::EXTEND_WITH_DRAIN),
     LintId::of(methods::ITER_NTH),
diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs
index a7339ef2721..dd1e1e1a8e3 100644
--- a/clippy_lints/src/lib.register_restriction.rs
+++ b/clippy_lints/src/lib.register_restriction.rs
@@ -4,11 +4,11 @@
 
 store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
     LintId::of(as_conversions::AS_CONVERSIONS),
-    LintId::of(as_underscore::AS_UNDERSCORE),
     LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
     LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
     LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
     LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON),
+    LintId::of(casts::AS_UNDERSCORE),
     LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
     LintId::of(create_dir::CREATE_DIR),
     LintId::of(dbg_macro::DBG_MACRO),
@@ -30,7 +30,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(large_include_file::LARGE_INCLUDE_FILE),
     LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
     LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
-    LintId::of(map_err_ignore::MAP_ERR_IGNORE),
     LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
     LintId::of(matches::TRY_ERR),
     LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
@@ -39,7 +38,9 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(methods::EXPECT_USED),
     LintId::of(methods::FILETYPE_IS_FILE),
     LintId::of(methods::GET_UNWRAP),
+    LintId::of(methods::MAP_ERR_IGNORE),
     LintId::of(methods::UNWRAP_USED),
+    LintId::of(methods::VERBOSE_FILE_READS),
     LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
     LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
     LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
@@ -81,7 +82,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(unicode::NON_ASCII_LITERAL),
     LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
     LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
-    LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
     LintId::of(write::PRINT_STDERR),
     LintId::of(write::PRINT_STDOUT),
     LintId::of(write::USE_DEBUG),
diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs
index bfa654238f1..b5cb078e7a3 100644
--- a/clippy_lints/src/lib.register_style.rs
+++ b/clippy_lints/src/lib.register_style.rs
@@ -29,7 +29,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(functions::DOUBLE_MUST_USE),
     LintId::of(functions::MUST_USE_UNIT),
     LintId::of(functions::RESULT_UNIT_ERR),
-    LintId::of(get_first::GET_FIRST),
     LintId::of(inherent_to_string::INHERENT_TO_STRING),
     LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
     LintId::of(len_zero::COMPARISON_TO_EMPTY),
@@ -45,7 +44,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
     LintId::of(manual_bits::MANUAL_BITS),
     LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
-    LintId::of(map_clone::MAP_CLONE),
     LintId::of(match_result_ok::MATCH_RESULT_OK),
     LintId::of(matches::COLLAPSIBLE_MATCH),
     LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
@@ -61,6 +59,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(methods::CHARS_LAST_CMP),
     LintId::of(methods::CHARS_NEXT_CMP),
     LintId::of(methods::ERR_EXPECT),
+    LintId::of(methods::GET_FIRST),
     LintId::of(methods::INTO_ITER_ON_REF),
     LintId::of(methods::IS_DIGIT_ASCII_RADIX),
     LintId::of(methods::ITER_CLONED_COLLECT),
@@ -68,7 +67,9 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(methods::ITER_NTH_ZERO),
     LintId::of(methods::ITER_SKIP_NEXT),
     LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
+    LintId::of(methods::MAP_CLONE),
     LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
+    LintId::of(methods::MUT_MUTEX_LOCK),
     LintId::of(methods::NEW_RET_NO_SELF),
     LintId::of(methods::OBFUSCATED_IF_ELSE),
     LintId::of(methods::OK_EXPECT),
@@ -88,7 +89,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
     LintId::of(misc_early::MIXED_CASE_HEX_LITERALS),
     LintId::of(misc_early::REDUNDANT_PATTERN),
-    LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
     LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
     LintId::of(needless_late_init::NEEDLESS_LATE_INIT),
     LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS),
diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs
index 964992bd94f..8f131bbf98b 100644
--- a/clippy_lints/src/lib.register_suspicious.rs
+++ b/clippy_lints/src/lib.register_suspicious.rs
@@ -11,6 +11,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
     LintId::of(casts::CAST_ABS_TO_UNSIGNED),
     LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
     LintId::of(casts::CAST_ENUM_TRUNCATION),
+    LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
     LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
     LintId::of(drop_forget_ref::DROP_NON_DROP),
     LintId::of(drop_forget_ref::FORGET_NON_DROP),
@@ -24,6 +25,8 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
     LintId::of(loops::MUT_RANGE_BOUND),
     LintId::of(methods::NO_EFFECT_REPLACE),
     LintId::of(methods::SUSPICIOUS_MAP),
+    LintId::of(methods::SUSPICIOUS_TO_OWNED),
+    LintId::of(multi_assignments::MULTI_ASSIGNMENTS),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
     LintId::of(octal_escapes::OCTAL_ESCAPES),
     LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS),
@@ -32,4 +35,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
     LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
     LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF),
+    LintId::of(unused_peekable::UNUSED_PEEKABLE),
+    LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS),
 ])
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index ec5c73c1357..dfdaf90f09f 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -171,7 +171,6 @@ mod renamed_lints;
 mod almost_complete_letter_range;
 mod approx_const;
 mod as_conversions;
-mod as_underscore;
 mod asm_syntax;
 mod assertions_on_constants;
 mod assertions_on_result_states;
@@ -181,12 +180,8 @@ mod await_holding_invalid;
 mod blocks_in_if_conditions;
 mod bool_assert_comparison;
 mod booleans;
-mod borrow_as_ptr;
 mod borrow_deref_ref;
-mod bytecount;
-mod bytes_count_to_len;
 mod cargo;
-mod case_sensitive_file_extension_comparisons;
 mod casts;
 mod checked_conversions;
 mod cognitive_complexity;
@@ -239,7 +234,6 @@ mod from_over_into;
 mod from_str_radix_10;
 mod functions;
 mod future_not_send;
-mod get_first;
 mod if_let_mutex;
 mod if_not_else;
 mod if_then_some_else_none;
@@ -276,12 +270,10 @@ mod manual_async_fn;
 mod manual_bits;
 mod manual_instant_elapsed;
 mod manual_non_exhaustive;
-mod manual_ok_or;
 mod manual_rem_euclid;
 mod manual_retain;
+mod manual_string_new;
 mod manual_strip;
-mod map_clone;
-mod map_err_ignore;
 mod map_unit_fn;
 mod match_result_ok;
 mod matches;
@@ -298,9 +290,9 @@ mod missing_enforced_import_rename;
 mod missing_inline;
 mod mixed_read_write_in_expression;
 mod module_style;
+mod multi_assignments;
 mod mut_key;
 mod mut_mut;
-mod mut_mutex_lock;
 mod mut_reference;
 mod mutable_debug_assertion;
 mod mutex_atomic;
@@ -325,7 +317,6 @@ mod non_send_fields_in_send_ty;
 mod nonstandard_macro_braces;
 mod octal_escapes;
 mod only_used_in_recursion;
-mod open_options;
 mod operators;
 mod option_env_unwrap;
 mod option_if_let_else;
@@ -335,7 +326,6 @@ mod panic_unimplemented;
 mod partialeq_ne_impl;
 mod partialeq_to_none;
 mod pass_by_ref_or_value;
-mod path_buf_push_overwrite;
 mod pattern_type_mismatch;
 mod precedence;
 mod ptr;
@@ -355,7 +345,6 @@ mod redundant_static_lifetimes;
 mod ref_option_ref;
 mod reference;
 mod regex;
-mod repeat_once;
 mod return_self_not_must_use;
 mod returns;
 mod same_name_method;
@@ -367,7 +356,6 @@ mod single_char_lifetime_names;
 mod single_component_path_imports;
 mod size_of_in_element_count;
 mod slow_vector_initialization;
-mod stable_sort_primitive;
 mod std_instead_of_core;
 mod strings;
 mod strlen_on_c_strings;
@@ -381,23 +369,21 @@ mod to_digit_is_some;
 mod trailing_empty_array;
 mod trait_bounds;
 mod transmute;
-mod transmuting_null;
 mod types;
 mod undocumented_unsafe_blocks;
 mod unicode;
 mod uninit_vec;
-mod unit_hash;
 mod unit_return_expecting_ord;
 mod unit_types;
 mod unnamed_address;
 mod unnecessary_owned_empty_strings;
 mod unnecessary_self_imports;
-mod unnecessary_sort_by;
 mod unnecessary_wraps;
 mod unnested_or_patterns;
 mod unsafe_removed_from_name;
 mod unused_async;
 mod unused_io_amount;
+mod unused_peekable;
 mod unused_rounding;
 mod unused_self;
 mod unused_unit;
@@ -408,8 +394,6 @@ mod use_self;
 mod useless_conversion;
 mod vec;
 mod vec_init_then_push;
-mod vec_resize_to_zero;
-mod verbose_file_reads;
 mod wildcard_imports;
 mod write;
 mod zero_div_zero;
@@ -597,7 +581,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
     store.register_late_pass(|| Box::new(unicode::Unicode));
     store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
-    store.register_late_pass(|| Box::new(unit_hash::UnitHash));
     store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
     store.register_late_pass(|| Box::new(strings::StringAdd));
     store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
@@ -635,8 +618,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark));
     store.register_late_pass(move || Box::new(casts::Casts::new(msrv)));
     store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv)));
-    store.register_late_pass(move || Box::new(map_clone::MapClone::new(msrv)));
-
     store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount));
     store.register_late_pass(|| Box::new(same_name_method::SameNameMethod));
     let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length;
@@ -646,7 +627,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
             msrv,
         ))
     });
-    store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore));
     store.register_late_pass(|| Box::new(shadow::Shadow::default()));
     store.register_late_pass(|| Box::new(unit_types::UnitTypes));
     store.register_late_pass(|| Box::new(loops::Loops));
@@ -654,7 +634,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(lifetimes::Lifetimes));
     store.register_late_pass(|| Box::new(entry::HashMapPass));
     store.register_late_pass(|| Box::new(minmax::MinMaxPass));
-    store.register_late_pass(|| Box::new(open_options::OpenOptions));
     store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv));
     store.register_late_pass(|| Box::new(mutex_atomic::Mutex));
     store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate));
@@ -690,10 +669,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone())));
     let too_many_arguments_threshold = conf.too_many_arguments_threshold;
     let too_many_lines_threshold = conf.too_many_lines_threshold;
+    let large_error_threshold = conf.large_error_threshold;
     store.register_late_pass(move || {
         Box::new(functions::Functions::new(
             too_many_arguments_threshold,
             too_many_lines_threshold,
+            large_error_threshold,
         ))
     });
     let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
@@ -720,7 +701,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     );
     store.register_late_pass(move || Box::new(pass_by_ref_or_value));
     store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef));
-    store.register_late_pass(|| Box::new(bytecount::ByteCount));
     store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter));
     store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody));
     store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default()));
@@ -738,12 +718,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
     store.register_late_pass(|| Box::new(redundant_clone::RedundantClone));
     store.register_late_pass(|| Box::new(slow_vector_initialization::SlowVectorInit));
-    store.register_late_pass(|| Box::new(unnecessary_sort_by::UnnecessarySortBy));
     store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
     store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants));
     store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates));
-    store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull));
-    store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite));
     store.register_late_pass(|| Box::new(inherent_to_string::InherentToString));
     let max_trait_bounds = conf.max_trait_bounds;
     store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
@@ -819,18 +796,15 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap));
     let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
     store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)));
-    store.register_late_pass(|| Box::new(verbose_file_reads::VerboseFileReads));
     store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default()));
     store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress));
-    store.register_late_pass(|| Box::new(dereference::Dereferencing::default()));
+    store.register_late_pass(move || Box::new(dereference::Dereferencing::new(msrv)));
     store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse));
     store.register_late_pass(|| Box::new(future_not_send::FutureNotSend));
     store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex));
     store.register_late_pass(|| Box::new(if_not_else::IfNotElse));
     store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
-    store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock));
     store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn));
-    store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero));
     store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn));
     let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
     store.register_early_pass(move || {
@@ -842,10 +816,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(&macro_matcher)));
     store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default()));
     store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch));
-    store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive));
-    store.register_late_pass(|| Box::new(repeat_once::RepeatOnce));
     store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult));
-    store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr));
     store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
     store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
     let disallowed_methods = conf.disallowed_methods.clone();
@@ -857,9 +828,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(strings::StringToString));
     store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues));
     store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default()));
-    store.register_late_pass(|| {
-        Box::new(case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons)
-    });
     store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing));
     store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10));
     store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
@@ -894,11 +862,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
     store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields));
     store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
-    store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv)));
     store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv)));
     store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation));
     store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes));
-    store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion));
+    store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion::default()));
     let allow_dbg_in_tests = conf.allow_dbg_in_tests;
     store.register_late_pass(move || Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
     let cargo_ignore_publish = conf.cargo_ignore_publish;
@@ -912,18 +879,15 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
     store.register_early_pass(|| Box::new(pub_use::PubUse));
     store.register_late_pass(|| Box::new(format_push_string::FormatPushString));
-    store.register_late_pass(|| Box::new(bytes_count_to_len::BytesCountToLen));
     let max_include_file_size = conf.max_include_file_size;
     store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size)));
     store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace));
     store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
     store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default()));
-    store.register_late_pass(|| Box::new(get_first::GetFirst));
     store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
     store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv)));
     store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef));
     store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch));
-    store.register_late_pass(|| Box::new(as_underscore::AsUnderscore));
     store.register_late_pass(|| Box::new(read_zero_byte_vec::ReadZeroByteVec));
     store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
     store.register_late_pass(move || Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv)));
@@ -934,6 +898,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default()));
     store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed));
     store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone));
+    store.register_late_pass(|| Box::new(manual_string_new::ManualStringNew));
+    store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable));
+    store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs
index ddaffc75188..6d987f393fa 100644
--- a/clippy_lints/src/loops/needless_collect.rs
+++ b/clippy_lints/src/loops/needless_collect.rs
@@ -1,5 +1,6 @@
 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;
@@ -184,10 +185,19 @@ struct IterFunctionVisitor<'a, 'tcx> {
 impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
     fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
         for (expr, hir_id) in block.stmts.iter().filter_map(get_expr_and_hir_id_from_stmt) {
+            if check_loop_kind(expr).is_some() {
+                continue;
+            }
             self.visit_block_expr(expr, hir_id);
         }
         if let Some(expr) = block.expr {
-            self.visit_block_expr(expr, None);
+            if let Some(loop_kind) = check_loop_kind(expr) {
+                if let LoopKind::Conditional(block_expr) = loop_kind {
+                    self.visit_block_expr(block_expr, None);
+                }
+            } else {
+                self.visit_block_expr(expr, None);
+            }
         }
     }
 
@@ -264,6 +274,28 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
     }
 }
 
+enum LoopKind<'tcx> {
+    Conditional(&'tcx Expr<'tcx>),
+    Loop,
+}
+
+fn check_loop_kind<'tcx>(expr: &Expr<'tcx>) -> Option<LoopKind<'tcx>> {
+    if let Some(higher::WhileLet { let_expr, .. }) = higher::WhileLet::hir(expr) {
+        return Some(LoopKind::Conditional(let_expr));
+    }
+    if let Some(higher::While { condition, .. }) = higher::While::hir(expr) {
+        return Some(LoopKind::Conditional(condition));
+    }
+    if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr) {
+        return Some(LoopKind::Conditional(arg));
+    }
+    if let ExprKind::Loop { .. } = expr.kind {
+        return Some(LoopKind::Loop);
+    }
+
+    None
+}
+
 impl<'tcx> IterFunctionVisitor<'_, 'tcx> {
     fn visit_block_expr(&mut self, expr: &'tcx Expr<'tcx>, hir_id: Option<HirId>) {
         self.current_statement_hir_id = hir_id;
diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs
index a0ca7e6ff1e..2502c8f880d 100644
--- a/clippy_lints/src/manual_async_fn.rs
+++ b/clippy_lints/src/manual_async_fn.rs
@@ -192,7 +192,7 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str,
     match output.kind {
         TyKind::Tup(tys) if tys.is_empty() => {
             let sugg = "remove the return type";
-            Some((sugg, "".into()))
+            Some((sugg, String::new()))
         },
         _ => {
             let sugg = "return the output of the future directly";
diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs
deleted file mode 100644
index cf5004399b8..00000000000
--- a/clippy_lints/src/manual_ok_or.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_lang_ctor, path_to_local_id};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::LangItem::{ResultErr, ResultOk};
-use rustc_hir::{Closure, Expr, ExprKind, PatKind};
-use rustc_lint::LintContext;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::sym;
-
-declare_clippy_lint! {
-    /// ### What it does
-    ///
-    /// Finds patterns that reimplement `Option::ok_or`.
-    ///
-    /// ### Why is this bad?
-    ///
-    /// Concise code helps focusing on behavior instead of boilerplate.
-    ///
-    /// ### Examples
-    /// ```rust
-    /// let foo: Option<i32> = None;
-    /// foo.map_or(Err("error"), |v| Ok(v));
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust
-    /// let foo: Option<i32> = None;
-    /// foo.ok_or("error");
-    /// ```
-    #[clippy::version = "1.49.0"]
-    pub MANUAL_OK_OR,
-    pedantic,
-    "finds patterns that can be encoded more concisely with `Option::ok_or`"
-}
-
-declare_lint_pass!(ManualOkOr => [MANUAL_OK_OR]);
-
-impl<'tcx> LateLintPass<'tcx> for ManualOkOr {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) {
-        if in_external_macro(cx.sess(), scrutinee.span) {
-            return;
-        }
-
-        if_chain! {
-            if let ExprKind::MethodCall(method_segment, [receiver, or_expr, map_expr], _) = scrutinee.kind;
-            if method_segment.ident.name == sym!(map_or);
-            let ty = cx.typeck_results().expr_ty(receiver);
-            if is_type_diagnostic_item(cx, ty, sym::Option);
-            if is_ok_wrapping(cx, map_expr);
-            if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind;
-            if is_lang_ctor(cx, err_path, ResultErr);
-            if let Some(method_receiver_snippet) = snippet_opt(cx, receiver.span);
-            if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span);
-            if let Some(indent) = indent_of(cx, scrutinee.span);
-            then {
-                let reindented_err_arg_snippet =
-                    reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4));
-                span_lint_and_sugg(
-                    cx,
-                    MANUAL_OK_OR,
-                    scrutinee.span,
-                    "this pattern reimplements `Option::ok_or`",
-                    "replace with",
-                    format!(
-                        "{}.ok_or({})",
-                        method_receiver_snippet,
-                        reindented_err_arg_snippet
-                    ),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-    }
-}
-
-fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool {
-    if let ExprKind::Path(ref qpath) = map_expr.kind {
-        if is_lang_ctor(cx, qpath, ResultOk) {
-            return true;
-        }
-    }
-    if_chain! {
-        if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind;
-        let body = cx.tcx.hir().body(body);
-        if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind;
-        if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind;
-        if is_lang_ctor(cx, ok_path, ResultOk);
-        then { path_to_local_id(ok_arg, param_id) } else { false }
-    }
-}
diff --git a/clippy_lints/src/manual_string_new.rs b/clippy_lints/src/manual_string_new.rs
new file mode 100644
index 00000000000..a90eaa8fdcb
--- /dev/null
+++ b/clippy_lints/src/manual_string_new.rs
@@ -0,0 +1,140 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability::MachineApplicable;
+use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, symbol, Span};
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for usage of `""` to create a `String`, such as `"".to_string()`, `"".to_owned()`,
+    /// `String::from("")` and others.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Different ways of creating an empty string makes your code less standardized, which can
+    /// be confusing.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let a = "".to_string();
+    /// let b: String = "".into();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let a = String::new();
+    /// let b = String::new();
+    /// ```
+    #[clippy::version = "1.65.0"]
+    pub MANUAL_STRING_NEW,
+    pedantic,
+    "empty String is being created manually"
+}
+declare_lint_pass!(ManualStringNew => [MANUAL_STRING_NEW]);
+
+impl LateLintPass<'_> for ManualStringNew {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if expr.span.from_expansion() {
+            return;
+        }
+
+        let ty = cx.typeck_results().expr_ty(expr);
+        match ty.kind() {
+            ty::Adt(adt_def, _) if adt_def.is_struct() => {
+                if !cx.tcx.is_diagnostic_item(sym::String, adt_def.did()) {
+                    return;
+                }
+            },
+            _ => return,
+        }
+
+        match expr.kind {
+            ExprKind::Call(func, args) => {
+                parse_call(cx, expr.span, func, args);
+            },
+            ExprKind::MethodCall(path_segment, args, _) => {
+                parse_method_call(cx, expr.span, path_segment, args);
+            },
+            _ => (),
+        }
+    }
+}
+
+/// Checks if an expression's kind corresponds to an empty &str.
+fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool {
+    if  let ExprKind::Lit(lit) = expr_kind &&
+        let LitKind::Str(value, _) = lit.node &&
+        value == symbol::kw::Empty
+    {
+        return true;
+    }
+
+    false
+}
+
+fn warn_then_suggest(cx: &LateContext<'_>, span: Span) {
+    span_lint_and_sugg(
+        cx,
+        MANUAL_STRING_NEW,
+        span,
+        "empty String is being created manually",
+        "consider using",
+        "String::new()".into(),
+        MachineApplicable,
+    );
+}
+
+/// Tries to parse an expression as a method call, emitting the warning if necessary.
+fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, args: &[Expr<'_>]) {
+    if args.is_empty() {
+        // When parsing TryFrom::try_from(...).expect(...), we will have more than 1 arg.
+        return;
+    }
+
+    let ident = path_segment.ident.as_str();
+    let method_arg_kind = &args[0].kind;
+    if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) {
+        warn_then_suggest(cx, span);
+    } else if let ExprKind::Call(func, args) = method_arg_kind {
+        // If our first argument is a function call itself, it could be an `unwrap`-like function.
+        // E.g. String::try_from("hello").unwrap(), TryFrom::try_from("").expect("hello"), etc.
+        parse_call(cx, span, func, args);
+    }
+}
+
+/// Tries to parse an expression as a function call, emitting the warning if necessary.
+fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_>]) {
+    if args.len() != 1 {
+        return;
+    }
+
+    let arg_kind = &args[0].kind;
+    if let ExprKind::Path(qpath) = &func.kind {
+        if let QPath::TypeRelative(_, _) = qpath {
+            // String::from(...) or String::try_from(...)
+            if  let QPath::TypeRelative(ty, path_seg) = qpath &&
+                [sym::from, sym::try_from].contains(&path_seg.ident.name) &&
+                let TyKind::Path(qpath) = &ty.kind &&
+                let QPath::Resolved(_, path) = qpath &&
+                let [path_seg] = path.segments &&
+                path_seg.ident.name == sym::String &&
+                is_expr_kind_empty_str(arg_kind)
+            {
+                warn_then_suggest(cx, span);
+            }
+        } else if let QPath::Resolved(_, path) = qpath {
+            // From::from(...) or TryFrom::try_from(...)
+            if  let [path_seg1, path_seg2] = path.segments &&
+                is_expr_kind_empty_str(arg_kind) && (
+                    (path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) ||
+                    (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from)
+                )
+            {
+                warn_then_suggest(cx, span);
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs
deleted file mode 100644
index 95c312f1fe2..00000000000
--- a/clippy_lints/src/map_clone.rs
+++ /dev/null
@@ -1,167 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
-use clippy_utils::{is_trait_method, meets_msrv, msrvs, peel_blocks};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::mir::Mutability;
-use rustc_middle::ty;
-use rustc_middle::ty::adjustment::Adjust;
-use rustc_semver::RustcVersion;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::Ident;
-use rustc_span::{sym, Span};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for usage of `map(|x| x.clone())` or
-    /// dereferencing closures for `Copy` types, on `Iterator` or `Option`,
-    /// and suggests `cloned()` or `copied()` instead
-    ///
-    /// ### Why is this bad?
-    /// Readability, this can be written more concisely
-    ///
-    /// ### Example
-    /// ```rust
-    /// let x = vec![42, 43];
-    /// let y = x.iter();
-    /// let z = y.map(|i| *i);
-    /// ```
-    ///
-    /// The correct use would be:
-    ///
-    /// ```rust
-    /// let x = vec![42, 43];
-    /// let y = x.iter();
-    /// let z = y.cloned();
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub MAP_CLONE,
-    style,
-    "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
-}
-
-pub struct MapClone {
-    msrv: Option<RustcVersion>,
-}
-
-impl_lint_pass!(MapClone => [MAP_CLONE]);
-
-impl MapClone {
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
-        Self { msrv }
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for MapClone {
-    fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
-        if e.span.from_expansion() {
-            return;
-        }
-
-        if_chain! {
-            if let hir::ExprKind::MethodCall(method, args, _) = e.kind;
-            if args.len() == 2;
-            if method.ident.name == sym::map;
-            let ty = cx.typeck_results().expr_ty(&args[0]);
-            if is_type_diagnostic_item(cx, ty, sym::Option) || is_trait_method(cx, e, sym::Iterator);
-            if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = args[1].kind;
-            then {
-                let closure_body = cx.tcx.hir().body(body);
-                let closure_expr = peel_blocks(&closure_body.value);
-                match closure_body.params[0].pat.kind {
-                    hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
-                        hir::BindingAnnotation::Unannotated, .., name, None
-                    ) = inner.kind {
-                        if ident_eq(name, closure_expr) {
-                            self.lint_explicit_closure(cx, e.span, args[0].span, true);
-                        }
-                    },
-                    hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
-                        match closure_expr.kind {
-                            hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
-                                if ident_eq(name, inner) {
-                                    if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
-                                        self.lint_explicit_closure(cx, e.span, args[0].span, true);
-                                    }
-                                }
-                            },
-                            hir::ExprKind::MethodCall(method, [obj], _) => if_chain! {
-                                if ident_eq(name, obj) && method.ident.name == sym::clone;
-                                if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
-                                if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
-                                if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id);
-                                // no autoderefs
-                                if !cx.typeck_results().expr_adjustments(obj).iter()
-                                    .any(|a| matches!(a.kind, Adjust::Deref(Some(..))));
-                                then {
-                                    let obj_ty = cx.typeck_results().expr_ty(obj);
-                                    if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
-                                        if matches!(mutability, Mutability::Not) {
-                                            let copy = is_copy(cx, *ty);
-                                            self.lint_explicit_closure(cx, e.span, args[0].span, copy);
-                                        }
-                                    } else {
-                                        lint_needless_cloning(cx, e.span, args[0].span);
-                                    }
-                                }
-                            },
-                            _ => {},
-                        }
-                    },
-                    _ => {},
-                }
-            }
-        }
-    }
-
-    extract_msrv_attr!(LateContext);
-}
-
-fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool {
-    if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind {
-        path.segments.len() == 1 && path.segments[0].ident == name
-    } else {
-        false
-    }
-}
-
-fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
-    span_lint_and_sugg(
-        cx,
-        MAP_CLONE,
-        root.trim_start(receiver).unwrap(),
-        "you are needlessly cloning iterator elements",
-        "remove the `map` call",
-        String::new(),
-        Applicability::MachineApplicable,
-    );
-}
-
-impl MapClone {
-    fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) {
-        let mut applicability = Applicability::MachineApplicable;
-
-        let (message, sugg_method) = if is_copy && meets_msrv(self.msrv, msrvs::ITERATOR_COPIED) {
-            ("you are using an explicit closure for copying elements", "copied")
-        } else {
-            ("you are using an explicit closure for cloning elements", "cloned")
-        };
-
-        span_lint_and_sugg(
-            cx,
-            MAP_CLONE,
-            replace,
-            message,
-            &format!("consider calling the dedicated `{}` method", sugg_method),
-            format!(
-                "{}.{}()",
-                snippet_with_applicability(cx, root, "..", &mut applicability),
-                sugg_method,
-            ),
-            applicability,
-        );
-    }
-}
diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs
deleted file mode 100644
index 1e542447c96..00000000000
--- a/clippy_lints/src/map_err_ignore.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for instances of `map_err(|_| Some::Enum)`
-    ///
-    /// ### Why is this bad?
-    /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error
-    ///
-    /// ### Example
-    /// Before:
-    /// ```rust
-    /// use std::fmt;
-    ///
-    /// #[derive(Debug)]
-    /// enum Error {
-    ///     Indivisible,
-    ///     Remainder(u8),
-    /// }
-    ///
-    /// impl fmt::Display for Error {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         match self {
-    ///             Error::Indivisible => write!(f, "could not divide input by three"),
-    ///             Error::Remainder(remainder) => write!(
-    ///                 f,
-    ///                 "input is not divisible by three, remainder = {}",
-    ///                 remainder
-    ///             ),
-    ///         }
-    ///     }
-    /// }
-    ///
-    /// impl std::error::Error for Error {}
-    ///
-    /// fn divisible_by_3(input: &str) -> Result<(), Error> {
-    ///     input
-    ///         .parse::<i32>()
-    ///         .map_err(|_| Error::Indivisible)
-    ///         .map(|v| v % 3)
-    ///         .and_then(|remainder| {
-    ///             if remainder == 0 {
-    ///                 Ok(())
-    ///             } else {
-    ///                 Err(Error::Remainder(remainder as u8))
-    ///             }
-    ///         })
-    /// }
-    ///  ```
-    ///
-    ///  After:
-    ///  ```rust
-    /// use std::{fmt, num::ParseIntError};
-    ///
-    /// #[derive(Debug)]
-    /// enum Error {
-    ///     Indivisible(ParseIntError),
-    ///     Remainder(u8),
-    /// }
-    ///
-    /// impl fmt::Display for Error {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         match self {
-    ///             Error::Indivisible(_) => write!(f, "could not divide input by three"),
-    ///             Error::Remainder(remainder) => write!(
-    ///                 f,
-    ///                 "input is not divisible by three, remainder = {}",
-    ///                 remainder
-    ///             ),
-    ///         }
-    ///     }
-    /// }
-    ///
-    /// impl std::error::Error for Error {
-    ///     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
-    ///         match self {
-    ///             Error::Indivisible(source) => Some(source),
-    ///             _ => None,
-    ///         }
-    ///     }
-    /// }
-    ///
-    /// fn divisible_by_3(input: &str) -> Result<(), Error> {
-    ///     input
-    ///         .parse::<i32>()
-    ///         .map_err(Error::Indivisible)
-    ///         .map(|v| v % 3)
-    ///         .and_then(|remainder| {
-    ///             if remainder == 0 {
-    ///                 Ok(())
-    ///             } else {
-    ///                 Err(Error::Remainder(remainder as u8))
-    ///             }
-    ///         })
-    /// }
-    /// ```
-    #[clippy::version = "1.48.0"]
-    pub MAP_ERR_IGNORE,
-    restriction,
-    "`map_err` should not ignore the original error"
-}
-
-declare_lint_pass!(MapErrIgnore => [MAP_ERR_IGNORE]);
-
-impl<'tcx> LateLintPass<'tcx> for MapErrIgnore {
-    // do not try to lint if this is from a macro or desugaring
-    fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
-        if e.span.from_expansion() {
-            return;
-        }
-
-        // check if this is a method call (e.g. x.foo())
-        if let ExprKind::MethodCall(method, [_, arg], _) = e.kind {
-            // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1]
-            // Enum::Variant[2]))
-            if method.ident.name == sym!(map_err) {
-                // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span
-                // fields
-                if let ExprKind::Closure(&Closure {
-                    capture_clause,
-                    body,
-                    fn_decl_span,
-                    ..
-                }) = arg.kind
-                {
-                    // check if this is by Reference (meaning there's no move statement)
-                    if capture_clause == CaptureBy::Ref {
-                        // Get the closure body to check the parameters and values
-                        let closure_body = cx.tcx.hir().body(body);
-                        // make sure there's only one parameter (`|_|`)
-                        if closure_body.params.len() == 1 {
-                            // make sure that parameter is the wild token (`_`)
-                            if let PatKind::Wild = closure_body.params[0].pat.kind {
-                                // span the area of the closure capture and warn that the
-                                // original error will be thrown away
-                                span_lint_and_help(
-                                    cx,
-                                    MAP_ERR_IGNORE,
-                                    fn_decl_span,
-                                    "`map_err(|_|...` wildcard pattern discards the original error",
-                                    None,
-                                    "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
-                                );
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs
index 0da4833f1df..34cc082687e 100644
--- a/clippy_lints/src/matches/match_like_matches.rs
+++ b/clippy_lints/src/matches/match_like_matches.rs
@@ -1,10 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 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_lint::LateContext;
+use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty;
 use rustc_span::source_map::Spanned;
 
@@ -76,6 +77,7 @@ where
         >,
 {
     if_chain! {
+        if !span_contains_comment(cx.sess().source_map(), expr.span);
         if iter.len() >= 2;
         if cx.typeck_results().expr_ty(expr).is_bool();
         if let Some((_, last_pat_opt, last_expr, _)) = iter.next_back();
diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs
index fa19cddd35e..6f037339ec7 100644
--- a/clippy_lints/src/matches/needless_match.rs
+++ b/clippy_lints/src/matches/needless_match.rs
@@ -8,7 +8,7 @@ use clippy_utils::{
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Node, Pat, PatKind, Path, QPath};
+use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath};
 use rustc_lint::LateContext;
 use rustc_span::sym;
 use rustc_typeck::hir_ty_to_ty;
@@ -65,8 +65,26 @@ pub(crate) fn check_if_let<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'_>, if_let:
 fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>]) -> bool {
     for arm in arms {
         let arm_expr = peel_blocks_with_stmt(arm.body);
+
+        if let Some(guard_expr) = &arm.guard {
+            match guard_expr {
+                // gives up if `pat if expr` can have side effects
+                Guard::If(if_cond) => {
+                    if if_cond.can_have_side_effects() {
+                        return false;
+                    }
+                },
+                // gives up `pat if let ...` arm
+                Guard::IfLet(_) => {
+                    return false;
+                },
+            };
+        }
+
         if let PatKind::Wild = arm.pat.kind {
-            return eq_expr_value(cx, match_expr, strip_return(arm_expr));
+            if !eq_expr_value(cx, match_expr, strip_return(arm_expr)) {
+                return false;
+            }
         } else if !pat_same_as_expr(arm.pat, arm_expr) {
             return false;
         }
diff --git a/clippy_lints/src/methods/bytecount.rs b/clippy_lints/src/methods/bytecount.rs
new file mode 100644
index 00000000000..6a7c63d76f7
--- /dev/null
+++ b/clippy_lints/src/methods/bytecount.rs
@@ -0,0 +1,70 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::match_type;
+use clippy_utils::visitors::is_local_used;
+use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, UintTy};
+use rustc_span::sym;
+
+use super::NAIVE_BYTECOUNT;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    filter_recv: &'tcx Expr<'_>,
+    filter_arg: &'tcx Expr<'_>,
+) {
+    if_chain! {
+        if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind;
+        let body = cx.tcx.hir().body(body);
+        if let [param] = body.params;
+        if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
+        if let ExprKind::Binary(ref op, l, r) = body.value.kind;
+        if op.node == BinOpKind::Eq;
+        if match_type(cx,
+                    cx.typeck_results().expr_ty(filter_recv).peel_refs(),
+                    &paths::SLICE_ITER);
+        let operand_is_arg = |expr| {
+            let expr = peel_ref_operators(cx, peel_blocks(expr));
+            path_to_local_id(expr, arg_id)
+        };
+        let needle = if operand_is_arg(l) {
+            r
+        } else if operand_is_arg(r) {
+            l
+        } else {
+            return;
+        };
+        if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
+        if !is_local_used(cx, needle, arg_id);
+        then {
+            let haystack = if let ExprKind::MethodCall(path, args, _) =
+                    filter_recv.kind {
+                let p = path.ident.name;
+                if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
+                    &args[0]
+                } else {
+                    filter_recv
+                }
+            } else {
+                filter_recv
+            };
+            let mut applicability = Applicability::MaybeIncorrect;
+            span_lint_and_sugg(
+                cx,
+                NAIVE_BYTECOUNT,
+                expr.span,
+                "you appear to be counting bytes the naive way",
+                "consider using the bytecount crate",
+                format!("bytecount::count({}, {})",
+                        snippet_with_applicability(cx, haystack.span, "..", &mut applicability),
+                        snippet_with_applicability(cx, needle.span, "..", &mut applicability)),
+                applicability,
+            );
+        }
+    };
+}
diff --git a/clippy_lints/src/methods/bytes_count_to_len.rs b/clippy_lints/src/methods/bytes_count_to_len.rs
new file mode 100644
index 00000000000..fcfc25b523d
--- /dev/null
+++ b/clippy_lints/src/methods/bytes_count_to_len.rs
@@ -0,0 +1,37 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::BYTES_COUNT_TO_LEN;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    count_recv: &'tcx hir::Expr<'_>,
+    bytes_recv: &'tcx hir::Expr<'_>,
+) {
+    if_chain! {
+        if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id);
+        if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id);
+        if cx.tcx.type_of(impl_id).is_str();
+        let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs();
+        if ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String);
+        then {
+            let mut applicability = Applicability::MachineApplicable;
+            span_lint_and_sugg(
+                cx,
+                BYTES_COUNT_TO_LEN,
+                expr.span,
+                "using long and hard to read `.bytes().count()`",
+                "consider calling `.len()` instead",
+                format!("{}.len()", snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)),
+                applicability
+            );
+        }
+    };
+}
diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
new file mode 100644
index 00000000000..b3c2c7c9a2d
--- /dev/null
+++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -0,0 +1,41 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::{source_map::Spanned, symbol::sym, Span};
+
+use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    call_span: Span,
+    recv: &'tcx Expr<'_>,
+    arg: &'tcx Expr<'_>,
+) {
+    if_chain! {
+        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 cx.tcx.type_of(impl_id).is_str();
+        if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind;
+        if (2..=6).contains(&ext_literal.as_str().len());
+        let ext_str = ext_literal.as_str();
+        if ext_str.starts_with('.');
+        if ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit())
+            || ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit());
+        let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs();
+        if recv_ty.is_str() || is_type_diagnostic_item(cx, recv_ty, sym::String);
+        then {
+            span_lint_and_help(
+                cx,
+                CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+                call_span,
+                "case-sensitive file extension comparison",
+                None,
+                "consider using a case-insensitive comparison instead",
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs
new file mode 100644
index 00000000000..561033be5b6
--- /dev/null
+++ b/clippy_lints/src/methods/collapsible_str_replace.rs
@@ -0,0 +1,96 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{eq_expr_value, get_parent_expr};
+use core::ops::ControlFlow;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use std::collections::VecDeque;
+
+use super::method_call;
+use super::COLLAPSIBLE_STR_REPLACE;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    from: &'tcx hir::Expr<'tcx>,
+    to: &'tcx hir::Expr<'tcx>,
+) {
+    let replace_methods = collect_replace_calls(cx, expr, to);
+    if replace_methods.methods.len() > 1 {
+        let from_kind = cx.typeck_results().expr_ty(from).peel_refs().kind();
+        // If the parent node's `to` argument is the same as the `to` argument
+        // of the last replace call in the current chain, don't lint as it was already linted
+        if let Some(parent) = get_parent_expr(cx, expr)
+            && let Some(("replace", [_, current_from, current_to], _)) = method_call(parent)
+            && eq_expr_value(cx, to, current_to)
+            && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
+        {
+            return;
+        }
+
+        check_consecutive_replace_calls(cx, expr, &replace_methods, to);
+    }
+}
+
+struct ReplaceMethods<'tcx> {
+    methods: VecDeque<&'tcx hir::Expr<'tcx>>,
+    from_args: VecDeque<&'tcx hir::Expr<'tcx>>,
+}
+
+fn collect_replace_calls<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    to_arg: &'tcx hir::Expr<'tcx>,
+) -> ReplaceMethods<'tcx> {
+    let mut methods = VecDeque::new();
+    let mut from_args = VecDeque::new();
+
+    let _: Option<()> = for_each_expr(expr, |e| {
+        if let Some(("replace", [_, from, to], _)) = method_call(e) {
+            if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
+                methods.push_front(e);
+                from_args.push_front(from);
+                ControlFlow::Continue(())
+            } else {
+                ControlFlow::BREAK
+            }
+        } else {
+            ControlFlow::Continue(())
+        }
+    });
+
+    ReplaceMethods { methods, from_args }
+}
+
+/// Check a chain of `str::replace` calls for `collapsible_str_replace` lint.
+fn check_consecutive_replace_calls<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'tcx>,
+    replace_methods: &ReplaceMethods<'tcx>,
+    to_arg: &'tcx hir::Expr<'tcx>,
+) {
+    let from_args = &replace_methods.from_args;
+    let from_arg_reprs: Vec<String> = from_args
+        .iter()
+        .map(|from_arg| snippet(cx, from_arg.span, "..").to_string())
+        .collect();
+    let app = Applicability::MachineApplicable;
+    let earliest_replace_call = replace_methods.methods.front().unwrap();
+    if let Some((_, [..], span_lo)) = method_call(earliest_replace_call) {
+        span_lint_and_sugg(
+            cx,
+            COLLAPSIBLE_STR_REPLACE,
+            expr.span.with_lo(span_lo.lo()),
+            "used consecutive `str::replace` call",
+            "replace with",
+            format!(
+                "replace([{}], {})",
+                from_arg_reprs.join(", "),
+                snippet(cx, to_arg.span, ".."),
+            ),
+            app,
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs
index 5ef08ca6290..d59fefa1ddc 100644
--- a/clippy_lints/src/methods/expect_used.rs
+++ b/clippy_lints/src/methods/expect_used.rs
@@ -7,18 +7,26 @@ use rustc_span::sym;
 
 use super::EXPECT_USED;
 
-/// lint use of `expect()` for `Option`s and `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_expect_in_tests: bool) {
+/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`.
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    recv: &hir::Expr<'_>,
+    is_err: bool,
+    allow_expect_in_tests: bool,
+) {
     let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
-    let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
+    let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
         Some((EXPECT_USED, "an Option", "None", ""))
     } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
-        Some((EXPECT_USED, "a Result", "Err", "an "))
+        Some((EXPECT_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
     } else {
         None
     };
 
+    let method = if is_err { "expect_err" } else { "expect" };
+
     if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
         return;
     }
@@ -28,7 +36,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
             cx,
             lint,
             expr.span,
-            &format!("used `expect()` on `{kind}` value"),
+            &format!("used `{method}()` on `{kind}` value"),
             None,
             &format!("if this value is {none_prefix}`{none_value}`, it will panic"),
         );
diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs
new file mode 100644
index 00000000000..4de77de7404
--- /dev/null
+++ b/clippy_lints/src/methods/get_first.rs
@@ -0,0 +1,39 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_slice_of_primitives;
+use clippy_utils::source::snippet_with_applicability;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+
+use super::GET_FIRST;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'_>,
+    arg: &'tcx hir::Expr<'_>,
+) {
+    if_chain! {
+        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 cx.tcx.type_of(impl_id).is_slice();
+        if let Some(_) = is_slice_of_primitives(cx, recv);
+        if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind;
+        then {
+            let mut app = Applicability::MachineApplicable;
+            let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
+            span_lint_and_sugg(
+                cx,
+                GET_FIRST,
+                expr.span,
+                &format!("accessing first element with `{0}.get(0)`", slice_name),
+                "try",
+                format!("{}.first()", slice_name),
+                app,
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
new file mode 100644
index 00000000000..cea7b0d82ff
--- /dev/null
+++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs
@@ -0,0 +1,107 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::{get_expr_use_or_unification_node, is_lang_ctor, is_no_std_crate};
+
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::{OptionNone, OptionSome};
+use rustc_hir::{Expr, ExprKind, Node};
+use rustc_lint::LateContext;
+
+use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS};
+
+enum IterType {
+    Iter,
+    IterMut,
+    IntoIter,
+}
+
+impl IterType {
+    fn ref_prefix(&self) -> &'static str {
+        match self {
+            Self::Iter => "&",
+            Self::IterMut => "&mut ",
+            Self::IntoIter => "",
+        }
+    }
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) {
+    let item = match &recv.kind {
+        ExprKind::Array(v) if v.len() <= 1 => v.first(),
+        ExprKind::Path(p) => {
+            if is_lang_ctor(cx, p, OptionNone) {
+                None
+            } else {
+                return;
+            }
+        },
+        ExprKind::Call(f, some_args) if some_args.len() == 1 => {
+            if let ExprKind::Path(p) = &f.kind {
+                if is_lang_ctor(cx, p, OptionSome) {
+                    Some(&some_args[0])
+                } else {
+                    return;
+                }
+            } else {
+                return;
+            }
+        },
+        _ => return,
+    };
+    let iter_type = match method_name {
+        "iter" => IterType::Iter,
+        "iter_mut" => IterType::IterMut,
+        "into_iter" => IterType::IntoIter,
+        _ => return,
+    };
+
+    let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) {
+        Some((Node::Expr(parent), child_id)) => match parent.kind {
+            ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false,
+            ExprKind::If(_, _, _)
+            | ExprKind::Match(_, _, _)
+            | ExprKind::Closure(_)
+            | ExprKind::Ret(_)
+            | ExprKind::Break(_, _) => true,
+            _ => false,
+        },
+        Some((Node::Stmt(_) | Node::Local(_), _)) => false,
+        _ => true,
+    };
+
+    if is_unified {
+        return;
+    }
+
+    if let Some(i) = item {
+        let sugg = format!(
+            "{}::iter::once({}{})",
+            if is_no_std_crate(cx) { "core" } else { "std" },
+            iter_type.ref_prefix(),
+            snippet(cx, i.span, "...")
+        );
+        span_lint_and_sugg(
+            cx,
+            ITER_ON_SINGLE_ITEMS,
+            expr.span,
+            &format!("`{method_name}` call on a collection with only one item"),
+            "try",
+            sugg,
+            Applicability::MaybeIncorrect,
+        );
+    } else {
+        span_lint_and_sugg(
+            cx,
+            ITER_ON_EMPTY_COLLECTIONS,
+            expr.span,
+            &format!("`{method_name}` call on an empty collection"),
+            "try",
+            if is_no_std_crate(cx) {
+                "core::iter::empty()".to_string()
+            } else {
+                "std::iter::empty()".to_string()
+            },
+            Applicability::MaybeIncorrect,
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs
new file mode 100644
index 00000000000..ffd2f4a38b8
--- /dev/null
+++ b/clippy_lints/src/methods/manual_ok_or.rs
@@ -0,0 +1,64 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_lang_ctor, path_to_local_id};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::{ResultErr, ResultOk};
+use rustc_hir::{Closure, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+
+use super::MANUAL_OK_OR;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    recv: &'tcx Expr<'_>,
+    or_expr: &'tcx Expr<'_>,
+    map_expr: &'tcx Expr<'_>,
+) {
+    if_chain! {
+        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), sym::Option);
+        if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, [err_arg]) = or_expr.kind;
+        if is_lang_ctor(cx, err_path, ResultErr);
+        if is_ok_wrapping(cx, map_expr);
+        if let Some(recv_snippet) = snippet_opt(cx, recv.span);
+        if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span);
+        if let Some(indent) = indent_of(cx, expr.span);
+        then {
+            let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4));
+            span_lint_and_sugg(
+                cx,
+                MANUAL_OK_OR,
+                expr.span,
+                "this pattern reimplements `Option::ok_or`",
+                "replace with",
+                format!(
+                    "{}.ok_or({})",
+                    recv_snippet,
+                    reindented_err_arg_snippet
+                ),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
+
+fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool {
+    if let ExprKind::Path(ref qpath) = map_expr.kind {
+        if is_lang_ctor(cx, qpath, ResultOk) {
+            return true;
+        }
+    }
+    if_chain! {
+        if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind;
+        let body = cx.tcx.hir().body(body);
+        if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind;
+        if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind;
+        if is_lang_ctor(cx, ok_path, ResultOk);
+        then { path_to_local_id(ok_arg, param_id) } else { false }
+    }
+}
diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs
new file mode 100644
index 00000000000..ffedda95ff8
--- /dev/null
+++ b/clippy_lints/src/methods/map_clone.rs
@@ -0,0 +1,122 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
+use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs, peel_blocks};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::mir::Mutability;
+use rustc_middle::ty;
+use rustc_middle::ty::adjustment::Adjust;
+use rustc_semver::RustcVersion;
+use rustc_span::symbol::Ident;
+use rustc_span::{sym, Span};
+
+use super::MAP_CLONE;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'_>,
+    e: &hir::Expr<'_>,
+    recv: &hir::Expr<'_>,
+    arg: &'tcx hir::Expr<'_>,
+    msrv: Option<RustcVersion>,
+) {
+    if_chain! {
+        if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id);
+        if cx.tcx.impl_of_method(method_id)
+            .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id), sym::Option))
+            || is_diag_trait_item(cx, method_id, sym::Iterator);
+        if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind;
+        then {
+            let closure_body = cx.tcx.hir().body(body);
+            let closure_expr = peel_blocks(&closure_body.value);
+            match closure_body.params[0].pat.kind {
+                hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
+                    hir::BindingAnnotation::Unannotated, .., name, None
+                ) = inner.kind {
+                    if ident_eq(name, closure_expr) {
+                        lint_explicit_closure(cx, e.span, recv.span, true, msrv);
+                    }
+                },
+                hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
+                    match closure_expr.kind {
+                        hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
+                            if ident_eq(name, inner) {
+                                if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
+                                    lint_explicit_closure(cx, e.span, recv.span, true, msrv);
+                                }
+                            }
+                        },
+                        hir::ExprKind::MethodCall(method, [obj], _) => if_chain! {
+                            if ident_eq(name, obj) && method.ident.name == sym::clone;
+                            if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
+                            if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
+                            if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id);
+                            // no autoderefs
+                            if !cx.typeck_results().expr_adjustments(obj).iter()
+                                .any(|a| matches!(a.kind, Adjust::Deref(Some(..))));
+                            then {
+                                let obj_ty = cx.typeck_results().expr_ty(obj);
+                                if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
+                                    if matches!(mutability, Mutability::Not) {
+                                        let copy = is_copy(cx, *ty);
+                                        lint_explicit_closure(cx, e.span, recv.span, copy, msrv);
+                                    }
+                                } else {
+                                    lint_needless_cloning(cx, e.span, recv.span);
+                                }
+                            }
+                        },
+                        _ => {},
+                    }
+                },
+                _ => {},
+            }
+        }
+    }
+}
+
+fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool {
+    if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind {
+        path.segments.len() == 1 && path.segments[0].ident == name
+    } else {
+        false
+    }
+}
+
+fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
+    span_lint_and_sugg(
+        cx,
+        MAP_CLONE,
+        root.trim_start(receiver).unwrap(),
+        "you are needlessly cloning iterator elements",
+        "remove the `map` call",
+        String::new(),
+        Applicability::MachineApplicable,
+    );
+}
+
+fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: Option<RustcVersion>) {
+    let mut applicability = Applicability::MachineApplicable;
+
+    let (message, sugg_method) = if is_copy && meets_msrv(msrv, msrvs::ITERATOR_COPIED) {
+        ("you are using an explicit closure for copying elements", "copied")
+    } else {
+        ("you are using an explicit closure for cloning elements", "cloned")
+    };
+
+    span_lint_and_sugg(
+        cx,
+        MAP_CLONE,
+        replace,
+        message,
+        &format!("consider calling the dedicated `{}` method", sugg_method),
+        format!(
+            "{}.{}()",
+            snippet_with_applicability(cx, root, "..", &mut applicability),
+            sugg_method,
+        ),
+        applicability,
+    );
+}
diff --git a/clippy_lints/src/methods/map_err_ignore.rs b/clippy_lints/src/methods/map_err_ignore.rs
new file mode 100644
index 00000000000..1fb6617145e
--- /dev/null
+++ b/clippy_lints/src/methods/map_err_ignore.rs
@@ -0,0 +1,34 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::MAP_ERR_IGNORE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'_>, e: &Expr<'_>, arg: &'tcx Expr<'_>) {
+    if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+        && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+        && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Result)
+        && let ExprKind::Closure(&Closure {
+            capture_clause: CaptureBy::Ref,
+            body,
+            fn_decl_span,
+            ..
+        }) = arg.kind
+        && let closure_body = cx.tcx.hir().body(body)
+        && let [param] = closure_body.params
+        && let PatKind::Wild = param.pat.kind
+    {
+        // span the area of the closure capture and warn that the
+        // original error will be thrown away
+        span_lint_and_help(
+            cx,
+            MAP_ERR_IGNORE,
+            fn_decl_span,
+            "`map_err(|_|...` wildcard pattern discards the original error",
+            None,
+            "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 5ac6b09f0aa..a0d190a58af 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -1,5 +1,8 @@
 mod bind_instead_of_map;
+mod bytecount;
+mod bytes_count_to_len;
 mod bytes_nth;
+mod case_sensitive_file_extension_comparisons;
 mod chars_cmp;
 mod chars_cmp_with_unwrap;
 mod chars_last_cmp;
@@ -9,6 +12,7 @@ mod chars_next_cmp_with_unwrap;
 mod clone_on_copy;
 mod clone_on_ref_ptr;
 mod cloned_instead_of_copied;
+mod collapsible_str_replace;
 mod err_expect;
 mod expect_fun_call;
 mod expect_used;
@@ -21,6 +25,7 @@ mod filter_next;
 mod flat_map_identity;
 mod flat_map_option;
 mod from_iter_instead_of_collect;
+mod get_first;
 mod get_last_with_len;
 mod get_unwrap;
 mod implicit_clone;
@@ -33,55 +38,72 @@ mod iter_count;
 mod iter_next_slice;
 mod iter_nth;
 mod iter_nth_zero;
+mod iter_on_single_or_empty_collections;
 mod iter_overeager_cloned;
 mod iter_skip_next;
 mod iter_with_drain;
 mod iterator_step_by_zero;
+mod manual_ok_or;
 mod manual_saturating_arithmetic;
 mod manual_str_repeat;
+mod map_clone;
 mod map_collect_result_unit;
+mod map_err_ignore;
 mod map_flatten;
 mod map_identity;
 mod map_unwrap_or;
+mod mut_mutex_lock;
 mod needless_option_as_deref;
 mod needless_option_take;
 mod no_effect_replace;
 mod obfuscated_if_else;
 mod ok_expect;
+mod open_options;
 mod option_as_ref_deref;
 mod option_map_or_none;
 mod option_map_unwrap_or;
 mod or_fun_call;
 mod or_then_unwrap;
+mod path_buf_push_overwrite;
+mod range_zip_with_len;
+mod repeat_once;
 mod search_is_some;
 mod single_char_add_str;
 mod single_char_insert_string;
 mod single_char_pattern;
 mod single_char_push_string;
 mod skip_while_next;
+mod stable_sort_primitive;
 mod str_splitn;
 mod string_extend_chars;
 mod suspicious_map;
 mod suspicious_splitn;
+mod suspicious_to_owned;
 mod uninit_assumed_init;
+mod unit_hash;
 mod unnecessary_filter_map;
 mod unnecessary_fold;
 mod unnecessary_iter_cloned;
 mod unnecessary_join;
 mod unnecessary_lazy_eval;
+mod unnecessary_sort_by;
 mod unnecessary_to_owned;
 mod unwrap_or_else_default;
 mod unwrap_used;
 mod useless_asref;
 mod utils;
+mod vec_resize_to_zero;
+mod verbose_file_reads;
 mod wrong_self_convention;
 mod zst_offset;
 
 use bind_instead_of_map::BindInsteadOfMap;
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
+use clippy_utils::ty::{contains_adt_constructor, implements_trait, is_copy, is_type_diagnostic_item};
+use clippy_utils::{
+    contains_return, get_trait_def_id, is_trait_method, iter_input_pats, meets_msrv, msrvs, paths, return_ty,
+};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -117,6 +139,32 @@ declare_clippy_lint! {
     "used `cloned` where `copied` could be used instead"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for consecutive calls to `str::replace` (2 or more)
+    /// that can be collapsed into a single call.
+    ///
+    /// ### Why is this bad?
+    /// Consecutive `str::replace` calls scan the string multiple times
+    /// with repetitive code.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let hello = "hesuo worpd"
+    ///     .replace('s', "l")
+    ///     .replace("u", "l")
+    ///     .replace('p', "l");
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l");
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub COLLAPSIBLE_STR_REPLACE,
+    perf,
+    "collapse consecutive calls to str::replace (2 or more) into a single call"
+}
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for usage of `_.cloned().<func>()` where call to `.cloned()` can be postponed.
@@ -173,7 +221,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `.unwrap()` calls on `Option`s and on `Result`s.
+    /// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s.
     ///
     /// ### Why is this bad?
     /// It is better to handle the `None` or `Err` case,
@@ -223,7 +271,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `.expect()` calls on `Option`s and `Result`s.
+    /// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s.
     ///
     /// ### Why is this bad?
     /// Usually it is better to handle the `None` or `Err` case.
@@ -2006,6 +2054,55 @@ declare_clippy_lint! {
     "replace `.iter().count()` with `.len()`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for the usage of `_.to_owned()`, on a `Cow<'_, _>`.
+    ///
+    /// ### Why is this bad?
+    /// Calling `to_owned()` on a `Cow` creates a clone of the `Cow`
+    /// itself, without taking ownership of the `Cow` contents (i.e.
+    /// it's equivalent to calling `Cow::clone`).
+    /// The similarly named `into_owned` method, on the other hand,
+    /// clones the `Cow` contents, effectively turning any `Cow::Borrowed`
+    /// into a `Cow::Owned`.
+    ///
+    /// Given the potential ambiguity, consider replacing `to_owned`
+    /// with `clone` for better readability or, if getting a `Cow::Owned`
+    /// was the original intent, using `into_owned` instead.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::borrow::Cow;
+    /// let s = "Hello world!";
+    /// let cow = Cow::Borrowed(s);
+    ///
+    /// let data = cow.to_owned();
+    /// assert!(matches!(data, Cow::Borrowed(_)))
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::borrow::Cow;
+    /// let s = "Hello world!";
+    /// let cow = Cow::Borrowed(s);
+    ///
+    /// let data = cow.clone();
+    /// assert!(matches!(data, Cow::Borrowed(_)))
+    /// ```
+    /// or
+    /// ```rust
+    /// # use std::borrow::Cow;
+    /// let s = "Hello world!";
+    /// let cow = Cow::Borrowed(s);
+    ///
+    /// let data = cow.into_owned();
+    /// assert!(matches!(data, String))
+    /// ```
+    #[clippy::version = "1.65.0"]
+    pub SUSPICIOUS_TO_OWNED,
+    suspicious,
+    "calls to `to_owned` on a `Cow<'_, _>` might not do what they are expected"
+}
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for calls to [`splitn`]
@@ -2269,7 +2366,7 @@ declare_clippy_lint! {
     /// "1234".replace("12", "12");
     /// "1234".replacen("12", "12", 1);
     /// ```
-    #[clippy::version = "1.62.0"]
+    #[clippy::version = "1.63.0"]
     pub NO_EFFECT_REPLACE,
     suspicious,
     "replace with no effect"
@@ -2304,6 +2401,640 @@ declare_clippy_lint! {
     more clearly with `if .. else ..`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item
+    ///
+    /// ### Why is this bad?
+    ///
+    /// It is simpler to use the once function from the standard library:
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let a = [123].iter();
+    /// let b = Some(123).into_iter();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::iter;
+    /// let a = iter::once(&123);
+    /// let b = iter::once(123);
+    /// ```
+    ///
+    /// ### Known problems
+    ///
+    /// The type of the resulting iterator might become incompatible with its usage
+    #[clippy::version = "1.64.0"]
+    pub ITER_ON_SINGLE_ITEMS,
+    nursery,
+    "Iterator for array of length 1"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections
+    ///
+    /// ### Why is this bad?
+    ///
+    /// It is simpler to use the empty function from the standard library:
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::{slice, option};
+    /// let a: slice::Iter<i32> = [].iter();
+    /// let f: option::IntoIter<i32> = None.into_iter();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::iter;
+    /// let a: iter::Empty<i32> = iter::empty();
+    /// let b: iter::Empty<i32> = iter::empty();
+    /// ```
+    ///
+    /// ### Known problems
+    ///
+    /// The type of the resulting iterator might become incompatible with its usage
+    #[clippy::version = "1.64.0"]
+    pub ITER_ON_EMPTY_COLLECTIONS,
+    nursery,
+    "Iterator for empty array"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for naive byte counts
+    ///
+    /// ### Why is this bad?
+    /// The [`bytecount`](https://crates.io/crates/bytecount)
+    /// crate has methods to count your bytes faster, especially for large slices.
+    ///
+    /// ### Known problems
+    /// If you have predominantly small slices, the
+    /// `bytecount::count(..)` method may actually be slower. However, if you can
+    /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
+    /// faster in those cases.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let vec = vec![1_u8];
+    /// let count = vec.iter().filter(|x| **x == 0u8).count();
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// # let vec = vec![1_u8];
+    /// let count = bytecount::count(&vec, 0u8);
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub NAIVE_BYTECOUNT,
+    pedantic,
+    "use of naive `<slice>.filter(|&x| x == y).count()` to count byte values"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// It checks for `str::bytes().count()` and suggests replacing it with
+    /// `str::len()`.
+    ///
+    /// ### Why is this bad?
+    /// `str::bytes().count()` is longer and may not be as performant as using
+    /// `str::len()`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// "hello".bytes().count();
+    /// String::from("hello").bytes().count();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// "hello".len();
+    /// String::from("hello").len();
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub BYTES_COUNT_TO_LEN,
+    complexity,
+    "Using `bytes().count()` when `len()` performs the same functionality"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `ends_with` with possible file extensions
+    /// and suggests to use a case-insensitive approach instead.
+    ///
+    /// ### Why is this bad?
+    /// `ends_with` is case-sensitive and may not detect files with a valid extension.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn is_rust_file(filename: &str) -> bool {
+    ///     filename.ends_with(".rs")
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn is_rust_file(filename: &str) -> bool {
+    ///     let filename = std::path::Path::new(filename);
+    ///     filename.extension()
+    ///         .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
+    /// }
+    /// ```
+    #[clippy::version = "1.51.0"]
+    pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+    pedantic,
+    "Checks for calls to ends_with with case-sensitive file extensions"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for using `x.get(0)` instead of
+    /// `x.first()`.
+    ///
+    /// ### Why is this bad?
+    /// Using `x.first()` is easier to read and has the same
+    /// result.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x = vec![2, 3, 5];
+    /// let first_element = x.get(0);
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// let x = vec![2, 3, 5];
+    /// let first_element = x.first();
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub GET_FIRST,
+    style,
+    "Using `x.get(0)` when `x.first()` is simpler"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Finds patterns that reimplement `Option::ok_or`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Concise code helps focusing on behavior instead of boilerplate.
+    ///
+    /// ### Examples
+    /// ```rust
+    /// let foo: Option<i32> = None;
+    /// foo.map_or(Err("error"), |v| Ok(v));
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// let foo: Option<i32> = None;
+    /// foo.ok_or("error");
+    /// ```
+    #[clippy::version = "1.49.0"]
+    pub MANUAL_OK_OR,
+    pedantic,
+    "finds patterns that can be encoded more concisely with `Option::ok_or`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `map(|x| x.clone())` or
+    /// dereferencing closures for `Copy` types, on `Iterator` or `Option`,
+    /// and suggests `cloned()` or `copied()` instead
+    ///
+    /// ### Why is this bad?
+    /// Readability, this can be written more concisely
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x = vec![42, 43];
+    /// let y = x.iter();
+    /// let z = y.map(|i| *i);
+    /// ```
+    ///
+    /// The correct use would be:
+    ///
+    /// ```rust
+    /// let x = vec![42, 43];
+    /// let y = x.iter();
+    /// let z = y.cloned();
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub MAP_CLONE,
+    style,
+    "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for instances of `map_err(|_| Some::Enum)`
+    ///
+    /// ### Why is this bad?
+    /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error
+    ///
+    /// ### Example
+    /// Before:
+    /// ```rust
+    /// use std::fmt;
+    ///
+    /// #[derive(Debug)]
+    /// enum Error {
+    ///     Indivisible,
+    ///     Remainder(u8),
+    /// }
+    ///
+    /// impl fmt::Display for Error {
+    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         match self {
+    ///             Error::Indivisible => write!(f, "could not divide input by three"),
+    ///             Error::Remainder(remainder) => write!(
+    ///                 f,
+    ///                 "input is not divisible by three, remainder = {}",
+    ///                 remainder
+    ///             ),
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// impl std::error::Error for Error {}
+    ///
+    /// fn divisible_by_3(input: &str) -> Result<(), Error> {
+    ///     input
+    ///         .parse::<i32>()
+    ///         .map_err(|_| Error::Indivisible)
+    ///         .map(|v| v % 3)
+    ///         .and_then(|remainder| {
+    ///             if remainder == 0 {
+    ///                 Ok(())
+    ///             } else {
+    ///                 Err(Error::Remainder(remainder as u8))
+    ///             }
+    ///         })
+    /// }
+    ///  ```
+    ///
+    ///  After:
+    ///  ```rust
+    /// use std::{fmt, num::ParseIntError};
+    ///
+    /// #[derive(Debug)]
+    /// enum Error {
+    ///     Indivisible(ParseIntError),
+    ///     Remainder(u8),
+    /// }
+    ///
+    /// impl fmt::Display for Error {
+    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         match self {
+    ///             Error::Indivisible(_) => write!(f, "could not divide input by three"),
+    ///             Error::Remainder(remainder) => write!(
+    ///                 f,
+    ///                 "input is not divisible by three, remainder = {}",
+    ///                 remainder
+    ///             ),
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// impl std::error::Error for Error {
+    ///     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+    ///         match self {
+    ///             Error::Indivisible(source) => Some(source),
+    ///             _ => None,
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// fn divisible_by_3(input: &str) -> Result<(), Error> {
+    ///     input
+    ///         .parse::<i32>()
+    ///         .map_err(Error::Indivisible)
+    ///         .map(|v| v % 3)
+    ///         .and_then(|remainder| {
+    ///             if remainder == 0 {
+    ///                 Ok(())
+    ///             } else {
+    ///                 Err(Error::Remainder(remainder as u8))
+    ///             }
+    ///         })
+    /// }
+    /// ```
+    #[clippy::version = "1.48.0"]
+    pub MAP_ERR_IGNORE,
+    restriction,
+    "`map_err` should not ignore the original error"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `&mut Mutex::lock` calls
+    ///
+    /// ### Why is this bad?
+    /// `Mutex::lock` is less efficient than
+    /// calling `Mutex::get_mut`. In addition you also have a statically
+    /// guarantee that the mutex isn't locked, instead of just a runtime
+    /// guarantee.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::sync::{Arc, Mutex};
+    ///
+    /// let mut value_rc = Arc::new(Mutex::new(42_u8));
+    /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
+    ///
+    /// let mut value = value_mutex.lock().unwrap();
+    /// *value += 1;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::sync::{Arc, Mutex};
+    ///
+    /// let mut value_rc = Arc::new(Mutex::new(42_u8));
+    /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
+    ///
+    /// let value = value_mutex.get_mut().unwrap();
+    /// *value += 1;
+    /// ```
+    #[clippy::version = "1.49.0"]
+    pub MUT_MUTEX_LOCK,
+    style,
+    "`&mut Mutex::lock` does unnecessary locking"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for duplicate open options as well as combinations
+    /// that make no sense.
+    ///
+    /// ### Why is this bad?
+    /// In the best case, the code will be harder to read than
+    /// necessary. I don't know the worst case.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::fs::OpenOptions;
+    ///
+    /// OpenOptions::new().read(true).truncate(true);
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub NONSENSICAL_OPEN_OPTIONS,
+    correctness,
+    "nonsensical combination of options for opening a file"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push)
+    /// calls on `PathBuf` that can cause overwrites.
+    ///
+    /// ### Why is this bad?
+    /// Calling `push` with a root path at the start can overwrite the
+    /// previous defined path.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::path::PathBuf;
+    ///
+    /// let mut x = PathBuf::from("/foo");
+    /// x.push("/bar");
+    /// assert_eq!(x, PathBuf::from("/bar"));
+    /// ```
+    /// Could be written:
+    ///
+    /// ```rust
+    /// use std::path::PathBuf;
+    ///
+    /// let mut x = PathBuf::from("/foo");
+    /// x.push("bar");
+    /// assert_eq!(x, PathBuf::from("/foo/bar"));
+    /// ```
+    #[clippy::version = "1.36.0"]
+    pub PATH_BUF_PUSH_OVERWRITE,
+    nursery,
+    "calling `push` with file system root on `PathBuf` can overwrite it"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for zipping a collection with the range of
+    /// `0.._.len()`.
+    ///
+    /// ### Why is this bad?
+    /// The code is better expressed with `.enumerate()`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let x = vec![1];
+    /// let _ = x.iter().zip(0..x.len());
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// # let x = vec![1];
+    /// let _ = x.iter().enumerate();
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub RANGE_ZIP_WITH_LEN,
+    complexity,
+    "zipping iterator with a range when `enumerate()` would do"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `.repeat(1)` and suggest the following method for each types.
+    /// - `.to_string()` for `str`
+    /// - `.clone()` for `String`
+    /// - `.to_vec()` for `slice`
+    ///
+    /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if
+    /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))
+    ///
+    /// ### Why is this bad?
+    /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning
+    /// the string is the intention behind this, `clone()` should be used.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn main() {
+    ///     let x = String::from("hello world").repeat(1);
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn main() {
+    ///     let x = String::from("hello world").clone();
+    /// }
+    /// ```
+    #[clippy::version = "1.47.0"]
+    pub REPEAT_ONCE,
+    complexity,
+    "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// When sorting primitive values (integers, bools, chars, as well
+    /// as arrays, slices, and tuples of such items), it is typically better to
+    /// use an unstable sort than a stable sort.
+    ///
+    /// ### Why is this bad?
+    /// Typically, using a stable sort consumes more memory and cpu cycles.
+    /// Because values which compare equal are identical, preserving their
+    /// relative order (the guarantee that a stable sort provides) means
+    /// nothing, while the extra costs still apply.
+    ///
+    /// ### Known problems
+    ///
+    /// As pointed out in
+    /// [issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241),
+    /// a stable sort can instead be significantly faster for certain scenarios
+    /// (eg. when a sorted vector is extended with new data and resorted).
+    ///
+    /// For more information and benchmarking results, please refer to the
+    /// issue linked above.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let mut vec = vec![2, 1, 3];
+    /// vec.sort();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let mut vec = vec![2, 1, 3];
+    /// vec.sort_unstable();
+    /// ```
+    #[clippy::version = "1.47.0"]
+    pub STABLE_SORT_PRIMITIVE,
+    pedantic,
+    "use of sort() when sort_unstable() is equivalent"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects `().hash(_)`.
+    ///
+    /// ### Why is this bad?
+    /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::hash::Hash;
+    /// # use std::collections::hash_map::DefaultHasher;
+    /// # enum Foo { Empty, WithValue(u8) }
+    /// # use Foo::*;
+    /// # let mut state = DefaultHasher::new();
+    /// # let my_enum = Foo::Empty;
+    /// match my_enum {
+    /// 	Empty => ().hash(&mut state),
+    /// 	WithValue(x) => x.hash(&mut state),
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::hash::Hash;
+    /// # use std::collections::hash_map::DefaultHasher;
+    /// # enum Foo { Empty, WithValue(u8) }
+    /// # use Foo::*;
+    /// # let mut state = DefaultHasher::new();
+    /// # let my_enum = Foo::Empty;
+    /// match my_enum {
+    /// 	Empty => 0_u8.hash(&mut state),
+    /// 	WithValue(x) => x.hash(&mut state),
+    /// }
+    /// ```
+    #[clippy::version = "1.58.0"]
+    pub UNIT_HASH,
+    correctness,
+    "hashing a unit value, which does nothing"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects uses of `Vec::sort_by` passing in a closure
+    /// which compares the two arguments, either directly or indirectly.
+    ///
+    /// ### Why is this bad?
+    /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
+    /// possible) than to use `Vec::sort_by` and a more complicated
+    /// closure.
+    ///
+    /// ### Known problems
+    /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
+    /// imported by a use statement, then it will need to be added manually.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # struct A;
+    /// # impl A { fn foo(&self) {} }
+    /// # let mut vec: Vec<A> = Vec::new();
+    /// vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # struct A;
+    /// # impl A { fn foo(&self) {} }
+    /// # let mut vec: Vec<A> = Vec::new();
+    /// vec.sort_by_key(|a| a.foo());
+    /// ```
+    #[clippy::version = "1.46.0"]
+    pub UNNECESSARY_SORT_BY,
+    complexity,
+    "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Finds occurrences of `Vec::resize(0, an_int)`
+    ///
+    /// ### Why is this bad?
+    /// This is probably an argument inversion mistake.
+    ///
+    /// ### Example
+    /// ```rust
+    /// vec!(1, 2, 3, 4, 5).resize(0, 5)
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// vec!(1, 2, 3, 4, 5).clear()
+    /// ```
+    #[clippy::version = "1.46.0"]
+    pub VEC_RESIZE_TO_ZERO,
+    correctness,
+    "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for use of File::read_to_end and File::read_to_string.
+    ///
+    /// ### Why is this bad?
+    /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values.
+    /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html)
+    ///
+    /// ### Example
+    /// ```rust,no_run
+    /// # use std::io::Read;
+    /// # use std::fs::File;
+    /// let mut f = File::open("foo.txt").unwrap();
+    /// let mut bytes = Vec::new();
+    /// f.read_to_end(&mut bytes).unwrap();
+    /// ```
+    /// Can be written more concisely as
+    /// ```rust,no_run
+    /// # use std::fs;
+    /// let mut bytes = fs::read("foo.txt").unwrap();
+    /// ```
+    #[clippy::version = "1.44.0"]
+    pub VERBOSE_FILE_READS,
+    restriction,
+    "use of `File::read_to_end` or `File::read_to_string`"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Option<RustcVersion>,
@@ -2347,6 +3078,7 @@ impl_lint_pass!(Methods => [
     CLONE_ON_COPY,
     CLONE_ON_REF_PTR,
     CLONE_DOUBLE_REF,
+    COLLAPSIBLE_STR_REPLACE,
     ITER_OVEREAGER_CLONED,
     CLONED_INSTEAD_OF_COPIED,
     FLAT_MAP_OPTION,
@@ -2393,6 +3125,7 @@ impl_lint_pass!(Methods => [
     FROM_ITER_INSTEAD_OF_COLLECT,
     INSPECT_FOR_EACH,
     IMPLICIT_CLONE,
+    SUSPICIOUS_TO_OWNED,
     SUSPICIOUS_SPLITN,
     MANUAL_STR_REPEAT,
     EXTEND_WITH_DRAIN,
@@ -2406,6 +3139,25 @@ impl_lint_pass!(Methods => [
     NEEDLESS_OPTION_TAKE,
     NO_EFFECT_REPLACE,
     OBFUSCATED_IF_ELSE,
+    ITER_ON_SINGLE_ITEMS,
+    ITER_ON_EMPTY_COLLECTIONS,
+    NAIVE_BYTECOUNT,
+    BYTES_COUNT_TO_LEN,
+    CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
+    GET_FIRST,
+    MANUAL_OK_OR,
+    MAP_CLONE,
+    MAP_ERR_IGNORE,
+    MUT_MUTEX_LOCK,
+    NONSENSICAL_OPEN_OPTIONS,
+    PATH_BUF_PUSH_OVERWRITE,
+    RANGE_ZIP_WITH_LEN,
+    REPEAT_ONCE,
+    STABLE_SORT_PRIMITIVE,
+    UNIT_HASH,
+    UNNECESSARY_SORT_BY,
+    VEC_RESIZE_TO_ZERO,
+    VERBOSE_FILE_READS,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -2541,7 +3293,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 if contains_adt_constructor(ret_ty, self_adt) {
                     return;
                 }
-            } else if contains_ty(ret_ty, self_ty) {
+            } else if ret_ty.contains(self_ty) {
                 return;
             }
 
@@ -2559,7 +3311,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                             if contains_adt_constructor(assoc_ty, self_adt) {
                                 return;
                             }
-                        } else if contains_ty(assoc_ty, self_ty) {
+                        } else if assoc_ty.contains(self_ty) {
                             return;
                         }
                     }
@@ -2608,7 +3360,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             if let TraitItemKind::Fn(_, _) = item.kind;
             let ret_ty = return_ty(cx, item.hir_id());
             let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder();
-            if !contains_ty(ret_ty, self_ty);
+            if !ret_ty.contains(self_ty);
 
             then {
                 span_lint(
@@ -2660,22 +3412,30 @@ impl Methods {
                     },
                     _ => {},
                 },
-                ("count", []) => match method_call(recv) {
+                ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
                     Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
                     Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
                         iter_count::check(cx, expr, recv2, name2);
                     },
                     Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
+                    Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg),
+                    Some(("bytes", [recv2], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
                     _ => {},
                 },
                 ("drain", [arg]) => {
                     iter_with_drain::check(cx, expr, recv, span, arg);
                 },
+                ("ends_with", [arg]) => {
+                    if let ExprKind::MethodCall(_, _, span) = expr.kind {
+                        case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
+                    }
+                },
                 ("expect", [_]) => match method_call(recv) {
                     Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
                     Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
-                    _ => expect_used::check(cx, expr, recv, self.allow_expect_in_tests),
+                    _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
                 },
+                ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
                 ("extend", [arg]) => {
                     string_extend_chars::check(cx, expr, recv, arg);
                     extend_with_drain::check(cx, expr, recv, arg);
@@ -2702,12 +3462,21 @@ impl Methods {
                         inspect_for_each::check(cx, expr, span2);
                     }
                 },
-                ("get", [arg]) => get_last_with_len::check(cx, expr, recv, arg),
+                ("get", [arg]) => {
+                    get_first::check(cx, expr, recv, arg);
+                    get_last_with_len::check(cx, expr, recv, arg);
+                },
                 ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
+                ("hash", [arg]) => {
+                    unit_hash::check(cx, expr, recv, arg);
+                },
                 ("is_file", []) => filetype_is_file::check(cx, expr, recv),
                 ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
                 ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
                 ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
+                ("iter" | "iter_mut" | "into_iter", []) => {
+                    iter_on_single_or_empty_collections::check(cx, expr, name, recv);
+                },
                 ("join", [join_arg]) => {
                     if let Some(("collect", _, span)) = method_call(recv) {
                         unnecessary_join::check(cx, expr, recv, join_arg, span);
@@ -2720,7 +3489,15 @@ impl Methods {
                         }
                     }
                 },
+                ("lock", []) => {
+                    mut_mutex_lock::check(cx, expr, recv, span);
+                },
                 (name @ ("map" | "map_err"), [m_arg]) => {
+                    if name == "map" {
+                        map_clone::check(cx, expr, recv, m_arg, self.msrv);
+                    } else {
+                        map_err_ignore::check(cx, expr, m_arg);
+                    }
                     if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
                         match (name, args) {
                             ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
@@ -2736,7 +3513,10 @@ impl Methods {
                     }
                     map_identity::check(cx, expr, recv, m_arg, name, span);
                 },
-                ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
+                ("map_or", [def, map]) => {
+                    option_map_or_none::check(cx, expr, recv, def, map);
+                    manual_ok_or::check(cx, expr, recv, def, map);
+                },
                 ("next", []) => {
                     if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
                         match (name2, args2) {
@@ -2758,11 +3538,46 @@ impl Methods {
                     _ => iter_nth_zero::check(cx, expr, recv, n_arg),
                 },
                 ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
+                ("open", [_]) => {
+                    open_options::check(cx, expr, recv);
+                },
                 ("or_else", [arg]) => {
                     if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
                         unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
                     }
                 },
+                ("push", [arg]) => {
+                    path_buf_push_overwrite::check(cx, expr, arg);
+                },
+                ("read_to_end", [_]) => {
+                    verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG);
+                },
+                ("read_to_string", [_]) => {
+                    verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG);
+                },
+                ("repeat", [arg]) => {
+                    repeat_once::check(cx, expr, recv, arg);
+                },
+                (name @ ("replace" | "replacen"), [arg1, arg2] | [arg1, arg2, _]) => {
+                    no_effect_replace::check(cx, expr, arg1, arg2);
+
+                    // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint
+                    if name == "replace" && let Some(("replace", ..)) = method_call(recv) {
+                        collapsible_str_replace::check(cx, expr, arg1, arg2);
+                    }
+                },
+                ("resize", [count_arg, default_arg]) => {
+                    vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span);
+                },
+                ("sort", []) => {
+                    stable_sort_primitive::check(cx, expr, recv);
+                },
+                ("sort_by", [arg]) => {
+                    unnecessary_sort_by::check(cx, expr, recv, arg, false);
+                },
+                ("sort_unstable_by", [arg]) => {
+                    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) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
@@ -2789,7 +3604,12 @@ impl Methods {
                     }
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
                 },
-                ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
+                ("to_owned", []) => {
+                    if !suspicious_to_owned::check(cx, expr, recv) {
+                        implicit_clone::check(cx, name, expr, recv);
+                    }
+                },
+                ("to_os_string" | "to_path_buf" | "to_vec", []) => {
                     implicit_clone::check(cx, name, expr, recv);
                 },
                 ("unwrap", []) => {
@@ -2805,8 +3625,9 @@ impl Methods {
                         },
                         _ => {},
                     }
-                    unwrap_used::check(cx, expr, recv, self.allow_unwrap_in_tests);
+                    unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
                 },
+                ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
                 ("unwrap_or", [u_arg]) => match method_call(recv) {
                     Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
                         manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
@@ -2827,8 +3648,12 @@ impl Methods {
                         unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
                     },
                 },
-                ("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => {
-                    no_effect_replace::check(cx, expr, arg1, arg2);
+                ("zip", [arg]) => {
+                    if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind
+                        && name.ident.name == sym::iter
+                    {
+                        range_zip_with_len::check(cx, expr, iter_recv, arg);
+                    }
                 },
                 _ => {},
             }
diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs
new file mode 100644
index 00000000000..bd8458a222e
--- /dev/null
+++ b/clippy_lints/src/methods/mut_mutex_lock.rs
@@ -0,0 +1,30 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, Mutability};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::{sym, Span};
+
+use super::MUT_MUTEX_LOCK;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) {
+    if_chain! {
+        if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind();
+        if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.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), sym::Mutex);
+        then {
+            span_lint_and_sugg(
+                cx,
+                MUT_MUTEX_LOCK,
+                name_span,
+                "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference",
+                "change this to",
+                "get_mut".to_owned(),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/methods/open_options.rs
similarity index 80%
rename from clippy_lints/src/open_options.rs
rename to clippy_lints/src/methods/open_options.rs
index 5a0b5042018..c3112823e34 100644
--- a/clippy_lints/src/open_options.rs
+++ b/clippy_lints/src/methods/open_options.rs
@@ -3,43 +3,19 @@ use clippy_utils::paths;
 use clippy_utils::ty::match_type;
 use rustc_ast::ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_lint::LateContext;
 use rustc_span::source_map::{Span, Spanned};
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for duplicate open options as well as combinations
-    /// that make no sense.
-    ///
-    /// ### Why is this bad?
-    /// In the best case, the code will be harder to read than
-    /// necessary. I don't know the worst case.
-    ///
-    /// ### Example
-    /// ```rust
-    /// use std::fs::OpenOptions;
-    ///
-    /// OpenOptions::new().read(true).truncate(true);
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub NONSENSICAL_OPEN_OPTIONS,
-    correctness,
-    "nonsensical combination of options for opening a file"
-}
+use super::NONSENSICAL_OPEN_OPTIONS;
 
-declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]);
-
-impl<'tcx> LateLintPass<'tcx> for OpenOptions {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::MethodCall(path, [self_arg, ..], _) = &e.kind {
-            let obj_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
-            if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) {
-                let mut options = Vec::new();
-                get_open_options(cx, self_arg, &mut options);
-                check_open_options(cx, &options, e.span);
-            }
-        }
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
+    if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+        && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+        && match_type(cx, cx.tcx.type_of(impl_id), &paths::OPEN_OPTIONS)
+    {
+        let mut options = Vec::new();
+        get_open_options(cx, recv, &mut options);
+        check_open_options(cx, &options, e.span);
     }
 }
 
diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs
index 6c641af59f9..3c4002a3aef 100644
--- a/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -78,7 +78,7 @@ pub(super) fn check<'tcx>(
                     map_span,
                     String::from(if unwrap_snippet_none { "and_then" } else { "map_or" }),
                 ),
-                (expr.span.with_lo(unwrap_recv.span.hi()), String::from("")),
+                (expr.span.with_lo(unwrap_recv.span.hi()), String::new()),
             ];
 
             if !unwrap_snippet_none {
diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs
new file mode 100644
index 00000000000..0cc28c0dcb3
--- /dev/null
+++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs
@@ -0,0 +1,37 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+use std::path::{Component, Path};
+
+use super::PATH_BUF_PUSH_OVERWRITE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
+    if_chain! {
+        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), sym::PathBuf);
+        if let ExprKind::Lit(ref 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();
+        if pushed_path.has_root();
+        if let Some(root) = pushed_path.components().next();
+        if root == Component::RootDir;
+        then {
+            span_lint_and_sugg(
+                cx,
+                PATH_BUF_PUSH_OVERWRITE,
+                lit.span,
+                "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition",
+                "try",
+                format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs
new file mode 100644
index 00000000000..00a2a0d14d1
--- /dev/null
+++ b/clippy_lints/src/methods/range_zip_with_len.rs
@@ -0,0 +1,34 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::source::snippet;
+use clippy_utils::{higher, SpanlessEq};
+use clippy_utils::{is_integer_const, is_trait_method};
+use if_chain::if_chain;
+use rustc_hir::{Expr, ExprKind, QPath};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::RANGE_ZIP_WITH_LEN;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, zip_arg: &'tcx Expr<'_>) {
+    if_chain! {
+        if is_trait_method(cx, expr, sym::Iterator);
+        // range expression in `.zip()` call: `0..x.len()`
+        if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
+        if is_integer_const(cx, start, 0);
+        // `.len()` call
+        if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind;
+        if len_path.ident.name == sym::len;
+        // `.iter()` and `.len()` called on same `Path`
+        if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind;
+        if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind;
+        if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
+        then {
+            span_lint(cx,
+                RANGE_ZIP_WITH_LEN,
+                expr.span,
+                &format!("it is more idiomatic to use `{}.iter().enumerate()`",
+                    snippet(cx, recv.span, "_"))
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/methods/repeat_once.rs b/clippy_lints/src/methods/repeat_once.rs
new file mode 100644
index 00000000000..0a14f9216ab
--- /dev/null
+++ b/clippy_lints/src/methods/repeat_once.rs
@@ -0,0 +1,52 @@
+use clippy_utils::consts::{constant_context, Constant};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::REPEAT_ONCE;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    recv: &'tcx Expr<'_>,
+    repeat_arg: &'tcx Expr<'_>,
+) {
+    if constant_context(cx, cx.typeck_results()).expr(repeat_arg) == Some(Constant::Int(1)) {
+        let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+        if ty.is_str() {
+            span_lint_and_sugg(
+                cx,
+                REPEAT_ONCE,
+                expr.span,
+                "calling `repeat(1)` on str",
+                "consider using `.to_string()` instead",
+                format!("{}.to_string()", snippet(cx, recv.span, r#""...""#)),
+                Applicability::MachineApplicable,
+            );
+        } else if ty.builtin_index().is_some() {
+            span_lint_and_sugg(
+                cx,
+                REPEAT_ONCE,
+                expr.span,
+                "calling `repeat(1)` on slice",
+                "consider using `.to_vec()` instead",
+                format!("{}.to_vec()", snippet(cx, recv.span, r#""...""#)),
+                Applicability::MachineApplicable,
+            );
+        } else if is_type_diagnostic_item(cx, ty, sym::String) {
+            span_lint_and_sugg(
+                cx,
+                REPEAT_ONCE,
+                expr.span,
+                "calling `repeat(1)` on a string literal",
+                "consider using `.clone()` instead",
+                format!("{}.clone()", snippet(cx, recv.span, r#""...""#)),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/methods/stable_sort_primitive.rs b/clippy_lints/src/methods/stable_sort_primitive.rs
new file mode 100644
index 00000000000..91951c65bb3
--- /dev/null
+++ b/clippy_lints/src/methods/stable_sort_primitive.rs
@@ -0,0 +1,31 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_slice_of_primitives;
+use clippy_utils::source::snippet_with_context;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+
+use super::STABLE_SORT_PRIMITIVE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
+    if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+        && let Some(impl_id) = cx.tcx.impl_of_method(method_id)
+        && cx.tcx.type_of(impl_id).is_slice()
+        && let Some(slice_type) = is_slice_of_primitives(cx, recv)
+    {
+        span_lint_and_then(
+            cx,
+            STABLE_SORT_PRIMITIVE,
+            e.span,
+            &format!("used `sort` on primitive type `{}`", slice_type),
+            |diag| {
+                let mut app = Applicability::MachineApplicable;
+                let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0;
+                diag.span_suggestion(e.span, "try", format!("{}.sort_unstable()", recv_snip), app);
+                diag.note(
+                    "an unstable sort typically performs faster without any observable difference for this data type",
+                );
+            },
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs
new file mode 100644
index 00000000000..6b306fbf008
--- /dev/null
+++ b/clippy_lints/src/methods/suspicious_to_owned.rs
@@ -0,0 +1,36 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_diag_trait_item;
+use clippy_utils::source::snippet_with_context;
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::sym;
+
+use super::SUSPICIOUS_TO_OWNED;
+
+pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -> bool {
+    if_chain! {
+        if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+        if is_diag_trait_item(cx, method_def_id, sym::ToOwned);
+        let input_type = cx.typeck_results().expr_ty(expr);
+        if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind();
+        if cx.tcx.is_diagnostic_item(sym::Cow, adt.did());
+        then {
+            let mut app = Applicability::MaybeIncorrect;
+            let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
+            span_lint_and_sugg(
+                cx,
+                SUSPICIOUS_TO_OWNED,
+                expr.span,
+                &format!("this `to_owned` call clones the {0} itself and does not cause the {0} contents to become owned", input_type),
+                "consider using, depending on intent",
+                format!("{0}.clone()` or `{0}.into_owned()", recv_snip),
+                app,
+            );
+            return true;
+        }
+    }
+    false
+}
diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs
index 77d21f1d373..a1c6294737c 100644
--- a/clippy_lints/src/methods/uninit_assumed_init.rs
+++ b/clippy_lints/src/methods/uninit_assumed_init.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_expr_diagnostic_item, ty::is_uninit_value_valid_for_ty};
+use clippy_utils::{is_path_diagnostic_item, ty::is_uninit_value_valid_for_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
     if_chain! {
         if let hir::ExprKind::Call(callee, args) = recv.kind;
         if args.is_empty();
-        if is_expr_diagnostic_item(cx, callee, sym::maybe_uninit_uninit);
+        if is_path_diagnostic_item(cx, callee, sym::maybe_uninit_uninit);
         if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr));
         then {
             span_lint(
diff --git a/clippy_lints/src/methods/unit_hash.rs b/clippy_lints/src/methods/unit_hash.rs
new file mode 100644
index 00000000000..3c7955bc469
--- /dev/null
+++ b/clippy_lints/src/methods/unit_hash.rs
@@ -0,0 +1,29 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_trait_method;
+use clippy_utils::source::snippet;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::UNIT_HASH;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
+    if is_trait_method(cx, expr, sym::Hash) && cx.typeck_results().expr_ty(recv).is_unit() {
+        span_lint_and_then(
+            cx,
+            UNIT_HASH,
+            expr.span,
+            "this call to `hash` on the unit type will do nothing",
+            |diag| {
+                diag.span_suggestion(
+                    expr.span,
+                    "remove the call to `hash` or consider using",
+                    format!("0_u8.hash({})", snippet(cx, arg.span, ".."),),
+                    Applicability::MaybeIncorrect,
+                );
+                diag.note("the implementation of `Hash` for `()` is a no-op");
+            },
+        );
+    }
+}
diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs
similarity index 63%
rename from clippy_lints/src/unnecessary_sort_by.rs
rename to clippy_lints/src/methods/unnecessary_sort_by.rs
index ea5aadbbca1..1966990bd77 100644
--- a/clippy_lints/src/unnecessary_sort_by.rs
+++ b/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -1,51 +1,17 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_trait_method;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::ty::implements_trait;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::LateContext;
 use rustc_middle::ty::{self, subst::GenericArgKind};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
 use rustc_span::symbol::Ident;
 use std::iter;
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Detects uses of `Vec::sort_by` passing in a closure
-    /// which compares the two arguments, either directly or indirectly.
-    ///
-    /// ### Why is this bad?
-    /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
-    /// possible) than to use `Vec::sort_by` and a more complicated
-    /// closure.
-    ///
-    /// ### Known problems
-    /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
-    /// imported by a use statement, then it will need to be added manually.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # struct A;
-    /// # impl A { fn foo(&self) {} }
-    /// # let mut vec: Vec<A> = Vec::new();
-    /// vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// # struct A;
-    /// # impl A { fn foo(&self) {} }
-    /// # let mut vec: Vec<A> = Vec::new();
-    /// vec.sort_by_key(|a| a.foo());
-    /// ```
-    #[clippy::version = "1.46.0"]
-    pub UNNECESSARY_SORT_BY,
-    complexity,
-    "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer"
-}
-
-declare_lint_pass!(UnnecessarySortBy => [UNNECESSARY_SORT_BY]);
+use super::UNNECESSARY_SORT_BY;
 
 enum LintTrigger {
     Sort(SortDetection),
@@ -54,7 +20,6 @@ enum LintTrigger {
 
 struct SortDetection {
     vec_name: String,
-    unstable: bool,
 }
 
 struct SortByKeyDetection {
@@ -62,7 +27,6 @@ struct SortByKeyDetection {
     closure_arg: String,
     closure_body: String,
     reverse: bool,
-    unstable: bool,
 }
 
 /// Detect if the two expressions are mirrored (identical, except one
@@ -150,20 +114,20 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident
     }
 }
 
-fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
+fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) -> Option<LintTrigger> {
     if_chain! {
-        if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind;
-        if let name = name_ident.ident.name.to_ident_string();
-        if name == "sort_by" || name == "sort_unstable_by";
-        if let [vec, Expr { kind: ExprKind::Closure(Closure { body: closure_body_id, .. }), .. }] = args;
-        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec);
-        if let closure_body = cx.tcx.hir().body(*closure_body_id);
+        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 cx.tcx.type_of(impl_id).is_slice();
+        if let ExprKind::Closure(&Closure { body, .. }) = arg.kind;
+        if let closure_body = cx.tcx.hir().body(body);
         if let &[
             Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
             Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
         ] = &closure_body.params;
-        if let ExprKind::MethodCall(method_path, [ref left_expr, ref right_expr], _) = &closure_body.value.kind;
+        if let ExprKind::MethodCall(method_path, [left_expr, right_expr], _) = closure_body.value.kind;
         if method_path.ident.name == sym::cmp;
+        if is_trait_method(cx, &closure_body.value, sym::Ord);
         then {
             let (closure_body, closure_arg, reverse) = if mirrored_exprs(
                 left_expr,
@@ -177,19 +141,18 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
             } else {
                 return None;
             };
-            let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
-            let unstable = name == "sort_unstable_by";
+            let vec_name = Sugg::hir(cx, recv, "..").to_string();
 
             if_chain! {
-            if let ExprKind::Path(QPath::Resolved(_, Path {
-                segments: [PathSegment { ident: left_name, .. }], ..
-            })) = &left_expr.kind;
-            if left_name == left_ident;
-            if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
-                implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
-            });
+                if let ExprKind::Path(QPath::Resolved(_, Path {
+                    segments: [PathSegment { ident: left_name, .. }], ..
+                })) = &left_expr.kind;
+                if left_name == left_ident;
+                if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
+                    implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
+                });
                 then {
-                    return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }));
+                    return Some(LintTrigger::Sort(SortDetection { vec_name }));
                 }
             }
 
@@ -199,7 +162,6 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
                     closure_arg,
                     closure_body,
                     reverse,
-                    unstable,
                 }));
             }
         }
@@ -213,46 +175,50 @@ fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
 }
 
-impl LateLintPass<'_> for UnnecessarySortBy {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        match detect_lint(cx, expr) {
-            Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg(
-                cx,
-                UNNECESSARY_SORT_BY,
-                expr.span,
-                "use Vec::sort_by_key here instead",
-                "try",
-                format!(
-                    "{}.sort{}_by_key(|{}| {})",
-                    trigger.vec_name,
-                    if trigger.unstable { "_unstable" } else { "" },
-                    trigger.closure_arg,
-                    if trigger.reverse {
-                        format!("std::cmp::Reverse({})", trigger.closure_body)
-                    } else {
-                        trigger.closure_body.to_string()
-                    },
-                ),
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    recv: &'tcx Expr<'_>,
+    arg: &'tcx Expr<'_>,
+    is_unstable: bool,
+) {
+    match detect_lint(cx, expr, recv, arg) {
+        Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg(
+            cx,
+            UNNECESSARY_SORT_BY,
+            expr.span,
+            "use Vec::sort_by_key here instead",
+            "try",
+            format!(
+                "{}.sort{}_by_key(|{}| {})",
+                trigger.vec_name,
+                if is_unstable { "_unstable" } else { "" },
+                trigger.closure_arg,
                 if trigger.reverse {
-                    Applicability::MaybeIncorrect
+                    format!("std::cmp::Reverse({})", trigger.closure_body)
                 } else {
-                    Applicability::MachineApplicable
+                    trigger.closure_body.to_string()
                 },
             ),
-            Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg(
-                cx,
-                UNNECESSARY_SORT_BY,
-                expr.span,
-                "use Vec::sort here instead",
-                "try",
-                format!(
-                    "{}.sort{}()",
-                    trigger.vec_name,
-                    if trigger.unstable { "_unstable" } else { "" },
-                ),
-                Applicability::MachineApplicable,
+            if trigger.reverse {
+                Applicability::MaybeIncorrect
+            } else {
+                Applicability::MachineApplicable
+            },
+        ),
+        Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg(
+            cx,
+            UNNECESSARY_SORT_BY,
+            expr.span,
+            "use Vec::sort here instead",
+            "try",
+            format!(
+                "{}.sort{}()",
+                trigger.vec_name,
+                if is_unstable { "_unstable" } else { "" },
             ),
-            None => {},
-        }
+            Applicability::MachineApplicable,
+        ),
+        None => {},
     }
 }
diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index b3276f1394e..44bf8435294 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -3,11 +3,10 @@ use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{
-    contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs,
+    get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, peel_mid_ty_refs,
 };
-use clippy_utils::{meets_msrv, msrvs};
-
 use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item};
+use clippy_utils::{meets_msrv, msrvs};
 use rustc_errors::Applicability;
 use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind};
 use rustc_lint::LateContext;
@@ -279,7 +278,19 @@ fn check_other_call_arg<'tcx>(
                 &trait_predicate.trait_ref.substs.iter().skip(1).collect::<Vec<_>>()[..],
                 call_substs,
             );
-            implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs)
+            // if `expr` is a `String` and generic target is [u8], skip
+            // (https://github.com/rust-lang/rust-clippy/issues/9317).
+            if let [subst] = composed_substs[..]
+                && let GenericArgKind::Type(arg_ty) = subst.unpack()
+                && arg_ty.is_slice()
+                && let inner_ty = arg_ty.builtin_index().unwrap()
+                && let ty::Uint(ty::UintTy::U8) = inner_ty.kind()
+                && let self_ty = cx.typeck_results().expr_ty(expr).peel_refs()
+                && is_type_diagnostic_item(cx, self_ty, sym::String) {
+                false
+            } else {
+                implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs)
+            }
         } else {
             false
         };
@@ -292,7 +303,7 @@ fn check_other_call_arg<'tcx>(
         // (https://github.com/rust-lang/rust-clippy/issues/8507).
         if (n_refs == 0 && !receiver_ty.is_ref())
             || trait_predicate.def_id() != as_ref_trait_id
-            || !contains_ty(fn_sig.output(), input);
+            || !fn_sig.output().contains(input);
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
             span_lint_and_sugg(
@@ -360,25 +371,15 @@ fn get_input_traits_and_projections<'tcx>(
 ) -> (Vec<TraitPredicate<'tcx>>, Vec<ProjectionPredicate<'tcx>>) {
     let mut trait_predicates = Vec::new();
     let mut projection_predicates = Vec::new();
-    for (predicate, _) in cx.tcx.predicates_of(callee_def_id).predicates.iter() {
-        // `substs` should have 1 + n elements. The first is the type on the left hand side of an
-        // `as`. The remaining n are trait parameters.
-        let is_input_substs = |substs: SubstsRef<'tcx>| {
-            if_chain! {
-                if let Some(arg) = substs.iter().next();
-                if let GenericArgKind::Type(arg_ty) = arg.unpack();
-                if arg_ty == input;
-                then { true } else { false }
-            }
-        };
+    for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() {
         match predicate.kind().skip_binder() {
             PredicateKind::Trait(trait_predicate) => {
-                if is_input_substs(trait_predicate.trait_ref.substs) {
+                if trait_predicate.trait_ref.self_ty() == input {
                     trait_predicates.push(trait_predicate);
                 }
             },
             PredicateKind::Projection(projection_predicate) => {
-                if is_input_substs(projection_predicate.projection_ty.substs) {
+                if projection_predicate.projection_ty.self_ty() == input {
                     projection_predicates.push(projection_predicate);
                 }
             },
diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs
index ce1a52e5480..ee17f2d7889 100644
--- a/clippy_lints/src/methods/unwrap_used.rs
+++ b/clippy_lints/src/methods/unwrap_used.rs
@@ -7,18 +7,26 @@ use rustc_span::sym;
 
 use super::{EXPECT_USED, UNWRAP_USED};
 
-/// lint use of `unwrap()` for `Option`s and `Result`s
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) {
+/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`.
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    recv: &hir::Expr<'_>,
+    is_err: bool,
+    allow_unwrap_in_tests: bool,
+) {
     let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
-    let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
+    let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
         Some((UNWRAP_USED, "an Option", "None", ""))
     } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
-        Some((UNWRAP_USED, "a Result", "Err", "an "))
+        Some((UNWRAP_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
     } else {
         None
     };
 
+    let method_suffix = if is_err { "_err" } else { "" };
+
     if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
         return;
     }
@@ -27,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
             format!(
                 "if you don't want to handle the `{none_value}` case gracefully, consider \
-                using `expect()` to provide a better panic message"
+                using `expect{method_suffix}()` to provide a better panic message"
             )
         } else {
             format!("if this value is {none_prefix}`{none_value}`, it will panic")
@@ -37,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
             cx,
             lint,
             expr.span,
-            &format!("used `unwrap()` on `{kind}` value"),
+            &format!("used `unwrap{method_suffix}()` on `{kind}` value"),
             None,
             &help,
         );
diff --git a/clippy_lints/src/methods/vec_resize_to_zero.rs b/clippy_lints/src/methods/vec_resize_to_zero.rs
new file mode 100644
index 00000000000..02d8364cb29
--- /dev/null
+++ b/clippy_lints/src/methods/vec_resize_to_zero.rs
@@ -0,0 +1,45 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::is_type_diagnostic_item;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+use rustc_span::{sym, Span};
+
+use super::VEC_RESIZE_TO_ZERO;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    count_arg: &'tcx Expr<'_>,
+    default_arg: &'tcx Expr<'_>,
+    name_span: Span,
+) {
+    if_chain! {
+        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), sym::Vec);
+        if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind;
+        if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind;
+        then {
+            let method_call_span = expr.span.with_lo(name_span.lo());
+            span_lint_and_then(
+                cx,
+                VEC_RESIZE_TO_ZERO,
+                expr.span,
+                "emptying a vector with `resize`",
+                |db| {
+                    db.help("the arguments may be inverted...");
+                    db.span_suggestion(
+                        method_call_span,
+                        "...or you can empty the vector with",
+                        "clear()".to_string(),
+                        Applicability::MaybeIncorrect,
+                    );
+                },
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/methods/verbose_file_reads.rs b/clippy_lints/src/methods/verbose_file_reads.rs
new file mode 100644
index 00000000000..2fe5ae9a9ad
--- /dev/null
+++ b/clippy_lints/src/methods/verbose_file_reads.rs
@@ -0,0 +1,28 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_trait_method;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_hir::{Expr, ExprKind, QPath};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::VERBOSE_FILE_READS;
+
+pub(super) const READ_TO_END_MSG: (&str, &str) = ("use of `File::read_to_end`", "consider using `fs::read` instead");
+pub(super) const READ_TO_STRING_MSG: (&str, &str) = (
+    "use of `File::read_to_string`",
+    "consider using `fs::read_to_string` instead",
+);
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    recv: &'tcx Expr<'_>,
+    (msg, help): (&str, &str),
+) {
+    if is_trait_method(cx, expr, sym::IoRead)
+        && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _)))
+        && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(recv).peel_refs(), sym::File)
+    {
+        span_lint_and_help(cx, VERBOSE_FILE_READS, expr.span, msg, None, help);
+    }
+}
diff --git a/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
index df044538fe1..7c4ae746e90 100644
--- a/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
+++ b/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
@@ -46,7 +46,7 @@ fn span_lint(cx: &EarlyContext<'_>, span: Span, only_one: bool) {
             "these patterns are unneeded as the `..` pattern can match those elements"
         },
         if only_one { "remove it" } else { "remove them" },
-        "".to_string(),
+        String::new(),
         Applicability::MachineApplicable,
     );
 }
diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs
index f763e0d24c9..020efeaebf0 100644
--- a/clippy_lints/src/mismatching_type_param_order.rs
+++ b/clippy_lints/src/mismatching_type_param_order.rs
@@ -40,7 +40,7 @@ declare_clippy_lint! {
     /// }
     /// impl<A, B> Foo<A, B> {}
     /// ```
-    #[clippy::version = "1.62.0"]
+    #[clippy::version = "1.63.0"]
     pub MISMATCHING_TYPE_PARAM_ORDER,
     pedantic,
     "type parameter positioned inconsistently between type def and impl block"
diff --git a/clippy_lints/src/multi_assignments.rs b/clippy_lints/src/multi_assignments.rs
new file mode 100644
index 00000000000..81eb1a085ae
--- /dev/null
+++ b/clippy_lints/src/multi_assignments.rs
@@ -0,0 +1,65 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for nested assignments.
+    ///
+    /// ### Why is this bad?
+    /// While this is in most cases already a type mismatch,
+    /// the result of an assignment being `()` can throw off people coming from languages like python or C,
+    /// where such assignments return a copy of the assigned value.
+    ///
+    /// ### Example
+    /// ```rust
+    ///# let (a, b);
+    /// a = b = 42;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    ///# let (a, b);
+    /// b = 42;
+    /// a = b;
+    /// ```
+    #[clippy::version = "1.65.0"]
+    pub MULTI_ASSIGNMENTS,
+    suspicious,
+    "instead of using `a = b = c;` use `a = c; b = c;`"
+}
+
+declare_lint_pass!(MultiAssignments => [MULTI_ASSIGNMENTS]);
+
+fn strip_paren_blocks(expr: &Expr) -> &Expr {
+    match &expr.kind {
+        ExprKind::Paren(e) => strip_paren_blocks(e),
+        ExprKind::Block(b, _) => {
+            if let [
+                Stmt {
+                    kind: StmtKind::Expr(e),
+                    ..
+                },
+            ] = &b.stmts[..]
+            {
+                strip_paren_blocks(e)
+            } else {
+                expr
+            }
+        },
+        _ => expr,
+    }
+}
+
+impl EarlyLintPass for MultiAssignments {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        if let ExprKind::Assign(target, source, _) = &expr.kind {
+            if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(target).kind {
+                span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively");
+            };
+            if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(source).kind {
+                span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively");
+            }
+        };
+    }
+}
diff --git a/clippy_lints/src/mut_mutex_lock.rs b/clippy_lints/src/mut_mutex_lock.rs
deleted file mode 100644
index b7f981faa2d..00000000000
--- a/clippy_lints/src/mut_mutex_lock.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, Mutability};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for `&mut Mutex::lock` calls
-    ///
-    /// ### Why is this bad?
-    /// `Mutex::lock` is less efficient than
-    /// calling `Mutex::get_mut`. In addition you also have a statically
-    /// guarantee that the mutex isn't locked, instead of just a runtime
-    /// guarantee.
-    ///
-    /// ### Example
-    /// ```rust
-    /// use std::sync::{Arc, Mutex};
-    ///
-    /// let mut value_rc = Arc::new(Mutex::new(42_u8));
-    /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
-    ///
-    /// let mut value = value_mutex.lock().unwrap();
-    /// *value += 1;
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// use std::sync::{Arc, Mutex};
-    ///
-    /// let mut value_rc = Arc::new(Mutex::new(42_u8));
-    /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
-    ///
-    /// let value = value_mutex.get_mut().unwrap();
-    /// *value += 1;
-    /// ```
-    #[clippy::version = "1.49.0"]
-    pub MUT_MUTEX_LOCK,
-    style,
-    "`&mut Mutex::lock` does unnecessary locking"
-}
-
-declare_lint_pass!(MutMutexLock => [MUT_MUTEX_LOCK]);
-
-impl<'tcx> LateLintPass<'tcx> for MutMutexLock {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>) {
-        if_chain! {
-            if let ExprKind::MethodCall(path, [self_arg, ..], _) = &ex.kind;
-            if path.ident.name == sym!(lock);
-            let ty = cx.typeck_results().expr_ty(self_arg);
-            if let ty::Ref(_, inner_ty, Mutability::Mut) = ty.kind();
-            if is_type_diagnostic_item(cx, *inner_ty, sym::Mutex);
-            then {
-                span_lint_and_sugg(
-                    cx,
-                    MUT_MUTEX_LOCK,
-                    path.ident.span,
-                    "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference",
-                    "change this to",
-                    "get_mut".to_owned(),
-                    Applicability::MaybeIncorrect,
-                );
-            }
-        }
-    }
-}
diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs
index 413a740be25..774a3540d1e 100644
--- a/clippy_lints/src/only_used_in_recursion.rs
+++ b/clippy_lints/src/only_used_in_recursion.rs
@@ -1,25 +1,16 @@
-use std::collections::VecDeque;
-
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_lint_allowed;
-use itertools::{izip, Itertools};
-use rustc_ast::{walk_list, Label, Mutability};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{get_expr_use_or_unification_node, get_parent_node, path_def_id, path_to_local, path_to_local_id};
+use core::cell::Cell;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
-use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
-use rustc_hir::intravisit::{walk_expr, walk_stmt, FnKind, Visitor};
-use rustc_hir::{
-    Arm, Block, Body, Closure, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path,
-    PathSegment, QPath, Stmt, StmtKind, TyKind, UnOp,
-};
+use rustc_hir::hir_id::HirIdMap;
+use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
-use rustc_middle::ty::{Ty, TyCtxt, TypeckResults};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::kw;
-use rustc_span::symbol::Ident;
+use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
+use rustc_middle::ty::{self, ConstKind};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -89,572 +80,323 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.61.0"]
     pub ONLY_USED_IN_RECURSION,
-    nursery,
+    complexity,
     "arguments that is only used in recursion can be removed"
 }
-declare_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]);
+impl_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]);
+
+#[derive(Clone, Copy)]
+enum FnKind {
+    Fn,
+    TraitFn,
+    // This is a hack. Ideally we would store a `SubstsRef<'tcx>` type here, but a lint pass must be `'static`.
+    // Substitutions are, however, interned. This allows us to store the pointer as a `usize` when comparing for
+    // equality.
+    ImplTraitFn(usize),
+}
+
+struct Param {
+    /// The function this is a parameter for.
+    fn_id: DefId,
+    fn_kind: FnKind,
+    /// The index of this parameter.
+    idx: usize,
+    ident: Ident,
+    /// Whether this parameter should be linted. Set by `Params::flag_for_linting`.
+    apply_lint: Cell<bool>,
+    /// All the uses of this parameter.
+    uses: Vec<Usage>,
+}
+impl Param {
+    fn new(fn_id: DefId, fn_kind: FnKind, idx: usize, ident: Ident) -> Self {
+        Self {
+            fn_id,
+            fn_kind,
+            idx,
+            ident,
+            apply_lint: Cell::new(true),
+            uses: Vec::new(),
+        }
+    }
+}
+
+#[derive(Debug)]
+struct Usage {
+    span: Span,
+    idx: usize,
+}
+impl Usage {
+    fn new(span: Span, idx: usize) -> Self {
+        Self { span, idx }
+    }
+}
+
+/// The parameters being checked by the lint, indexed by both the parameter's `HirId` and the
+/// `DefId` of the function paired with the parameter's index.
+#[derive(Default)]
+struct Params {
+    params: Vec<Param>,
+    by_id: HirIdMap<usize>,
+    by_fn: FxHashMap<(DefId, usize), usize>,
+}
+impl Params {
+    fn insert(&mut self, param: Param, id: HirId) {
+        let idx = self.params.len();
+        self.by_id.insert(id, idx);
+        self.by_fn.insert((param.fn_id, param.idx), idx);
+        self.params.push(param);
+    }
+
+    fn remove_by_id(&mut self, id: HirId) {
+        if let Some(param) = self.get_by_id_mut(id) {
+            param.uses = Vec::new();
+            let key = (param.fn_id, param.idx);
+            self.by_fn.remove(&key);
+            self.by_id.remove(&id);
+        }
+    }
+
+    fn get_by_id_mut(&mut self, id: HirId) -> Option<&mut Param> {
+        self.params.get_mut(*self.by_id.get(&id)?)
+    }
+
+    fn get_by_fn(&self, id: DefId, idx: usize) -> Option<&Param> {
+        self.params.get(*self.by_fn.get(&(id, idx))?)
+    }
+
+    fn clear(&mut self) {
+        self.params.clear();
+        self.by_id.clear();
+        self.by_fn.clear();
+    }
+
+    /// Sets the `apply_lint` flag on each parameter.
+    fn flag_for_linting(&mut self) {
+        // Stores the list of parameters currently being resolved. Needed to avoid cycles.
+        let mut eval_stack = Vec::new();
+        for param in &self.params {
+            self.try_disable_lint_for_param(param, &mut eval_stack);
+        }
+    }
+
+    // Use by calling `flag_for_linting`.
+    fn try_disable_lint_for_param(&self, param: &Param, eval_stack: &mut Vec<usize>) -> bool {
+        if !param.apply_lint.get() {
+            true
+        } else if param.uses.is_empty() {
+            // Don't lint on unused parameters.
+            param.apply_lint.set(false);
+            true
+        } else if eval_stack.contains(&param.idx) {
+            // Already on the evaluation stack. Returning false will continue to evaluate other dependencies.
+            false
+        } else {
+            eval_stack.push(param.idx);
+            // Check all cases when used at a different parameter index.
+            // Needed to catch cases like: `fn f(x: u32, y: u32) { f(y, x) }`
+            for usage in param.uses.iter().filter(|u| u.idx != param.idx) {
+                if self
+                    .get_by_fn(param.fn_id, usage.idx)
+                    // If the parameter can't be found, then it's used for more than just recursion.
+                    .map_or(true, |p| self.try_disable_lint_for_param(p, eval_stack))
+                {
+                    param.apply_lint.set(false);
+                    eval_stack.pop();
+                    return true;
+                }
+            }
+            eval_stack.pop();
+            false
+        }
+    }
+}
+
+#[derive(Default)]
+pub struct OnlyUsedInRecursion {
+    /// Track the top-level body entered. Needed to delay reporting when entering nested bodies.
+    entered_body: Option<HirId>,
+    params: Params,
+}
 
 impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'tcx>,
-        kind: FnKind<'tcx>,
-        decl: &'tcx rustc_hir::FnDecl<'tcx>,
-        body: &'tcx Body<'tcx>,
-        _: Span,
-        id: HirId,
-    ) {
-        if is_lint_allowed(cx, ONLY_USED_IN_RECURSION, id) {
+    fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
+        if body.value.span.from_expansion() {
             return;
         }
-        if let FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) = kind {
-            let def_id = id.owner.to_def_id();
-            let data = cx.tcx.def_path(def_id).data;
-
-            if data.len() > 1 {
-                match data.get(data.len() - 2) {
-                    Some(DisambiguatedDefPathData {
-                        data: DefPathData::Impl,
-                        disambiguator,
-                    }) if *disambiguator != 0 => return,
-                    _ => {},
-                }
-            }
-
-            let has_self = !matches!(decl.implicit_self, ImplicitSelfKind::None);
-
-            let ty_res = cx.typeck_results();
-            let param_span = body
-                .params
-                .iter()
-                .flat_map(|param| {
-                    let mut v = Vec::new();
-                    param.pat.each_binding(|_, hir_id, span, ident| {
-                        v.push((hir_id, span, ident));
-                    });
-                    v
-                })
-                .skip(if has_self { 1 } else { 0 })
-                .filter(|(_, _, ident)| !ident.name.as_str().starts_with('_'))
-                .collect_vec();
-
-            let params = body.params.iter().map(|param| param.pat).collect();
-
-            let mut visitor = SideEffectVisit {
-                graph: FxHashMap::default(),
-                has_side_effect: FxHashSet::default(),
-                ret_vars: Vec::new(),
-                contains_side_effect: false,
-                break_vars: FxHashMap::default(),
-                params,
-                fn_ident: ident,
-                fn_def_id: def_id,
-                is_method: matches!(kind, FnKind::Method(..)),
-                has_self,
-                ty_res,
-                tcx: cx.tcx,
-                visited_exprs: FxHashSet::default(),
-            };
-
-            visitor.visit_expr(&body.value);
-            let vars = std::mem::take(&mut visitor.ret_vars);
-            // this would set the return variables to side effect
-            visitor.add_side_effect(vars);
-
-            let mut queue = visitor.has_side_effect.iter().copied().collect::<VecDeque<_>>();
-
-            // a simple BFS to check all the variables that have side effect
-            while let Some(id) = queue.pop_front() {
-                if let Some(next) = visitor.graph.get(&id) {
-                    for i in next {
-                        if !visitor.has_side_effect.contains(i) {
-                            visitor.has_side_effect.insert(*i);
-                            queue.push_back(*i);
-                        }
-                    }
-                }
-            }
-
-            for (id, span, ident) in param_span {
-                // if the variable is not used in recursion, it would be marked as unused
-                if !visitor.has_side_effect.contains(&id) {
-                    let mut queue = VecDeque::new();
-                    let mut visited = FxHashSet::default();
-
-                    queue.push_back(id);
-
-                    // a simple BFS to check the graph can reach to itself
-                    // if it can't, it means the variable is never used in recursion
-                    while let Some(id) = queue.pop_front() {
-                        if let Some(next) = visitor.graph.get(&id) {
-                            for i in next {
-                                if !visited.contains(i) {
-                                    visited.insert(id);
-                                    queue.push_back(*i);
-                                }
-                            }
-                        }
-                    }
-
-                    if visited.contains(&id) {
-                        span_lint_and_sugg(
-                            cx,
-                            ONLY_USED_IN_RECURSION,
-                            span,
-                            "parameter is only used in recursion",
-                            "if this is intentional, prefix with an underscore",
-                            format!("_{}", ident.name.as_str()),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-            }
-        }
-    }
-}
-
-pub fn is_primitive(ty: Ty<'_>) -> bool {
-    let ty = ty.peel_refs();
-    ty.is_primitive() || ty.is_str()
-}
-
-pub fn is_array(ty: Ty<'_>) -> bool {
-    let ty = ty.peel_refs();
-    ty.is_array() || ty.is_array_slice()
-}
-
-/// This builds the graph of side effect.
-/// The edge `a -> b` means if `a` has side effect, `b` will have side effect.
-///
-/// There are some example in following code:
-/// ```rust, ignore
-/// let b = 1;
-/// let a = b; // a -> b
-/// let (c, d) = (a, b); // c -> b, d -> b
-///
-/// let e = if a == 0 { // e -> a
-///     c // e -> c
-/// } else {
-///     d // e -> d
-/// };
-/// ```
-pub struct SideEffectVisit<'tcx> {
-    graph: FxHashMap<HirId, FxHashSet<HirId>>,
-    has_side_effect: FxHashSet<HirId>,
-    // bool for if the variable was dereferenced from mutable reference
-    ret_vars: Vec<(HirId, bool)>,
-    contains_side_effect: bool,
-    // break label
-    break_vars: FxHashMap<Ident, Vec<(HirId, bool)>>,
-    params: Vec<&'tcx Pat<'tcx>>,
-    fn_ident: Ident,
-    fn_def_id: DefId,
-    is_method: bool,
-    has_self: bool,
-    ty_res: &'tcx TypeckResults<'tcx>,
-    tcx: TyCtxt<'tcx>,
-    visited_exprs: FxHashSet<HirId>,
-}
-
-impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> {
-    fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) {
-        match s.kind {
-            StmtKind::Local(Local {
-                pat, init: Some(init), ..
-            }) => {
-                self.visit_pat_expr(pat, init, false);
-            },
-            StmtKind::Item(_) | StmtKind::Expr(_) | StmtKind::Semi(_) => {
-                walk_stmt(self, s);
-            },
-            StmtKind::Local(_) => {},
-        }
-        self.ret_vars.clear();
-    }
-
-    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
-        if !self.visited_exprs.insert(ex.hir_id) {
-            return;
-        }
-        match ex.kind {
-            ExprKind::Array(exprs) | ExprKind::Tup(exprs) => {
-                self.ret_vars = exprs
-                    .iter()
-                    .flat_map(|expr| {
-                        self.visit_expr(expr);
-                        std::mem::take(&mut self.ret_vars)
-                    })
-                    .collect();
-            },
-            ExprKind::Call(callee, args) => self.visit_fn(callee, args),
-            ExprKind::MethodCall(path, args, _) => self.visit_method_call(path, args),
-            ExprKind::Binary(_, lhs, rhs) => {
-                self.visit_bin_op(lhs, rhs);
-            },
-            ExprKind::Unary(op, expr) => self.visit_un_op(op, expr),
-            ExprKind::Let(Let { pat, init, .. }) => self.visit_pat_expr(pat, init, false),
-            ExprKind::If(bind, then_expr, else_expr) => {
-                self.visit_if(bind, then_expr, else_expr);
-            },
-            ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms),
-            // since analysing the closure is not easy, just set all variables in it to side-effect
-            ExprKind::Closure(&Closure { body, .. }) => {
-                let body = self.tcx.hir().body(body);
-                self.visit_body(body);
-                let vars = std::mem::take(&mut self.ret_vars);
-                self.add_side_effect(vars);
-            },
-            ExprKind::Loop(block, label, _, _) | ExprKind::Block(block, label) => {
-                self.visit_block_label(block, label);
-            },
-            ExprKind::Assign(bind, expr, _) => {
-                self.visit_assign(bind, expr);
-            },
-            ExprKind::AssignOp(_, bind, expr) => {
-                self.visit_assign(bind, expr);
-                self.visit_bin_op(bind, expr);
-            },
-            ExprKind::Field(expr, _) => {
-                self.visit_expr(expr);
-                if matches!(self.ty_res.expr_ty(expr).kind(), ty::Ref(_, _, Mutability::Mut)) {
-                    self.ret_vars.iter_mut().for_each(|(_, b)| *b = true);
+        // `skip_params` is either `0` or `1` to skip the `self` parameter in trait functions.
+        // It can't be renamed, and it can't be removed without removing it from multiple functions.
+        let (fn_id, fn_kind, skip_params) = match get_parent_node(cx.tcx, body.value.hir_id) {
+            Some(Node::Item(i)) => (i.def_id.to_def_id(), FnKind::Fn, 0),
+            Some(Node::TraitItem(&TraitItem {
+                kind: TraitItemKind::Fn(ref sig, _),
+                def_id,
+                ..
+            })) => (
+                def_id.to_def_id(),
+                FnKind::TraitFn,
+                if sig.decl.implicit_self.has_implicit_self() {
+                    1
+                } else {
+                    0
+                },
+            ),
+            Some(Node::ImplItem(&ImplItem {
+                kind: ImplItemKind::Fn(ref sig, _),
+                def_id,
+                ..
+            })) => {
+                #[allow(trivial_casts)]
+                if let Some(Node::Item(item)) = get_parent_node(cx.tcx, cx.tcx.hir().local_def_id_to_hir_id(def_id))
+                    && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.def_id)
+                    && let Some(trait_item_id) = cx.tcx.associated_item(def_id).trait_item_def_id
+                {
+                    (
+                        trait_item_id,
+                        FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const _ as usize),
+                        if sig.decl.implicit_self.has_implicit_self() {
+                            1
+                        } else {
+                            0
+                        },
+                    )
+                } else {
+                    (def_id.to_def_id(), FnKind::Fn, 0)
                 }
             },
-            ExprKind::Index(expr, index) => {
-                self.visit_expr(expr);
-                let mut vars = std::mem::take(&mut self.ret_vars);
-                self.visit_expr(index);
-                self.ret_vars.append(&mut vars);
-
-                if !is_array(self.ty_res.expr_ty(expr)) {
-                    self.add_side_effect(self.ret_vars.clone());
-                } else if matches!(self.ty_res.expr_ty(expr).kind(), ty::Ref(_, _, Mutability::Mut)) {
-                    self.ret_vars.iter_mut().for_each(|(_, b)| *b = true);
-                }
-            },
-            ExprKind::Break(dest, Some(expr)) => {
-                self.visit_expr(expr);
-                if let Some(label) = dest.label {
-                    self.break_vars
-                        .entry(label.ident)
-                        .or_insert(Vec::new())
-                        .append(&mut self.ret_vars);
-                }
-                self.contains_side_effect = true;
-            },
-            ExprKind::Ret(Some(expr)) => {
-                self.visit_expr(expr);
-                let vars = std::mem::take(&mut self.ret_vars);
-                self.add_side_effect(vars);
-                self.contains_side_effect = true;
-            },
-            ExprKind::Break(_, None) | ExprKind::Continue(_) | ExprKind::Ret(None) => {
-                self.contains_side_effect = true;
-            },
-            ExprKind::Struct(_, exprs, expr) => {
-                let mut ret_vars = exprs
-                    .iter()
-                    .flat_map(|field| {
-                        self.visit_expr(field.expr);
-                        std::mem::take(&mut self.ret_vars)
-                    })
-                    .collect();
-
-                walk_list!(self, visit_expr, expr);
-                self.ret_vars.append(&mut ret_vars);
-            },
-            _ => walk_expr(self, ex),
-        }
-    }
-
-    fn visit_path(&mut self, path: &'tcx Path<'tcx>, _id: HirId) {
-        if let Res::Local(id) = path.res {
-            self.ret_vars.push((id, false));
-        }
-    }
-}
-
-impl<'tcx> SideEffectVisit<'tcx> {
-    fn visit_assign(&mut self, lhs: &'tcx Expr<'tcx>, rhs: &'tcx Expr<'tcx>) {
-        // Just support array and tuple unwrapping for now.
-        //
-        // ex) `(a, b) = (c, d);`
-        // The graph would look like this:
-        //   a -> c
-        //   b -> d
-        //
-        // This would minimize the connection of the side-effect graph.
-        match (&lhs.kind, &rhs.kind) {
-            (ExprKind::Array(lhs), ExprKind::Array(rhs)) | (ExprKind::Tup(lhs), ExprKind::Tup(rhs)) => {
-                // if not, it is a compile error
-                debug_assert!(lhs.len() == rhs.len());
-                izip!(*lhs, *rhs).for_each(|(lhs, rhs)| self.visit_assign(lhs, rhs));
-            },
-            // in other assigns, we have to connect all each other
-            // because they can be connected somehow
-            _ => {
-                self.visit_expr(lhs);
-                let lhs_vars = std::mem::take(&mut self.ret_vars);
-                self.visit_expr(rhs);
-                let rhs_vars = std::mem::take(&mut self.ret_vars);
-                self.connect_assign(&lhs_vars, &rhs_vars, false);
-            },
-        }
-    }
-
-    fn visit_block_label(&mut self, block: &'tcx Block<'tcx>, label: Option<Label>) {
-        self.visit_block(block);
-        let _ = label.and_then(|label| {
-            self.break_vars
-                .remove(&label.ident)
-                .map(|mut break_vars| self.ret_vars.append(&mut break_vars))
-        });
-    }
-
-    fn visit_bin_op(&mut self, lhs: &'tcx Expr<'tcx>, rhs: &'tcx Expr<'tcx>) {
-        self.visit_expr(lhs);
-        let mut ret_vars = std::mem::take(&mut self.ret_vars);
-        self.visit_expr(rhs);
-        self.ret_vars.append(&mut ret_vars);
-
-        // the binary operation between non primitive values are overloaded operators
-        // so they can have side-effects
-        if !is_primitive(self.ty_res.expr_ty(lhs)) || !is_primitive(self.ty_res.expr_ty(rhs)) {
-            self.ret_vars.iter().for_each(|id| {
-                self.has_side_effect.insert(id.0);
-            });
-            self.contains_side_effect = true;
-        }
-    }
-
-    fn visit_un_op(&mut self, op: UnOp, expr: &'tcx Expr<'tcx>) {
-        self.visit_expr(expr);
-        let ty = self.ty_res.expr_ty(expr);
-        // dereferencing a reference has no side-effect
-        if !is_primitive(ty) && !matches!((op, ty.kind()), (UnOp::Deref, ty::Ref(..))) {
-            self.add_side_effect(self.ret_vars.clone());
-        }
-
-        if matches!((op, ty.kind()), (UnOp::Deref, ty::Ref(_, _, Mutability::Mut))) {
-            self.ret_vars.iter_mut().for_each(|(_, b)| *b = true);
-        }
-    }
-
-    fn visit_pat_expr(&mut self, pat: &'tcx Pat<'tcx>, expr: &'tcx Expr<'tcx>, connect_self: bool) {
-        match (&pat.kind, &expr.kind) {
-            (PatKind::Tuple(pats, _), ExprKind::Tup(exprs)) => {
-                self.ret_vars = izip!(*pats, *exprs)
-                    .flat_map(|(pat, expr)| {
-                        self.visit_pat_expr(pat, expr, connect_self);
-                        std::mem::take(&mut self.ret_vars)
-                    })
-                    .collect();
-            },
-            (PatKind::Slice(front_exprs, _, back_exprs), ExprKind::Array(exprs)) => {
-                let mut vars = izip!(*front_exprs, *exprs)
-                    .flat_map(|(pat, expr)| {
-                        self.visit_pat_expr(pat, expr, connect_self);
-                        std::mem::take(&mut self.ret_vars)
-                    })
-                    .collect();
-                self.ret_vars = izip!(back_exprs.iter().rev(), exprs.iter().rev())
-                    .flat_map(|(pat, expr)| {
-                        self.visit_pat_expr(pat, expr, connect_self);
-                        std::mem::take(&mut self.ret_vars)
-                    })
-                    .collect();
-                self.ret_vars.append(&mut vars);
-            },
-            _ => {
-                let mut lhs_vars = Vec::new();
-                pat.each_binding(|_, id, _, _| lhs_vars.push((id, false)));
-                self.visit_expr(expr);
-                let rhs_vars = std::mem::take(&mut self.ret_vars);
-                self.connect_assign(&lhs_vars, &rhs_vars, connect_self);
-                self.ret_vars = rhs_vars;
-            },
-        }
-    }
-
-    fn visit_fn(&mut self, callee: &'tcx Expr<'tcx>, args: &'tcx [Expr<'tcx>]) {
-        self.visit_expr(callee);
-        let mut ret_vars = std::mem::take(&mut self.ret_vars);
-        self.add_side_effect(ret_vars.clone());
-
-        let mut is_recursive = false;
-
-        if_chain! {
-            if !self.has_self;
-            if let ExprKind::Path(QPath::Resolved(_, path)) = callee.kind;
-            if let Res::Def(DefKind::Fn, def_id) = path.res;
-            if self.fn_def_id == def_id;
-            then {
-                is_recursive = true;
-            }
-        }
-
-        if_chain! {
-            if !self.has_self && self.is_method;
-            if let ExprKind::Path(QPath::TypeRelative(ty, segment)) = callee.kind;
-            if segment.ident == self.fn_ident;
-            if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
-            if let Res::SelfTy{ .. } = path.res;
-            then {
-                is_recursive = true;
-            }
-        }
-
-        if is_recursive {
-            izip!(self.params.clone(), args).for_each(|(pat, expr)| {
-                self.visit_pat_expr(pat, expr, true);
-                self.ret_vars.clear();
-            });
-        } else {
-            // This would set arguments used in closure that does not have side-effect.
-            // Closure itself can be detected whether there is a side-effect, but the
-            // value of variable that is holding closure can change.
-            // So, we just check the variables.
-            self.ret_vars = args
-                .iter()
-                .flat_map(|expr| {
-                    self.visit_expr(expr);
-                    std::mem::take(&mut self.ret_vars)
-                })
-                .collect_vec()
-                .into_iter()
-                .map(|id| {
-                    self.has_side_effect.insert(id.0);
-                    id
-                })
-                .collect();
-            self.contains_side_effect = true;
-        }
-
-        self.ret_vars.append(&mut ret_vars);
-    }
-
-    fn visit_method_call(&mut self, path: &'tcx PathSegment<'tcx>, args: &'tcx [Expr<'tcx>]) {
-        if_chain! {
-            if self.is_method;
-            if path.ident == self.fn_ident;
-            if let ExprKind::Path(QPath::Resolved(_, path)) = args.first().unwrap().kind;
-            if let Res::Local(..) = path.res;
-            let ident = path.segments.last().unwrap().ident;
-            if ident.name == kw::SelfLower;
-            then {
-                izip!(self.params.clone(), args.iter())
-                    .for_each(|(pat, expr)| {
-                        self.visit_pat_expr(pat, expr, true);
-                        self.ret_vars.clear();
-                    });
-            } else {
-                self.ret_vars = args
-                    .iter()
-                    .flat_map(|expr| {
-                        self.visit_expr(expr);
-                        std::mem::take(&mut self.ret_vars)
-                    })
-                    .collect_vec()
-                    .into_iter()
-                    .map(|a| {
-                        self.has_side_effect.insert(a.0);
-                        a
-                    })
-                    .collect();
-                self.contains_side_effect = true;
-            }
-        }
-    }
-
-    fn visit_if(&mut self, bind: &'tcx Expr<'tcx>, then_expr: &'tcx Expr<'tcx>, else_expr: Option<&'tcx Expr<'tcx>>) {
-        let contains_side_effect = self.contains_side_effect;
-        self.contains_side_effect = false;
-        self.visit_expr(bind);
-        let mut vars = std::mem::take(&mut self.ret_vars);
-        self.visit_expr(then_expr);
-        let mut then_vars = std::mem::take(&mut self.ret_vars);
-        walk_list!(self, visit_expr, else_expr);
-        if self.contains_side_effect {
-            self.add_side_effect(vars.clone());
-        }
-        self.contains_side_effect |= contains_side_effect;
-        self.ret_vars.append(&mut vars);
-        self.ret_vars.append(&mut then_vars);
-    }
-
-    fn visit_match(&mut self, expr: &'tcx Expr<'tcx>, arms: &'tcx [Arm<'tcx>]) {
-        self.visit_expr(expr);
-        let mut expr_vars = std::mem::take(&mut self.ret_vars);
-        self.ret_vars = arms
+            _ => return,
+        };
+        body.params
             .iter()
-            .flat_map(|arm| {
-                let contains_side_effect = self.contains_side_effect;
-                self.contains_side_effect = false;
-                // this would visit `expr` multiple times
-                // but couldn't think of a better way
-                self.visit_pat_expr(arm.pat, expr, false);
-                let mut vars = std::mem::take(&mut self.ret_vars);
-                let _ = arm.guard.as_ref().map(|guard| {
-                    self.visit_expr(match guard {
-                        Guard::If(expr) | Guard::IfLet(Let { init: expr, .. }) => expr,
-                    });
-                    vars.append(&mut self.ret_vars);
-                });
-                self.visit_expr(arm.body);
-                if self.contains_side_effect {
-                    self.add_side_effect(vars.clone());
-                    self.add_side_effect(expr_vars.clone());
-                }
-                self.contains_side_effect |= contains_side_effect;
-                vars.append(&mut self.ret_vars);
-                vars
+            .enumerate()
+            .skip(skip_params)
+            .filter_map(|(idx, p)| match p.pat.kind {
+                PatKind::Binding(_, id, ident, None) if !ident.as_str().starts_with('_') => {
+                    Some((id, Param::new(fn_id, fn_kind, idx, ident)))
+                },
+                _ => None,
             })
-            .collect();
-        self.ret_vars.append(&mut expr_vars);
+            .for_each(|(id, param)| self.params.insert(param, id));
+        if self.entered_body.is_none() {
+            self.entered_body = Some(body.value.hir_id);
+        }
     }
 
-    fn connect_assign(&mut self, lhs: &[(HirId, bool)], rhs: &[(HirId, bool)], connect_self: bool) {
-        // if mutable dereference is on assignment it can have side-effect
-        // (this can lead to parameter mutable dereference and change the original value)
-        // too hard to detect whether this value is from parameter, so this would all
-        // check mutable dereference assignment to side effect
-        lhs.iter().filter(|(_, b)| *b).for_each(|(id, _)| {
-            self.has_side_effect.insert(*id);
-            self.contains_side_effect = true;
-        });
-
-        // there is no connection
-        if lhs.is_empty() || rhs.is_empty() {
-            return;
-        }
-
-        // by connected rhs in cycle, the connections would decrease
-        // from `n * m` to `n + m`
-        // where `n` and `m` are length of `lhs` and `rhs`.
-
-        // unwrap is possible since rhs is not empty
-        let rhs_first = rhs.first().unwrap();
-        for (id, _) in lhs.iter() {
-            if connect_self || *id != rhs_first.0 {
-                self.graph
-                    .entry(*id)
-                    .or_insert_with(FxHashSet::default)
-                    .insert(rhs_first.0);
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) {
+        if let Some(id) = path_to_local(e)
+            && let Some(param) = self.params.get_by_id_mut(id)
+        {
+            let typeck = cx.typeck_results();
+            let span = e.span;
+            let mut e = e;
+            loop {
+                match get_expr_use_or_unification_node(cx.tcx, e) {
+                    None | Some((Node::Stmt(_), _)) => return,
+                    Some((Node::Expr(parent), child_id)) => match parent.kind {
+                        // Recursive call. Track which index the parameter is used in.
+                        ExprKind::Call(callee, args)
+                            if path_def_id(cx, callee).map_or(false, |id| {
+                                id == param.fn_id
+                                    && has_matching_substs(param.fn_kind, typeck.node_substs(callee.hir_id))
+                            }) =>
+                        {
+                            if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) {
+                                param.uses.push(Usage::new(span, idx));
+                            }
+                            return;
+                        },
+                        ExprKind::MethodCall(_, args, _)
+                            if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| {
+                                id == param.fn_id
+                                    && has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id))
+                            }) =>
+                        {
+                            if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) {
+                                param.uses.push(Usage::new(span, idx));
+                            }
+                            return;
+                        },
+                        // Assignment to a parameter is fine.
+                        ExprKind::Assign(lhs, _, _) | ExprKind::AssignOp(_, lhs, _) if lhs.hir_id == child_id => {
+                            return;
+                        },
+                        // Parameter update e.g. `x = x + 1`
+                        ExprKind::Assign(lhs, rhs, _) | ExprKind::AssignOp(_, lhs, rhs)
+                            if rhs.hir_id == child_id && path_to_local_id(lhs, id) =>
+                        {
+                            return;
+                        },
+                        // Side-effect free expressions. Walk to the parent expression.
+                        ExprKind::Binary(_, lhs, rhs)
+                            if typeck.expr_ty(lhs).is_primitive() && typeck.expr_ty(rhs).is_primitive() =>
+                        {
+                            e = parent;
+                            continue;
+                        },
+                        ExprKind::Unary(_, arg) if typeck.expr_ty(arg).is_primitive() => {
+                            e = parent;
+                            continue;
+                        },
+                        ExprKind::AddrOf(..) | ExprKind::Cast(..) => {
+                            e = parent;
+                            continue;
+                        },
+                        // Only allow field accesses without auto-deref
+                        ExprKind::Field(..) if typeck.adjustments().get(child_id).is_none() => {
+                            e = parent;
+                            continue
+                        }
+                        _ => (),
+                    },
+                    _ => (),
+                }
+                self.params.remove_by_id(id);
+                return;
             }
         }
-
-        let rhs = rhs.iter();
-        izip!(rhs.clone().cycle().skip(1), rhs).for_each(|(from, to)| {
-            if connect_self || from.0 != to.0 {
-                self.graph.entry(from.0).or_insert_with(FxHashSet::default).insert(to.0);
-            }
-        });
     }
 
-    fn add_side_effect(&mut self, v: Vec<(HirId, bool)>) {
-        for (id, _) in v {
-            self.has_side_effect.insert(id);
-            self.contains_side_effect = true;
+    fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) {
+        if self.entered_body == Some(body.value.hir_id) {
+            self.entered_body = None;
+            self.params.flag_for_linting();
+            for param in &self.params.params {
+                if param.apply_lint.get() {
+                    span_lint_and_then(
+                        cx,
+                        ONLY_USED_IN_RECURSION,
+                        param.ident.span,
+                        "parameter is only used in recursion",
+                        |diag| {
+                            if param.ident.name != kw::SelfLower {
+                                diag.span_suggestion(
+                                    param.ident.span,
+                                    "if this is intentional, prefix it with an underscore",
+                                    format!("_{}", param.ident.name),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                            diag.span_note(
+                                param.uses.iter().map(|x| x.span).collect::<Vec<_>>(),
+                                "parameter used here",
+                            );
+                        },
+                    );
+                }
+            }
+            self.params.clear();
         }
     }
 }
+
+fn has_matching_substs(kind: FnKind, substs: SubstsRef<'_>) -> bool {
+    match kind {
+        FnKind::Fn => true,
+        FnKind::TraitFn => substs.iter().enumerate().all(|(idx, subst)| match subst.unpack() {
+            GenericArgKind::Lifetime(_) => true,
+            GenericArgKind::Type(ty) => matches!(*ty.kind(), ty::Param(ty) if ty.index as usize == idx),
+            GenericArgKind::Const(c) => matches!(c.kind(), ConstKind::Param(c) if c.index as usize == idx),
+        }),
+        #[allow(trivial_casts)]
+        FnKind::ImplTraitFn(expected_substs) => substs as *const _ as usize == expected_substs,
+    }
+}
diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs
index 44f153cffac..9602d0d1d2e 100644
--- a/clippy_lints/src/option_if_let_else.rs
+++ b/clippy_lints/src/option_if_let_else.rs
@@ -1,21 +1,22 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{
     can_move_expr_to_closure, eager_or_lazy, higher, in_constant, is_else_clause, is_lang_ctor, peel_blocks,
     peel_hir_expr_while, CaptureKind,
 };
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::LangItem::OptionSome;
-use rustc_hir::{def::Res, BindingAnnotation, Expr, ExprKind, Mutability, PatKind, Path, QPath, UnOp};
+use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
+use rustc_hir::{
+    def::Res, Arm, BindingAnnotation, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Lints usage of `if let Some(v) = ... { y } else { x }` which is more
+    /// Lints usage of `if let Some(v) = ... { y } else { x }` and
+    /// `match .. { Some(v) => y, None/_ => x }` which are more
     /// idiomatically done with `Option::map_or` (if the else bit is a pure
     /// expression) or `Option::map_or_else` (if the else bit is an impure
     /// expression).
@@ -39,6 +40,10 @@ declare_clippy_lint! {
     /// } else {
     ///     5
     /// };
+    /// let _ = match optional {
+    ///     Some(val) => val + 1,
+    ///     None => 5
+    /// };
     /// let _ = if let Some(foo) = optional {
     ///     foo
     /// } else {
@@ -53,11 +58,14 @@ declare_clippy_lint! {
     /// # let optional: Option<u32> = Some(0);
     /// # fn do_complicated_function() -> u32 { 5 };
     /// let _ = optional.map_or(5, |foo| foo);
+    /// let _ = optional.map_or(5, |val| val + 1);
     /// let _ = optional.map_or_else(||{
     ///     let y = do_complicated_function();
     ///     y*y
     /// }, |foo| foo);
     /// ```
+    // FIXME: Before moving this lint out of nursery, the lint name needs to be updated. It now also
+    // covers matches and `Result`.
     #[clippy::version = "1.47.0"]
     pub OPTION_IF_LET_ELSE,
     nursery,
@@ -66,19 +74,21 @@ declare_clippy_lint! {
 
 declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]);
 
-/// Returns true iff the given expression is the result of calling `Result::ok`
-fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool {
-    if let ExprKind::MethodCall(path, &[ref receiver], _) = &expr.kind {
-        path.ident.name.as_str() == "ok"
-            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::Result)
-    } else {
-        false
-    }
-}
-
-/// A struct containing information about occurrences of the
-/// `if let Some(..) = .. else` construct that this lint detects.
-struct OptionIfLetElseOccurrence {
+/// A struct containing information about occurrences of construct that this lint detects
+///
+/// Such as:
+///
+/// ```ignore
+/// if let Some(..) = {..} else {..}
+/// ```
+/// or
+/// ```ignore
+/// match x {
+///     Some(..) => {..},
+///     None/_ => {..}
+/// }
+/// ```
+struct OptionOccurence {
     option: String,
     method_sugg: String,
     some_expr: String,
@@ -99,43 +109,38 @@ fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: boo
     )
 }
 
-/// If this expression is the option if let/else construct we're detecting, then
-/// this function returns an `OptionIfLetElseOccurrence` struct with details if
-/// this construct is found, or None if this construct is not found.
-fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionIfLetElseOccurrence> {
+fn try_get_option_occurence<'tcx>(
+    cx: &LateContext<'tcx>,
+    pat: &Pat<'tcx>,
+    expr: &Expr<'_>,
+    if_then: &'tcx Expr<'_>,
+    if_else: &'tcx Expr<'_>,
+) -> Option<OptionOccurence> {
+    let cond_expr = match expr.kind {
+        ExprKind::Unary(UnOp::Deref, inner_expr) | ExprKind::AddrOf(_, _, inner_expr) => inner_expr,
+        _ => expr,
+    };
+    let inner_pat = try_get_inner_pat(cx, pat)?;
     if_chain! {
-        if !expr.span.from_expansion(); // Don't lint macros, because it behaves weirdly
-        if !in_constant(cx, expr.hir_id);
-        if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) })
-            = higher::IfLet::hir(cx, expr);
-        if !is_else_clause(cx.tcx, expr);
-        if !is_result_ok(cx, let_expr); // Don't lint on Result::ok because a different lint does it already
-        if let PatKind::TupleStruct(struct_qpath, [inner_pat], _) = &let_pat.kind;
-        if is_lang_ctor(cx, struct_qpath, OptionSome);
-        if let PatKind::Binding(bind_annotation, _, id, None) = &inner_pat.kind;
+        if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind;
         if let Some(some_captures) = can_move_expr_to_closure(cx, if_then);
         if let Some(none_captures) = can_move_expr_to_closure(cx, if_else);
         if some_captures
             .iter()
             .filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2)))
             .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref());
-
         then {
-            let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
+            let capture_mut = if bind_annotation == BindingAnnotation::Mutable { "mut " } else { "" };
             let some_body = peel_blocks(if_then);
             let none_body = peel_blocks(if_else);
             let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" };
             let capture_name = id.name.to_ident_string();
-            let (as_ref, as_mut) = match &let_expr.kind {
+            let (as_ref, as_mut) = match &expr.kind {
                 ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
                 ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
-                _ => (bind_annotation == &BindingAnnotation::Ref, bind_annotation == &BindingAnnotation::RefMut),
-            };
-            let cond_expr = match let_expr.kind {
-                // Pointer dereferencing happens automatically, so we can omit it in the suggestion
-                ExprKind::Unary(UnOp::Deref, expr) | ExprKind::AddrOf(_, _, expr) => expr,
-                _ => let_expr,
+                _ => (bind_annotation == BindingAnnotation::Ref, bind_annotation == BindingAnnotation::RefMut),
             };
+
             // Check if captures the closure will need conflict with borrows made in the scrutinee.
             // TODO: check all the references made in the scrutinee expression. This will require interacting
             // with the borrow checker. Currently only `<local>[.<field>]*` is checked for.
@@ -154,30 +159,100 @@ fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) ->
                     }
                 }
             }
-            Some(OptionIfLetElseOccurrence {
+
+            return Some(OptionOccurence {
                 option: format_option_in_sugg(cx, cond_expr, as_ref, as_mut),
                 method_sugg: method_sugg.to_string(),
                 some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir_with_macro_callsite(cx, some_body, "..")),
                 none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir_with_macro_callsite(cx, none_body, "..")),
-            })
+            });
+        }
+    }
+
+    None
+}
+
+fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&'tcx Pat<'tcx>> {
+    if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind {
+        if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk) {
+            return Some(inner_pat);
+        }
+    }
+    None
+}
+
+/// If this expression is the option if let/else construct we're detecting, then
+/// this function returns an `OptionOccurence` struct with details if
+/// this construct is found, or None if this construct is not found.
+fn detect_option_if_let_else<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionOccurence> {
+    if let Some(higher::IfLet {
+        let_pat,
+        let_expr,
+        if_then,
+        if_else: Some(if_else),
+    }) = higher::IfLet::hir(cx, expr)
+    {
+        if !is_else_clause(cx.tcx, expr) {
+            return try_get_option_occurence(cx, let_pat, let_expr, if_then, if_else);
+        }
+    }
+    None
+}
+
+fn detect_option_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<OptionOccurence> {
+    if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
+        if let Some((let_pat, if_then, if_else)) = try_convert_match(cx, arms) {
+            return try_get_option_occurence(cx, let_pat, ex, if_then, if_else);
+        }
+    }
+    None
+}
+
+fn try_convert_match<'tcx>(
+    cx: &LateContext<'tcx>,
+    arms: &[Arm<'tcx>],
+) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
+    if arms.len() == 2 {
+        return if is_none_or_err_arm(cx, &arms[1]) {
+            Some((arms[0].pat, arms[0].body, arms[1].body))
+        } else if is_none_or_err_arm(cx, &arms[0]) {
+            Some((arms[1].pat, arms[1].body, arms[0].body))
         } else {
             None
-        }
+        };
+    }
+    None
+}
+
+fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
+    match arm.pat.kind {
+        PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
+        PatKind::TupleStruct(ref qpath, [first_pat], _) => {
+            is_lang_ctor(cx, qpath, ResultErr) && matches!(first_pat.kind, PatKind::Wild)
+        },
+        PatKind::Wild => true,
+        _ => false,
     }
 }
 
 impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
-        if let Some(detection) = detect_option_if_let_else(cx, expr) {
+        // Don't lint macros and constants
+        if expr.span.from_expansion() || in_constant(cx, expr.hir_id) {
+            return;
+        }
+
+        let detection = detect_option_if_let_else(cx, expr).or_else(|| detect_option_match(cx, expr));
+        if let Some(det) = detection {
             span_lint_and_sugg(
                 cx,
                 OPTION_IF_LET_ELSE,
                 expr.span,
-                format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(),
+                format!("use Option::{} instead of an if let/else", det.method_sugg).as_str(),
                 "try",
                 format!(
                     "{}.{}({}, {})",
-                    detection.option, detection.method_sugg, detection.none_expr, detection.some_expr,
+                    det.option, det.method_sugg, det.none_expr, det.some_expr
                 ),
                 Applicability::MaybeIncorrect,
             );
diff --git a/clippy_lints/src/partialeq_to_none.rs b/clippy_lints/src/partialeq_to_none.rs
index eee7642068d..000b0ba7a14 100644
--- a/clippy_lints/src/partialeq_to_none.rs
+++ b/clippy_lints/src/partialeq_to_none.rs
@@ -53,7 +53,8 @@ impl<'tcx> LateLintPass<'tcx> for PartialeqToNone {
 
         // If the expression is a literal `Option::None`
         let is_none_ctor = |expr: &Expr<'_>| {
-            matches!(&peel_hir_expr_refs(expr).0.kind,
+            !expr.span.from_expansion()
+                && matches!(&peel_hir_expr_refs(expr).0.kind,
             ExprKind::Path(p) if is_lang_ctor(cx, p, LangItem::OptionNone))
         };
 
diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs
deleted file mode 100644
index bc6a918f703..00000000000
--- a/clippy_lints/src/path_buf_push_overwrite.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::sym;
-use std::path::{Component, Path};
-
-declare_clippy_lint! {
-    /// ### What it does
-    ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push)
-    /// calls on `PathBuf` that can cause overwrites.
-    ///
-    /// ### Why is this bad?
-    /// Calling `push` with a root path at the start can overwrite the
-    /// previous defined path.
-    ///
-    /// ### Example
-    /// ```rust
-    /// use std::path::PathBuf;
-    ///
-    /// let mut x = PathBuf::from("/foo");
-    /// x.push("/bar");
-    /// assert_eq!(x, PathBuf::from("/bar"));
-    /// ```
-    /// Could be written:
-    ///
-    /// ```rust
-    /// use std::path::PathBuf;
-    ///
-    /// let mut x = PathBuf::from("/foo");
-    /// x.push("bar");
-    /// assert_eq!(x, PathBuf::from("/foo/bar"));
-    /// ```
-    #[clippy::version = "1.36.0"]
-    pub PATH_BUF_PUSH_OVERWRITE,
-    nursery,
-    "calling `push` with file system root on `PathBuf` can overwrite it"
-}
-
-declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]);
-
-impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let ExprKind::MethodCall(path, [recv, get_index_arg], _) = expr.kind;
-            if path.ident.name == sym!(push);
-            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::PathBuf);
-            if let ExprKind::Lit(ref lit) = get_index_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();
-            if pushed_path.has_root();
-            if let Some(root) = pushed_path.components().next();
-            if root == Component::RootDir;
-            then {
-                span_lint_and_sugg(
-                    cx,
-                    PATH_BUF_PUSH_OVERWRITE,
-                    lit.span,
-                    "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition",
-                    "try",
-                    format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-    }
-}
diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs
index 964a057f00d..b432ccb1ee3 100644
--- a/clippy_lints/src/question_mark.rs
+++ b/clippy_lints/src/question_mark.rs
@@ -123,7 +123,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
         if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr);
         if !is_else_clause(cx.tcx, expr);
         if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind;
-        if let PatKind::Binding(annot, bind_id, ident, _) = field.kind;
+        if let PatKind::Binding(annot, bind_id, ident, None) = field.kind;
         let caller_ty = cx.typeck_results().expr_ty(let_expr);
         let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else);
         if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id))
diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs
index fbf842c339e..490f345d297 100644
--- a/clippy_lints/src/ranges.rs
+++ b/clippy_lints/src/ranges.rs
@@ -1,46 +1,20 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::higher;
 use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local};
-use clippy_utils::{higher, SpanlessEq};
 use if_chain::if_chain;
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, PathSegment, QPath};
+use rustc_hir::{BinOpKind, Expr, ExprKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{Span, Spanned};
-use rustc_span::sym;
 use std::cmp::Ordering;
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for zipping a collection with the range of
-    /// `0.._.len()`.
-    ///
-    /// ### Why is this bad?
-    /// The code is better expressed with `.enumerate()`.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # let x = vec![1];
-    /// let _ = x.iter().zip(0..x.len());
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust
-    /// # let x = vec![1];
-    /// let _ = x.iter().enumerate();
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub RANGE_ZIP_WITH_LEN,
-    complexity,
-    "zipping iterator with a range when `enumerate()` would do"
-}
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for exclusive ranges where 1 is added to the
@@ -198,7 +172,6 @@ impl Ranges {
 }
 
 impl_lint_pass!(Ranges => [
-    RANGE_ZIP_WITH_LEN,
     RANGE_PLUS_ONE,
     RANGE_MINUS_ONE,
     REVERSED_EMPTY_RANGES,
@@ -207,16 +180,10 @@ impl_lint_pass!(Ranges => [
 
 impl<'tcx> LateLintPass<'tcx> for Ranges {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        match expr.kind {
-            ExprKind::MethodCall(path, args, _) => {
-                check_range_zip_with_len(cx, path, args, expr.span);
-            },
-            ExprKind::Binary(ref op, l, r) => {
-                if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
-                    check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
-                }
-            },
-            _ => {},
+        if let ExprKind::Binary(ref op, l, r) = expr.kind {
+            if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
+                check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
+            }
         }
 
         check_exclusive_range_plus_one(cx, expr);
@@ -380,34 +347,6 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R
     None
 }
 
-fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) {
-    if_chain! {
-        if path.ident.as_str() == "zip";
-        if let [iter, zip_arg] = args;
-        // `.iter()` call
-        if let ExprKind::MethodCall(iter_path, [iter_caller, ..], _) = iter.kind;
-        if iter_path.ident.name == sym::iter;
-        // range expression in `.zip()` call: `0..x.len()`
-        if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
-        if is_integer_const(cx, start, 0);
-        // `.len()` call
-        if let ExprKind::MethodCall(len_path, [len_caller], _) = end.kind;
-        if len_path.ident.name == sym::len;
-        // `.iter()` and `.len()` called on same `Path`
-        if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_caller.kind;
-        if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_caller.kind;
-        if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
-        then {
-            span_lint(cx,
-                RANGE_ZIP_WITH_LEN,
-                span,
-                &format!("it is more idiomatic to use `{}.iter().enumerate()`",
-                    snippet(cx, iter_caller.span, "_"))
-            );
-        }
-    }
-}
-
 // exclusive range plus one: `x..(y+1)`
 fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs
index 8db8c4e9b78..e82aa3a7b98 100644
--- a/clippy_lints/src/rc_clone_in_vec_init.rs
+++ b/clippy_lints/src/rc_clone_in_vec_init.rs
@@ -41,7 +41,7 @@ declare_clippy_lint! {
     /// let data = std::rc::Rc::new("some data".to_string());
     /// let v = vec![data; 100];
     /// ```
-    #[clippy::version = "1.62.0"]
+    #[clippy::version = "1.63.0"]
     pub RC_CLONE_IN_VEC_INIT,
     suspicious,
     "initializing reference-counted pointer in `vec![elem; len]`"
diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs
index db6c97f3739..8693ca9af83 100644
--- a/clippy_lints/src/redundant_slicing.rs
+++ b/clippy_lints/src/redundant_slicing.rs
@@ -11,6 +11,8 @@ use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::subst::GenericArg;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
+use std::iter;
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for redundant slicing expressions which use the full range, and
@@ -134,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                 } else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
                     if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
                         cx.param_env,
-                        cx.tcx.mk_projection(target_id, cx.tcx.mk_substs([GenericArg::from(indexed_ty)].into_iter())),
+                        cx.tcx.mk_projection(target_id, cx.tcx.mk_substs(iter::once(GenericArg::from(indexed_ty)))),
                     ) {
                         if deref_ty == expr_ty {
                             let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs
index f8801f769e8..2d751c27467 100644
--- a/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/clippy_lints/src/redundant_static_lifetimes.rs
@@ -48,15 +48,15 @@ impl_lint_pass!(RedundantStaticLifetimes => [REDUNDANT_STATIC_LIFETIMES]);
 
 impl RedundantStaticLifetimes {
     // Recursively visit types
-    fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
+    fn visit_type(ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
         match ty.kind {
             // Be careful of nested structures (arrays and tuples)
             TyKind::Array(ref ty, _) | TyKind::Slice(ref ty) => {
-                self.visit_type(ty, cx, reason);
+                Self::visit_type(ty, cx, reason);
             },
             TyKind::Tup(ref tup) => {
                 for tup_ty in tup {
-                    self.visit_type(tup_ty, cx, reason);
+                    Self::visit_type(tup_ty, cx, reason);
                 }
             },
             // This is what we are looking for !
@@ -87,7 +87,7 @@ impl RedundantStaticLifetimes {
                         _ => {},
                     }
                 }
-                self.visit_type(&borrow_type.ty, cx, reason);
+                Self::visit_type(&borrow_type.ty, cx, reason);
             },
             _ => {},
         }
@@ -102,13 +102,13 @@ impl EarlyLintPass for RedundantStaticLifetimes {
 
         if !item.span.from_expansion() {
             if let ItemKind::Const(_, ref var_type, _) = item.kind {
-                self.visit_type(var_type, cx, "constants have by default a `'static` lifetime");
+                Self::visit_type(var_type, cx, "constants have by default a `'static` lifetime");
                 // Don't check associated consts because `'static` cannot be elided on those (issue
                 // #2438)
             }
 
             if let ItemKind::Static(ref var_type, _, _) = item.kind {
-                self.visit_type(var_type, cx, "statics have by default a `'static` lifetime");
+                Self::visit_type(var_type, cx, "statics have by default a `'static` lifetime");
             }
         }
     }
diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs
deleted file mode 100644
index 898c70ace66..00000000000
--- a/clippy_lints/src/repeat_once.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-use clippy_utils::consts::{constant_context, Constant};
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-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 usage of `.repeat(1)` and suggest the following method for each types.
-    /// - `.to_string()` for `str`
-    /// - `.clone()` for `String`
-    /// - `.to_vec()` for `slice`
-    ///
-    /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if
-    /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))
-    ///
-    /// ### Why is this bad?
-    /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning
-    /// the string is the intention behind this, `clone()` should be used.
-    ///
-    /// ### Example
-    /// ```rust
-    /// fn main() {
-    ///     let x = String::from("hello world").repeat(1);
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// fn main() {
-    ///     let x = String::from("hello world").clone();
-    /// }
-    /// ```
-    #[clippy::version = "1.47.0"]
-    pub REPEAT_ONCE,
-    complexity,
-    "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` "
-}
-
-declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]);
-
-impl<'tcx> LateLintPass<'tcx> for RepeatOnce {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let ExprKind::MethodCall(path, [receiver, count], _) = &expr.kind;
-            if path.ident.name == sym!(repeat);
-            if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1));
-            if !receiver.span.from_expansion();
-            then {
-                let ty = cx.typeck_results().expr_ty(receiver).peel_refs();
-                if ty.is_str() {
-                    span_lint_and_sugg(
-                        cx,
-                        REPEAT_ONCE,
-                        expr.span,
-                        "calling `repeat(1)` on str",
-                        "consider using `.to_string()` instead",
-                        format!("{}.to_string()", snippet(cx, receiver.span, r#""...""#)),
-                        Applicability::MachineApplicable,
-                    );
-                } else if ty.builtin_index().is_some() {
-                    span_lint_and_sugg(
-                        cx,
-                        REPEAT_ONCE,
-                        expr.span,
-                        "calling `repeat(1)` on slice",
-                        "consider using `.to_vec()` instead",
-                        format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)),
-                        Applicability::MachineApplicable,
-                    );
-                } else if is_type_diagnostic_item(cx, ty, sym::String) {
-                    span_lint_and_sugg(
-                        cx,
-                        REPEAT_ONCE,
-                        expr.span,
-                        "calling `repeat(1)` on a string literal",
-                        "consider using `.clone()` instead",
-                        format!("{}.clone()", snippet(cx, receiver.span, r#""...""#)),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-        }
-    }
-}
diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs
index 1d9a2abf706..1926661c596 100644
--- a/clippy_lints/src/returns.rs
+++ b/clippy_lints/src/returns.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::{snippet_opt, snippet_with_context};
 use clippy_utils::{fn_def_id, path_to_local_id};
 use if_chain::if_chain;
-use rustc_ast::ast::Attribute;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind};
@@ -11,7 +10,6 @@ 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::source_map::Span;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -152,10 +150,6 @@ impl<'tcx> LateLintPass<'tcx> for Return {
     }
 }
 
-fn attr_is_cfg(attr: &Attribute) -> bool {
-    attr.meta_item_list().is_some() && attr.has_name(sym::cfg)
-}
-
 fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) {
     if let Some(expr) = block.expr {
         check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty);
@@ -178,9 +172,7 @@ fn check_final_expr<'tcx>(
     match expr.kind {
         // simple return is always "bad"
         ExprKind::Ret(ref inner) => {
-            // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
-            let attrs = cx.tcx.hir().attrs(expr.hir_id);
-            if !attrs.iter().any(attr_is_cfg) {
+            if cx.tcx.hir().attrs(expr.hir_id).is_empty() {
                 let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
                 if !borrows {
                     emit_return_lint(
diff --git a/clippy_lints/src/self_named_constructors.rs b/clippy_lints/src/self_named_constructors.rs
index d07c26d7c89..9cea4d88067 100644
--- a/clippy_lints/src/self_named_constructors.rs
+++ b/clippy_lints/src/self_named_constructors.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::return_ty;
-use clippy_utils::ty::{contains_adt_constructor, contains_ty};
+use clippy_utils::ty::contains_adt_constructor;
 use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors {
             if !contains_adt_constructor(ret_ty, self_adt) {
                 return;
             }
-        } else if !contains_ty(ret_ty, self_ty) {
+        } else if !ret_ty.contains(self_ty) {
             return;
         }
 
diff --git a/clippy_lints/src/stable_sort_primitive.rs b/clippy_lints/src/stable_sort_primitive.rs
deleted file mode 100644
index 6d54935f81a..00000000000
--- a/clippy_lints/src/stable_sort_primitive.rs
+++ /dev/null
@@ -1,144 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{is_slice_of_primitives, sugg::Sugg};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// When sorting primitive values (integers, bools, chars, as well
-    /// as arrays, slices, and tuples of such items), it is typically better to
-    /// use an unstable sort than a stable sort.
-    ///
-    /// ### Why is this bad?
-    /// Typically, using a stable sort consumes more memory and cpu cycles.
-    /// Because values which compare equal are identical, preserving their
-    /// relative order (the guarantee that a stable sort provides) means
-    /// nothing, while the extra costs still apply.
-    ///
-    /// ### Known problems
-    ///
-    /// As pointed out in
-    /// [issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241),
-    /// a stable sort can instead be significantly faster for certain scenarios
-    /// (eg. when a sorted vector is extended with new data and resorted).
-    ///
-    /// For more information and benchmarking results, please refer to the
-    /// issue linked above.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let mut vec = vec![2, 1, 3];
-    /// vec.sort();
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// let mut vec = vec![2, 1, 3];
-    /// vec.sort_unstable();
-    /// ```
-    #[clippy::version = "1.47.0"]
-    pub STABLE_SORT_PRIMITIVE,
-    pedantic,
-    "use of sort() when sort_unstable() is equivalent"
-}
-
-declare_lint_pass!(StableSortPrimitive => [STABLE_SORT_PRIMITIVE]);
-
-/// The three "kinds" of sorts
-enum SortingKind {
-    Vanilla,
-    /* The other kinds of lint are currently commented out because they
-     * can map distinct values to equal ones. If the key function is
-     * provably one-to-one, or if the Cmp function conserves equality,
-     * then they could be linted on, but I don't know if we can check
-     * for that. */
-
-    /* ByKey,
-     * ByCmp, */
-}
-impl SortingKind {
-    /// The name of the stable version of this kind of sort
-    fn stable_name(&self) -> &str {
-        match self {
-            SortingKind::Vanilla => "sort",
-            /* SortingKind::ByKey => "sort_by_key",
-             * SortingKind::ByCmp => "sort_by", */
-        }
-    }
-    /// The name of the unstable version of this kind of sort
-    fn unstable_name(&self) -> &str {
-        match self {
-            SortingKind::Vanilla => "sort_unstable",
-            /* SortingKind::ByKey => "sort_unstable_by_key",
-             * SortingKind::ByCmp => "sort_unstable_by", */
-        }
-    }
-    /// Takes the name of a function call and returns the kind of sort
-    /// that corresponds to that function name (or None if it isn't)
-    fn from_stable_name(name: &str) -> Option<SortingKind> {
-        match name {
-            "sort" => Some(SortingKind::Vanilla),
-            // "sort_by" => Some(SortingKind::ByCmp),
-            // "sort_by_key" => Some(SortingKind::ByKey),
-            _ => None,
-        }
-    }
-}
-
-/// A detected instance of this lint
-struct LintDetection {
-    slice_name: String,
-    method: SortingKind,
-    method_args: String,
-    slice_type: String,
-}
-
-fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintDetection> {
-    if_chain! {
-        if let ExprKind::MethodCall(method_name, [slice, args @ ..], _) = &expr.kind;
-        if let Some(method) = SortingKind::from_stable_name(method_name.ident.name.as_str());
-        if let Some(slice_type) = is_slice_of_primitives(cx, slice);
-        then {
-            let args_str = args.iter().map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", ");
-            Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type })
-        } else {
-            None
-        }
-    }
-}
-
-impl LateLintPass<'_> for StableSortPrimitive {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if let Some(detection) = detect_stable_sort_primitive(cx, expr) {
-            span_lint_and_then(
-                cx,
-                STABLE_SORT_PRIMITIVE,
-                expr.span,
-                format!(
-                    "used `{}` on primitive type `{}`",
-                    detection.method.stable_name(),
-                    detection.slice_type,
-                )
-                .as_str(),
-                |diag| {
-                    diag.span_suggestion(
-                        expr.span,
-                        "try",
-                        format!(
-                            "{}.{}({})",
-                            detection.slice_name,
-                            detection.method.unstable_name(),
-                            detection.method_args,
-                        ),
-                        Applicability::MachineApplicable,
-                    );
-                    diag.note(
-                        "an unstable sort typically performs faster without any observable difference for this data type",
-                    );
-                },
-            );
-        }
-    }
-}
diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 0a42a31fb8c..2ffa022b04f 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -4,7 +4,7 @@ use clippy_utils::{SpanlessEq, SpanlessHash};
 use core::hash::{Hash, Hasher};
 use if_chain::if_chain;
 use itertools::Itertools;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -15,6 +15,7 @@ use rustc_hir::{
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{BytePos, Span};
+use std::collections::hash_map::Entry;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -103,7 +104,6 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
     fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
         self.check_type_repetition(cx, gen);
         check_trait_bound_duplication(cx, gen);
-        check_bounds_or_where_duplication(cx, gen);
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
@@ -234,35 +234,61 @@ impl TraitBounds {
 }
 
 fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
-    if gen.span.from_expansion() || gen.params.is_empty() || gen.predicates.is_empty() {
+    if gen.span.from_expansion() {
         return;
     }
 
-    let mut map = FxHashMap::<_, Vec<_>>::default();
-    for predicate in gen.predicates {
+    // Explanation:
+    // fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+    // where T: Clone + Default, { unimplemented!(); }
+    //       ^^^^^^^^^^^^^^^^^^
+    //       |
+    // collects each of these where clauses into a set keyed by generic name and comparable trait
+    // eg. (T, Clone)
+    let where_predicates = gen
+        .predicates
+        .iter()
+        .filter_map(|pred| {
+            if_chain! {
+                if pred.in_where_clause();
+                if let WherePredicate::BoundPredicate(bound_predicate) = pred;
+                if let TyKind::Path(QPath::Resolved(_, path)) =  bound_predicate.bounded_ty.kind;
+                then {
+                    return Some(
+                        rollup_traits(cx, bound_predicate.bounds, "these where clauses contain repeated elements")
+                        .into_iter().map(|(trait_ref, _)| (path.res, trait_ref)))
+                }
+            }
+            None
+        })
+        .flatten()
+        .collect::<FxHashSet<_>>();
+
+    // Explanation:
+    // fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z) ...
+    //            ^^^^^^^^^^^^^^^^^^  ^^^^^^^
+    //            |
+    // compare trait bounds keyed by generic name and comparable trait to collected where
+    // predicates eg. (T, Clone)
+    for predicate in gen.predicates.iter().filter(|pred| !pred.in_where_clause()) {
         if_chain! {
-            if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
+            if let WherePredicate::BoundPredicate(bound_predicate) = predicate;
             if bound_predicate.origin != PredicateOrigin::ImplTrait;
             if !bound_predicate.span.from_expansion();
-            if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
-            if let Some(segment) = segments.first();
+            if let TyKind::Path(QPath::Resolved(_, path)) =  bound_predicate.bounded_ty.kind;
             then {
-                for (res_where, _, span_where) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
-                    let trait_resolutions_direct = map.entry(segment.ident).or_default();
-                    if let Some((_, span_direct)) = trait_resolutions_direct
-                                                .iter()
-                                                .find(|(res_direct, _)| *res_direct == res_where) {
+                let traits = rollup_traits(cx, bound_predicate.bounds, "these bounds contain repeated elements");
+                for (trait_ref, span) in traits {
+                    let key = (path.res, trait_ref);
+                    if where_predicates.contains(&key) {
                         span_lint_and_help(
                             cx,
                             TRAIT_DUPLICATION_IN_BOUNDS,
-                            *span_direct,
+                            span,
                             "this trait bound is already specified in the where clause",
                             None,
                             "consider removing this trait bound",
-                        );
-                    }
-                    else {
-                        trait_resolutions_direct.push((res_where, span_where));
+                            );
                     }
                 }
             }
@@ -270,23 +296,11 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
     }
 }
 
-#[derive(PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
 struct ComparableTraitRef(Res, Vec<Res>);
-
-fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
-    if gen.span.from_expansion() {
-        return;
-    }
-
-    for predicate in gen.predicates {
-        if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate {
-            let msg = if predicate.in_where_clause() {
-                "these where clauses contain repeated elements"
-            } else {
-                "these bounds contain repeated elements"
-            };
-            rollup_traits(cx, bound_predicate.bounds, msg);
-        }
+impl Default for ComparableTraitRef {
+    fn default() -> Self {
+        Self(Res::Err, Vec::new())
     }
 }
 
@@ -331,7 +345,7 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef {
     )
 }
 
-fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) {
+fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -> Vec<(ComparableTraitRef, Span)> {
     let mut map = FxHashMap::default();
     let mut repeated_res = false;
 
@@ -343,23 +357,33 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) {
         }
     };
 
+    let mut i = 0usize;
     for bound in bounds.iter().filter_map(only_comparable_trait_refs) {
         let (comparable_bound, span_direct) = bound;
-        if map.insert(comparable_bound, span_direct).is_some() {
-            repeated_res = true;
+        match map.entry(comparable_bound) {
+            Entry::Occupied(_) => repeated_res = true,
+            Entry::Vacant(e) => {
+                e.insert((span_direct, i));
+                i += 1;
+            },
         }
     }
 
+    // Put bounds in source order
+    let mut comparable_bounds = vec![Default::default(); map.len()];
+    for (k, (v, i)) in map {
+        comparable_bounds[i] = (k, v);
+    }
+
     if_chain! {
         if repeated_res;
         if let [first_trait, .., last_trait] = bounds;
         then {
             let all_trait_span = first_trait.span().to(last_trait.span());
 
-            let mut traits = map.values()
-                .filter_map(|span| snippet_opt(cx, *span))
+            let traits = comparable_bounds.iter()
+                .filter_map(|&(_, span)| snippet_opt(cx, span))
                 .collect::<Vec<_>>();
-            traits.sort_unstable();
             let traits = traits.join(" + ");
 
             span_lint_and_sugg(
@@ -373,4 +397,6 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) {
             );
         }
     }
+
+    comparable_bounds
 }
diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs
index 5f3e98144f4..424a6e9264e 100644
--- a/clippy_lints/src/transmute/mod.rs
+++ b/clippy_lints/src/transmute/mod.rs
@@ -9,6 +9,7 @@ mod transmute_ptr_to_ref;
 mod transmute_ref_to_ref;
 mod transmute_undefined_repr;
 mod transmutes_expressible_as_ptr_casts;
+mod transmuting_null;
 mod unsound_collection_transmute;
 mod useless_transmute;
 mod utils;
@@ -386,6 +387,28 @@ declare_clippy_lint! {
     "transmute to or from a type with an undefined representation"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for transmute calls which would receive a null pointer.
+    ///
+    /// ### Why is this bad?
+    /// Transmuting a null pointer is undefined behavior.
+    ///
+    /// ### Known problems
+    /// Not all cases can be detected at the moment of this writing.
+    /// For example, variables which hold a null pointer and are then fed to a `transmute`
+    /// call, aren't detectable yet.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
+    /// ```
+    #[clippy::version = "1.35.0"]
+    pub TRANSMUTING_NULL,
+    correctness,
+    "transmutes from a null pointer to a reference, which is undefined behavior"
+}
+
 pub struct Transmute {
     msrv: Option<RustcVersion>,
 }
@@ -404,6 +427,7 @@ impl_lint_pass!(Transmute => [
     UNSOUND_COLLECTION_TRANSMUTE,
     TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
     TRANSMUTE_UNDEFINED_REPR,
+    TRANSMUTING_NULL,
 ]);
 impl Transmute {
     #[must_use]
@@ -436,6 +460,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
 
                 let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
                     | crosspointer_transmute::check(cx, e, from_ty, to_ty)
+                    | transmuting_null::check(cx, e, arg, to_ty)
                     | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
                     | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
                     | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 20b348fc14f..b6d7d9f5b42 100644
--- a/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -5,9 +5,9 @@ use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy};
-use rustc_span::Span;
+use rustc_span::DUMMY_SP;
 
-#[allow(clippy::too_many_lines)]
+#[expect(clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     e: &'tcx Expr<'_>,
@@ -18,116 +18,89 @@ pub(super) fn check<'tcx>(
     let mut to_ty = cx.tcx.erase_regions(to_ty_orig);
 
     while from_ty != to_ty {
-        match reduce_refs(cx, e.span, from_ty, to_ty) {
-            ReducedTys::FromFatPtr {
-                unsized_ty,
-                to_ty: to_sub_ty,
-            } => match reduce_ty(cx, to_sub_ty) {
-                ReducedTy::TypeErasure => break,
-                ReducedTy::UnorderedFields(ty) if is_size_pair(ty) => break,
-                ReducedTy::Ref(to_sub_ty) => {
-                    from_ty = unsized_ty;
-                    to_ty = to_sub_ty;
-                    continue;
-                },
-                _ => {
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
-                        |diag| {
-                            if from_ty_orig.peel_refs() != unsized_ty {
-                                diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty));
-                            }
-                        },
-                    );
-                    return true;
-                },
+        let reduced_tys = reduce_refs(cx, from_ty, to_ty);
+        match (reduce_ty(cx, reduced_tys.from_ty), reduce_ty(cx, reduced_tys.to_ty)) {
+            // Various forms of type erasure.
+            (ReducedTy::TypeErasure { raw_ptr_only: false }, _)
+            | (_, ReducedTy::TypeErasure { raw_ptr_only: false }) => return false,
+            (ReducedTy::TypeErasure { .. }, _) if reduced_tys.from_raw_ptr => return false,
+            (_, ReducedTy::TypeErasure { .. }) if reduced_tys.to_raw_ptr => return false,
+
+            // `Repr(C)` <-> unordered type.
+            // If the first field of the `Repr(C)` type matches then the transmute is ok
+            (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::UnorderedFields(to_sub_ty))
+            | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty))) => {
+                from_ty = from_sub_ty;
+                to_ty = to_sub_ty;
+                continue;
             },
-            ReducedTys::ToFatPtr {
-                unsized_ty,
-                from_ty: from_sub_ty,
-            } => match reduce_ty(cx, from_sub_ty) {
-                ReducedTy::TypeErasure => break,
-                ReducedTy::UnorderedFields(ty) if is_size_pair(ty) => break,
-                ReducedTy::Ref(from_sub_ty) => {
-                    from_ty = from_sub_ty;
-                    to_ty = unsized_ty;
-                    continue;
-                },
-                _ => {
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!("transmute to `{}` which has an undefined layout", to_ty_orig),
-                        |diag| {
-                            if to_ty_orig.peel_refs() != unsized_ty {
-                                diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty));
-                            }
-                        },
-                    );
-                    return true;
-                },
+            (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => {
+                from_ty = from_sub_ty;
+                to_ty = to_sub_ty;
+                continue;
             },
-            ReducedTys::ToPtr {
-                from_ty: from_sub_ty,
-                to_ty: to_sub_ty,
-            } => match reduce_ty(cx, from_sub_ty) {
-                ReducedTy::UnorderedFields(from_ty) => {
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
-                        |diag| {
-                            if from_ty_orig.peel_refs() != from_ty {
-                                diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
-                            }
-                        },
-                    );
-                    return true;
-                },
-                ReducedTy::Ref(from_sub_ty) => {
-                    from_ty = from_sub_ty;
-                    to_ty = to_sub_ty;
-                    continue;
-                },
-                _ => break,
+            (ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
+                if reduced_tys.from_fat_ptr =>
+            {
+                from_ty = from_sub_ty;
+                to_ty = to_sub_ty;
+                continue;
             },
-            ReducedTys::FromPtr {
-                from_ty: from_sub_ty,
-                to_ty: to_sub_ty,
-            } => match reduce_ty(cx, to_sub_ty) {
-                ReducedTy::UnorderedFields(to_ty) => {
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!("transmute to `{}` which has an undefined layout", to_ty_orig),
-                        |diag| {
-                            if to_ty_orig.peel_refs() != to_ty {
-                                diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
-                            }
-                        },
-                    );
-                    return true;
-                },
-                ReducedTy::Ref(to_sub_ty) => {
-                    from_ty = from_sub_ty;
-                    to_ty = to_sub_ty;
-                    continue;
-                },
-                _ => break,
+
+            // ptr <-> ptr
+            (ReducedTy::Other(from_sub_ty), ReducedTy::Other(to_sub_ty))
+                if matches!(from_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_))
+                    && matches!(to_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_)) =>
+            {
+                from_ty = from_sub_ty;
+                to_ty = to_sub_ty;
+                continue;
             },
-            ReducedTys::Other {
-                from_ty: from_sub_ty,
-                to_ty: to_sub_ty,
-            } => match (reduce_ty(cx, from_sub_ty), reduce_ty(cx, to_sub_ty)) {
-                (ReducedTy::TypeErasure, _) | (_, ReducedTy::TypeErasure) => return false,
-                (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
-                    let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
+
+            // fat ptr <-> (*size, *size)
+            (ReducedTy::Other(_), ReducedTy::UnorderedFields(to_ty))
+                if reduced_tys.from_fat_ptr && is_size_pair(to_ty) =>
+            {
+                return false;
+            },
+            (ReducedTy::UnorderedFields(from_ty), ReducedTy::Other(_))
+                if reduced_tys.to_fat_ptr && is_size_pair(from_ty) =>
+            {
+                return false;
+            },
+
+            // fat ptr -> some struct | some struct -> fat ptr
+            (ReducedTy::Other(_), _) if reduced_tys.from_fat_ptr => {
+                span_lint_and_then(
+                    cx,
+                    TRANSMUTE_UNDEFINED_REPR,
+                    e.span,
+                    &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
+                    |diag| {
+                        if from_ty_orig.peel_refs() != from_ty.peel_refs() {
+                            diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
+                        }
+                    },
+                );
+                return true;
+            },
+            (_, ReducedTy::Other(_)) if reduced_tys.to_fat_ptr => {
+                span_lint_and_then(
+                    cx,
+                    TRANSMUTE_UNDEFINED_REPR,
+                    e.span,
+                    &format!("transmute to `{}` which has an undefined layout", to_ty_orig),
+                    |diag| {
+                        if to_ty_orig.peel_refs() != to_ty.peel_refs() {
+                            diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
+                        }
+                    },
+                );
+                return true;
+            },
+
+            (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
+                let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
                         = (from_ty.kind(), to_ty.kind())
                         && from_def == to_def
                     {
@@ -138,79 +111,72 @@ pub(super) fn check<'tcx>(
                     } else {
                         None
                     };
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!(
-                            "transmute from `{}` to `{}`, both of which have an undefined layout",
-                            from_ty_orig, to_ty_orig
-                        ),
-                        |diag| {
-                            if let Some(same_adt_did) = same_adt_did {
-                                diag.note(&format!(
-                                    "two instances of the same generic type (`{}`) may have different layouts",
-                                    cx.tcx.item_name(same_adt_did)
-                                ));
-                            } else {
-                                if from_ty_orig.peel_refs() != from_ty {
-                                    diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
-                                }
-                                if to_ty_orig.peel_refs() != to_ty {
-                                    diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
-                                }
-                            }
-                        },
-                    );
-                    return true;
-                },
-                (
-                    ReducedTy::UnorderedFields(from_ty),
-                    ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
-                ) => {
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
-                        |diag| {
+                span_lint_and_then(
+                    cx,
+                    TRANSMUTE_UNDEFINED_REPR,
+                    e.span,
+                    &format!(
+                        "transmute from `{}` to `{}`, both of which have an undefined layout",
+                        from_ty_orig, to_ty_orig
+                    ),
+                    |diag| {
+                        if let Some(same_adt_did) = same_adt_did {
+                            diag.note(&format!(
+                                "two instances of the same generic type (`{}`) may have different layouts",
+                                cx.tcx.item_name(same_adt_did)
+                            ));
+                        } else {
                             if from_ty_orig.peel_refs() != from_ty {
                                 diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
                             }
-                        },
-                    );
-                    return true;
-                },
-                (
-                    ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
-                    ReducedTy::UnorderedFields(to_ty),
-                ) => {
-                    span_lint_and_then(
-                        cx,
-                        TRANSMUTE_UNDEFINED_REPR,
-                        e.span,
-                        &format!("transmute into `{}` which has an undefined layout", to_ty_orig),
-                        |diag| {
                             if to_ty_orig.peel_refs() != to_ty {
                                 diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
                             }
-                        },
-                    );
-                    return true;
-                },
-                (ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => {
-                    from_ty = from_sub_ty;
-                    to_ty = to_sub_ty;
-                    continue;
-                },
-                (
-                    ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
-                    ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param,
-                )
-                | (
-                    ReducedTy::UnorderedFields(_) | ReducedTy::Param,
-                    ReducedTy::UnorderedFields(_) | ReducedTy::Param,
-                ) => break,
+                        }
+                    },
+                );
+                return true;
+            },
+            (
+                ReducedTy::UnorderedFields(from_ty),
+                ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true },
+            ) => {
+                span_lint_and_then(
+                    cx,
+                    TRANSMUTE_UNDEFINED_REPR,
+                    e.span,
+                    &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
+                    |diag| {
+                        if from_ty_orig.peel_refs() != from_ty {
+                            diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
+                        }
+                    },
+                );
+                return true;
+            },
+            (
+                ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true },
+                ReducedTy::UnorderedFields(to_ty),
+            ) => {
+                span_lint_and_then(
+                    cx,
+                    TRANSMUTE_UNDEFINED_REPR,
+                    e.span,
+                    &format!("transmute into `{}` which has an undefined layout", to_ty_orig),
+                    |diag| {
+                        if to_ty_orig.peel_refs() != to_ty {
+                            diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
+                        }
+                    },
+                );
+                return true;
+            },
+            (
+                ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true },
+                ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true },
+            )
+            | (ReducedTy::UnorderedFields(_), ReducedTy::UnorderedFields(_)) => {
+                break;
             },
         }
     }
@@ -218,64 +184,64 @@ pub(super) fn check<'tcx>(
     false
 }
 
-enum ReducedTys<'tcx> {
-    FromFatPtr { unsized_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
-    ToFatPtr { unsized_ty: Ty<'tcx>, from_ty: Ty<'tcx> },
-    ToPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
-    FromPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
-    Other { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
+#[expect(clippy::struct_excessive_bools)]
+struct ReducedTys<'tcx> {
+    from_ty: Ty<'tcx>,
+    to_ty: Ty<'tcx>,
+    from_raw_ptr: bool,
+    to_raw_ptr: bool,
+    from_fat_ptr: bool,
+    to_fat_ptr: bool,
 }
 
 /// Remove references so long as both types are references.
-fn reduce_refs<'tcx>(
-    cx: &LateContext<'tcx>,
-    span: Span,
-    mut from_ty: Ty<'tcx>,
-    mut to_ty: Ty<'tcx>,
-) -> ReducedTys<'tcx> {
-    loop {
-        return match (from_ty.kind(), to_ty.kind()) {
+fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: Ty<'tcx>) -> ReducedTys<'tcx> {
+    let mut from_raw_ptr = false;
+    let mut to_raw_ptr = false;
+    let (from_fat_ptr, to_fat_ptr) = loop {
+        break match (from_ty.kind(), to_ty.kind()) {
             (
                 &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
                 &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })),
             ) => {
+                from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_));
                 from_ty = from_sub_ty;
+                to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_));
                 to_ty = to_sub_ty;
                 continue;
             },
             (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })), _)
-                if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) =>
+                if !unsized_ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env) =>
             {
-                ReducedTys::FromFatPtr { unsized_ty, to_ty }
+                (true, false)
             },
             (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })))
-                if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) =>
+                if !unsized_ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env) =>
             {
-                ReducedTys::ToFatPtr { unsized_ty, from_ty }
+                (false, true)
             },
-            (&(ty::Ref(_, from_ty, _) | ty::RawPtr(TypeAndMut { ty: from_ty, .. })), _) => {
-                ReducedTys::FromPtr { from_ty, to_ty }
-            },
-            (_, &(ty::Ref(_, to_ty, _) | ty::RawPtr(TypeAndMut { ty: to_ty, .. }))) => {
-                ReducedTys::ToPtr { from_ty, to_ty }
-            },
-            _ => ReducedTys::Other { from_ty, to_ty },
+            _ => (false, false),
         };
+    };
+    ReducedTys {
+        from_ty,
+        to_ty,
+        from_raw_ptr,
+        to_raw_ptr,
+        from_fat_ptr,
+        to_fat_ptr,
     }
 }
 
 enum ReducedTy<'tcx> {
     /// The type can be used for type erasure.
-    TypeErasure,
+    TypeErasure { raw_ptr_only: bool },
     /// The type is a struct containing either zero non-zero sized fields, or multiple non-zero
     /// sized fields with a defined order.
-    OrderedFields(Ty<'tcx>),
+    /// The second value is the first non-zero sized type.
+    OrderedFields(Ty<'tcx>, Option<Ty<'tcx>>),
     /// The type is a struct containing multiple non-zero sized fields with no defined order.
     UnorderedFields(Ty<'tcx>),
-    /// The type is a reference to the contained type.
-    Ref(Ty<'tcx>),
-    /// The type is a generic parameter.
-    Param,
     /// Any other type.
     Other(Ty<'tcx>),
 }
@@ -285,16 +251,18 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
     loop {
         ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty);
         return match *ty.kind() {
-            ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => ReducedTy::TypeErasure,
+            ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => {
+                ReducedTy::TypeErasure { raw_ptr_only: false }
+            },
             ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
                 ty = sub_ty;
                 continue;
             },
-            ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure,
+            ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure { raw_ptr_only: false },
             ty::Tuple(args) => {
                 let mut iter = args.iter();
                 let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
-                    return ReducedTy::OrderedFields(ty);
+                    return ReducedTy::OrderedFields(ty, None);
                 };
                 if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
                     ty = sized_ty;
@@ -309,27 +277,25 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx>
                     .iter()
                     .map(|f| cx.tcx.bound_type_of(f.did).subst(cx.tcx, substs));
                 let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else {
-                    return ReducedTy::TypeErasure;
+                    return ReducedTy::TypeErasure { raw_ptr_only: false };
                 };
                 if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
                     ty = sized_ty;
                     continue;
                 }
                 if def.repr().inhibit_struct_field_reordering_opt() {
-                    ReducedTy::OrderedFields(ty)
+                    ReducedTy::OrderedFields(ty, Some(sized_ty))
                 } else {
                     ReducedTy::UnorderedFields(ty)
                 }
             },
             ty::Adt(def, _) if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) => {
-                ReducedTy::TypeErasure
+                ReducedTy::TypeErasure { raw_ptr_only: false }
             },
             // TODO: Check if the conversion to or from at least one of a union's fields is valid.
-            ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure,
-            ty::Foreign(_) => ReducedTy::TypeErasure,
-            ty::Ref(_, ty, _) => ReducedTy::Ref(ty),
-            ty::RawPtr(ty) => ReducedTy::Ref(ty.ty),
-            ty::Param(_) => ReducedTy::Param,
+            ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure { raw_ptr_only: false },
+            ty::Foreign(_) | ty::Param(_) => ReducedTy::TypeErasure { raw_ptr_only: false },
+            ty::Int(_) | ty::Uint(_) => ReducedTy::TypeErasure { raw_ptr_only: true },
             _ => ReducedTy::Other(ty),
         };
     }
diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs
new file mode 100644
index 00000000000..d8e349af7af
--- /dev/null
+++ b/clippy_lints/src/transmute/transmuting_null.rs
@@ -0,0 +1,61 @@
+use clippy_utils::consts::{constant_context, Constant};
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::is_path_diagnostic_item;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::symbol::sym;
+
+use super::TRANSMUTING_NULL;
+
+const LINT_MSG: &str = "transmuting a known null pointer into a reference";
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, to_ty: Ty<'tcx>) -> bool {
+    if !to_ty.is_ref() {
+        return false;
+    }
+
+    // Catching transmute over constants that resolve to `null`.
+    let mut const_eval_context = constant_context(cx, cx.typeck_results());
+    if_chain! {
+        if let ExprKind::Path(ref _qpath) = arg.kind;
+        if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg);
+        if x == 0;
+        then {
+            span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
+            return true;
+        }
+    }
+
+    // Catching:
+    // `std::mem::transmute(0 as *const i32)`
+    if_chain! {
+        if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind;
+        if let ExprKind::Lit(ref lit) = inner_expr.kind;
+        if let LitKind::Int(0, _) = lit.node;
+        then {
+            span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
+            return true;
+        }
+    }
+
+    // Catching:
+    // `std::mem::transmute(std::ptr::null::<i32>())`
+    if_chain! {
+        if let ExprKind::Call(func1, []) = arg.kind;
+        if is_path_diagnostic_item(cx, func1, sym::ptr_null);
+        then {
+            span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
+            return true;
+        }
+    }
+
+    // FIXME:
+    // Also catch transmutations of variables which are known nulls.
+    // To do this, MIR const propagation seems to be the better tool.
+    // Whenever MIR const prop routines are more developed, this will
+    // become available. As of this writing (25/03/19) it is not yet.
+    false
+}
diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs
deleted file mode 100644
index 7939dfedc3a..00000000000
--- a/clippy_lints/src/transmuting_null.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-use clippy_utils::consts::{constant_context, Constant};
-use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_expr_diagnostic_item;
-use if_chain::if_chain;
-use rustc_ast::LitKind;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::sym;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for transmute calls which would receive a null pointer.
-    ///
-    /// ### Why is this bad?
-    /// Transmuting a null pointer is undefined behavior.
-    ///
-    /// ### Known problems
-    /// Not all cases can be detected at the moment of this writing.
-    /// For example, variables which hold a null pointer and are then fed to a `transmute`
-    /// call, aren't detectable yet.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
-    /// ```
-    #[clippy::version = "1.35.0"]
-    pub TRANSMUTING_NULL,
-    correctness,
-    "transmutes from a null pointer to a reference, which is undefined behavior"
-}
-
-declare_lint_pass!(TransmutingNull => [TRANSMUTING_NULL]);
-
-const LINT_MSG: &str = "transmuting a known null pointer into a reference";
-
-impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        if_chain! {
-            if let ExprKind::Call(func, [arg]) = expr.kind;
-            if is_expr_diagnostic_item(cx, func, sym::transmute);
-
-            then {
-                // Catching transmute over constants that resolve to `null`.
-                let mut const_eval_context = constant_context(cx, cx.typeck_results());
-                if_chain! {
-                    if let ExprKind::Path(ref _qpath) = arg.kind;
-                    if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg);
-                    if x == 0;
-                    then {
-                        span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
-                    }
-                }
-
-                // Catching:
-                // `std::mem::transmute(0 as *const i32)`
-                if_chain! {
-                    if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind;
-                    if let ExprKind::Lit(ref lit) = inner_expr.kind;
-                    if let LitKind::Int(0, _) = lit.node;
-                    then {
-                        span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
-                    }
-                }
-
-                // Catching:
-                // `std::mem::transmute(std::ptr::null::<i32>())`
-                if_chain! {
-                    if let ExprKind::Call(func1, []) = arg.kind;
-                    if is_expr_diagnostic_item(cx, func1, sym::ptr_null);
-                    then {
-                        span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
-                    }
-                }
-
-                // FIXME:
-                // Also catch transmutations of variables which are known nulls.
-                // To do this, MIR const propagation seems to be the better tool.
-                // Whenever MIR const prop routines are more developed, this will
-                // become available. As of this writing (25/03/19) it is not yet.
-            }
-        }
-    }
-}
diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs
index cc64d17be05..8980283e5c8 100644
--- a/clippy_lints/src/unicode.rs
+++ b/clippy_lints/src/unicode.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_lint_allowed;
+use clippy_utils::macros::span_is_local;
 use clippy_utils::source::snippet;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -98,6 +99,10 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String {
 }
 
 fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
+    if !span_is_local(span) {
+        return;
+    }
+
     let string = snippet(cx, span, "");
     if string.chars().any(|c| ['\u{200B}', '\u{ad}', '\u{2060}'].contains(&c)) {
         span_lint_and_sugg(
@@ -113,6 +118,7 @@ fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
             Applicability::MachineApplicable,
         );
     }
+
     if string.chars().any(|c| c as u32 > 0x7F) {
         span_lint_and_sugg(
             cx,
@@ -128,6 +134,7 @@ fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
             Applicability::MachineApplicable,
         );
     }
+
     if is_lint_allowed(cx, NON_ASCII_LITERAL, id) && string.chars().zip(string.nfc()).any(|(a, b)| a != b) {
         span_lint_and_sugg(
             cx,
diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs
index 9f4c5555f11..9a41603f2f4 100644
--- a/clippy_lints/src/uninit_vec.rs
+++ b/clippy_lints/src/uninit_vec.rs
@@ -45,7 +45,7 @@ declare_clippy_lint! {
     ///    let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
     ///    vec.set_len(1000);  // `MaybeUninit` can be uninitialized
     ///    ```
-    /// 3. If you are on nightly, `Vec::spare_capacity_mut()` is available:
+    /// 3. If you are on 1.60.0 or later, `Vec::spare_capacity_mut()` is available:
     ///    ```rust,ignore
     ///    let mut vec: Vec<u8> = Vec::with_capacity(1000);
     ///    let remaining = vec.spare_capacity_mut();  // `&mut [MaybeUninit<u8>]`
diff --git a/clippy_lints/src/unit_hash.rs b/clippy_lints/src/unit_hash.rs
deleted file mode 100644
index 88ca0cb20a1..00000000000
--- a/clippy_lints/src/unit_hash.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Detects `().hash(_)`.
-    ///
-    /// ### Why is this bad?
-    /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # use std::hash::Hash;
-    /// # use std::collections::hash_map::DefaultHasher;
-    /// # enum Foo { Empty, WithValue(u8) }
-    /// # use Foo::*;
-    /// # let mut state = DefaultHasher::new();
-    /// # let my_enum = Foo::Empty;
-    /// match my_enum {
-    /// 	Empty => ().hash(&mut state),
-    /// 	WithValue(x) => x.hash(&mut state),
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// # use std::hash::Hash;
-    /// # use std::collections::hash_map::DefaultHasher;
-    /// # enum Foo { Empty, WithValue(u8) }
-    /// # use Foo::*;
-    /// # let mut state = DefaultHasher::new();
-    /// # let my_enum = Foo::Empty;
-    /// match my_enum {
-    /// 	Empty => 0_u8.hash(&mut state),
-    /// 	WithValue(x) => x.hash(&mut state),
-    /// }
-    /// ```
-    #[clippy::version = "1.58.0"]
-    pub UNIT_HASH,
-    correctness,
-    "hashing a unit value, which does nothing"
-}
-declare_lint_pass!(UnitHash => [UNIT_HASH]);
-
-impl<'tcx> LateLintPass<'tcx> for UnitHash {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if_chain! {
-            if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind;
-            if name_ident.ident.name == sym::hash;
-            if let [recv, state_param] = args;
-            if cx.typeck_results().expr_ty(recv).is_unit();
-            then {
-                span_lint_and_then(
-                    cx,
-                    UNIT_HASH,
-                    expr.span,
-                    "this call to `hash` on the unit type will do nothing",
-                    |diag| {
-                        diag.span_suggestion(
-                            expr.span,
-                            "remove the call to `hash` or consider using",
-                            format!(
-                                "0_u8.hash({})",
-                                snippet(cx, state_param.span, ".."),
-                            ),
-                            Applicability::MaybeIncorrect,
-                        );
-                        diag.note("the implementation of `Hash` for `()` is a no-op");
-                    }
-                );
-            }
-        }
-    }
-}
diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs
index f4f5a4336a3..a5afbb8ff9d 100644
--- a/clippy_lints/src/unnecessary_wraps.rs
+++ b/clippy_lints/src/unnecessary_wraps.rs
@@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
                         (
                             ret_expr.span,
                             if inner_type.is_unit() {
-                                "".to_string()
+                                String::new()
                             } else {
                                 snippet(cx, arg.span.source_callsite(), "..").to_string()
                             }
diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs
new file mode 100644
index 00000000000..ac73173697e
--- /dev/null
+++ b/clippy_lints/src/unused_peekable.rs
@@ -0,0 +1,225 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::{match_type, peel_mid_ty_refs_is_mutable};
+use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, paths, peel_ref_operators};
+use rustc_ast::Mutability;
+use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind};
+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 the creation of a `peekable` iterator that is never `.peek()`ed
+    ///
+    /// ### Why is this bad?
+    /// Creating a peekable iterator without using any of its methods is likely a mistake,
+    /// or just a leftover after a refactor.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let collection = vec![1, 2, 3];
+    /// let iter = collection.iter().peekable();
+    ///
+    /// for item in iter {
+    ///     // ...
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// let collection = vec![1, 2, 3];
+    /// let iter = collection.iter();
+    ///
+    /// for item in iter {
+    ///     // ...
+    /// }
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub UNUSED_PEEKABLE,
+    suspicious,
+    "creating a peekable iterator without using any of its methods"
+}
+
+declare_lint_pass!(UnusedPeekable => [UNUSED_PEEKABLE]);
+
+impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
+        // Don't lint `Peekable`s returned from a block
+        if let Some(expr) = block.expr
+            && let Some(ty) = cx.typeck_results().expr_ty_opt(peel_ref_operators(cx, expr))
+            && match_type(cx, ty, &paths::PEEKABLE)
+        {
+            return;
+        }
+
+        for (idx, stmt) in block.stmts.iter().enumerate() {
+            if !stmt.span.from_expansion()
+                && let StmtKind::Local(local) = stmt.kind
+                && let PatKind::Binding(_, binding, ident, _) = local.pat.kind
+                && let Some(init) = local.init
+                && !init.span.from_expansion()
+                && let Some(ty) = cx.typeck_results().expr_ty_opt(init)
+                && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
+                && match_type(cx, ty, &paths::PEEKABLE)
+            {
+                let mut vis = PeekableVisitor::new(cx, binding);
+
+                if idx + 1 == block.stmts.len() && block.expr.is_none() {
+                    return;
+                }
+
+                for stmt in &block.stmts[idx..] {
+                    vis.visit_stmt(stmt);
+                }
+
+                if let Some(expr) = block.expr {
+                    vis.visit_expr(expr);
+                }
+
+                if !vis.found_peek_call {
+                    span_lint_and_help(
+                        cx,
+                        UNUSED_PEEKABLE,
+                        ident.span,
+                        "`peek` never called on `Peekable` iterator",
+                        None,
+                        "consider removing the call to `peekable`"
+                   );
+                }
+            }
+        }
+    }
+}
+
+struct PeekableVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    expected_hir_id: HirId,
+    found_peek_call: bool,
+}
+
+impl<'a, 'tcx> PeekableVisitor<'a, 'tcx> {
+    fn new(cx: &'a LateContext<'tcx>, expected_hir_id: HirId) -> Self {
+        Self {
+            cx,
+            expected_hir_id,
+            found_peek_call: false,
+        }
+    }
+}
+
+impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
+    fn visit_expr(&mut self, ex: &'_ Expr<'_>) {
+        if self.found_peek_call {
+            return;
+        }
+
+        if path_to_local_id(ex, self.expected_hir_id) {
+            for (_, node) in self.cx.tcx.hir().parent_iter(ex.hir_id) {
+                match node {
+                    Node::Expr(expr) => {
+                        match expr.kind {
+                            // some_function(peekable)
+                            //
+                            // If the Peekable is passed to a function, stop
+                            ExprKind::Call(_, args) => {
+                                if let Some(func_did) = fn_def_id(self.cx, expr)
+                                    && let Ok(into_iter_did) = self
+                                        .cx
+                                        .tcx
+                                        .lang_items()
+                                        .require(LangItem::IntoIterIntoIter)
+                                    && func_did == into_iter_did
+                                {
+                                    // Probably a for loop desugar, stop searching
+                                    return;
+                                }
+
+                                if args.iter().any(|arg| {
+                                    matches!(arg.kind, ExprKind::Path(_)) && arg_is_mut_peekable(self.cx, arg)
+                                }) {
+                                    self.found_peek_call = true;
+                                    return;
+                                }
+                            },
+                            // Catch anything taking a Peekable mutably
+                            ExprKind::MethodCall(
+                                PathSegment {
+                                    ident: method_name_ident,
+                                    ..
+                                },
+                                [self_arg, remaining_args @ ..],
+                                _,
+                            ) => {
+                                let method_name = method_name_ident.name.as_str();
+
+                                // `Peekable` methods
+                                if matches!(method_name, "peek" | "peek_mut" | "next_if" | "next_if_eq")
+                                    && arg_is_mut_peekable(self.cx, self_arg)
+                                {
+                                    self.found_peek_call = true;
+                                    return;
+                                }
+
+                                // foo.some_method() excluding Iterator methods
+                                if remaining_args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg))
+                                    && !is_trait_method(self.cx, expr, sym::Iterator)
+                                {
+                                    self.found_peek_call = true;
+                                    return;
+                                }
+
+                                // foo.by_ref(), keep checking for `peek`
+                                if method_name == "by_ref" {
+                                    continue;
+                                }
+
+                                return;
+                            },
+                            ExprKind::AddrOf(_, Mutability::Mut, _) | ExprKind::Unary(..) | ExprKind::DropTemps(_) => {
+                            },
+                            ExprKind::AddrOf(_, Mutability::Not, _) => return,
+                            _ => {
+                                self.found_peek_call = true;
+                                return;
+                            },
+                        }
+                    },
+                    Node::Local(Local { init: Some(init), .. }) => {
+                        if arg_is_mut_peekable(self.cx, init) {
+                            self.found_peek_call = true;
+                            return;
+                        }
+
+                        break;
+                    },
+                    Node::Stmt(stmt) => match stmt.kind {
+                        StmtKind::Expr(_) | StmtKind::Semi(_) => {},
+                        _ => {
+                            self.found_peek_call = true;
+                            return;
+                        },
+                    },
+                    Node::Block(_) | Node::ExprField(_) => {},
+                    _ => {
+                        break;
+                    },
+                }
+            }
+        }
+
+        walk_expr(self, ex);
+    }
+}
+
+fn arg_is_mut_peekable(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
+    if let Some(ty) = cx.typeck_results().expr_ty_opt(arg)
+        && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
+        && match_type(cx, ty, &paths::PEEKABLE)
+    {
+        true
+    } else {
+        false
+    }
+}
diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs
index e1ec357838d..b8a5d4ea8c9 100644
--- a/clippy_lints/src/unused_rounding.rs
+++ b/clippy_lints/src/unused_rounding.rs
@@ -22,7 +22,7 @@ declare_clippy_lint! {
     /// ```rust
     /// let x = 1f32;
     /// ```
-    #[clippy::version = "1.62.0"]
+    #[clippy::version = "1.63.0"]
     pub UNUSED_ROUNDING,
     nursery,
     "Uselessly rounding a whole number floating-point literal"
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 3faae9ac0d2..84e65d5fa0b 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -350,7 +350,7 @@ define_Conf! {
     /// Lint: DISALLOWED_SCRIPT_IDENTS.
     ///
     /// The list of unicode scripts allowed to be used in the scope.
-    (allowed_scripts: Vec<String> = ["Latin"].iter().map(ToString::to_string).collect()),
+    (allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
     /// Lint: NON_SEND_FIELDS_IN_SEND_TY.
     ///
     /// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
@@ -379,6 +379,10 @@ define_Conf! {
     ///
     /// Whether `dbg!` should be allowed in test functions
     (allow_dbg_in_tests: bool = false),
+    /// Lint: RESULT_LARGE_ERR
+    ///
+    /// The maximum size of the `Err`-variant in a `Result` returned from a function
+    (large_error_threshold: u64 = 128),
 }
 
 /// Search for the configuration file.
diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs
index 5dcacd604be..eb34085a2ab 100644
--- a/clippy_lints/src/utils/internal_lints.rs
+++ b/clippy_lints/src/utils/internal_lints.rs
@@ -593,8 +593,8 @@ fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Opt
     attrs.iter().find_map(|attr| {
         if_chain! {
             // Identify attribute
-            if let ast::AttrKind::Normal(ref attr_kind, _) = &attr.kind;
-            if let [tool_name, attr_name] = &attr_kind.path.segments[..];
+            if let ast::AttrKind::Normal(ref attr_kind) = &attr.kind;
+            if let [tool_name, attr_name] = &attr_kind.item.path.segments[..];
             if tool_name.ident.name == sym::clippy;
             if attr_name.ident.name == sym::version;
             if let Some(version) = attr.value_str();
diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 92cf42c7ad4..b1148bccc2a 100644
--- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -797,7 +797,7 @@ fn get_lint_group_and_level_or_lint(
     let result = cx.lint_store.check_lint_name(
         lint_name,
         Some(sym::clippy),
-        &[Ident::with_dummy_span(sym::clippy)].into_iter().collect(),
+        &std::iter::once(Ident::with_dummy_span(sym::clippy)).collect(),
     );
     if let CheckLintNameResult::Tool(Ok(lint_lst)) = result {
         if let Some(group) = get_lint_group(cx, lint_lst[0]) {
diff --git a/clippy_lints/src/vec_resize_to_zero.rs b/clippy_lints/src/vec_resize_to_zero.rs
deleted file mode 100644
index 0fee3e812d2..00000000000
--- a/clippy_lints/src/vec_resize_to_zero.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{match_def_path, paths};
-use if_chain::if_chain;
-use rustc_ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Spanned;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Finds occurrences of `Vec::resize(0, an_int)`
-    ///
-    /// ### Why is this bad?
-    /// This is probably an argument inversion mistake.
-    ///
-    /// ### Example
-    /// ```rust
-    /// vec!(1, 2, 3, 4, 5).resize(0, 5)
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust
-    /// vec!(1, 2, 3, 4, 5).clear()
-    /// ```
-    #[clippy::version = "1.46.0"]
-    pub VEC_RESIZE_TO_ZERO,
-    correctness,
-    "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake"
-}
-
-declare_lint_pass!(VecResizeToZero => [VEC_RESIZE_TO_ZERO]);
-
-impl<'tcx> LateLintPass<'tcx> for VecResizeToZero {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let hir::ExprKind::MethodCall(path_segment, args, _) = expr.kind;
-            if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
-            if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3;
-            if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind;
-            if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = args[2].kind;
-            then {
-                let method_call_span = expr.span.with_lo(path_segment.ident.span.lo());
-                span_lint_and_then(
-                    cx,
-                    VEC_RESIZE_TO_ZERO,
-                    expr.span,
-                    "emptying a vector with `resize`",
-                    |db| {
-                        db.help("the arguments may be inverted...");
-                        db.span_suggestion(
-                            method_call_span,
-                            "...or you can empty the vector with",
-                            "clear()".to_string(),
-                            Applicability::MaybeIncorrect,
-                        );
-                    },
-                );
-            }
-        }
-    }
-}
diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs
deleted file mode 100644
index afd0077a658..00000000000
--- a/clippy_lints/src/verbose_file_reads.rs
+++ /dev/null
@@ -1,88 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::paths;
-use clippy_utils::ty::match_type;
-use if_chain::if_chain;
-use rustc_hir::{Expr, ExprKind, QPath};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for use of File::read_to_end and File::read_to_string.
-    ///
-    /// ### Why is this bad?
-    /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values.
-    /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html)
-    ///
-    /// ### Example
-    /// ```rust,no_run
-    /// # use std::io::Read;
-    /// # use std::fs::File;
-    /// let mut f = File::open("foo.txt").unwrap();
-    /// let mut bytes = Vec::new();
-    /// f.read_to_end(&mut bytes).unwrap();
-    /// ```
-    /// Can be written more concisely as
-    /// ```rust,no_run
-    /// # use std::fs;
-    /// let mut bytes = fs::read("foo.txt").unwrap();
-    /// ```
-    #[clippy::version = "1.44.0"]
-    pub VERBOSE_FILE_READS,
-    restriction,
-    "use of `File::read_to_end` or `File::read_to_string`"
-}
-
-declare_lint_pass!(VerboseFileReads => [VERBOSE_FILE_READS]);
-
-impl<'tcx> LateLintPass<'tcx> for VerboseFileReads {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if is_file_read_to_end(cx, expr) {
-            span_lint_and_help(
-                cx,
-                VERBOSE_FILE_READS,
-                expr.span,
-                "use of `File::read_to_end`",
-                None,
-                "consider using `fs::read` instead",
-            );
-        } else if is_file_read_to_string(cx, expr) {
-            span_lint_and_help(
-                cx,
-                VERBOSE_FILE_READS,
-                expr.span,
-                "use of `File::read_to_string`",
-                None,
-                "consider using `fs::read_to_string` instead",
-            );
-        }
-    }
-}
-
-fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
-    if_chain! {
-        if let ExprKind::MethodCall(method_name, [recv, ..], _) = expr.kind;
-        if method_name.ident.as_str() == "read_to_end";
-        if let ExprKind::Path(QPath::Resolved(None, _)) = &recv.kind;
-        let ty = cx.typeck_results().expr_ty(recv);
-        if match_type(cx, ty, &paths::FILE);
-        then {
-            return true
-        }
-    }
-    false
-}
-
-fn is_file_read_to_string<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
-    if_chain! {
-        if let ExprKind::MethodCall(method_name, exprs, _) = expr.kind;
-        if method_name.ident.as_str() == "read_to_string";
-        if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
-        let ty = cx.typeck_results().expr_ty(&exprs[0]);
-        if match_type(cx, ty, &paths::FILE);
-        then {
-            return true
-        }
-    }
-    false
-}
diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs
index fa2383066f3..5533840b166 100644
--- a/clippy_lints/src/write.rs
+++ b/clippy_lints/src/write.rs
@@ -3,8 +3,9 @@ use std::iter;
 use std::ops::{Deref, Range};
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet_opt, snippet_with_applicability};
+use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
 use rustc_ast::ast::{Expr, ExprKind, Impl, Item, ItemKind, MacCall, Path, StrLit, StrStyle};
+use rustc_ast::ptr::P;
 use rustc_ast::token::{self, LitKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_errors::{Applicability, DiagnosticBuilder};
@@ -256,6 +257,28 @@ declare_clippy_lint! {
     "writing a literal with a format string"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// This lint warns when a named parameter in a format string is used as a positional one.
+    ///
+    /// ### Why is this bad?
+    /// It may be confused for an assignment and obfuscates which parameter is being used.
+    ///
+    /// ### Example
+    /// ```rust
+    /// println!("{}", x = 10);
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// println!("{x}", x = 10);
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub POSITIONAL_NAMED_FORMAT_PARAMETERS,
+    suspicious,
+    "named parameter in a format string is used positionally"
+}
+
 #[derive(Default)]
 pub struct Write {
     in_debug_impl: bool,
@@ -270,7 +293,8 @@ impl_lint_pass!(Write => [
     PRINT_LITERAL,
     WRITE_WITH_NEWLINE,
     WRITELN_EMPTY_STRING,
-    WRITE_LITERAL
+    WRITE_LITERAL,
+    POSITIONAL_NAMED_FORMAT_PARAMETERS,
 ]);
 
 impl EarlyLintPass for Write {
@@ -408,6 +432,7 @@ fn newline_span(fmtstr: &StrLit) -> (Span, bool) {
 #[derive(Default)]
 struct SimpleFormatArgs {
     unnamed: Vec<Vec<Span>>,
+    complex_unnamed: Vec<Vec<Span>>,
     named: Vec<(Symbol, Vec<Span>)>,
 }
 impl SimpleFormatArgs {
@@ -419,6 +444,10 @@ impl SimpleFormatArgs {
         })
     }
 
+    fn get_complex_unnamed(&self) -> impl Iterator<Item = &[Span]> {
+        self.complex_unnamed.iter().map(Vec::as_slice)
+    }
+
     fn get_named(&self, n: &Path) -> &[Span] {
         self.named.iter().find(|x| *n == x.0).map_or(&[], |x| x.1.as_slice())
     }
@@ -479,6 +508,61 @@ impl SimpleFormatArgs {
             },
         };
     }
+
+    fn push_to_complex(&mut self, span: Span, position: usize) {
+        if self.complex_unnamed.len() <= position {
+            self.complex_unnamed.resize_with(position, Vec::new);
+            self.complex_unnamed.push(vec![span]);
+        } else {
+            let args: &mut Vec<Span> = &mut self.complex_unnamed[position];
+            args.push(span);
+        }
+    }
+
+    fn push_complex(
+        &mut self,
+        cx: &EarlyContext<'_>,
+        arg: rustc_parse_format::Argument<'_>,
+        str_lit_span: Span,
+        fmt_span: Span,
+    ) {
+        use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam};
+
+        let snippet = snippet_opt(cx, fmt_span);
+
+        let end = snippet
+            .as_ref()
+            .and_then(|s| s.find(':'))
+            .or_else(|| fmt_span.hi().0.checked_sub(fmt_span.lo().0 + 1).map(|u| u as usize));
+
+        if let (ArgumentIs(n) | ArgumentImplicitlyIs(n), Some(end)) = (arg.position, end) {
+            let span = fmt_span.from_inner(InnerSpan::new(1, end));
+            self.push_to_complex(span, n);
+        };
+
+        if let (CountIsParam(n), Some(span)) = (arg.format.precision, arg.format.precision_span) {
+            // We need to do this hack as precision spans should be converted from .* to .foo$
+            let hack = if snippet.as_ref().and_then(|s| s.find('*')).is_some() {
+                0
+            } else {
+                1
+            };
+
+            let span = str_lit_span.from_inner(InnerSpan {
+                start: span.start + 1,
+                end: span.end - hack,
+            });
+            self.push_to_complex(span, n);
+        };
+
+        if let (CountIsParam(n), Some(span)) = (arg.format.width, arg.format.width_span) {
+            let span = str_lit_span.from_inner(InnerSpan {
+                start: span.start,
+                end: span.end - 1,
+            });
+            self.push_to_complex(span, n);
+        };
+    }
 }
 
 impl Write {
@@ -511,8 +595,8 @@ impl Write {
                 // FIXME: modify rustc's fmt string parser to give us the current span
                 span_lint(cx, USE_DEBUG, span, "use of `Debug`-based formatting");
             }
-
             args.push(arg, span);
+            args.push_complex(cx, arg, str_lit.span, span);
         }
 
         parser.errors.is_empty().then_some(args)
@@ -566,6 +650,7 @@ impl Write {
 
         let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL };
         let mut unnamed_args = args.get_unnamed();
+        let mut complex_unnamed_args = args.get_complex_unnamed();
         loop {
             if !parser.eat(&token::Comma) {
                 return (Some(fmtstr), expr);
@@ -577,11 +662,20 @@ impl Write {
             } else {
                 return (Some(fmtstr), None);
             };
+            let complex_unnamed_arg = complex_unnamed_args.next();
+
             let (fmt_spans, lit) = match &token_expr.kind {
                 ExprKind::Lit(lit) => (unnamed_args.next().unwrap_or(&[]), lit),
-                ExprKind::Assign(lhs, rhs, _) => match (&lhs.kind, &rhs.kind) {
-                    (ExprKind::Path(_, p), ExprKind::Lit(lit)) => (args.get_named(p), lit),
-                    _ => continue,
+                ExprKind::Assign(lhs, rhs, _) => {
+                    if let Some(span) = complex_unnamed_arg {
+                        for x in span {
+                            Self::report_positional_named_param(cx, *x, lhs, rhs);
+                        }
+                    }
+                    match (&lhs.kind, &rhs.kind) {
+                        (ExprKind::Path(_, p), ExprKind::Lit(lit)) => (args.get_named(p), lit),
+                        _ => continue,
+                    }
                 },
                 _ => {
                     unnamed_args.next();
@@ -637,6 +731,29 @@ impl Write {
         }
     }
 
+    fn report_positional_named_param(cx: &EarlyContext<'_>, span: Span, lhs: &P<Expr>, _rhs: &P<Expr>) {
+        if let ExprKind::Path(_, _p) = &lhs.kind {
+            let mut applicability = Applicability::MachineApplicable;
+            let name = snippet_with_applicability(cx, lhs.span, "name", &mut applicability);
+            // We need to do this hack as precision spans should be converted from .* to .foo$
+            let hack = snippet(cx, span, "").contains('*');
+
+            span_lint_and_sugg(
+                cx,
+                POSITIONAL_NAMED_FORMAT_PARAMETERS,
+                span,
+                &format!("named parameter {} is used as a positional parameter", name),
+                "replace it with",
+                if hack {
+                    format!("{}$", name)
+                } else {
+                    format!("{}", name)
+                },
+                applicability,
+            );
+        };
+    }
+
     fn lint_println_empty_string(&self, cx: &EarlyContext<'_>, mac: &MacCall) {
         if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
             if fmt_str.symbol == kw::Empty {
diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml
index a688050f63a..c36bca06507 100644
--- a/clippy_utils/Cargo.toml
+++ b/clippy_utils/Cargo.toml
@@ -7,6 +7,7 @@ publish = false
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
 if_chain = "1.0"
+itertools = "0.10.1"
 rustc-semver = "1.1"
 
 [features]
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 313f1f1d9a6..997e773b5da 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -28,6 +28,7 @@ extern crate rustc_infer;
 extern crate rustc_lexer;
 extern crate rustc_lint;
 extern crate rustc_middle;
+extern crate rustc_parse_format;
 extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
@@ -87,6 +88,7 @@ use rustc_hir::{
     Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
     TraitRef, TyKind, UnOp,
 };
+use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::ty as rustc_ty;
@@ -104,6 +106,7 @@ use rustc_semver::RustcVersion;
 use rustc_session::Session;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
+use rustc_span::source_map::SourceMap;
 use rustc_span::sym;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -372,15 +375,19 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
 
 /// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
 ///
-/// Please use `is_expr_diagnostic_item` if the target is a diagnostic item.
+/// Please use `is_path_diagnostic_item` if the target is a diagnostic item.
 pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
     path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments))
 }
 
-/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given
-/// diagnostic item.
-pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
-    path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
+/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
+/// it matches the given diagnostic item.
+pub fn is_path_diagnostic_item<'tcx>(
+    cx: &LateContext<'_>,
+    maybe_path: &impl MaybePath<'tcx>,
+    diag_item: Symbol,
+) -> bool {
+    path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
 }
 
 /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
@@ -2274,6 +2281,18 @@ pub fn walk_to_expr_usage<'tcx, T>(
     None
 }
 
+/// 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 {
+    let Ok(snippet) = sm.span_to_snippet(span) else { return false };
+    return tokenize(&snippet).any(|token| {
+        matches!(
+            token.kind,
+            TokenKind::BlockComment { .. } | TokenKind::LineComment { .. }
+        )
+    });
+}
+
 macro_rules! op_utils {
     ($($name:ident $assign:ident)*) => {
         /// Binary operation traits like `LangItem::Add`
diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs
index a268e339bb1..e5ca3545540 100644
--- a/clippy_utils/src/macros.rs
+++ b/clippy_utils/src/macros.rs
@@ -1,16 +1,21 @@
 #![allow(clippy::similar_names)] // `expr` and `expn`
 
+use crate::is_path_diagnostic_item;
+use crate::source::snippet_opt;
 use crate::visitors::expr_visitor_no_bodies;
 
 use arrayvec::ArrayVec;
-use if_chain::if_chain;
+use itertools::{izip, Either, Itertools};
 use rustc_ast::ast::LitKind;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath};
+use rustc_lexer::unescape::unescape_literal;
+use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
 use rustc_lint::LateContext;
+use rustc_parse_format::{self as rpf, Alignment};
 use rustc_span::def_id::DefId;
 use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
-use rustc_span::{sym, ExpnData, ExpnId, ExpnKind, Span, Symbol};
+use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol};
 use std::ops::ControlFlow;
 
 const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[
@@ -332,121 +337,495 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) ->
     }
 }
 
-/// A parsed `format_args!` expansion
+/// The format string doesn't exist in the HIR, so we reassemble it from source code
 #[derive(Debug)]
-pub struct FormatArgsExpn<'tcx> {
-    /// Span of the first argument, the format string
-    pub format_string_span: Span,
-    /// The format string split by formatted args like `{..}`
-    pub format_string_parts: Vec<Symbol>,
-    /// Values passed after the format string
-    pub value_args: Vec<&'tcx Expr<'tcx>>,
-    /// Each element is a `value_args` index and a formatting trait (e.g. `sym::Debug`)
-    pub formatters: Vec<(usize, Symbol)>,
-    /// List of `fmt::v1::Argument { .. }` expressions. If this is empty,
-    /// then `formatters` represents the format args (`{..}`).
-    /// If this is non-empty, it represents the format args, and the `position`
-    /// parameters within the struct expressions are indexes of `formatters`.
-    pub specs: Vec<&'tcx Expr<'tcx>>,
+pub struct FormatString {
+    /// Span of the whole format string literal, including `[r#]"`.
+    pub span: Span,
+    /// Snippet of the whole format string literal, including `[r#]"`.
+    pub snippet: String,
+    /// If the string is raw `r"..."`/`r#""#`, how many `#`s does it have on each side.
+    pub style: Option<usize>,
+    /// The unescaped value of the format string, e.g. `"val – {}"` for the literal
+    /// `"val \u{2013} {}"`.
+    pub unescaped: String,
+    /// The format string split by format args like `{..}`.
+    pub parts: Vec<Symbol>,
 }
 
-impl<'tcx> FormatArgsExpn<'tcx> {
-    /// Parses an expanded `format_args!` or `format_args_nl!` invocation
-    pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<Self> {
-        macro_backtrace(expr.span).find(|macro_call| {
-            matches!(
-                cx.tcx.item_name(macro_call.def_id),
-                sym::const_format_args | sym::format_args | sym::format_args_nl
-            )
-        })?;
-        let mut format_string_span: Option<Span> = None;
-        let mut format_string_parts: Vec<Symbol> = Vec::new();
-        let mut value_args: Vec<&Expr<'_>> = Vec::new();
-        let mut formatters: Vec<(usize, Symbol)> = Vec::new();
-        let mut specs: Vec<&Expr<'_>> = Vec::new();
-        expr_visitor_no_bodies(|e| {
-            // if we're still inside of the macro definition...
-            if e.span.ctxt() == expr.span.ctxt() {
-                // ArgumentV1::new_<format_trait>(<value>)
-                if_chain! {
-                    if let ExprKind::Call(callee, [val]) = e.kind;
-                    if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind;
-                    if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
-                    if path.segments.last().unwrap().ident.name == sym::ArgumentV1;
-                    if seg.ident.name.as_str().starts_with("new_");
-                    then {
-                        let val_idx = if_chain! {
-                            if val.span.ctxt() == expr.span.ctxt();
-                            if let ExprKind::Field(_, field) = val.kind;
-                            if let Ok(idx) = field.name.as_str().parse();
-                            then {
-                                // tuple index
-                                idx
-                            } else {
-                                // assume the value expression is passed directly
-                                formatters.len()
-                            }
-                        };
-                        let fmt_trait = match seg.ident.name.as_str() {
-                            "new_display" => "Display",
-                            "new_debug" => "Debug",
-                            "new_lower_exp" => "LowerExp",
-                            "new_upper_exp" => "UpperExp",
-                            "new_octal" => "Octal",
-                            "new_pointer" => "Pointer",
-                            "new_binary" => "Binary",
-                            "new_lower_hex" => "LowerHex",
-                            "new_upper_hex" => "UpperHex",
-                            _ => unreachable!(),
-                        };
-                        formatters.push((val_idx, Symbol::intern(fmt_trait)));
-                    }
+impl FormatString {
+    fn new(cx: &LateContext<'_>, pieces: &Expr<'_>) -> Option<Self> {
+        // format_args!(r"a {} b \", 1);
+        //
+        // expands to
+        //
+        // ::core::fmt::Arguments::new_v1(&["a ", " b \\"],
+        //      &[::core::fmt::ArgumentV1::new_display(&1)]);
+        //
+        // where `pieces` is the expression `&["a ", " b \\"]`. It has the span of `r"a {} b \"`
+        let span = pieces.span;
+        let snippet = snippet_opt(cx, span)?;
+
+        let (inner, style) = match tokenize(&snippet).next()?.kind {
+            TokenKind::Literal { kind, .. } => {
+                let style = match kind {
+                    LiteralKind::Str { .. } => None,
+                    LiteralKind::RawStr { n_hashes: Some(n), .. } => Some(n.into()),
+                    _ => return None,
+                };
+
+                let start = style.map_or(1, |n| 2 + n);
+                let end = snippet.len() - style.map_or(1, |n| 1 + n);
+
+                (&snippet[start..end], style)
+            },
+            _ => return None,
+        };
+
+        let mode = if style.is_some() {
+            unescape::Mode::RawStr
+        } else {
+            unescape::Mode::Str
+        };
+
+        let mut unescaped = String::with_capacity(inner.len());
+        unescape_literal(inner, mode, &mut |_, ch| {
+            unescaped.push(ch.unwrap());
+        });
+
+        let mut parts = Vec::new();
+        expr_visitor_no_bodies(|expr| {
+            if let ExprKind::Lit(lit) = &expr.kind {
+                if let LitKind::Str(symbol, _) = lit.node {
+                    parts.push(symbol);
                 }
-                if let ExprKind::Struct(QPath::Resolved(_, path), ..) = e.kind {
-                    if path.segments.last().unwrap().ident.name == sym::Argument {
-                        specs.push(e);
-                    }
-                }
-                // walk through the macro expansion
-                return true;
             }
-            // assume that the first expr with a differing context represents
-            // (and has the span of) the format string
-            if format_string_span.is_none() {
-                format_string_span = Some(e.span);
-                let span = e.span;
-                // walk the expr and collect string literals which are format string parts
-                expr_visitor_no_bodies(|e| {
-                    if e.span.ctxt() != span.ctxt() {
-                        // defensive check, probably doesn't happen
-                        return false;
-                    }
-                    if let ExprKind::Lit(lit) = &e.kind {
-                        if let LitKind::Str(symbol, _s) = lit.node {
-                            format_string_parts.push(symbol);
-                        }
-                    }
-                    true
-                })
-                .visit_expr(e);
-            } else {
-                // assume that any further exprs with a differing context are value args
-                value_args.push(e);
-            }
-            // don't walk anything not from the macro expansion (e.a. inputs)
-            false
+
+            true
         })
-        .visit_expr(expr);
-        Some(FormatArgsExpn {
-            format_string_span: format_string_span?,
-            format_string_parts,
+        .visit_expr(pieces);
+
+        Some(Self {
+            span,
+            snippet,
+            style,
+            unescaped,
+            parts,
+        })
+    }
+}
+
+struct FormatArgsValues<'tcx> {
+    /// See `FormatArgsExpn::value_args`
+    value_args: Vec<&'tcx Expr<'tcx>>,
+    /// Maps an `rt::v1::Argument::position` or an `rt::v1::Count::Param` to its index in
+    /// `value_args`
+    pos_to_value_index: Vec<usize>,
+    /// Used to check if a value is declared inline & to resolve `InnerSpan`s.
+    format_string_span: SpanData,
+}
+
+impl<'tcx> FormatArgsValues<'tcx> {
+    fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self {
+        let mut pos_to_value_index = Vec::new();
+        let mut value_args = Vec::new();
+        expr_visitor_no_bodies(|expr| {
+            if expr.span.ctxt() == args.span.ctxt() {
+                // ArgumentV1::new_<format_trait>(<val>)
+                // ArgumentV1::from_usize(<val>)
+                if let ExprKind::Call(callee, [val]) = expr.kind
+                    && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind
+                    && let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind
+                    && path.segments.last().unwrap().ident.name == sym::ArgumentV1
+                {
+                    let val_idx = if val.span.ctxt() == expr.span.ctxt()
+                        && let ExprKind::Field(_, field) = val.kind
+                        && let Ok(idx) = field.name.as_str().parse()
+                    {
+                        // tuple index
+                        idx
+                    } else {
+                        // assume the value expression is passed directly
+                        pos_to_value_index.len()
+                    };
+
+                    pos_to_value_index.push(val_idx);
+                }
+
+                true
+            } else {
+                // assume that any expr with a differing span is a value
+                value_args.push(expr);
+
+                false
+            }
+        })
+        .visit_expr(args);
+
+        Self {
             value_args,
-            formatters,
-            specs,
+            pos_to_value_index,
+            format_string_span,
+        }
+    }
+}
+
+/// The positions of a format argument's value, precision and width
+///
+/// A position is an index into the second argument of `Arguments::new_v1[_formatted]`
+#[derive(Debug, Default, Copy, Clone)]
+struct ParamPosition {
+    /// The position stored in `rt::v1::Argument::position`.
+    value: usize,
+    /// The position stored in `rt::v1::FormatSpec::width` if it is a `Count::Param`.
+    width: Option<usize>,
+    /// The position stored in `rt::v1::FormatSpec::precision` if it is a `Count::Param`.
+    precision: Option<usize>,
+}
+
+/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)`
+fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option<impl Iterator<Item = ParamPosition> + 'tcx> {
+    fn parse_count(expr: &Expr<'_>) -> Option<usize> {
+        // ::core::fmt::rt::v1::Count::Param(1usize),
+        if let ExprKind::Call(ctor, [val]) = expr.kind
+            && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind
+            && path.segments.last()?.ident.name == sym::Param
+            && let ExprKind::Lit(lit) = &val.kind
+            && let LitKind::Int(pos, _) = lit.node
+        {
+            Some(pos as usize)
+        } else {
+            None
+        }
+    }
+
+    if let ExprKind::AddrOf(.., array) = fmt_arg.kind
+        && let ExprKind::Array(specs) = array.kind
+    {
+        Some(specs.iter().map(|spec| {
+            let mut position = ParamPosition::default();
+
+            // ::core::fmt::rt::v1::Argument {
+            //     position: 0usize,
+            //     format: ::core::fmt::rt::v1::FormatSpec {
+            //         ..
+            //         precision: ::core::fmt::rt::v1::Count::Implied,
+            //         width: ::core::fmt::rt::v1::Count::Implied,
+            //     },
+            // }
+
+            // TODO: this can be made much nicer next sync with `Visitor::visit_expr_field`
+            if let ExprKind::Struct(_, fields, _) = spec.kind {
+                for field in fields {
+                    match (field.ident.name, &field.expr.kind) {
+                        (sym::position, ExprKind::Lit(lit)) => {
+                            if let LitKind::Int(pos, _) = lit.node {
+                                position.value = pos as usize;
+                            }
+                        },
+                        (sym::format, &ExprKind::Struct(_, spec_fields, _)) => {
+                            for spec_field in spec_fields {
+                                match spec_field.ident.name {
+                                    sym::precision => {
+                                        position.precision = parse_count(spec_field.expr);
+                                    },
+                                    sym::width => {
+                                        position.width = parse_count(spec_field.expr);
+                                    },
+                                    _ => {},
+                                }
+                            }
+                        },
+                        _ => {},
+                    }
+                }
+            }
+
+            position
+        }))
+    } else {
+        None
+    }
+}
+
+/// `Span::from_inner`, but for `rustc_parse_format`'s `InnerSpan`
+fn span_from_inner(base: SpanData, inner: rpf::InnerSpan) -> Span {
+    Span::new(
+        base.lo + BytePos::from_usize(inner.start),
+        base.lo + BytePos::from_usize(inner.end),
+        base.ctxt,
+        base.parent,
+    )
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum FormatParamKind {
+    /// An implicit parameter , such as `{}` or `{:?}`.
+    Implicit,
+    /// A parameter with an explicit number, or an asterisk precision. e.g. `{1}`, `{0:?}`,
+    /// `{:.0$}` or `{:.*}`.
+    Numbered,
+    /// A named parameter with a named `value_arg`, such as the `x` in `format!("{x}", x = 1)`.
+    Named(Symbol),
+    /// An implicit named parameter, such as the `y` in `format!("{y}")`.
+    NamedInline(Symbol),
+}
+
+/// A `FormatParam` is any place in a `FormatArgument` that refers to a supplied value, e.g.
+///
+/// ```
+/// let precision = 2;
+/// format!("{:.precision$}", 0.1234);
+/// ```
+///
+/// has two `FormatParam`s, a [`FormatParamKind::Implicit`] `.kind` with a `.value` of `0.1234`
+/// and a [`FormatParamKind::NamedInline("precision")`] `.kind` with a `.value` of `2`
+#[derive(Debug, Copy, Clone)]
+pub struct FormatParam<'tcx> {
+    /// The expression this parameter refers to.
+    pub value: &'tcx Expr<'tcx>,
+    /// How this parameter refers to its `value`.
+    pub kind: FormatParamKind,
+    /// Span of the parameter, may be zero width. Includes the whitespace of implicit parameters.
+    ///
+    /// ```text
+    /// format!("{}, {  }, {0}, {name}", ...);
+    ///          ^    ~~    ~    ~~~~
+    /// ```
+    pub span: Span,
+}
+
+impl<'tcx> FormatParam<'tcx> {
+    fn new(
+        mut kind: FormatParamKind,
+        position: usize,
+        inner: rpf::InnerSpan,
+        values: &FormatArgsValues<'tcx>,
+    ) -> Option<Self> {
+        let value_index = *values.pos_to_value_index.get(position)?;
+        let value = *values.value_args.get(value_index)?;
+        let span = span_from_inner(values.format_string_span, inner);
+
+        // if a param is declared inline, e.g. `format!("{x}")`, the generated expr's span points
+        // into the format string
+        if let FormatParamKind::Named(name) = kind && values.format_string_span.contains(value.span.data()) {
+            kind = FormatParamKind::NamedInline(name);
+        }
+
+        Some(Self { value, kind, span })
+    }
+}
+
+/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and
+/// [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
+#[derive(Debug, Copy, Clone)]
+pub enum Count<'tcx> {
+    /// Specified with a literal number, stores the value.
+    Is(usize, Span),
+    /// Specified using `$` and `*` syntaxes. The `*` format is still considered to be
+    /// `FormatParamKind::Numbered`.
+    Param(FormatParam<'tcx>),
+    /// Not specified.
+    Implied,
+}
+
+impl<'tcx> Count<'tcx> {
+    fn new(
+        count: rpf::Count<'_>,
+        position: Option<usize>,
+        inner: Option<rpf::InnerSpan>,
+        values: &FormatArgsValues<'tcx>,
+    ) -> Option<Self> {
+        Some(match count {
+            rpf::Count::CountIs(val) => Self::Is(val, span_from_inner(values.format_string_span, inner?)),
+            rpf::Count::CountIsName(name, span) => Self::Param(FormatParam::new(
+                FormatParamKind::Named(Symbol::intern(name)),
+                position?,
+                span,
+                values,
+            )?),
+            rpf::Count::CountIsParam(_) => {
+                Self::Param(FormatParam::new(FormatParamKind::Numbered, position?, inner?, values)?)
+            },
+            rpf::Count::CountImplied => Self::Implied,
         })
     }
 
-    /// Finds a nested call to `format_args!` within a `format!`-like macro call
+    pub fn is_implied(self) -> bool {
+        matches!(self, Count::Implied)
+    }
+
+    pub fn param(self) -> Option<FormatParam<'tcx>> {
+        match self {
+            Count::Param(param) => Some(param),
+            _ => None,
+        }
+    }
+}
+
+/// Specification for the formatting of an argument in the format string. See
+/// <https://doc.rust-lang.org/std/fmt/index.html#formatting-parameters> for the precise meanings.
+#[derive(Debug)]
+pub struct FormatSpec<'tcx> {
+    /// Optionally specified character to fill alignment with.
+    pub fill: Option<char>,
+    /// Optionally specified alignment.
+    pub align: Alignment,
+    /// Packed version of various flags provided, see [`rustc_parse_format::Flag`].
+    pub flags: u32,
+    /// Represents either the maximum width or the integer precision.
+    pub precision: Count<'tcx>,
+    /// The minimum width, will be padded according to `width`/`align`
+    pub width: Count<'tcx>,
+    /// The formatting trait used by the argument, e.g. `sym::Display` for `{}`, `sym::Debug` for
+    /// `{:?}`.
+    pub r#trait: Symbol,
+    pub trait_span: Option<Span>,
+}
+
+impl<'tcx> FormatSpec<'tcx> {
+    fn new(spec: rpf::FormatSpec<'_>, positions: ParamPosition, values: &FormatArgsValues<'tcx>) -> Option<Self> {
+        Some(Self {
+            fill: spec.fill,
+            align: spec.align,
+            flags: spec.flags,
+            precision: Count::new(spec.precision, positions.precision, spec.precision_span, values)?,
+            width: Count::new(spec.width, positions.width, spec.width_span, values)?,
+            r#trait: match spec.ty {
+                "" => sym::Display,
+                "?" => sym::Debug,
+                "o" => sym!(Octal),
+                "x" => sym!(LowerHex),
+                "X" => sym!(UpperHex),
+                "p" => sym::Pointer,
+                "b" => sym!(Binary),
+                "e" => sym!(LowerExp),
+                "E" => sym!(UpperExp),
+                _ => return None,
+            },
+            trait_span: spec
+                .ty_span
+                .map(|span| span_from_inner(values.format_string_span, span)),
+        })
+    }
+
+    /// Returns true if this format spec would change the contents of a string when formatted
+    pub fn has_string_formatting(&self) -> bool {
+        self.r#trait != sym::Display || !self.width.is_implied() || !self.precision.is_implied()
+    }
+}
+
+/// A format argument, such as `{}`, `{foo:?}`.
+#[derive(Debug)]
+pub struct FormatArg<'tcx> {
+    /// The parameter the argument refers to.
+    pub param: FormatParam<'tcx>,
+    /// How to format `param`.
+    pub format: FormatSpec<'tcx>,
+    /// span of the whole argument, `{..}`.
+    pub span: Span,
+}
+
+/// A parsed `format_args!` expansion.
+#[derive(Debug)]
+pub struct FormatArgsExpn<'tcx> {
+    /// The format string literal.
+    pub format_string: FormatString,
+    // The format arguments, such as `{:?}`.
+    pub args: Vec<FormatArg<'tcx>>,
+    /// Has an added newline due to `println!()`/`writeln!()`/etc. The last format string part will
+    /// include this added newline.
+    pub newline: bool,
+    /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for
+    /// `format!("{x} {} {y}", 1, z + 2)`.
+    value_args: Vec<&'tcx Expr<'tcx>>,
+}
+
+impl<'tcx> FormatArgsExpn<'tcx> {
+    pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<Self> {
+        let macro_name = macro_backtrace(expr.span)
+            .map(|macro_call| cx.tcx.item_name(macro_call.def_id))
+            .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?;
+        let newline = macro_name == sym::format_args_nl;
+
+        // ::core::fmt::Arguments::new_v1(pieces, args)
+        // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg)
+        if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind
+            && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind
+            && is_path_diagnostic_item(cx, ty, sym::Arguments)
+            && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted")
+        {
+            let format_string = FormatString::new(cx, pieces)?;
+
+            let mut parser = rpf::Parser::new(
+                &format_string.unescaped,
+                format_string.style,
+                Some(format_string.snippet.clone()),
+                // `format_string.unescaped` does not contain the appended newline
+                false,
+                rpf::ParseMode::Format,
+            );
+
+            let parsed_args = parser
+                .by_ref()
+                .filter_map(|piece| match piece {
+                    rpf::Piece::NextArgument(a) => Some(a),
+                    rpf::Piece::String(_) => None,
+                })
+                .collect_vec();
+            if !parser.errors.is_empty() {
+                return None;
+            }
+
+            let positions = if let Some(fmt_arg) = rest.first() {
+                // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse
+                // them.
+
+                Either::Left(parse_rt_fmt(fmt_arg)?)
+            } else {
+                // If no format specs are given, the positions are in the given order and there are
+                // no `precision`/`width`s to consider.
+
+                Either::Right((0..).map(|n| ParamPosition {
+                    value: n,
+                    width: None,
+                    precision: None,
+                }))
+            };
+
+            let values = FormatArgsValues::new(args, format_string.span.data());
+
+            let args = izip!(positions, parsed_args, parser.arg_places)
+                .map(|(position, parsed_arg, arg_span)| {
+                    Some(FormatArg {
+                        param: FormatParam::new(
+                            match parsed_arg.position {
+                                rpf::Position::ArgumentImplicitlyIs(_) => FormatParamKind::Implicit,
+                                rpf::Position::ArgumentIs(_) => FormatParamKind::Numbered,
+                                // NamedInline is handled by `FormatParam::new()`
+                                rpf::Position::ArgumentNamed(name) => FormatParamKind::Named(Symbol::intern(name)),
+                            },
+                            position.value,
+                            parsed_arg.position_span,
+                            &values,
+                        )?,
+                        format: FormatSpec::new(parsed_arg.format, position, &values)?,
+                        span: span_from_inner(values.format_string_span, arg_span),
+                    })
+                })
+                .collect::<Option<Vec<_>>>()?;
+
+            Some(Self {
+                format_string,
+                args,
+                value_args: values.value_args,
+                newline,
+            })
+        } else {
+            None
+        }
+    }
+
     pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option<Self> {
         let mut format_args = None;
         expr_visitor_no_bodies(|e| {
@@ -466,88 +845,23 @@ impl<'tcx> FormatArgsExpn<'tcx> {
         format_args
     }
 
-    /// Returns a vector of `FormatArgsArg`.
-    pub fn args(&self) -> Option<Vec<FormatArgsArg<'tcx>>> {
-        if self.specs.is_empty() {
-            let args = std::iter::zip(&self.value_args, &self.formatters)
-                .map(|(value, &(_, format_trait))| FormatArgsArg {
-                    value,
-                    format_trait,
-                    spec: None,
-                })
-                .collect();
-            return Some(args);
-        }
-        self.specs
-            .iter()
-            .map(|spec| {
-                if_chain! {
-                    // struct `core::fmt::rt::v1::Argument`
-                    if let ExprKind::Struct(_, fields, _) = spec.kind;
-                    if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position);
-                    if let ExprKind::Lit(lit) = &position_field.expr.kind;
-                    if let LitKind::Int(position, _) = lit.node;
-                    if let Ok(i) = usize::try_from(position);
-                    if let Some(&(j, format_trait)) = self.formatters.get(i);
-                    then {
-                        Some(FormatArgsArg {
-                            value: self.value_args[j],
-                            format_trait,
-                            spec: Some(spec),
-                        })
-                    } else {
-                        None
-                    }
-                }
-            })
-            .collect()
-    }
-
     /// Source callsite span of all inputs
     pub fn inputs_span(&self) -> Span {
         match *self.value_args {
-            [] => self.format_string_span,
+            [] => self.format_string.span,
             [.., last] => self
-                .format_string_span
-                .to(hygiene::walk_chain(last.span, self.format_string_span.ctxt())),
+                .format_string
+                .span
+                .to(hygiene::walk_chain(last.span, self.format_string.span.ctxt())),
         }
     }
-}
 
-/// Type representing a `FormatArgsExpn`'s format arguments
-pub struct FormatArgsArg<'tcx> {
-    /// An element of `value_args` according to `position`
-    pub value: &'tcx Expr<'tcx>,
-    /// An element of `args` according to `position`
-    pub format_trait: Symbol,
-    /// An element of `specs`
-    pub spec: Option<&'tcx Expr<'tcx>>,
-}
-
-impl<'tcx> FormatArgsArg<'tcx> {
-    /// Returns true if any formatting parameters are used that would have an effect on strings,
-    /// like `{:+2}` instead of just `{}`.
-    pub fn has_string_formatting(&self) -> bool {
-        self.spec.map_or(false, |spec| {
-            // `!` because these conditions check that `self` is unformatted.
-            !if_chain! {
-                // struct `core::fmt::rt::v1::Argument`
-                if let ExprKind::Struct(_, fields, _) = spec.kind;
-                if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
-                // struct `core::fmt::rt::v1::FormatSpec`
-                if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind;
-                if subfields.iter().all(|field| match field.ident.name {
-                    sym::precision | sym::width => match field.expr.kind {
-                        ExprKind::Path(QPath::Resolved(_, path)) => {
-                            path.segments.last().unwrap().ident.name == sym::Implied
-                        }
-                        _ => false,
-                    }
-                    _ => true,
-                });
-                then { true } else { false }
-            }
-        })
+    /// Iterator of all format params, both values and those referenced by `width`/`precision`s.
+    pub fn params(&'tcx self) -> impl Iterator<Item = FormatParam<'tcx>> {
+        self.args
+            .iter()
+            .flat_map(|arg| [Some(arg.param), arg.format.precision.param(), arg.format.width.param()])
+            .flatten()
     }
 }
 
diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs
index 9e238c6f1ac..62020e21c81 100644
--- a/clippy_utils/src/msrvs.rs
+++ b/clippy_utils/src/msrvs.rs
@@ -13,7 +13,7 @@ macro_rules! msrv_aliases {
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
     1,62,0 { BOOL_THEN_SOME }
-    1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN }
+    1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
     1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
     1,51,0 { BORROW_AS_PTR, UNSIGNED_ABS }
     1,50,0 { BOOL_THEN }
@@ -32,8 +32,8 @@ msrv_aliases! {
     1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
     1,28,0 { FROM_BOOL }
     1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN }
+    1,24,0 { IS_ASCII_DIGIT }
     1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN }
     1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
     1,16,0 { STR_REPEAT }
-    1,24,0 { IS_ASCII_DIGIT }
 }
diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs
index 8d697a301c4..fb0d34e02ee 100644
--- a/clippy_utils/src/paths.rs
+++ b/clippy_utils/src/paths.rs
@@ -71,7 +71,6 @@ pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"];
 pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"];
 pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"];
 pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
 #[cfg(feature = "internal")]
 pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
@@ -96,6 +95,7 @@ pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwL
 pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"];
 pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
 pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
+pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"];
 pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
 #[cfg_attr(not(unix), allow(clippy::invalid_paths))]
 pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"];
diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs
index e7d670766a0..5a7f9568441 100644
--- a/clippy_utils/src/ty.rs
+++ b/clippy_utils/src/ty.rs
@@ -43,14 +43,6 @@ pub fn can_partially_move_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool
     }
 }
 
-/// Walks into `ty` and returns `true` if any inner type is the same as `other_ty`
-pub fn contains_ty<'tcx>(ty: Ty<'tcx>, other_ty: Ty<'tcx>) -> bool {
-    ty.walk().any(|inner| match inner.unpack() {
-        GenericArgKind::Type(inner_ty) => other_ty == inner_ty,
-        GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
-    })
-}
-
 /// Walks into `ty` and returns `true` if any inner type is an instance of the given adt
 /// constructor.
 pub fn contains_adt_constructor<'tcx>(ty: Ty<'tcx>, adt: AdtDef<'tcx>) -> bool {
@@ -410,7 +402,7 @@ pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
     peel(ty, 0)
 }
 
-/// Peels off all references on the type.Returns the underlying type, the number of references
+/// Peels off all references on the type. Returns the underlying type, the number of references
 /// removed, and whether the pointer is ultimately mutable or not.
 pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
     fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) {
@@ -839,3 +831,53 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc
         })
         .unwrap_or(false)
 }
+
+/// Comes up with an "at least" guesstimate for the type's size, not taking into
+/// account the layout of type parameters.
+pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
+    use rustc_middle::ty::layout::LayoutOf;
+    if !is_normalizable(cx, cx.param_env, ty) {
+        return 0;
+    }
+    match (cx.layout_of(ty).map(|layout| layout.size.bytes()), ty.kind()) {
+        (Ok(size), _) => size,
+        (Err(_), ty::Tuple(list)) => list.as_substs().types().map(|t| approx_ty_size(cx, t)).sum(),
+        (Err(_), ty::Array(t, n)) => {
+            n.try_eval_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t)
+        },
+        (Err(_), ty::Adt(def, subst)) if def.is_struct() => def
+            .variants()
+            .iter()
+            .map(|v| {
+                v.fields
+                    .iter()
+                    .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst)))
+                    .sum::<u64>()
+            })
+            .sum(),
+        (Err(_), ty::Adt(def, subst)) if def.is_enum() => def
+            .variants()
+            .iter()
+            .map(|v| {
+                v.fields
+                    .iter()
+                    .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst)))
+                    .sum::<u64>()
+            })
+            .max()
+            .unwrap_or_default(),
+        (Err(_), ty::Adt(def, subst)) if def.is_union() => def
+            .variants()
+            .iter()
+            .map(|v| {
+                v.fields
+                    .iter()
+                    .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst)))
+                    .max()
+                    .unwrap_or_default()
+            })
+            .max()
+            .unwrap_or_default(),
+        (Err(_), _) => 0,
+    }
+}
diff --git a/rust-toolchain b/rust-toolchain
index 7e14df4feea..85b60fefd60 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-08-11"
+channel = "nightly-2022-08-27"
 components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs
index 5f289918a7c..429dddc42ea 100644
--- a/rustc_tools_util/src/lib.rs
+++ b/rustc_tools_util/src/lib.rs
@@ -84,7 +84,7 @@ impl std::fmt::Debug for VersionInfo {
 #[must_use]
 pub fn get_commit_hash() -> Option<String> {
     std::process::Command::new("git")
-        .args(&["rev-parse", "--short", "HEAD"])
+        .args(["rev-parse", "--short", "HEAD"])
         .output()
         .ok()
         .and_then(|r| String::from_utf8(r.stdout).ok())
@@ -93,7 +93,7 @@ pub fn get_commit_hash() -> Option<String> {
 #[must_use]
 pub fn get_commit_date() -> Option<String> {
     std::process::Command::new("git")
-        .args(&["log", "-1", "--date=short", "--pretty=format:%cd"])
+        .args(["log", "-1", "--date=short", "--pretty=format:%cd"])
         .output()
         .ok()
         .and_then(|r| String::from_utf8(r.stdout).ok())
diff --git a/tests/check-fmt.rs b/tests/check-fmt.rs
index 0defd45b68b..e106583de4a 100644
--- a/tests/check-fmt.rs
+++ b/tests/check-fmt.rs
@@ -13,7 +13,7 @@ fn fmt() {
     let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     let output = Command::new("cargo")
         .current_dir(root_dir)
-        .args(&["dev", "fmt", "--check"])
+        .args(["dev", "fmt", "--check"])
         .output()
         .unwrap();
 
diff --git a/tests/compile-test.rs b/tests/compile-test.rs
index 92ac1a2be56..ba6186e599e 100644
--- a/tests/compile-test.rs
+++ b/tests/compile-test.rs
@@ -393,8 +393,8 @@ const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[
     "search_is_some.rs",
     "single_component_path_imports_nested_first.rs",
     "string_add.rs",
+    "suspicious_to_owned.rs",
     "toplevel_ref_arg_non_rustfix.rs",
-    "trait_duplication_in_bounds.rs",
     "unit_arg.rs",
     "unnecessary_clone.rs",
     "unnecessary_lazy_eval_unfixable.rs",
@@ -404,16 +404,23 @@ const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[
 ];
 
 fn check_rustfix_coverage() {
-    let missing_coverage_path = Path::new("target/debug/test/ui/rustfix_missing_coverage.txt");
+    let missing_coverage_path = Path::new("debug/test/ui/rustfix_missing_coverage.txt");
+    let missing_coverage_path = if let Ok(target_dir) = std::env::var("CARGO_TARGET_DIR") {
+        PathBuf::from(target_dir).join(missing_coverage_path)
+    } else {
+        missing_coverage_path.to_path_buf()
+    };
 
     if let Ok(missing_coverage_contents) = std::fs::read_to_string(missing_coverage_path) {
         assert!(RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS.iter().is_sorted_by_key(Path::new));
 
-        for rs_path in missing_coverage_contents.lines() {
-            if Path::new(rs_path).starts_with("tests/ui/crashes") {
+        for rs_file in missing_coverage_contents.lines() {
+            let rs_path = Path::new(rs_file);
+            if rs_path.starts_with("tests/ui/crashes") {
                 continue;
             }
-            let filename = Path::new(rs_path).strip_prefix("tests/ui/").unwrap();
+            assert!(rs_path.starts_with("tests/ui/"), "{:?}", rs_file);
+            let filename = rs_path.strip_prefix("tests/ui/").unwrap();
             assert!(
                 RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS
                     .binary_search_by_key(&filename, Path::new)
@@ -421,7 +428,7 @@ fn check_rustfix_coverage() {
                 "`{}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \
                 Please either add `// run-rustfix` at the top of the file or add the file to \
                 `RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS` in `tests/compile-test.rs`.",
-                rs_path,
+                rs_file,
             );
         }
     }
diff --git a/tests/dogfood.rs b/tests/dogfood.rs
index 5697e8680cd..961525bbd91 100644
--- a/tests/dogfood.rs
+++ b/tests/dogfood.rs
@@ -87,11 +87,11 @@ fn run_clippy_for_package(project: &str, args: &[&str]) {
 
     if cfg!(feature = "internal") {
         // internal lints only exist if we build with the internal feature
-        command.args(&["-D", "clippy::internal"]);
+        command.args(["-D", "clippy::internal"]);
     } else {
         // running a clippy built without internal lints on the clippy source
         // that contains e.g. `allow(clippy::invalid_paths)`
-        command.args(&["-A", "unknown_lints"]);
+        command.args(["-A", "unknown_lints"]);
     }
 
     let output = command.output().unwrap();
diff --git a/tests/integration.rs b/tests/integration.rs
index c64425fa01a..23a9bef3ccc 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -19,7 +19,7 @@ fn integration_test() {
     repo_dir.push(crate_name);
 
     let st = Command::new("git")
-        .args(&[
+        .args([
             OsStr::new("clone"),
             OsStr::new("--depth=1"),
             OsStr::new(&repo_url),
@@ -37,7 +37,7 @@ fn integration_test() {
         .current_dir(repo_dir)
         .env("RUST_BACKTRACE", "full")
         .env("CARGO_TARGET_DIR", target_dir)
-        .args(&[
+        .args([
             "clippy",
             "--all-targets",
             "--all-features",
diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs
index c3aae1a9aa2..2e0f4e76075 100644
--- a/tests/lint_message_convention.rs
+++ b/tests/lint_message_convention.rs
@@ -19,7 +19,7 @@ impl Message {
         // we don't want the first letter after "error: ", "help: " ... to be capitalized
         // also no punctuation (except for "?" ?) at the end of a line
         static REGEX_SET: LazyLock<RegexSet> = LazyLock::new(|| {
-            RegexSet::new(&[
+            RegexSet::new([
                 r"error: [A-Z]",
                 r"help: [A-Z]",
                 r"warning: [A-Z]",
@@ -37,7 +37,7 @@ impl Message {
         // sometimes the first character is capitalized and it is legal (like in "C-like enum variants") or
         // we want to ask a question ending in "?"
         static EXCEPTIONS_SET: LazyLock<RegexSet> = LazyLock::new(|| {
-            RegexSet::new(&[
+            RegexSet::new([
                 r"\.\.\.$",
                 r".*C-like enum variant discriminant is not portable to 32-bit targets",
                 r".*Intel x86 assembly syntax used",
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 9f8e778b3b9..a52a0b5289f 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -19,6 +19,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            enforced-import-renames
            enum-variant-name-threshold
            enum-variant-size-threshold
+           large-error-threshold
            literal-representation-threshold
            max-fn-params-bools
            max-include-file-size
diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs
index 0d65071af15..6f0485b5279 100644
--- a/tests/ui/case_sensitive_file_extension_comparisons.rs
+++ b/tests/ui/case_sensitive_file_extension_comparisons.rs
@@ -14,31 +14,31 @@ fn is_rust_file(filename: &str) -> bool {
 
 fn main() {
     // std::string::String and &str should trigger the lint failure with .ext12
-    let _ = String::from("").ends_with(".ext12");
+    let _ = String::new().ends_with(".ext12");
     let _ = "str".ends_with(".ext12");
 
     // The test struct should not trigger the lint failure with .ext12
     TestStruct {}.ends_with(".ext12");
 
     // std::string::String and &str should trigger the lint failure with .EXT12
-    let _ = String::from("").ends_with(".EXT12");
+    let _ = String::new().ends_with(".EXT12");
     let _ = "str".ends_with(".EXT12");
 
     // The test struct should not trigger the lint failure with .EXT12
     TestStruct {}.ends_with(".EXT12");
 
     // Should not trigger the lint failure with .eXT12
-    let _ = String::from("").ends_with(".eXT12");
+    let _ = String::new().ends_with(".eXT12");
     let _ = "str".ends_with(".eXT12");
     TestStruct {}.ends_with(".eXT12");
 
     // Should not trigger the lint failure with .EXT123 (too long)
-    let _ = String::from("").ends_with(".EXT123");
+    let _ = String::new().ends_with(".EXT123");
     let _ = "str".ends_with(".EXT123");
     TestStruct {}.ends_with(".EXT123");
 
     // Shouldn't fail if it doesn't start with a dot
-    let _ = String::from("").ends_with("a.ext");
+    let _ = String::new().ends_with("a.ext");
     let _ = "str".ends_with("a.extA");
     TestStruct {}.ends_with("a.ext");
 }
diff --git a/tests/ui/case_sensitive_file_extension_comparisons.stderr b/tests/ui/case_sensitive_file_extension_comparisons.stderr
index 05b98169f2d..5d9a043edb9 100644
--- a/tests/ui/case_sensitive_file_extension_comparisons.stderr
+++ b/tests/ui/case_sensitive_file_extension_comparisons.stderr
@@ -8,10 +8,10 @@ LL |     filename.ends_with(".rs")
    = help: consider using a case-insensitive comparison instead
 
 error: case-sensitive file extension comparison
-  --> $DIR/case_sensitive_file_extension_comparisons.rs:17:30
+  --> $DIR/case_sensitive_file_extension_comparisons.rs:17:27
    |
-LL |     let _ = String::from("").ends_with(".ext12");
-   |                              ^^^^^^^^^^^^^^^^^^^
+LL |     let _ = String::new().ends_with(".ext12");
+   |                           ^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using a case-insensitive comparison instead
 
@@ -24,10 +24,10 @@ LL |     let _ = "str".ends_with(".ext12");
    = help: consider using a case-insensitive comparison instead
 
 error: case-sensitive file extension comparison
-  --> $DIR/case_sensitive_file_extension_comparisons.rs:24:30
+  --> $DIR/case_sensitive_file_extension_comparisons.rs:24:27
    |
-LL |     let _ = String::from("").ends_with(".EXT12");
-   |                              ^^^^^^^^^^^^^^^^^^^
+LL |     let _ = String::new().ends_with(".EXT12");
+   |                           ^^^^^^^^^^^^^^^^^^^
    |
    = help: consider using a case-insensitive comparison instead
 
diff --git a/tests/ui/cast_raw_slice_pointer_cast.fixed b/tests/ui/cast_raw_slice_pointer_cast.fixed
new file mode 100644
index 00000000000..b70c1912951
--- /dev/null
+++ b/tests/ui/cast_raw_slice_pointer_cast.fixed
@@ -0,0 +1,24 @@
+// run-rustfix
+#![warn(clippy::cast_slice_from_raw_parts)]
+
+#[allow(unused_imports, unused_unsafe)]
+fn main() {
+    let mut vec = vec![0u8; 1];
+    let ptr: *const u8 = vec.as_ptr();
+    let mptr = vec.as_mut_ptr();
+    let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) };
+    let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) };
+    let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+    {
+        use core::slice;
+        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+        use slice as one;
+        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+    }
+    {
+        use std::slice;
+        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+        use slice as one;
+        let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
+    }
+}
diff --git a/tests/ui/cast_raw_slice_pointer_cast.rs b/tests/ui/cast_raw_slice_pointer_cast.rs
new file mode 100644
index 00000000000..c1b316765c9
--- /dev/null
+++ b/tests/ui/cast_raw_slice_pointer_cast.rs
@@ -0,0 +1,24 @@
+// run-rustfix
+#![warn(clippy::cast_slice_from_raw_parts)]
+
+#[allow(unused_imports, unused_unsafe)]
+fn main() {
+    let mut vec = vec![0u8; 1];
+    let ptr: *const u8 = vec.as_ptr();
+    let mptr = vec.as_mut_ptr();
+    let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] };
+    let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] };
+    let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8];
+    {
+        use core::slice;
+        let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+        use slice as one;
+        let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+    }
+    {
+        use std::slice;
+        let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+        use slice as one;
+        let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+    }
+}
diff --git a/tests/ui/cast_raw_slice_pointer_cast.stderr b/tests/ui/cast_raw_slice_pointer_cast.stderr
new file mode 100644
index 00000000000..f07801c197c
--- /dev/null
+++ b/tests/ui/cast_raw_slice_pointer_cast.stderr
@@ -0,0 +1,46 @@
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:9:35
+   |
+LL |     let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+   |
+   = note: `-D clippy::cast-slice-from-raw-parts` implied by `-D warnings`
+
+error: casting the result of `from_raw_parts_mut` to *mut [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:10:35
+   |
+LL |     let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:11:26
+   |
+LL |     let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8];
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:14:30
+   |
+LL |         let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:16:30
+   |
+LL |         let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:20:30
+   |
+LL |         let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: casting the result of `from_raw_parts` to *const [u8]
+  --> $DIR/cast_raw_slice_pointer_cast.rs:22:30
+   |
+LL |         let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
+
+error: aborting due to 7 previous errors
+
diff --git a/tests/ui/collapsible_str_replace.fixed b/tests/ui/collapsible_str_replace.fixed
new file mode 100644
index 00000000000..49fc9a9629e
--- /dev/null
+++ b/tests/ui/collapsible_str_replace.fixed
@@ -0,0 +1,73 @@
+// run-rustfix
+
+#![warn(clippy::collapsible_str_replace)]
+
+fn get_filter() -> char {
+    'u'
+}
+
+fn main() {
+    let d = 'd';
+    let p = 'p';
+    let s = 's';
+    let u = 'u';
+    let l = "l";
+
+    let mut iter = ["l", "z"].iter();
+
+    // LINT CASES
+    let _ = "hesuo worpd".replace(['s', 'u'], "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u'], l);
+
+    let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l");
+
+    let _ = "hesuo worpd"
+        .replace(['s', 'u', 'p', 'd'], "l");
+
+    let _ = "hesuo world".replace([s, 'u'], "l");
+
+    let _ = "hesuo worpd".replace([s, 'u', 'p'], "l");
+
+    let _ = "hesuo worpd".replace([s, u, 'p'], "l");
+
+    let _ = "hesuo worpd".replace([s, u, p], "l");
+
+    let _ = "hesuo worlp".replace(['s', 'u'], "l").replace('p', "d");
+
+    let _ = "hesuo worpd".replace('s', "x").replace(['u', 'p'], "l");
+
+    // Note: Future iterations could lint `replace(|c| matches!(c, "su" | 'd' | 'p'), "l")`
+    let _ = "hesudo worpd".replace("su", "l").replace(['d', 'p'], "l");
+
+    let _ = "hesudo worpd".replace([d, 'p'], "l").replace("su", "l");
+
+    let _ = "hesuo world".replace([get_filter(), 's'], "l");
+
+    // NO LINT CASES
+    let _ = "hesuo world".replace('s', "l").replace('u', "p");
+
+    let _ = "hesuo worpd".replace('s', "l").replace('p', l);
+
+    let _ = "hesudo worpd".replace('d', "l").replace("su", "l").replace('p', "l");
+
+    // Note: Future iterations of `collapsible_str_replace` might lint this and combine to `[s, u, p]`
+    let _ = "hesuo worpd".replace([s, u], "l").replace([u, p], "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u'], "l").replace(['u', 'p'], "l");
+
+    let _ = "hesuo worpd".replace('s', "l").replace(['u', 'p'], "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l").replace('r', "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u', 'p'], l).replace('r', l);
+
+    let _ = "hesuo worpd".replace(['s', u, 'p'], "l").replace('r', "l");
+
+    let _ = "hesuo worpd".replace([s, u], "l").replace(p, "l");
+
+    // Regression test
+    let _ = "hesuo worpd"
+        .replace('u', iter.next().unwrap())
+        .replace('s', iter.next().unwrap());
+}
diff --git a/tests/ui/collapsible_str_replace.rs b/tests/ui/collapsible_str_replace.rs
new file mode 100644
index 00000000000..e3e25c4146f
--- /dev/null
+++ b/tests/ui/collapsible_str_replace.rs
@@ -0,0 +1,76 @@
+// run-rustfix
+
+#![warn(clippy::collapsible_str_replace)]
+
+fn get_filter() -> char {
+    'u'
+}
+
+fn main() {
+    let d = 'd';
+    let p = 'p';
+    let s = 's';
+    let u = 'u';
+    let l = "l";
+
+    let mut iter = ["l", "z"].iter();
+
+    // LINT CASES
+    let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
+
+    let _ = "hesuo worpd".replace('s', l).replace('u', l);
+
+    let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l");
+
+    let _ = "hesuo worpd"
+        .replace('s', "l")
+        .replace('u', "l")
+        .replace('p', "l")
+        .replace('d', "l");
+
+    let _ = "hesuo world".replace(s, "l").replace('u', "l");
+
+    let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l");
+
+    let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l");
+
+    let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l");
+
+    let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d");
+
+    let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l");
+
+    // Note: Future iterations could lint `replace(|c| matches!(c, "su" | 'd' | 'p'), "l")`
+    let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l");
+
+    let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l");
+
+    let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l");
+
+    // NO LINT CASES
+    let _ = "hesuo world".replace('s', "l").replace('u', "p");
+
+    let _ = "hesuo worpd".replace('s', "l").replace('p', l);
+
+    let _ = "hesudo worpd".replace('d', "l").replace("su", "l").replace('p', "l");
+
+    // Note: Future iterations of `collapsible_str_replace` might lint this and combine to `[s, u, p]`
+    let _ = "hesuo worpd".replace([s, u], "l").replace([u, p], "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u'], "l").replace(['u', 'p'], "l");
+
+    let _ = "hesuo worpd".replace('s', "l").replace(['u', 'p'], "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l").replace('r', "l");
+
+    let _ = "hesuo worpd".replace(['s', 'u', 'p'], l).replace('r', l);
+
+    let _ = "hesuo worpd".replace(['s', u, 'p'], "l").replace('r', "l");
+
+    let _ = "hesuo worpd".replace([s, u], "l").replace(p, "l");
+
+    // Regression test
+    let _ = "hesuo worpd"
+        .replace('u', iter.next().unwrap())
+        .replace('s', iter.next().unwrap());
+}
diff --git a/tests/ui/collapsible_str_replace.stderr b/tests/ui/collapsible_str_replace.stderr
new file mode 100644
index 00000000000..8e3daf3b898
--- /dev/null
+++ b/tests/ui/collapsible_str_replace.stderr
@@ -0,0 +1,86 @@
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:19:27
+   |
+LL |     let _ = "hesuo worpd".replace('s', "l").replace('u', "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
+   |
+   = note: `-D clippy::collapsible-str-replace` implied by `-D warnings`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:21:27
+   |
+LL |     let _ = "hesuo worpd".replace('s', l).replace('u', l);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], l)`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:23:27
+   |
+LL |     let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u', 'p'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:26:10
+   |
+LL |           .replace('s', "l")
+   |  __________^
+LL | |         .replace('u', "l")
+LL | |         .replace('p', "l")
+LL | |         .replace('d', "l");
+   | |__________________________^ help: replace with: `replace(['s', 'u', 'p', 'd'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:31:27
+   |
+LL |     let _ = "hesuo world".replace(s, "l").replace('u', "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:33:27
+   |
+LL |     let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u', 'p'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:35:27
+   |
+LL |     let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, 'p'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:37:27
+   |
+LL |     let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, p], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:39:27
+   |
+LL |     let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:41:45
+   |
+LL |     let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l");
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['u', 'p'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:44:47
+   |
+LL |     let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l");
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['d', 'p'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:46:28
+   |
+LL |     let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l");
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([d, 'p'], "l")`
+
+error: used consecutive `str::replace` call
+  --> $DIR/collapsible_str_replace.rs:48:27
+   |
+LL |     let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l");
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([get_filter(), 's'], "l")`
+
+error: aborting due to 13 previous errors
+
diff --git a/tests/ui/expect.rs b/tests/ui/expect.rs
index 1073acf6f0c..d742595e14d 100644
--- a/tests/ui/expect.rs
+++ b/tests/ui/expect.rs
@@ -6,8 +6,9 @@ fn expect_option() {
 }
 
 fn expect_result() {
-    let res: Result<u8, ()> = Ok(0);
+    let res: Result<u8, u8> = Ok(0);
     let _ = res.expect("");
+    let _ = res.expect_err("");
 }
 
 fn main() {
diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr
index ab28aac4556..904c0904645 100644
--- a/tests/ui/expect.stderr
+++ b/tests/ui/expect.stderr
@@ -15,5 +15,13 @@ LL |     let _ = res.expect("");
    |
    = help: if this value is an `Err`, it will panic
 
-error: aborting due to 2 previous errors
+error: used `expect_err()` on `a Result` value
+  --> $DIR/expect.rs:11:13
+   |
+LL |     let _ = res.expect_err("");
+   |             ^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this value is an `Ok`, it will panic
+
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/floating_point_exp.fixed b/tests/ui/floating_point_exp.fixed
index ae7805fdf01..c86a502d15f 100644
--- a/tests/ui/floating_point_exp.fixed
+++ b/tests/ui/floating_point_exp.fixed
@@ -5,6 +5,7 @@ fn main() {
     let x = 2f32;
     let _ = x.exp_m1();
     let _ = x.exp_m1() + 2.0;
+    let _ = (x as f32).exp_m1() + 2.0;
     // Cases where the lint shouldn't be applied
     let _ = x.exp() - 2.0;
     let _ = x.exp() - 1.0 * 2.0;
diff --git a/tests/ui/floating_point_exp.rs b/tests/ui/floating_point_exp.rs
index 27e0b9bcbc9..e59589f912a 100644
--- a/tests/ui/floating_point_exp.rs
+++ b/tests/ui/floating_point_exp.rs
@@ -5,6 +5,7 @@ fn main() {
     let x = 2f32;
     let _ = x.exp() - 1.0;
     let _ = x.exp() - 1.0 + 2.0;
+    let _ = (x as f32).exp() - 1.0 + 2.0;
     // Cases where the lint shouldn't be applied
     let _ = x.exp() - 2.0;
     let _ = x.exp() - 1.0 * 2.0;
diff --git a/tests/ui/floating_point_exp.stderr b/tests/ui/floating_point_exp.stderr
index 5cd999ad47c..f84eede1987 100644
--- a/tests/ui/floating_point_exp.stderr
+++ b/tests/ui/floating_point_exp.stderr
@@ -13,16 +13,22 @@ LL |     let _ = x.exp() - 1.0 + 2.0;
    |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
 
 error: (e.pow(x) - 1) can be computed more accurately
-  --> $DIR/floating_point_exp.rs:13:13
+  --> $DIR/floating_point_exp.rs:8:13
+   |
+LL |     let _ = (x as f32).exp() - 1.0 + 2.0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).exp_m1()`
+
+error: (e.pow(x) - 1) can be computed more accurately
+  --> $DIR/floating_point_exp.rs:14:13
    |
 LL |     let _ = x.exp() - 1.0;
    |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
 
 error: (e.pow(x) - 1) can be computed more accurately
-  --> $DIR/floating_point_exp.rs:14:13
+  --> $DIR/floating_point_exp.rs:15:13
    |
 LL |     let _ = x.exp() - 1.0 + 2.0;
    |             ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/floating_point_log.fixed b/tests/ui/floating_point_log.fixed
index 5b487bb8fcf..4def9300bb7 100644
--- a/tests/ui/floating_point_log.fixed
+++ b/tests/ui/floating_point_log.fixed
@@ -12,6 +12,7 @@ fn check_log_base() {
     let _ = x.ln();
     let _ = x.log2();
     let _ = x.ln();
+    let _ = (x as f32).log2();
 
     let x = 1f64;
     let _ = x.log2();
diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs
index 01181484e7d..1e04caa7d2a 100644
--- a/tests/ui/floating_point_log.rs
+++ b/tests/ui/floating_point_log.rs
@@ -12,6 +12,7 @@ fn check_log_base() {
     let _ = x.log(std::f32::consts::E);
     let _ = x.log(TWO);
     let _ = x.log(E);
+    let _ = (x as f32).log(2f32);
 
     let x = 1f64;
     let _ = x.log(2f64);
diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr
index 96e5a154441..89800a13a6e 100644
--- a/tests/ui/floating_point_log.stderr
+++ b/tests/ui/floating_point_log.stderr
@@ -31,25 +31,31 @@ LL |     let _ = x.log(E);
    |             ^^^^^^^^ help: consider using: `x.ln()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> $DIR/floating_point_log.rs:17:13
+  --> $DIR/floating_point_log.rs:15:13
+   |
+LL |     let _ = (x as f32).log(2f32);
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log2()`
+
+error: logarithm for bases 2, 10 and e can be computed more accurately
+  --> $DIR/floating_point_log.rs:18:13
    |
 LL |     let _ = x.log(2f64);
    |             ^^^^^^^^^^^ help: consider using: `x.log2()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> $DIR/floating_point_log.rs:18:13
+  --> $DIR/floating_point_log.rs:19:13
    |
 LL |     let _ = x.log(10f64);
    |             ^^^^^^^^^^^^ help: consider using: `x.log10()`
 
 error: logarithm for bases 2, 10 and e can be computed more accurately
-  --> $DIR/floating_point_log.rs:19:13
+  --> $DIR/floating_point_log.rs:20:13
    |
 LL |     let _ = x.log(std::f64::consts::E);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:24:13
+  --> $DIR/floating_point_log.rs:25:13
    |
 LL |     let _ = (1f32 + 2.).ln();
    |             ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
@@ -57,118 +63,118 @@ LL |     let _ = (1f32 + 2.).ln();
    = note: `-D clippy::imprecise-flops` implied by `-D warnings`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:25:13
+  --> $DIR/floating_point_log.rs:26:13
    |
 LL |     let _ = (1f32 + 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:26:13
+  --> $DIR/floating_point_log.rs:27:13
    |
 LL |     let _ = (1.0 + x).ln();
    |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:27:13
+  --> $DIR/floating_point_log.rs:28:13
    |
 LL |     let _ = (1.0 + x / 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:28:13
+  --> $DIR/floating_point_log.rs:29:13
    |
 LL |     let _ = (1.0 + x.powi(3)).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:29:13
+  --> $DIR/floating_point_log.rs:30:13
    |
 LL |     let _ = (1.0 + x.powi(3) / 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(3) / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:30:13
+  --> $DIR/floating_point_log.rs:31:13
    |
 LL |     let _ = (1.0 + (std::f32::consts::E - 1.0)).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(std::f32::consts::E - 1.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:31:13
+  --> $DIR/floating_point_log.rs:32:13
    |
 LL |     let _ = (x + 1.0).ln();
    |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:32:13
+  --> $DIR/floating_point_log.rs:33:13
    |
 LL |     let _ = (x.powi(3) + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:33:13
+  --> $DIR/floating_point_log.rs:34:13
    |
 LL |     let _ = (x + 2.0 + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:34:13
+  --> $DIR/floating_point_log.rs:35:13
    |
 LL |     let _ = (x / 2.0 + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:42:13
+  --> $DIR/floating_point_log.rs:43:13
    |
 LL |     let _ = (1f64 + 2.).ln();
    |             ^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:43:13
+  --> $DIR/floating_point_log.rs:44:13
    |
 LL |     let _ = (1f64 + 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:44:13
+  --> $DIR/floating_point_log.rs:45:13
    |
 LL |     let _ = (1.0 + x).ln();
    |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:45:13
+  --> $DIR/floating_point_log.rs:46:13
    |
 LL |     let _ = (1.0 + x / 2.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:46:13
+  --> $DIR/floating_point_log.rs:47:13
    |
 LL |     let _ = (1.0 + x.powi(3)).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:47:13
+  --> $DIR/floating_point_log.rs:48:13
    |
 LL |     let _ = (x + 1.0).ln();
    |             ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:48:13
+  --> $DIR/floating_point_log.rs:49:13
    |
 LL |     let _ = (x.powi(3) + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:49:13
+  --> $DIR/floating_point_log.rs:50:13
    |
 LL |     let _ = (x + 2.0 + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()`
 
 error: ln(1 + x) can be computed more accurately
-  --> $DIR/floating_point_log.rs:50:13
+  --> $DIR/floating_point_log.rs:51:13
    |
 LL |     let _ = (x / 2.0 + 1.0).ln();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()`
 
-error: aborting due to 28 previous errors
+error: aborting due to 29 previous errors
 
diff --git a/tests/ui/floating_point_logbase.fixed b/tests/ui/floating_point_logbase.fixed
index 13962a272d4..936462f9406 100644
--- a/tests/ui/floating_point_logbase.fixed
+++ b/tests/ui/floating_point_logbase.fixed
@@ -5,6 +5,7 @@ fn main() {
     let x = 3f32;
     let y = 5f32;
     let _ = x.log(y);
+    let _ = (x as f32).log(y);
     let _ = x.log(y);
     let _ = x.log(y);
     let _ = x.log(y);
diff --git a/tests/ui/floating_point_logbase.rs b/tests/ui/floating_point_logbase.rs
index 26bc20d5370..0b56fa8fa41 100644
--- a/tests/ui/floating_point_logbase.rs
+++ b/tests/ui/floating_point_logbase.rs
@@ -5,6 +5,7 @@ fn main() {
     let x = 3f32;
     let y = 5f32;
     let _ = x.ln() / y.ln();
+    let _ = (x as f32).ln() / y.ln();
     let _ = x.log2() / y.log2();
     let _ = x.log10() / y.log10();
     let _ = x.log(5f32) / y.log(5f32);
diff --git a/tests/ui/floating_point_logbase.stderr b/tests/ui/floating_point_logbase.stderr
index 78354c2f62d..384e3554cbb 100644
--- a/tests/ui/floating_point_logbase.stderr
+++ b/tests/ui/floating_point_logbase.stderr
@@ -9,20 +9,26 @@ LL |     let _ = x.ln() / y.ln();
 error: log base can be expressed more clearly
   --> $DIR/floating_point_logbase.rs:8:13
    |
+LL |     let _ = (x as f32).ln() / y.ln();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log(y)`
+
+error: log base can be expressed more clearly
+  --> $DIR/floating_point_logbase.rs:9:13
+   |
 LL |     let _ = x.log2() / y.log2();
    |             ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
 
 error: log base can be expressed more clearly
-  --> $DIR/floating_point_logbase.rs:9:13
+  --> $DIR/floating_point_logbase.rs:10:13
    |
 LL |     let _ = x.log10() / y.log10();
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
 
 error: log base can be expressed more clearly
-  --> $DIR/floating_point_logbase.rs:10:13
+  --> $DIR/floating_point_logbase.rs:11:13
    |
 LL |     let _ = x.log(5f32) / y.log(5f32);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed
index b0641a100cd..7efe10a10f9 100644
--- a/tests/ui/floating_point_powf.fixed
+++ b/tests/ui/floating_point_powf.fixed
@@ -11,10 +11,13 @@ fn main() {
     let _ = (-3.1f32).exp();
     let _ = x.sqrt();
     let _ = x.cbrt();
+    let _ = (x as f32).cbrt();
     let _ = x.powi(3);
     let _ = x.powi(-2);
     let _ = x.powi(16_777_215);
     let _ = x.powi(-16_777_215);
+    let _ = (x as f32).powi(-16_777_215);
+    let _ = (x as f32).powi(3);
     // Cases where the lint shouldn't be applied
     let _ = x.powf(2.1);
     let _ = x.powf(-2.1);
diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs
index a0a2c973900..445080417f2 100644
--- a/tests/ui/floating_point_powf.rs
+++ b/tests/ui/floating_point_powf.rs
@@ -11,10 +11,13 @@ fn main() {
     let _ = std::f32::consts::E.powf(-3.1);
     let _ = x.powf(1.0 / 2.0);
     let _ = x.powf(1.0 / 3.0);
+    let _ = (x as f32).powf(1.0 / 3.0);
     let _ = x.powf(3.0);
     let _ = x.powf(-2.0);
     let _ = x.powf(16_777_215.0);
     let _ = x.powf(-16_777_215.0);
+    let _ = (x as f32).powf(-16_777_215.0);
+    let _ = (x as f32).powf(3.0);
     // Cases where the lint shouldn't be applied
     let _ = x.powf(2.1);
     let _ = x.powf(-2.1);
diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr
index 2422eb911e9..6ee696e6ada 100644
--- a/tests/ui/floating_point_powf.stderr
+++ b/tests/ui/floating_point_powf.stderr
@@ -50,101 +50,119 @@ LL |     let _ = x.powf(1.0 / 3.0);
    |
    = note: `-D clippy::imprecise-flops` implied by `-D warnings`
 
-error: exponentiation with integer powers can be computed more efficiently
+error: cube-root of a number can be computed more accurately
   --> $DIR/floating_point_powf.rs:14:13
    |
+LL |     let _ = (x as f32).powf(1.0 / 3.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).cbrt()`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:15:13
+   |
 LL |     let _ = x.powf(3.0);
    |             ^^^^^^^^^^^ help: consider using: `x.powi(3)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:15:13
+  --> $DIR/floating_point_powf.rs:16:13
    |
 LL |     let _ = x.powf(-2.0);
    |             ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:16:13
+  --> $DIR/floating_point_powf.rs:17:13
    |
 LL |     let _ = x.powf(16_777_215.0);
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(16_777_215)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:17:13
+  --> $DIR/floating_point_powf.rs:18:13
    |
 LL |     let _ = x.powf(-16_777_215.0);
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-16_777_215)`
 
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:19:13
+   |
+LL |     let _ = (x as f32).powf(-16_777_215.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(-16_777_215)`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:20:13
+   |
+LL |     let _ = (x as f32).powf(3.0);
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(3)`
+
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:25:13
+  --> $DIR/floating_point_powf.rs:28:13
    |
 LL |     let _ = 2f64.powf(x);
    |             ^^^^^^^^^^^^ help: consider using: `x.exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:26:13
+  --> $DIR/floating_point_powf.rs:29:13
    |
 LL |     let _ = 2f64.powf(3.1);
    |             ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:27:13
+  --> $DIR/floating_point_powf.rs:30:13
    |
 LL |     let _ = 2f64.powf(-3.1);
    |             ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:28:13
+  --> $DIR/floating_point_powf.rs:31:13
    |
 LL |     let _ = std::f64::consts::E.powf(x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:29:13
+  --> $DIR/floating_point_powf.rs:32:13
    |
 LL |     let _ = std::f64::consts::E.powf(3.1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:30:13
+  --> $DIR/floating_point_powf.rs:33:13
    |
 LL |     let _ = std::f64::consts::E.powf(-3.1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()`
 
 error: square-root of a number can be computed more efficiently and accurately
-  --> $DIR/floating_point_powf.rs:31:13
+  --> $DIR/floating_point_powf.rs:34:13
    |
 LL |     let _ = x.powf(1.0 / 2.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()`
 
 error: cube-root of a number can be computed more accurately
-  --> $DIR/floating_point_powf.rs:32:13
+  --> $DIR/floating_point_powf.rs:35:13
    |
 LL |     let _ = x.powf(1.0 / 3.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:33:13
+  --> $DIR/floating_point_powf.rs:36:13
    |
 LL |     let _ = x.powf(3.0);
    |             ^^^^^^^^^^^ help: consider using: `x.powi(3)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:34:13
+  --> $DIR/floating_point_powf.rs:37:13
    |
 LL |     let _ = x.powf(-2.0);
    |             ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:35:13
+  --> $DIR/floating_point_powf.rs:38:13
    |
 LL |     let _ = x.powf(-2_147_483_648.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:36:13
+  --> $DIR/floating_point_powf.rs:39:13
    |
 LL |     let _ = x.powf(2_147_483_647.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)`
 
-error: aborting due to 24 previous errors
+error: aborting due to 27 previous errors
 
diff --git a/tests/ui/floating_point_powi.fixed b/tests/ui/floating_point_powi.fixed
index 85f7c531e39..5758db7c6c8 100644
--- a/tests/ui/floating_point_powi.fixed
+++ b/tests/ui/floating_point_powi.fixed
@@ -8,6 +8,7 @@ fn main() {
     let y = 4f32;
     let _ = x.mul_add(x, y);
     let _ = y.mul_add(y, x);
+    let _ = (y as f32).mul_add(y as f32, x);
     let _ = x.mul_add(x, y).sqrt();
     let _ = y.mul_add(y, x).sqrt();
     // Cases where the lint shouldn't be applied
diff --git a/tests/ui/floating_point_powi.rs b/tests/ui/floating_point_powi.rs
index ece61d1bec4..5926bf1b000 100644
--- a/tests/ui/floating_point_powi.rs
+++ b/tests/ui/floating_point_powi.rs
@@ -8,6 +8,7 @@ fn main() {
     let y = 4f32;
     let _ = x.powi(2) + y;
     let _ = x + y.powi(2);
+    let _ = x + (y as f32).powi(2);
     let _ = (x.powi(2) + y).sqrt();
     let _ = (x + y.powi(2)).sqrt();
     // Cases where the lint shouldn't be applied
diff --git a/tests/ui/floating_point_powi.stderr b/tests/ui/floating_point_powi.stderr
index 37d840988bb..a3c74544212 100644
--- a/tests/ui/floating_point_powi.stderr
+++ b/tests/ui/floating_point_powi.stderr
@@ -15,14 +15,20 @@ LL |     let _ = x + y.powi(2);
 error: multiply and add expressions can be calculated more efficiently and accurately
   --> $DIR/floating_point_powi.rs:11:13
    |
-LL |     let _ = (x.powi(2) + y).sqrt();
-   |             ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
+LL |     let _ = x + (y as f32).powi(2);
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y as f32).mul_add(y as f32, x)`
 
 error: multiply and add expressions can be calculated more efficiently and accurately
   --> $DIR/floating_point_powi.rs:12:13
    |
+LL |     let _ = (x.powi(2) + y).sqrt();
+   |             ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
+
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:13:13
+   |
 LL |     let _ = (x + y.powi(2)).sqrt();
    |             ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/tests/ui/floating_point_rad.fixed b/tests/ui/floating_point_rad.fixed
index ce91fe176c6..27674b8a455 100644
--- a/tests/ui/floating_point_rad.fixed
+++ b/tests/ui/floating_point_rad.fixed
@@ -8,6 +8,11 @@ pub const fn const_context() {
     let _ = x * 180f32 / std::f32::consts::PI;
 }
 
+pub fn issue9391(degrees: i64) {
+    let _ = (degrees as f64).to_radians();
+    let _ = (degrees as f64).to_degrees();
+}
+
 fn main() {
     let x = 3f32;
     let _ = x.to_degrees();
diff --git a/tests/ui/floating_point_rad.rs b/tests/ui/floating_point_rad.rs
index 8f323498614..f1ea73df398 100644
--- a/tests/ui/floating_point_rad.rs
+++ b/tests/ui/floating_point_rad.rs
@@ -8,6 +8,11 @@ pub const fn const_context() {
     let _ = x * 180f32 / std::f32::consts::PI;
 }
 
+pub fn issue9391(degrees: i64) {
+    let _ = degrees as f64 * std::f64::consts::PI / 180.0;
+    let _ = degrees as f64 * 180.0 / std::f64::consts::PI;
+}
+
 fn main() {
     let x = 3f32;
     let _ = x * 180f32 / std::f32::consts::PI;
diff --git a/tests/ui/floating_point_rad.stderr b/tests/ui/floating_point_rad.stderr
index f12d3d23f3a..979442f2c24 100644
--- a/tests/ui/floating_point_rad.stderr
+++ b/tests/ui/floating_point_rad.stderr
@@ -1,40 +1,52 @@
-error: conversion to degrees can be done more accurately
-  --> $DIR/floating_point_rad.rs:13:13
+error: conversion to radians can be done more accurately
+  --> $DIR/floating_point_rad.rs:12:13
    |
-LL |     let _ = x * 180f32 / std::f32::consts::PI;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()`
+LL |     let _ = degrees as f64 * std::f64::consts::PI / 180.0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_radians()`
    |
    = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
 
 error: conversion to degrees can be done more accurately
-  --> $DIR/floating_point_rad.rs:14:13
+  --> $DIR/floating_point_rad.rs:13:13
+   |
+LL |     let _ = degrees as f64 * 180.0 / std::f64::consts::PI;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_degrees()`
+
+error: conversion to degrees can be done more accurately
+  --> $DIR/floating_point_rad.rs:18:13
+   |
+LL |     let _ = x * 180f32 / std::f32::consts::PI;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()`
+
+error: conversion to degrees can be done more accurately
+  --> $DIR/floating_point_rad.rs:19:13
    |
 LL |     let _ = 90. * 180f64 / std::f64::consts::PI;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_degrees()`
 
 error: conversion to degrees can be done more accurately
-  --> $DIR/floating_point_rad.rs:15:13
+  --> $DIR/floating_point_rad.rs:20:13
    |
 LL |     let _ = 90.5 * 180f64 / std::f64::consts::PI;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_degrees()`
 
 error: conversion to radians can be done more accurately
-  --> $DIR/floating_point_rad.rs:16:13
+  --> $DIR/floating_point_rad.rs:21:13
    |
 LL |     let _ = x * std::f32::consts::PI / 180f32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()`
 
 error: conversion to radians can be done more accurately
-  --> $DIR/floating_point_rad.rs:17:13
+  --> $DIR/floating_point_rad.rs:22:13
    |
 LL |     let _ = 90. * std::f32::consts::PI / 180f32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_radians()`
 
 error: conversion to radians can be done more accurately
-  --> $DIR/floating_point_rad.rs:18:13
+  --> $DIR/floating_point_rad.rs:23:13
    |
 LL |     let _ = 90.5 * std::f32::consts::PI / 180f32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_radians()`
 
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed
index 6b754f3bd71..b56d6aec508 100644
--- a/tests/ui/format.fixed
+++ b/tests/ui/format.fixed
@@ -33,7 +33,7 @@ fn main() {
     format!("foo {}", "bar");
     format!("{} bar", "foo");
 
-    let arg: String = "".to_owned();
+    let arg = String::new();
     arg.to_string();
     format!("{:?}", arg); // Don't warn about debug.
     format!("{:8}", arg);
diff --git a/tests/ui/format.rs b/tests/ui/format.rs
index ca9826b356e..4c1a3a840ed 100644
--- a/tests/ui/format.rs
+++ b/tests/ui/format.rs
@@ -35,7 +35,7 @@ fn main() {
     format!("foo {}", "bar");
     format!("{} bar", "foo");
 
-    let arg: String = "".to_owned();
+    let arg = String::new();
     format!("{}", arg);
     format!("{:?}", arg); // Don't warn about debug.
     format!("{:8}", arg);
diff --git a/tests/ui/format_args.fixed b/tests/ui/format_args.fixed
index 69b5e1c722e..e1c2d4d70be 100644
--- a/tests/ui/format_args.fixed
+++ b/tests/ui/format_args.fixed
@@ -1,8 +1,6 @@
 // run-rustfix
 
-#![allow(unreachable_code)]
-#![allow(unused_macros)]
-#![allow(unused_variables)]
+#![allow(unused)]
 #![allow(clippy::assertions_on_constants)]
 #![allow(clippy::eq_op)]
 #![allow(clippy::print_literal)]
@@ -115,3 +113,50 @@ fn main() {
     // https://github.com/rust-lang/rust-clippy/issues/7903
     println!("{foo}{foo:?}", foo = "foo".to_string());
 }
+
+fn issue8643(vendor_id: usize, product_id: usize, name: &str) {
+    println!(
+        "{:<9}  {:<10}  {}",
+        format!("0x{:x}", vendor_id),
+        format!("0x{:x}", product_id),
+        name
+    );
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/8855
+mod issue_8855 {
+    #![allow(dead_code)]
+
+    struct A {}
+
+    impl std::fmt::Display for A {
+        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+            write!(f, "test")
+        }
+    }
+
+    fn main() {
+        let a = A {};
+        let b = A {};
+
+        let x = format!("{} {}", a, b);
+        dbg!(x);
+
+        let x = format!("{:>6} {:>6}", a, b.to_string());
+        dbg!(x);
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/9256
+mod issue_9256 {
+    #![allow(dead_code)]
+
+    fn print_substring(original: &str) {
+        assert!(original.len() > 10);
+        println!("{}", &original[..10]);
+    }
+
+    fn main() {
+        print_substring("Hello, world!");
+    }
+}
diff --git a/tests/ui/format_args.rs b/tests/ui/format_args.rs
index 3a434c5bf00..b9a4d66c28a 100644
--- a/tests/ui/format_args.rs
+++ b/tests/ui/format_args.rs
@@ -1,8 +1,6 @@
 // run-rustfix
 
-#![allow(unreachable_code)]
-#![allow(unused_macros)]
-#![allow(unused_variables)]
+#![allow(unused)]
 #![allow(clippy::assertions_on_constants)]
 #![allow(clippy::eq_op)]
 #![allow(clippy::print_literal)]
@@ -115,3 +113,50 @@ fn main() {
     // https://github.com/rust-lang/rust-clippy/issues/7903
     println!("{foo}{foo:?}", foo = "foo".to_string());
 }
+
+fn issue8643(vendor_id: usize, product_id: usize, name: &str) {
+    println!(
+        "{:<9}  {:<10}  {}",
+        format!("0x{:x}", vendor_id),
+        format!("0x{:x}", product_id),
+        name
+    );
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/8855
+mod issue_8855 {
+    #![allow(dead_code)]
+
+    struct A {}
+
+    impl std::fmt::Display for A {
+        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+            write!(f, "test")
+        }
+    }
+
+    fn main() {
+        let a = A {};
+        let b = A {};
+
+        let x = format!("{} {}", a, b.to_string());
+        dbg!(x);
+
+        let x = format!("{:>6} {:>6}", a, b.to_string());
+        dbg!(x);
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/9256
+mod issue_9256 {
+    #![allow(dead_code)]
+
+    fn print_substring(original: &str) {
+        assert!(original.len() > 10);
+        println!("{}", original[..10].to_string());
+    }
+
+    fn main() {
+        print_substring("Hello, world!");
+    }
+}
diff --git a/tests/ui/format_args.stderr b/tests/ui/format_args.stderr
index c0cbca50795..aa6e3659b43 100644
--- a/tests/ui/format_args.stderr
+++ b/tests/ui/format_args.stderr
@@ -1,5 +1,5 @@
 error: `to_string` applied to a type that implements `Display` in `format!` args
-  --> $DIR/format_args.rs:76:72
+  --> $DIR/format_args.rs:74:72
    |
 LL |     let _ = format!("error: something failed at {}", Location::caller().to_string());
    |                                                                        ^^^^^^^^^^^^ help: remove this
@@ -7,124 +7,136 @@ LL |     let _ = format!("error: something failed at {}", Location::caller().to_
    = note: `-D clippy::to-string-in-format-args` implied by `-D warnings`
 
 error: `to_string` applied to a type that implements `Display` in `write!` args
-  --> $DIR/format_args.rs:80:27
+  --> $DIR/format_args.rs:78:27
    |
 LL |         Location::caller().to_string()
    |                           ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `writeln!` args
-  --> $DIR/format_args.rs:85:27
+  --> $DIR/format_args.rs:83:27
    |
 LL |         Location::caller().to_string()
    |                           ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `print!` args
-  --> $DIR/format_args.rs:87:63
+  --> $DIR/format_args.rs:85:63
    |
 LL |     print!("error: something failed at {}", Location::caller().to_string());
    |                                                               ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:88:65
+  --> $DIR/format_args.rs:86:65
    |
 LL |     println!("error: something failed at {}", Location::caller().to_string());
    |                                                                 ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `eprint!` args
-  --> $DIR/format_args.rs:89:64
+  --> $DIR/format_args.rs:87:64
    |
 LL |     eprint!("error: something failed at {}", Location::caller().to_string());
    |                                                                ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `eprintln!` args
-  --> $DIR/format_args.rs:90:66
+  --> $DIR/format_args.rs:88:66
    |
 LL |     eprintln!("error: something failed at {}", Location::caller().to_string());
    |                                                                  ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `format_args!` args
-  --> $DIR/format_args.rs:91:77
+  --> $DIR/format_args.rs:89:77
    |
 LL |     let _ = format_args!("error: something failed at {}", Location::caller().to_string());
    |                                                                             ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `assert!` args
-  --> $DIR/format_args.rs:92:70
+  --> $DIR/format_args.rs:90:70
    |
 LL |     assert!(true, "error: something failed at {}", Location::caller().to_string());
    |                                                                      ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `assert_eq!` args
-  --> $DIR/format_args.rs:93:73
+  --> $DIR/format_args.rs:91:73
    |
 LL |     assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
    |                                                                         ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `assert_ne!` args
-  --> $DIR/format_args.rs:94:73
+  --> $DIR/format_args.rs:92:73
    |
 LL |     assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
    |                                                                         ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `panic!` args
-  --> $DIR/format_args.rs:95:63
+  --> $DIR/format_args.rs:93:63
    |
 LL |     panic!("error: something failed at {}", Location::caller().to_string());
    |                                                               ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:96:20
+  --> $DIR/format_args.rs:94:20
    |
 LL |     println!("{}", X(1).to_string());
    |                    ^^^^^^^^^^^^^^^^ help: use this: `*X(1)`
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:97:20
+  --> $DIR/format_args.rs:95:20
    |
 LL |     println!("{}", Y(&X(1)).to_string());
    |                    ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))`
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:98:24
+  --> $DIR/format_args.rs:96:24
    |
 LL |     println!("{}", Z(1).to_string());
    |                        ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:99:20
+  --> $DIR/format_args.rs:97:20
    |
 LL |     println!("{}", x.to_string());
    |                    ^^^^^^^^^^^^^ help: use this: `**x`
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:100:20
+  --> $DIR/format_args.rs:98:20
    |
 LL |     println!("{}", x_ref.to_string());
    |                    ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref`
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:102:39
+  --> $DIR/format_args.rs:100:39
    |
 LL |     println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar");
    |                                       ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:103:52
+  --> $DIR/format_args.rs:101:52
    |
 LL |     println!("{foo}{bar}", foo = "foo", bar = "bar".to_string());
    |                                                    ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:104:39
+  --> $DIR/format_args.rs:102:39
    |
 LL |     println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo");
    |                                       ^^^^^^^^^^^^ help: remove this
 
 error: `to_string` applied to a type that implements `Display` in `println!` args
-  --> $DIR/format_args.rs:105:52
+  --> $DIR/format_args.rs:103:52
    |
 LL |     println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
    |                                                    ^^^^^^^^^^^^ help: remove this
 
-error: aborting due to 21 previous errors
+error: `to_string` applied to a type that implements `Display` in `format!` args
+  --> $DIR/format_args.rs:142:38
+   |
+LL |         let x = format!("{} {}", a, b.to_string());
+   |                                      ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+  --> $DIR/format_args.rs:156:24
+   |
+LL |         println!("{}", original[..10].to_string());
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use this: `&original[..10]`
+
+error: aborting due to 23 previous errors
 
diff --git a/tests/ui/identity_op.fixed b/tests/ui/identity_op.fixed
index 5f9cebe212a..fa564e23cd2 100644
--- a/tests/ui/identity_op.fixed
+++ b/tests/ui/identity_op.fixed
@@ -68,7 +68,7 @@ fn main() {
     &x;
     x;
 
-    let mut a = A("".into());
+    let mut a = A(String::new());
     let b = a << 0; // no error: non-integer
 
     1 * Meter; // no error: non-integer
diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs
index ca799c9cfac..3d06d2a73b6 100644
--- a/tests/ui/identity_op.rs
+++ b/tests/ui/identity_op.rs
@@ -68,7 +68,7 @@ fn main() {
     &x >> 0;
     x >> &0;
 
-    let mut a = A("".into());
+    let mut a = A(String::new());
     let b = a << 0; // no error: non-integer
 
     1 * Meter; // no error: non-integer
diff --git a/tests/ui/if_let_mutex.rs b/tests/ui/if_let_mutex.rs
index 6cbfafbb38b..321feb0224e 100644
--- a/tests/ui/if_let_mutex.rs
+++ b/tests/ui/if_let_mutex.rs
@@ -39,4 +39,12 @@ fn if_let_different_mutex() {
     };
 }
 
+fn mutex_ref(mutex: &Mutex<i32>) {
+    if let Ok(i) = mutex.lock() {
+        do_stuff(i);
+    } else {
+        let _x = mutex.lock();
+    };
+}
+
 fn main() {}
diff --git a/tests/ui/if_let_mutex.stderr b/tests/ui/if_let_mutex.stderr
index e9c4d916332..8a4d5dbac59 100644
--- a/tests/ui/if_let_mutex.stderr
+++ b/tests/ui/if_let_mutex.stderr
@@ -1,10 +1,14 @@
 error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
   --> $DIR/if_let_mutex.rs:10:5
    |
-LL | /     if let Err(locked) = m.lock() {
+LL |       if let Err(locked) = m.lock() {
+   |       ^                    - this Mutex will remain locked for the entire `if let`-block...
+   |  _____|
+   | |
 LL | |         do_stuff(locked);
 LL | |     } else {
 LL | |         let lock = m.lock().unwrap();
+   | |                    - ... and is tried to lock again here, which will always deadlock.
 LL | |         do_stuff(lock);
 LL | |     };
    | |_____^
@@ -15,15 +19,35 @@ LL | |     };
 error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
   --> $DIR/if_let_mutex.rs:22:5
    |
-LL | /     if let Some(locked) = m.lock().unwrap().deref() {
+LL |       if let Some(locked) = m.lock().unwrap().deref() {
+   |       ^                     - this Mutex will remain locked for the entire `if let`-block...
+   |  _____|
+   | |
 LL | |         do_stuff(locked);
 LL | |     } else {
 LL | |         let lock = m.lock().unwrap();
+   | |                    - ... and is tried to lock again here, which will always deadlock.
 LL | |         do_stuff(lock);
 LL | |     };
    | |_____^
    |
    = help: move the lock call outside of the `if let ...` expression
 
-error: aborting due to 2 previous errors
+error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
+  --> $DIR/if_let_mutex.rs:43:5
+   |
+LL |       if let Ok(i) = mutex.lock() {
+   |       ^              ----- this Mutex will remain locked for the entire `if let`-block...
+   |  _____|
+   | |
+LL | |         do_stuff(i);
+LL | |     } else {
+LL | |         let _x = mutex.lock();
+   | |                  ----- ... and is tried to lock again here, which will always deadlock.
+LL | |     };
+   | |_____^
+   |
+   = help: move the lock call outside of the `if let ...` expression
+
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/if_then_some_else_none.stderr b/tests/ui/if_then_some_else_none.stderr
index 8cb22d569f4..c22ace30d2d 100644
--- a/tests/ui/if_then_some_else_none.stderr
+++ b/tests/ui/if_then_some_else_none.stderr
@@ -27,21 +27,21 @@ LL | |     };
    |
    = help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })`
 
-error: this could be simplified with `bool::then`
+error: this could be simplified with `bool::then_some`
   --> $DIR/if_then_some_else_none.rs:23:28
    |
 LL |     let _ = x.and_then(|o| if o < 32 { Some(o) } else { None });
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider using `bool::then` like: `(o < 32).then(|| o)`
+   = help: consider using `bool::then_some` like: `(o < 32).then_some(o)`
 
-error: this could be simplified with `bool::then`
+error: this could be simplified with `bool::then_some`
   --> $DIR/if_then_some_else_none.rs:27:13
    |
 LL |     let _ = if !x { Some(0) } else { None };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider using `bool::then` like: `(!x).then(|| 0)`
+   = help: consider using `bool::then_some` like: `(!x).then_some(0)`
 
 error: this could be simplified with `bool::then`
   --> $DIR/if_then_some_else_none.rs:82:13
diff --git a/tests/ui/iter_on_empty_collections.fixed b/tests/ui/iter_on_empty_collections.fixed
new file mode 100644
index 00000000000..bd9b07aefbf
--- /dev/null
+++ b/tests/ui/iter_on_empty_collections.fixed
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::iter_on_empty_collections)]
+#![allow(clippy::iter_next_slice, clippy::redundant_clone)]
+
+fn array() {
+    assert_eq!(std::iter::empty().next(), Option::<i32>::None);
+    assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None);
+    assert_eq!(std::iter::empty().next(), Option::<&i32>::None);
+    assert_eq!(std::iter::empty().next(), Option::<i32>::None);
+    assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None);
+    assert_eq!(std::iter::empty().next(), Option::<&i32>::None);
+
+    // Don't trigger on non-iter methods
+    let _: Option<String> = None.clone();
+    let _: [String; 0] = [].clone();
+
+    // Don't trigger on match or if branches
+    let _ = match 123 {
+        123 => [].iter(),
+        _ => ["test"].iter(),
+    };
+
+    let _ = if false { ["test"].iter() } else { [].iter() };
+}
+
+macro_rules! in_macros {
+    () => {
+        assert_eq!([].into_iter().next(), Option::<i32>::None);
+        assert_eq!([].iter_mut().next(), Option::<&mut i32>::None);
+        assert_eq!([].iter().next(), Option::<&i32>::None);
+        assert_eq!(None.into_iter().next(), Option::<i32>::None);
+        assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None);
+        assert_eq!(None.iter().next(), Option::<&i32>::None);
+    };
+}
+
+// Don't trigger on a `None` that isn't std's option
+mod custom_option {
+    #[allow(unused)]
+    enum CustomOption {
+        Some(i32),
+        None,
+    }
+
+    impl CustomOption {
+        fn iter(&self) {}
+        fn iter_mut(&mut self) {}
+        fn into_iter(self) {}
+    }
+    use CustomOption::*;
+
+    pub fn custom_option() {
+        None.iter();
+        None.iter_mut();
+        None.into_iter();
+    }
+}
+
+fn main() {
+    array();
+    custom_option::custom_option();
+    in_macros!();
+}
diff --git a/tests/ui/iter_on_empty_collections.rs b/tests/ui/iter_on_empty_collections.rs
new file mode 100644
index 00000000000..e15ba94bd46
--- /dev/null
+++ b/tests/ui/iter_on_empty_collections.rs
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::iter_on_empty_collections)]
+#![allow(clippy::iter_next_slice, clippy::redundant_clone)]
+
+fn array() {
+    assert_eq!([].into_iter().next(), Option::<i32>::None);
+    assert_eq!([].iter_mut().next(), Option::<&mut i32>::None);
+    assert_eq!([].iter().next(), Option::<&i32>::None);
+    assert_eq!(None.into_iter().next(), Option::<i32>::None);
+    assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None);
+    assert_eq!(None.iter().next(), Option::<&i32>::None);
+
+    // Don't trigger on non-iter methods
+    let _: Option<String> = None.clone();
+    let _: [String; 0] = [].clone();
+
+    // Don't trigger on match or if branches
+    let _ = match 123 {
+        123 => [].iter(),
+        _ => ["test"].iter(),
+    };
+
+    let _ = if false { ["test"].iter() } else { [].iter() };
+}
+
+macro_rules! in_macros {
+    () => {
+        assert_eq!([].into_iter().next(), Option::<i32>::None);
+        assert_eq!([].iter_mut().next(), Option::<&mut i32>::None);
+        assert_eq!([].iter().next(), Option::<&i32>::None);
+        assert_eq!(None.into_iter().next(), Option::<i32>::None);
+        assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None);
+        assert_eq!(None.iter().next(), Option::<&i32>::None);
+    };
+}
+
+// Don't trigger on a `None` that isn't std's option
+mod custom_option {
+    #[allow(unused)]
+    enum CustomOption {
+        Some(i32),
+        None,
+    }
+
+    impl CustomOption {
+        fn iter(&self) {}
+        fn iter_mut(&mut self) {}
+        fn into_iter(self) {}
+    }
+    use CustomOption::*;
+
+    pub fn custom_option() {
+        None.iter();
+        None.iter_mut();
+        None.into_iter();
+    }
+}
+
+fn main() {
+    array();
+    custom_option::custom_option();
+    in_macros!();
+}
diff --git a/tests/ui/iter_on_empty_collections.stderr b/tests/ui/iter_on_empty_collections.stderr
new file mode 100644
index 00000000000..cbd61176956
--- /dev/null
+++ b/tests/ui/iter_on_empty_collections.stderr
@@ -0,0 +1,40 @@
+error: `into_iter` call on an empty collection
+  --> $DIR/iter_on_empty_collections.rs:6:16
+   |
+LL |     assert_eq!([].into_iter().next(), Option::<i32>::None);
+   |                ^^^^^^^^^^^^^^ help: try: `std::iter::empty()`
+   |
+   = note: `-D clippy::iter-on-empty-collections` implied by `-D warnings`
+
+error: `iter_mut` call on an empty collection
+  --> $DIR/iter_on_empty_collections.rs:7:16
+   |
+LL |     assert_eq!([].iter_mut().next(), Option::<&mut i32>::None);
+   |                ^^^^^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: `iter` call on an empty collection
+  --> $DIR/iter_on_empty_collections.rs:8:16
+   |
+LL |     assert_eq!([].iter().next(), Option::<&i32>::None);
+   |                ^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: `into_iter` call on an empty collection
+  --> $DIR/iter_on_empty_collections.rs:9:16
+   |
+LL |     assert_eq!(None.into_iter().next(), Option::<i32>::None);
+   |                ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: `iter_mut` call on an empty collection
+  --> $DIR/iter_on_empty_collections.rs:10:16
+   |
+LL |     assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None);
+   |                ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: `iter` call on an empty collection
+  --> $DIR/iter_on_empty_collections.rs:11:16
+   |
+LL |     assert_eq!(None.iter().next(), Option::<&i32>::None);
+   |                ^^^^^^^^^^^ help: try: `std::iter::empty()`
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/iter_on_single_items.fixed b/tests/ui/iter_on_single_items.fixed
new file mode 100644
index 00000000000..1fa4b03641b
--- /dev/null
+++ b/tests/ui/iter_on_single_items.fixed
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::iter_on_single_items)]
+#![allow(clippy::iter_next_slice, clippy::redundant_clone)]
+
+fn array() {
+    assert_eq!(std::iter::once(123).next(), Some(123));
+    assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123));
+    assert_eq!(std::iter::once(&123).next(), Some(&123));
+    assert_eq!(std::iter::once(123).next(), Some(123));
+    assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123));
+    assert_eq!(std::iter::once(&123).next(), Some(&123));
+
+    // Don't trigger on non-iter methods
+    let _: Option<String> = Some("test".to_string()).clone();
+    let _: [String; 1] = ["test".to_string()].clone();
+
+    // Don't trigger on match or if branches
+    let _ = match 123 {
+        123 => [].iter(),
+        _ => ["test"].iter(),
+    };
+
+    let _ = if false { ["test"].iter() } else { [].iter() };
+}
+
+macro_rules! in_macros {
+    () => {
+        assert_eq!([123].into_iter().next(), Some(123));
+        assert_eq!([123].iter_mut().next(), Some(&mut 123));
+        assert_eq!([123].iter().next(), Some(&123));
+        assert_eq!(Some(123).into_iter().next(), Some(123));
+        assert_eq!(Some(123).iter_mut().next(), Some(&mut 123));
+        assert_eq!(Some(123).iter().next(), Some(&123));
+    };
+}
+
+// Don't trigger on a `Some` that isn't std's option
+mod custom_option {
+    #[allow(unused)]
+    enum CustomOption {
+        Some(i32),
+        None,
+    }
+
+    impl CustomOption {
+        fn iter(&self) {}
+        fn iter_mut(&mut self) {}
+        fn into_iter(self) {}
+    }
+    use CustomOption::*;
+
+    pub fn custom_option() {
+        Some(3).iter();
+        Some(3).iter_mut();
+        Some(3).into_iter();
+    }
+}
+
+fn main() {
+    array();
+    custom_option::custom_option();
+    in_macros!();
+}
diff --git a/tests/ui/iter_on_single_items.rs b/tests/ui/iter_on_single_items.rs
new file mode 100644
index 00000000000..ea96d8066c5
--- /dev/null
+++ b/tests/ui/iter_on_single_items.rs
@@ -0,0 +1,63 @@
+// run-rustfix
+#![warn(clippy::iter_on_single_items)]
+#![allow(clippy::iter_next_slice, clippy::redundant_clone)]
+
+fn array() {
+    assert_eq!([123].into_iter().next(), Some(123));
+    assert_eq!([123].iter_mut().next(), Some(&mut 123));
+    assert_eq!([123].iter().next(), Some(&123));
+    assert_eq!(Some(123).into_iter().next(), Some(123));
+    assert_eq!(Some(123).iter_mut().next(), Some(&mut 123));
+    assert_eq!(Some(123).iter().next(), Some(&123));
+
+    // Don't trigger on non-iter methods
+    let _: Option<String> = Some("test".to_string()).clone();
+    let _: [String; 1] = ["test".to_string()].clone();
+
+    // Don't trigger on match or if branches
+    let _ = match 123 {
+        123 => [].iter(),
+        _ => ["test"].iter(),
+    };
+
+    let _ = if false { ["test"].iter() } else { [].iter() };
+}
+
+macro_rules! in_macros {
+    () => {
+        assert_eq!([123].into_iter().next(), Some(123));
+        assert_eq!([123].iter_mut().next(), Some(&mut 123));
+        assert_eq!([123].iter().next(), Some(&123));
+        assert_eq!(Some(123).into_iter().next(), Some(123));
+        assert_eq!(Some(123).iter_mut().next(), Some(&mut 123));
+        assert_eq!(Some(123).iter().next(), Some(&123));
+    };
+}
+
+// Don't trigger on a `Some` that isn't std's option
+mod custom_option {
+    #[allow(unused)]
+    enum CustomOption {
+        Some(i32),
+        None,
+    }
+
+    impl CustomOption {
+        fn iter(&self) {}
+        fn iter_mut(&mut self) {}
+        fn into_iter(self) {}
+    }
+    use CustomOption::*;
+
+    pub fn custom_option() {
+        Some(3).iter();
+        Some(3).iter_mut();
+        Some(3).into_iter();
+    }
+}
+
+fn main() {
+    array();
+    custom_option::custom_option();
+    in_macros!();
+}
diff --git a/tests/ui/iter_on_single_items.stderr b/tests/ui/iter_on_single_items.stderr
new file mode 100644
index 00000000000..d6c54711636
--- /dev/null
+++ b/tests/ui/iter_on_single_items.stderr
@@ -0,0 +1,40 @@
+error: `into_iter` call on a collection with only one item
+  --> $DIR/iter_on_single_items.rs:6:16
+   |
+LL |     assert_eq!([123].into_iter().next(), Some(123));
+   |                ^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)`
+   |
+   = note: `-D clippy::iter-on-single-items` implied by `-D warnings`
+
+error: `iter_mut` call on a collection with only one item
+  --> $DIR/iter_on_single_items.rs:7:16
+   |
+LL |     assert_eq!([123].iter_mut().next(), Some(&mut 123));
+   |                ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)`
+
+error: `iter` call on a collection with only one item
+  --> $DIR/iter_on_single_items.rs:8:16
+   |
+LL |     assert_eq!([123].iter().next(), Some(&123));
+   |                ^^^^^^^^^^^^ help: try: `std::iter::once(&123)`
+
+error: `into_iter` call on a collection with only one item
+  --> $DIR/iter_on_single_items.rs:9:16
+   |
+LL |     assert_eq!(Some(123).into_iter().next(), Some(123));
+   |                ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)`
+
+error: `iter_mut` call on a collection with only one item
+  --> $DIR/iter_on_single_items.rs:10:16
+   |
+LL |     assert_eq!(Some(123).iter_mut().next(), Some(&mut 123));
+   |                ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)`
+
+error: `iter` call on a collection with only one item
+  --> $DIR/iter_on_single_items.rs:11:16
+   |
+LL |     assert_eq!(Some(123).iter().next(), Some(&123));
+   |                ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&123)`
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/manual_string_new.fixed b/tests/ui/manual_string_new.fixed
new file mode 100644
index 00000000000..a376411bfbc
--- /dev/null
+++ b/tests/ui/manual_string_new.fixed
@@ -0,0 +1,63 @@
+// run-rustfix
+
+#![warn(clippy::manual_string_new)]
+
+macro_rules! create_strings_from_macro {
+    // When inside a macro, nothing should warn to prevent false positives.
+    ($some_str:expr) => {
+        let _: String = $some_str.into();
+        let _ = $some_str.to_string();
+    };
+}
+
+fn main() {
+    // Method calls
+    let _ = String::new();
+    let _ = "no warning".to_string();
+
+    let _ = String::new();
+    let _ = "no warning".to_owned();
+
+    let _: String = String::new();
+    let _: String = "no warning".into();
+
+    let _: SomeOtherStruct = "no warning".into();
+    let _: SomeOtherStruct = "".into(); // No warning too. We are not converting into String.
+
+    // Calls
+    let _ = String::new();
+    let _ = String::new();
+    let _ = String::from("no warning");
+    let _ = SomeOtherStruct::from("no warning");
+    let _ = SomeOtherStruct::from(""); // Again: no warning.
+
+    let _ = String::new();
+    let _ = String::try_from("no warning").unwrap();
+    let _ = String::try_from("no warning").expect("this should not warn");
+    let _ = SomeOtherStruct::try_from("no warning").unwrap();
+    let _ = SomeOtherStruct::try_from("").unwrap(); // Again: no warning.
+
+    let _: String = String::new();
+    let _: String = From::from("no warning");
+    let _: SomeOtherStruct = From::from("no warning");
+    let _: SomeOtherStruct = From::from(""); // Again: no warning.
+
+    let _: String = String::new();
+    let _: String = TryFrom::try_from("no warning").unwrap();
+    let _: String = TryFrom::try_from("no warning").expect("this should not warn");
+    let _: String = String::new();
+    let _: SomeOtherStruct = TryFrom::try_from("no_warning").unwrap();
+    let _: SomeOtherStruct = TryFrom::try_from("").unwrap(); // Again: no warning.
+
+    // Macros (never warn)
+    create_strings_from_macro!("");
+    create_strings_from_macro!("Hey");
+}
+
+struct SomeOtherStruct {}
+
+impl From<&str> for SomeOtherStruct {
+    fn from(_value: &str) -> Self {
+        Self {}
+    }
+}
diff --git a/tests/ui/manual_string_new.rs b/tests/ui/manual_string_new.rs
new file mode 100644
index 00000000000..6bfc52fb1bc
--- /dev/null
+++ b/tests/ui/manual_string_new.rs
@@ -0,0 +1,63 @@
+// run-rustfix
+
+#![warn(clippy::manual_string_new)]
+
+macro_rules! create_strings_from_macro {
+    // When inside a macro, nothing should warn to prevent false positives.
+    ($some_str:expr) => {
+        let _: String = $some_str.into();
+        let _ = $some_str.to_string();
+    };
+}
+
+fn main() {
+    // Method calls
+    let _ = "".to_string();
+    let _ = "no warning".to_string();
+
+    let _ = "".to_owned();
+    let _ = "no warning".to_owned();
+
+    let _: String = "".into();
+    let _: String = "no warning".into();
+
+    let _: SomeOtherStruct = "no warning".into();
+    let _: SomeOtherStruct = "".into(); // No warning too. We are not converting into String.
+
+    // Calls
+    let _ = String::from("");
+    let _ = <String>::from("");
+    let _ = String::from("no warning");
+    let _ = SomeOtherStruct::from("no warning");
+    let _ = SomeOtherStruct::from(""); // Again: no warning.
+
+    let _ = String::try_from("").unwrap();
+    let _ = String::try_from("no warning").unwrap();
+    let _ = String::try_from("no warning").expect("this should not warn");
+    let _ = SomeOtherStruct::try_from("no warning").unwrap();
+    let _ = SomeOtherStruct::try_from("").unwrap(); // Again: no warning.
+
+    let _: String = From::from("");
+    let _: String = From::from("no warning");
+    let _: SomeOtherStruct = From::from("no warning");
+    let _: SomeOtherStruct = From::from(""); // Again: no warning.
+
+    let _: String = TryFrom::try_from("").unwrap();
+    let _: String = TryFrom::try_from("no warning").unwrap();
+    let _: String = TryFrom::try_from("no warning").expect("this should not warn");
+    let _: String = TryFrom::try_from("").expect("this should warn");
+    let _: SomeOtherStruct = TryFrom::try_from("no_warning").unwrap();
+    let _: SomeOtherStruct = TryFrom::try_from("").unwrap(); // Again: no warning.
+
+    // Macros (never warn)
+    create_strings_from_macro!("");
+    create_strings_from_macro!("Hey");
+}
+
+struct SomeOtherStruct {}
+
+impl From<&str> for SomeOtherStruct {
+    fn from(_value: &str) -> Self {
+        Self {}
+    }
+}
diff --git a/tests/ui/manual_string_new.stderr b/tests/ui/manual_string_new.stderr
new file mode 100644
index 00000000000..e5ecfc61947
--- /dev/null
+++ b/tests/ui/manual_string_new.stderr
@@ -0,0 +1,58 @@
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:15:13
+   |
+LL |     let _ = "".to_string();
+   |             ^^^^^^^^^^^^^^ help: consider using: `String::new()`
+   |
+   = note: `-D clippy::manual-string-new` implied by `-D warnings`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:18:13
+   |
+LL |     let _ = "".to_owned();
+   |             ^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:21:21
+   |
+LL |     let _: String = "".into();
+   |                     ^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:28:13
+   |
+LL |     let _ = String::from("");
+   |             ^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:29:13
+   |
+LL |     let _ = <String>::from("");
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:34:13
+   |
+LL |     let _ = String::try_from("").unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:40:21
+   |
+LL |     let _: String = From::from("");
+   |                     ^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:45:21
+   |
+LL |     let _: String = TryFrom::try_from("").unwrap();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: empty String is being created manually
+  --> $DIR/manual_string_new.rs:48:21
+   |
+LL |     let _: String = TryFrom::try_from("").expect("this should warn");
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui/match_expr_like_matches_macro.fixed b/tests/ui/match_expr_like_matches_macro.fixed
index 1ccbfda64b7..95ca571d07b 100644
--- a/tests/ui/match_expr_like_matches_macro.fixed
+++ b/tests/ui/match_expr_like_matches_macro.fixed
@@ -167,4 +167,29 @@ fn main() {
             _ => false,
         };
     }
+
+    let x = ' ';
+    // ignore if match block contains comment
+    let _line_comments = match x {
+        // numbers are bad!
+        '1' | '2' | '3' => true,
+        // spaces are very important to be true.
+        ' ' => true,
+        // as are dots
+        '.' => true,
+        _ => false,
+    };
+
+    let _block_comments = match x {
+        /* numbers are bad!
+         */
+        '1' | '2' | '3' => true,
+        /* spaces are very important to be true.
+         */
+        ' ' => true,
+        /* as are dots
+         */
+        '.' => true,
+        _ => false,
+    };
 }
diff --git a/tests/ui/match_expr_like_matches_macro.rs b/tests/ui/match_expr_like_matches_macro.rs
index a49991f5941..3b9c8cadadc 100644
--- a/tests/ui/match_expr_like_matches_macro.rs
+++ b/tests/ui/match_expr_like_matches_macro.rs
@@ -208,4 +208,29 @@ fn main() {
             _ => false,
         };
     }
+
+    let x = ' ';
+    // ignore if match block contains comment
+    let _line_comments = match x {
+        // numbers are bad!
+        '1' | '2' | '3' => true,
+        // spaces are very important to be true.
+        ' ' => true,
+        // as are dots
+        '.' => true,
+        _ => false,
+    };
+
+    let _block_comments = match x {
+        /* numbers are bad!
+         */
+        '1' | '2' | '3' => true,
+        /* spaces are very important to be true.
+         */
+        ' ' => true,
+        /* as are dots
+         */
+        '.' => true,
+        _ => false,
+    };
 }
diff --git a/tests/ui/multi_assignments.rs b/tests/ui/multi_assignments.rs
new file mode 100644
index 00000000000..b186bf8bbdb
--- /dev/null
+++ b/tests/ui/multi_assignments.rs
@@ -0,0 +1,9 @@
+#![warn(clippy::multi_assignments)]
+fn main() {
+    let (mut a, mut b, mut c, mut d) = ((), (), (), ());
+    a = b = c;
+    a = b = c = d;
+    a = b = { c };
+    a = { b = c };
+    a = (b = c);
+}
diff --git a/tests/ui/multi_assignments.stderr b/tests/ui/multi_assignments.stderr
new file mode 100644
index 00000000000..d6c42bb698c
--- /dev/null
+++ b/tests/ui/multi_assignments.stderr
@@ -0,0 +1,40 @@
+error: assignments don't nest intuitively
+  --> $DIR/multi_assignments.rs:4:5
+   |
+LL |     a = b = c;
+   |     ^^^^^^^^^
+   |
+   = note: `-D clippy::multi-assignments` implied by `-D warnings`
+
+error: assignments don't nest intuitively
+  --> $DIR/multi_assignments.rs:5:5
+   |
+LL |     a = b = c = d;
+   |     ^^^^^^^^^^^^^
+
+error: assignments don't nest intuitively
+  --> $DIR/multi_assignments.rs:5:9
+   |
+LL |     a = b = c = d;
+   |         ^^^^^^^^^
+
+error: assignments don't nest intuitively
+  --> $DIR/multi_assignments.rs:6:5
+   |
+LL |     a = b = { c };
+   |     ^^^^^^^^^^^^^
+
+error: assignments don't nest intuitively
+  --> $DIR/multi_assignments.rs:7:5
+   |
+LL |     a = { b = c };
+   |     ^^^^^^^^^^^^^
+
+error: assignments don't nest intuitively
+  --> $DIR/multi_assignments.rs:8:5
+   |
+LL |     a = (b = c);
+   |     ^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed
index bfd2725ecaa..8cf93bd2481 100644
--- a/tests/ui/needless_borrow.fixed
+++ b/tests/ui/needless_borrow.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![feature(lint_reasons)]
+#![feature(custom_inner_attributes, lint_reasons)]
 
 #[warn(clippy::all, clippy::needless_borrow)]
 #[allow(unused_variables, clippy::unnecessary_mut_passed)]
@@ -127,6 +127,20 @@ fn main() {
             0
         }
     }
+
+    let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap();
+    let _ = std::path::Path::new(".").join(".");
+    deref_target_is_x(X);
+    multiple_constraints([[""]]);
+    multiple_constraints_normalizes_to_same(X, X);
+    let _ = Some("").unwrap_or("");
+
+    only_sized(&""); // Don't lint. `Sized` is only bound
+    let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound
+    let _ = Box::new(&""); // Don't lint. Type parameter appears in return type
+    ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter
+    refs_only(&()); // Don't lint. `&T` implements trait, but `T` doesn't
+    multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments
 }
 
 #[allow(clippy::needless_borrowed_reference)]
@@ -183,3 +197,104 @@ mod issue9160 {
         }
     }
 }
+
+#[derive(Clone, Copy)]
+struct X;
+
+impl std::ops::Deref for X {
+    type Target = X;
+    fn deref(&self) -> &Self::Target {
+        self
+    }
+}
+
+fn deref_target_is_x<T>(_: T)
+where
+    T: std::ops::Deref<Target = X>,
+{
+}
+
+fn multiple_constraints<T, U, V, X, Y>(_: T)
+where
+    T: IntoIterator<Item = U> + IntoIterator<Item = X>,
+    U: IntoIterator<Item = V>,
+    V: AsRef<str>,
+    X: IntoIterator<Item = Y>,
+    Y: AsRef<std::ffi::OsStr>,
+{
+}
+
+fn multiple_constraints_normalizes_to_same<T, U, V>(_: T, _: V)
+where
+    T: std::ops::Deref<Target = U>,
+    U: std::ops::Deref<Target = V>,
+{
+}
+
+fn only_sized<T>(_: T) {}
+
+fn ref_as_ref_path<T: 'static>(_: &'static T)
+where
+    &'static T: AsRef<std::path::Path>,
+{
+}
+
+trait RefsOnly {
+    type Referent;
+}
+
+impl<T> RefsOnly for &T {
+    type Referent = T;
+}
+
+fn refs_only<T, U>(_: T)
+where
+    T: RefsOnly<Referent = U>,
+{
+}
+
+fn multiple_constraints_normalizes_to_different<T, U, V>(_: T, _: U)
+where
+    T: IntoIterator<Item = U>,
+    U: IntoIterator<Item = V>,
+    V: AsRef<str>,
+{
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
+#[allow(dead_code)]
+mod copyable_iterator {
+    #[derive(Clone, Copy)]
+    struct Iter;
+    impl Iterator for Iter {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            None
+        }
+    }
+    fn takes_iter(_: impl Iterator) {}
+    fn dont_warn(mut x: Iter) {
+        takes_iter(&mut x);
+    }
+    fn warn(mut x: &mut Iter) {
+        takes_iter(&mut x)
+    }
+}
+
+mod under_msrv {
+    #![allow(dead_code)]
+    #![clippy::msrv = "1.52.0"]
+
+    fn foo() {
+        let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+    }
+}
+
+mod meets_msrv {
+    #![allow(dead_code)]
+    #![clippy::msrv = "1.53.0"]
+
+    fn foo() {
+        let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap();
+    }
+}
diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs
index c457d8c5471..fd9b2a11df9 100644
--- a/tests/ui/needless_borrow.rs
+++ b/tests/ui/needless_borrow.rs
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![feature(lint_reasons)]
+#![feature(custom_inner_attributes, lint_reasons)]
 
 #[warn(clippy::all, clippy::needless_borrow)]
 #[allow(unused_variables, clippy::unnecessary_mut_passed)]
@@ -127,6 +127,20 @@ fn main() {
             0
         }
     }
+
+    let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+    let _ = std::path::Path::new(".").join(&&".");
+    deref_target_is_x(&X);
+    multiple_constraints(&[[""]]);
+    multiple_constraints_normalizes_to_same(&X, X);
+    let _ = Some("").unwrap_or(&"");
+
+    only_sized(&""); // Don't lint. `Sized` is only bound
+    let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound
+    let _ = Box::new(&""); // Don't lint. Type parameter appears in return type
+    ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter
+    refs_only(&()); // Don't lint. `&T` implements trait, but `T` doesn't
+    multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments
 }
 
 #[allow(clippy::needless_borrowed_reference)]
@@ -183,3 +197,104 @@ mod issue9160 {
         }
     }
 }
+
+#[derive(Clone, Copy)]
+struct X;
+
+impl std::ops::Deref for X {
+    type Target = X;
+    fn deref(&self) -> &Self::Target {
+        self
+    }
+}
+
+fn deref_target_is_x<T>(_: T)
+where
+    T: std::ops::Deref<Target = X>,
+{
+}
+
+fn multiple_constraints<T, U, V, X, Y>(_: T)
+where
+    T: IntoIterator<Item = U> + IntoIterator<Item = X>,
+    U: IntoIterator<Item = V>,
+    V: AsRef<str>,
+    X: IntoIterator<Item = Y>,
+    Y: AsRef<std::ffi::OsStr>,
+{
+}
+
+fn multiple_constraints_normalizes_to_same<T, U, V>(_: T, _: V)
+where
+    T: std::ops::Deref<Target = U>,
+    U: std::ops::Deref<Target = V>,
+{
+}
+
+fn only_sized<T>(_: T) {}
+
+fn ref_as_ref_path<T: 'static>(_: &'static T)
+where
+    &'static T: AsRef<std::path::Path>,
+{
+}
+
+trait RefsOnly {
+    type Referent;
+}
+
+impl<T> RefsOnly for &T {
+    type Referent = T;
+}
+
+fn refs_only<T, U>(_: T)
+where
+    T: RefsOnly<Referent = U>,
+{
+}
+
+fn multiple_constraints_normalizes_to_different<T, U, V>(_: T, _: U)
+where
+    T: IntoIterator<Item = U>,
+    U: IntoIterator<Item = V>,
+    V: AsRef<str>,
+{
+}
+
+// https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
+#[allow(dead_code)]
+mod copyable_iterator {
+    #[derive(Clone, Copy)]
+    struct Iter;
+    impl Iterator for Iter {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            None
+        }
+    }
+    fn takes_iter(_: impl Iterator) {}
+    fn dont_warn(mut x: Iter) {
+        takes_iter(&mut x);
+    }
+    fn warn(mut x: &mut Iter) {
+        takes_iter(&mut x)
+    }
+}
+
+mod under_msrv {
+    #![allow(dead_code)]
+    #![clippy::msrv = "1.52.0"]
+
+    fn foo() {
+        let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+    }
+}
+
+mod meets_msrv {
+    #![allow(dead_code)]
+    #![clippy::msrv = "1.53.0"]
+
+    fn foo() {
+        let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+    }
+}
diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr
index 66588689d81..5af68706d4b 100644
--- a/tests/ui/needless_borrow.stderr
+++ b/tests/ui/needless_borrow.stderr
@@ -120,17 +120,59 @@ error: this expression creates a reference which is immediately dereferenced by
 LL |     (&&5).foo();
    |     ^^^^^ help: change this to: `(&5)`
 
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:131:51
+   |
+LL |     let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+   |                                                   ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]`
+
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:132:44
+   |
+LL |     let _ = std::path::Path::new(".").join(&&".");
+   |                                            ^^^^^ help: change this to: `"."`
+
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:133:23
+   |
+LL |     deref_target_is_x(&X);
+   |                       ^^ help: change this to: `X`
+
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:134:26
+   |
+LL |     multiple_constraints(&[[""]]);
+   |                          ^^^^^^^ help: change this to: `[[""]]`
+
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:135:45
+   |
+LL |     multiple_constraints_normalizes_to_same(&X, X);
+   |                                             ^^ help: change this to: `X`
+
+error: this expression creates a reference which is immediately dereferenced by the compiler
+  --> $DIR/needless_borrow.rs:136:32
+   |
+LL |     let _ = Some("").unwrap_or(&"");
+   |                                ^^^ help: change this to: `""`
+
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:173:13
+  --> $DIR/needless_borrow.rs:187:13
    |
 LL |             (&self.f)()
    |             ^^^^^^^^^ help: change this to: `(self.f)`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:182:13
+  --> $DIR/needless_borrow.rs:196:13
    |
 LL |             (&mut self.f)()
    |             ^^^^^^^^^^^^^ help: change this to: `(self.f)`
 
-error: aborting due to 22 previous errors
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:298:55
+   |
+LL |         let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap();
+   |                                                       ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]`
+
+error: aborting due to 29 previous errors
 
diff --git a/tests/ui/needless_collect_indirect.rs b/tests/ui/needless_collect_indirect.rs
index 1f11d1f8d56..12a9ace1ee6 100644
--- a/tests/ui/needless_collect_indirect.rs
+++ b/tests/ui/needless_collect_indirect.rs
@@ -112,3 +112,192 @@ fn allow_test() {
     let v = [1].iter().collect::<Vec<_>>();
     v.into_iter().collect::<HashSet<_>>();
 }
+
+mod issue_8553 {
+    fn test_for() {
+        let vec = vec![1, 2];
+        let w: Vec<usize> = vec.iter().map(|i| i * i).collect();
+
+        for i in 0..2 {
+            // Do not lint, because this method call is in the loop
+            w.contains(&i);
+        }
+
+        for i in 0..2 {
+            let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+            let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+            // Do lint
+            y.contains(&i);
+            for j in 0..2 {
+                // Do not lint, because this method call is in the loop
+                z.contains(&j);
+            }
+        }
+
+        // Do not lint, because this variable is used.
+        w.contains(&0);
+    }
+
+    fn test_while() {
+        let vec = vec![1, 2];
+        let x: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let mut n = 0;
+        while n > 1 {
+            // Do not lint, because this method call is in the loop
+            x.contains(&n);
+            n += 1;
+        }
+
+        while n > 2 {
+            let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+            let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+            // Do lint
+            y.contains(&n);
+            n += 1;
+            while n > 4 {
+                // Do not lint, because this method call is in the loop
+                z.contains(&n);
+                n += 1;
+            }
+        }
+    }
+
+    fn test_loop() {
+        let vec = vec![1, 2];
+        let x: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let mut n = 0;
+        loop {
+            if n < 1 {
+                // Do not lint, because this method call is in the loop
+                x.contains(&n);
+                n += 1;
+            } else {
+                break;
+            }
+        }
+
+        loop {
+            if n < 2 {
+                let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+                let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+                // Do lint
+                y.contains(&n);
+                n += 1;
+                loop {
+                    if n < 4 {
+                        // Do not lint, because this method call is in the loop
+                        z.contains(&n);
+                        n += 1;
+                    } else {
+                        break;
+                    }
+                }
+            } else {
+                break;
+            }
+        }
+    }
+
+    fn test_while_let() {
+        let vec = vec![1, 2];
+        let x: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let optional = Some(0);
+        let mut n = 0;
+        while let Some(value) = optional {
+            if n < 1 {
+                // Do not lint, because this method call is in the loop
+                x.contains(&n);
+                n += 1;
+            } else {
+                break;
+            }
+        }
+
+        while let Some(value) = optional {
+            let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+            let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+            if n < 2 {
+                // Do lint
+                y.contains(&n);
+                n += 1;
+            } else {
+                break;
+            }
+
+            while let Some(value) = optional {
+                if n < 4 {
+                    // Do not lint, because this method call is in the loop
+                    z.contains(&n);
+                    n += 1;
+                } else {
+                    break;
+                }
+            }
+        }
+    }
+
+    fn test_if_cond() {
+        let vec = vec![1, 2];
+        let v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let w = v.iter().collect::<Vec<_>>();
+        // Do lint
+        for _ in 0..w.len() {
+            todo!();
+        }
+    }
+
+    fn test_if_cond_false_case() {
+        let vec = vec![1, 2];
+        let v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let w = v.iter().collect::<Vec<_>>();
+        // Do not lint, because w is used.
+        for _ in 0..w.len() {
+            todo!();
+        }
+
+        w.len();
+    }
+
+    fn test_while_cond() {
+        let mut vec = vec![1, 2];
+        let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let mut w = v.iter().collect::<Vec<_>>();
+        // Do lint
+        while 1 == w.len() {
+            todo!();
+        }
+    }
+
+    fn test_while_cond_false_case() {
+        let mut vec = vec![1, 2];
+        let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let mut w = v.iter().collect::<Vec<_>>();
+        // Do not lint, because w is used.
+        while 1 == w.len() {
+            todo!();
+        }
+
+        w.len();
+    }
+
+    fn test_while_let_cond() {
+        let mut vec = vec![1, 2];
+        let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let mut w = v.iter().collect::<Vec<_>>();
+        // Do lint
+        while let Some(i) = Some(w.len()) {
+            todo!();
+        }
+    }
+
+    fn test_while_let_cond_false_case() {
+        let mut vec = vec![1, 2];
+        let mut v: Vec<usize> = vec.iter().map(|i| i * i).collect();
+        let mut w = v.iter().collect::<Vec<_>>();
+        // Do not lint, because w is used.
+        while let Some(i) = Some(w.len()) {
+            todo!();
+        }
+        w.len();
+    }
+}
diff --git a/tests/ui/needless_collect_indirect.stderr b/tests/ui/needless_collect_indirect.stderr
index 0f5e78f9119..9f0880cc606 100644
--- a/tests/ui/needless_collect_indirect.stderr
+++ b/tests/ui/needless_collect_indirect.stderr
@@ -125,5 +125,122 @@ LL ~
 LL ~         sample.iter().count()
    |
 
-error: aborting due to 9 previous errors
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:127:59
+   |
+LL |             let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+   |                                                           ^^^^^^^
+...
+LL |             y.contains(&i);
+   |             -------------- the iterator could be used here instead
+   |
+help: check if the original Iterator contains an element instead of collecting then checking
+   |
+LL ~             
+LL |             let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+LL |             // Do lint
+LL ~             vec.iter().map(|k| k * k).any(|x| x == i);
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:152:59
+   |
+LL |             let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+   |                                                           ^^^^^^^
+...
+LL |             y.contains(&n);
+   |             -------------- the iterator could be used here instead
+   |
+help: check if the original Iterator contains an element instead of collecting then checking
+   |
+LL ~             
+LL |             let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+LL |             // Do lint
+LL ~             vec.iter().map(|k| k * k).any(|x| x == n);
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:181:63
+   |
+LL |                 let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+   |                                                               ^^^^^^^
+...
+LL |                 y.contains(&n);
+   |                 -------------- the iterator could be used here instead
+   |
+help: check if the original Iterator contains an element instead of collecting then checking
+   |
+LL ~                 
+LL |                 let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+LL |                 // Do lint
+LL ~                 vec.iter().map(|k| k * k).any(|x| x == n);
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:217:59
+   |
+LL |             let y: Vec<usize> = vec.iter().map(|k| k * k).collect();
+   |                                                           ^^^^^^^
+...
+LL |                 y.contains(&n);
+   |                 -------------- the iterator could be used here instead
+   |
+help: check if the original Iterator contains an element instead of collecting then checking
+   |
+LL ~             
+LL |             let z: Vec<usize> = vec.iter().map(|k| k * k).collect();
+LL |             if n < 2 {
+LL |                 // Do lint
+LL ~                 vec.iter().map(|k| k * k).any(|x| x == n);
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:242:26
+   |
+LL |         let w = v.iter().collect::<Vec<_>>();
+   |                          ^^^^^^^
+LL |         // Do lint
+LL |         for _ in 0..w.len() {
+   |                     ------- the iterator could be used here instead
+   |
+help: take the original Iterator's count instead of collecting it and finding the length
+   |
+LL ~         
+LL |         // Do lint
+LL ~         for _ in 0..v.iter().count() {
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:264:30
+   |
+LL |         let mut w = v.iter().collect::<Vec<_>>();
+   |                              ^^^^^^^
+LL |         // Do lint
+LL |         while 1 == w.len() {
+   |                    ------- the iterator could be used here instead
+   |
+help: take the original Iterator's count instead of collecting it and finding the length
+   |
+LL ~         
+LL |         // Do lint
+LL ~         while 1 == v.iter().count() {
+   |
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect_indirect.rs:286:30
+   |
+LL |         let mut w = v.iter().collect::<Vec<_>>();
+   |                              ^^^^^^^
+LL |         // Do lint
+LL |         while let Some(i) = Some(w.len()) {
+   |                                  ------- the iterator could be used here instead
+   |
+help: take the original Iterator's count instead of collecting it and finding the length
+   |
+LL ~         
+LL |         // Do lint
+LL ~         while let Some(i) = Some(v.iter().count()) {
+   |
+
+error: aborting due to 16 previous errors
 
diff --git a/tests/ui/needless_match.fixed b/tests/ui/needless_match.fixed
index 0c9178fb85e..7e47406798c 100644
--- a/tests/ui/needless_match.fixed
+++ b/tests/ui/needless_match.fixed
@@ -207,4 +207,43 @@ impl Tr for Result<i32, i32> {
     }
 }
 
+mod issue9084 {
+    fn wildcard_if() {
+        let mut some_bool = true;
+        let e = Some(1);
+
+        // should lint
+        let _ = e;
+
+        // should lint
+        let _ = e;
+
+        // should not lint
+        let _ = match e {
+            _ if some_bool => e,
+            _ => Some(2),
+        };
+
+        // should not lint
+        let _ = match e {
+            Some(i) => Some(i + 1),
+            _ if some_bool => e,
+            _ => e,
+        };
+
+        // should not lint (guard has side effects)
+        let _ = match e {
+            Some(i) => Some(i),
+            _ if {
+                some_bool = false;
+                some_bool
+            } =>
+            {
+                e
+            },
+            _ => e,
+        };
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/needless_match.rs b/tests/ui/needless_match.rs
index f66f01d7cca..809c694bf40 100644
--- a/tests/ui/needless_match.rs
+++ b/tests/ui/needless_match.rs
@@ -244,4 +244,50 @@ impl Tr for Result<i32, i32> {
     }
 }
 
+mod issue9084 {
+    fn wildcard_if() {
+        let mut some_bool = true;
+        let e = Some(1);
+
+        // should lint
+        let _ = match e {
+            _ if some_bool => e,
+            _ => e,
+        };
+
+        // should lint
+        let _ = match e {
+            Some(i) => Some(i),
+            _ if some_bool => e,
+            _ => e,
+        };
+
+        // should not lint
+        let _ = match e {
+            _ if some_bool => e,
+            _ => Some(2),
+        };
+
+        // should not lint
+        let _ = match e {
+            Some(i) => Some(i + 1),
+            _ if some_bool => e,
+            _ => e,
+        };
+
+        // should not lint (guard has side effects)
+        let _ = match e {
+            Some(i) => Some(i),
+            _ if {
+                some_bool = false;
+                some_bool
+            } =>
+            {
+                e
+            },
+            _ => e,
+        };
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/needless_match.stderr b/tests/ui/needless_match.stderr
index 5bc79800a1a..28e78441c25 100644
--- a/tests/ui/needless_match.stderr
+++ b/tests/ui/needless_match.stderr
@@ -109,5 +109,26 @@ LL | |             Complex::D(E::VariantB(ea, eb), b) => Complex::D(E::VariantB(
 LL | |         };
    | |_________^ help: replace it with: `ce`
 
-error: aborting due to 11 previous errors
+error: this match expression is unnecessary
+  --> $DIR/needless_match.rs:253:17
+   |
+LL |           let _ = match e {
+   |  _________________^
+LL | |             _ if some_bool => e,
+LL | |             _ => e,
+LL | |         };
+   | |_________^ help: replace it with: `e`
+
+error: this match expression is unnecessary
+  --> $DIR/needless_match.rs:259:17
+   |
+LL |           let _ = match e {
+   |  _________________^
+LL | |             Some(i) => Some(i),
+LL | |             _ if some_bool => e,
+LL | |             _ => e,
+LL | |         };
+   | |_________^ help: replace it with: `e`
+
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed
index 0bc0d0011ef..87c8fc03b3c 100644
--- a/tests/ui/needless_return.fixed
+++ b/tests/ui/needless_return.fixed
@@ -228,13 +228,9 @@ fn needless_return_macro() -> String {
     format!("Hello {}", "world!")
 }
 
-fn check_expect() -> bool {
-    if true {
-        // no error!
-        return true;
-    }
-    #[expect(clippy::needless_return)]
-    return true;
+fn issue_9361() -> i32 {
+    #[allow(clippy::integer_arithmetic)]
+    return 1 + 2;
 }
 
 fn main() {}
diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs
index eb9f72e8e78..5a86e656255 100644
--- a/tests/ui/needless_return.rs
+++ b/tests/ui/needless_return.rs
@@ -228,13 +228,9 @@ fn needless_return_macro() -> String {
     return format!("Hello {}", "world!");
 }
 
-fn check_expect() -> bool {
-    if true {
-        // no error!
-        return true;
-    }
-    #[expect(clippy::needless_return)]
-    return true;
+fn issue_9361() -> i32 {
+    #[allow(clippy::integer_arithmetic)]
+    return 1 + 2;
 }
 
 fn main() {}
diff --git a/tests/ui/only_used_in_recursion.rs b/tests/ui/only_used_in_recursion.rs
index 5768434f988..f71e8ead519 100644
--- a/tests/ui/only_used_in_recursion.rs
+++ b/tests/ui/only_used_in_recursion.rs
@@ -1,122 +1,113 @@
 #![warn(clippy::only_used_in_recursion)]
 
-fn simple(a: usize, b: usize) -> usize {
-    if a == 0 { 1 } else { simple(a - 1, b) }
+fn _simple(x: u32) -> u32 {
+    x
 }
 
-fn with_calc(a: usize, b: isize) -> usize {
-    if a == 0 { 1 } else { with_calc(a - 1, -b + 1) }
+fn _simple2(x: u32) -> u32 {
+    _simple(x)
 }
 
-fn tuple((a, b): (usize, usize)) -> usize {
-    if a == 0 { 1 } else { tuple((a - 1, b + 1)) }
+fn _one_unused(flag: u32, a: usize) -> usize {
+    if flag == 0 { 0 } else { _one_unused(flag - 1, a) }
 }
 
-fn let_tuple(a: usize, b: usize) -> usize {
-    let (c, d) = (a, b);
-    if c == 0 { 1 } else { let_tuple(c - 1, d + 1) }
+fn _two_unused(flag: u32, a: u32, b: i32) -> usize {
+    if flag == 0 { 0 } else { _two_unused(flag - 1, a, b) }
 }
 
-fn array([a, b]: [usize; 2]) -> usize {
-    if a == 0 { 1 } else { array([a - 1, b + 1]) }
+fn _with_calc(flag: u32, a: i64) -> usize {
+    if flag == 0 {
+        0
+    } else {
+        _with_calc(flag - 1, (-a + 10) * 5)
+    }
 }
 
-fn index(a: usize, mut b: &[usize], c: usize) -> usize {
-    if a == 0 { 1 } else { index(a - 1, b, c + b[0]) }
+// Don't lint
+fn _used_with_flag(flag: u32, a: u32) -> usize {
+    if flag == 0 { 0 } else { _used_with_flag(flag ^ a, a - 1) }
 }
 
-fn break_(a: usize, mut b: usize, mut c: usize) -> usize {
-    let c = loop {
-        b += 1;
-        c += 1;
-        if c == 10 {
-            break b;
-        }
-    };
-
-    if a == 0 { 1 } else { break_(a - 1, c, c) }
+fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize {
+    if flag == 0 {
+        0
+    } else {
+        _used_with_unused(flag - 1, -a, a + b)
+    }
 }
 
-// this has a side effect
-fn mut_ref(a: usize, b: &mut usize) -> usize {
-    *b = 1;
-    if a == 0 { 1 } else { mut_ref(a - 1, b) }
+fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize {
+    if flag == 0 {
+        0
+    } else {
+        _codependent_unused(flag - 1, a * b, a + b)
+    }
 }
 
-fn mut_ref2(a: usize, b: &mut usize) -> usize {
-    let mut c = *b;
-    if a == 0 { 1 } else { mut_ref2(a - 1, &mut c) }
-}
-
-fn not_primitive(a: usize, b: String) -> usize {
-    if a == 0 { 1 } else { not_primitive(a - 1, b) }
-}
-
-// this doesn't have a side effect,
-// but `String` is not primitive.
-fn not_primitive_op(a: usize, b: String, c: &str) -> usize {
-    if a == 1 { 1 } else { not_primitive_op(a, b + c, c) }
+fn _not_primitive(flag: u32, b: String) -> usize {
+    if flag == 0 { 0 } else { _not_primitive(flag - 1, b) }
 }
 
 struct A;
 
 impl A {
-    fn method(a: usize, b: usize) -> usize {
-        if a == 0 { 1 } else { A::method(a - 1, b - 1) }
+    fn _method(flag: usize, a: usize) -> usize {
+        if flag == 0 { 0 } else { Self::_method(flag - 1, a) }
     }
 
-    fn method2(&self, a: usize, b: usize) -> usize {
-        if a == 0 { 1 } else { self.method2(a - 1, b + 1) }
+    fn _method_self(&self, flag: usize, a: usize) -> usize {
+        if flag == 0 { 0 } else { self._method_self(flag - 1, a) }
     }
 }
 
 trait B {
-    fn hello(a: usize, b: usize) -> usize;
-
-    fn hello2(&self, a: usize, b: usize) -> usize;
+    fn method(flag: u32, a: usize) -> usize;
+    fn method_self(&self, flag: u32, a: usize) -> usize;
 }
 
 impl B for A {
-    fn hello(a: usize, b: usize) -> usize {
-        if a == 0 { 1 } else { A::hello(a - 1, b + 1) }
+    fn method(flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { Self::method(flag - 1, a) }
     }
 
-    fn hello2(&self, a: usize, b: usize) -> usize {
-        if a == 0 { 1 } else { self.hello2(a - 1, b + 1) }
+    fn method_self(&self, flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { self.method_self(flag - 1, a) }
+    }
+}
+
+impl B for () {
+    fn method(flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { a }
+    }
+
+    fn method_self(&self, flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { a }
+    }
+}
+
+impl B for u32 {
+    fn method(flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { <() as B>::method(flag, a) }
+    }
+
+    fn method_self(&self, flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { ().method_self(flag, a) }
     }
 }
 
 trait C {
-    fn hello(a: usize, b: usize) -> usize {
-        if a == 0 { 1 } else { Self::hello(a - 1, b + 1) }
+    fn method(flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { Self::method(flag - 1, a) }
     }
 
-    fn hello2(&self, a: usize, b: usize) -> usize {
-        if a == 0 { 1 } else { self.hello2(a - 1, b + 1) }
+    fn method_self(&self, flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { self.method_self(flag - 1, a) }
     }
 }
 
-fn ignore(a: usize, _: usize) -> usize {
-    if a == 1 { 1 } else { ignore(a - 1, 0) }
-}
-
-fn ignore2(a: usize, _b: usize) -> usize {
-    if a == 1 { 1 } else { ignore2(a - 1, _b) }
-}
-
-fn f1(a: u32) -> u32 {
-    a
-}
-
-fn f2(a: u32) -> u32 {
-    f1(a)
-}
-
-fn inner_fn(a: u32) -> u32 {
-    fn inner_fn(a: u32) -> u32 {
-        a
-    }
-    inner_fn(a)
+fn _ignore(flag: usize, _a: usize) -> usize {
+    if flag == 0 { 0 } else { _ignore(flag - 1, _a) }
 }
 
 fn main() {}
diff --git a/tests/ui/only_used_in_recursion.stderr b/tests/ui/only_used_in_recursion.stderr
index 6fe9361bf5f..74057ddcfda 100644
--- a/tests/ui/only_used_in_recursion.stderr
+++ b/tests/ui/only_used_in_recursion.stderr
@@ -1,82 +1,195 @@
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:3:21
+  --> $DIR/only_used_in_recursion.rs:11:27
    |
-LL | fn simple(a: usize, b: usize) -> usize {
-   |                     ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _one_unused(flag: u32, a: usize) -> usize {
+   |                           ^ help: if this is intentional, prefix it with an underscore: `_a`
    |
    = note: `-D clippy::only-used-in-recursion` implied by `-D warnings`
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:12:53
+   |
+LL |     if flag == 0 { 0 } else { _one_unused(flag - 1, a) }
+   |                                                     ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:7:24
+  --> $DIR/only_used_in_recursion.rs:15:27
    |
-LL | fn with_calc(a: usize, b: isize) -> usize {
-   |                        ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _two_unused(flag: u32, a: u32, b: i32) -> usize {
+   |                           ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:16:53
+   |
+LL |     if flag == 0 { 0 } else { _two_unused(flag - 1, a, b) }
+   |                                                     ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:11:14
+  --> $DIR/only_used_in_recursion.rs:15:35
    |
-LL | fn tuple((a, b): (usize, usize)) -> usize {
-   |              ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _two_unused(flag: u32, a: u32, b: i32) -> usize {
+   |                                   ^ help: if this is intentional, prefix it with an underscore: `_b`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:16:56
+   |
+LL |     if flag == 0 { 0 } else { _two_unused(flag - 1, a, b) }
+   |                                                        ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:15:24
+  --> $DIR/only_used_in_recursion.rs:19:26
    |
-LL | fn let_tuple(a: usize, b: usize) -> usize {
-   |                        ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _with_calc(flag: u32, a: i64) -> usize {
+   |                          ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:23:32
+   |
+LL |         _with_calc(flag - 1, (-a + 10) * 5)
+   |                                ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:20:14
+  --> $DIR/only_used_in_recursion.rs:32:33
    |
-LL | fn array([a, b]: [usize; 2]) -> usize {
-   |              ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize {
+   |                                 ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:36:38
+   |
+LL |         _used_with_unused(flag - 1, -a, a + b)
+   |                                      ^  ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:24:20
+  --> $DIR/only_used_in_recursion.rs:32:41
    |
-LL | fn index(a: usize, mut b: &[usize], c: usize) -> usize {
-   |                    ^^^^^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize {
+   |                                         ^ help: if this is intentional, prefix it with an underscore: `_b`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:36:45
+   |
+LL |         _used_with_unused(flag - 1, -a, a + b)
+   |                                             ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:24:37
+  --> $DIR/only_used_in_recursion.rs:40:35
    |
-LL | fn index(a: usize, mut b: &[usize], c: usize) -> usize {
-   |                                     ^ help: if this is intentional, prefix with an underscore: `_c`
+LL | fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize {
+   |                                   ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:44:39
+   |
+LL |         _codependent_unused(flag - 1, a * b, a + b)
+   |                                       ^      ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:28:21
+  --> $DIR/only_used_in_recursion.rs:40:43
    |
-LL | fn break_(a: usize, mut b: usize, mut c: usize) -> usize {
-   |                     ^^^^^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize {
+   |                                           ^ help: if this is intentional, prefix it with an underscore: `_b`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:44:43
+   |
+LL |         _codependent_unused(flag - 1, a * b, a + b)
+   |                                           ^      ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:46:23
+  --> $DIR/only_used_in_recursion.rs:48:30
    |
-LL | fn mut_ref2(a: usize, b: &mut usize) -> usize {
-   |                       ^ help: if this is intentional, prefix with an underscore: `_b`
+LL | fn _not_primitive(flag: u32, b: String) -> usize {
+   |                              ^ help: if this is intentional, prefix it with an underscore: `_b`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:49:56
+   |
+LL |     if flag == 0 { 0 } else { _not_primitive(flag - 1, b) }
+   |                                                        ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:51:28
+  --> $DIR/only_used_in_recursion.rs:55:29
    |
-LL | fn not_primitive(a: usize, b: String) -> usize {
-   |                            ^ help: if this is intentional, prefix with an underscore: `_b`
+LL |     fn _method(flag: usize, a: usize) -> usize {
+   |                             ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:56:59
+   |
+LL |         if flag == 0 { 0 } else { Self::_method(flag - 1, a) }
+   |                                                           ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:68:33
+  --> $DIR/only_used_in_recursion.rs:59:22
    |
-LL |     fn method2(&self, a: usize, b: usize) -> usize {
-   |                                 ^ help: if this is intentional, prefix with an underscore: `_b`
+LL |     fn _method_self(&self, flag: usize, a: usize) -> usize {
+   |                      ^^^^
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:60:35
+   |
+LL |         if flag == 0 { 0 } else { self._method_self(flag - 1, a) }
+   |                                   ^^^^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:90:24
+  --> $DIR/only_used_in_recursion.rs:59:41
    |
-LL |     fn hello(a: usize, b: usize) -> usize {
-   |                        ^ help: if this is intentional, prefix with an underscore: `_b`
+LL |     fn _method_self(&self, flag: usize, a: usize) -> usize {
+   |                                         ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:60:63
+   |
+LL |         if flag == 0 { 0 } else { self._method_self(flag - 1, a) }
+   |                                                               ^
 
 error: parameter is only used in recursion
-  --> $DIR/only_used_in_recursion.rs:94:32
+  --> $DIR/only_used_in_recursion.rs:70:26
    |
-LL |     fn hello2(&self, a: usize, b: usize) -> usize {
-   |                                ^ help: if this is intentional, prefix with an underscore: `_b`
+LL |     fn method(flag: u32, a: usize) -> usize {
+   |                          ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:71:58
+   |
+LL |         if flag == 0 { 0 } else { Self::method(flag - 1, a) }
+   |                                                          ^
 
-error: aborting due to 13 previous errors
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion.rs:74:38
+   |
+LL |     fn method_self(&self, flag: u32, a: usize) -> usize {
+   |                                      ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:75:62
+   |
+LL |         if flag == 0 { 0 } else { self.method_self(flag - 1, a) }
+   |                                                              ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion.rs:100:26
+   |
+LL |     fn method(flag: u32, a: usize) -> usize {
+   |                          ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:101:58
+   |
+LL |         if flag == 0 { 0 } else { Self::method(flag - 1, a) }
+   |                                                          ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion.rs:104:38
+   |
+LL |     fn method_self(&self, flag: u32, a: usize) -> usize {
+   |                                      ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion.rs:105:62
+   |
+LL |         if flag == 0 { 0 } else { self.method_self(flag - 1, a) }
+   |                                                              ^
+
+error: aborting due to 16 previous errors
 
diff --git a/tests/ui/only_used_in_recursion2.rs b/tests/ui/only_used_in_recursion2.rs
new file mode 100644
index 00000000000..45dd0553f58
--- /dev/null
+++ b/tests/ui/only_used_in_recursion2.rs
@@ -0,0 +1,91 @@
+#![warn(clippy::only_used_in_recursion)]
+
+fn _with_inner(flag: u32, a: u32, b: u32) -> usize {
+    fn inner(flag: u32, a: u32) -> u32 {
+        if flag == 0 { 0 } else { inner(flag, a) }
+    }
+
+    let x = inner(flag, a);
+    if flag == 0 { 0 } else { _with_inner(flag, a, b + x) }
+}
+
+fn _with_closure(a: Option<u32>, b: u32, f: impl Fn(u32, u32) -> Option<u32>) -> u32 {
+    if let Some(x) = a.and_then(|x| f(x, x)) {
+        _with_closure(Some(x), b, f)
+    } else {
+        0
+    }
+}
+
+// Issue #8560
+trait D {
+    fn foo(&mut self, arg: u32) -> u32;
+}
+
+mod m {
+    pub struct S(u32);
+    impl S {
+        pub fn foo(&mut self, arg: u32) -> u32 {
+            arg + self.0
+        }
+    }
+}
+
+impl D for m::S {
+    fn foo(&mut self, arg: u32) -> u32 {
+        self.foo(arg)
+    }
+}
+
+// Issue #8782
+fn only_let(x: u32) {
+    let y = 10u32;
+    let _z = x * y;
+}
+
+trait E<T: E<()>> {
+    fn method(flag: u32, a: usize) -> usize {
+        if flag == 0 {
+            0
+        } else {
+            <T as E<()>>::method(flag - 1, a)
+        }
+    }
+}
+
+impl E<()> for () {
+    fn method(flag: u32, a: usize) -> usize {
+        if flag == 0 { 0 } else { a }
+    }
+}
+
+fn overwritten_param(flag: u32, mut a: usize) -> usize {
+    if flag == 0 {
+        return 0;
+    } else if flag > 5 {
+        a += flag as usize;
+    } else {
+        a = 5;
+    }
+    overwritten_param(flag, a)
+}
+
+fn field_direct(flag: u32, mut a: (usize,)) -> usize {
+    if flag == 0 {
+        0
+    } else {
+        a.0 += 5;
+        field_direct(flag - 1, a)
+    }
+}
+
+fn field_deref(flag: u32, a: &mut Box<(usize,)>) -> usize {
+    if flag == 0 {
+        0
+    } else {
+        a.0 += 5;
+        field_deref(flag - 1, a)
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/only_used_in_recursion2.stderr b/tests/ui/only_used_in_recursion2.stderr
new file mode 100644
index 00000000000..23f6ffd30c9
--- /dev/null
+++ b/tests/ui/only_used_in_recursion2.stderr
@@ -0,0 +1,63 @@
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion2.rs:3:35
+   |
+LL | fn _with_inner(flag: u32, a: u32, b: u32) -> usize {
+   |                                   ^ help: if this is intentional, prefix it with an underscore: `_b`
+   |
+   = note: `-D clippy::only-used-in-recursion` implied by `-D warnings`
+note: parameter used here
+  --> $DIR/only_used_in_recursion2.rs:9:52
+   |
+LL |     if flag == 0 { 0 } else { _with_inner(flag, a, b + x) }
+   |                                                    ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion2.rs:4:25
+   |
+LL |     fn inner(flag: u32, a: u32) -> u32 {
+   |                         ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion2.rs:5:47
+   |
+LL |         if flag == 0 { 0 } else { inner(flag, a) }
+   |                                               ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion2.rs:12:34
+   |
+LL | fn _with_closure(a: Option<u32>, b: u32, f: impl Fn(u32, u32) -> Option<u32>) -> u32 {
+   |                                  ^ help: if this is intentional, prefix it with an underscore: `_b`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion2.rs:14:32
+   |
+LL |         _with_closure(Some(x), b, f)
+   |                                ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion2.rs:62:37
+   |
+LL | fn overwritten_param(flag: u32, mut a: usize) -> usize {
+   |                                     ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion2.rs:70:29
+   |
+LL |     overwritten_param(flag, a)
+   |                             ^
+
+error: parameter is only used in recursion
+  --> $DIR/only_used_in_recursion2.rs:73:32
+   |
+LL | fn field_direct(flag: u32, mut a: (usize,)) -> usize {
+   |                                ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: parameter used here
+  --> $DIR/only_used_in_recursion2.rs:78:32
+   |
+LL |         field_direct(flag - 1, a)
+   |                                ^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed
index b6d5e106f05..f15ac551bb3 100644
--- a/tests/ui/option_if_let_else.fixed
+++ b/tests/ui/option_if_let_else.fixed
@@ -179,4 +179,13 @@ fn main() {
 
     let _ = pattern_to_vec("hello world");
     let _ = complex_subpat();
+
+    // issue #8492
+    let _ = s.map_or(1, |string| string.len());
+    let _ = Some(10).map_or(5, |a| a + 1);
+
+    let res: Result<i32, i32> = Ok(5);
+    let _ = res.map_or(1, |a| a + 1);
+    let _ = res.map_or(1, |a| a + 1);
+    let _ = res.map_or(5, |a| a + 1);
 }
diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs
index 35bae159343..9eeaea12d3b 100644
--- a/tests/ui/option_if_let_else.rs
+++ b/tests/ui/option_if_let_else.rs
@@ -208,4 +208,25 @@ fn main() {
 
     let _ = pattern_to_vec("hello world");
     let _ = complex_subpat();
+
+    // issue #8492
+    let _ = match s {
+        Some(string) => string.len(),
+        None => 1,
+    };
+    let _ = match Some(10) {
+        Some(a) => a + 1,
+        None => 5,
+    };
+
+    let res: Result<i32, i32> = Ok(5);
+    let _ = match res {
+        Ok(a) => a + 1,
+        _ => 1,
+    };
+    let _ = match res {
+        Err(_) => 1,
+        Ok(a) => a + 1,
+    };
+    let _ = if let Ok(a) = res { a + 1 } else { 5 };
 }
diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr
index daba606004e..a5dbf6e1f22 100644
--- a/tests/ui/option_if_let_else.stderr
+++ b/tests/ui/option_if_let_else.stderr
@@ -206,5 +206,51 @@ LL +         s.len() + x
 LL ~     });
    |
 
-error: aborting due to 15 previous errors
+error: use Option::map_or instead of an if let/else
+  --> $DIR/option_if_let_else.rs:213:13
+   |
+LL |       let _ = match s {
+   |  _____________^
+LL | |         Some(string) => string.len(),
+LL | |         None => 1,
+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
+   |
+LL |       let _ = match Some(10) {
+   |  _____________^
+LL | |         Some(a) => a + 1,
+LL | |         None => 5,
+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
+   |
+LL |       let _ = match res {
+   |  _____________^
+LL | |         Ok(a) => a + 1,
+LL | |         _ => 1,
+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
+   |
+LL |       let _ = match res {
+   |  _____________^
+LL | |         Err(_) => 1,
+LL | |         Ok(a) => a + 1,
+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
+   |
+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
 
diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed
index fdb08d953ff..18ea4e55029 100644
--- a/tests/ui/or_fun_call.fixed
+++ b/tests/ui/or_fun_call.fixed
@@ -90,8 +90,8 @@ fn or_fun_call() {
     let mut btree_vec = BTreeMap::<u64, Vec<i32>>::new();
     btree_vec.entry(42).or_insert(vec![]);
 
-    let stringy = Some(String::from(""));
-    let _ = stringy.unwrap_or_else(|| "".to_owned());
+    let stringy = Some(String::new());
+    let _ = stringy.unwrap_or_default();
 
     let opt = Some(1);
     let hello = "Hello";
diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs
index 57ab5f03ee2..c353b41e449 100644
--- a/tests/ui/or_fun_call.rs
+++ b/tests/ui/or_fun_call.rs
@@ -90,8 +90,8 @@ fn or_fun_call() {
     let mut btree_vec = BTreeMap::<u64, Vec<i32>>::new();
     btree_vec.entry(42).or_insert(vec![]);
 
-    let stringy = Some(String::from(""));
-    let _ = stringy.unwrap_or("".to_owned());
+    let stringy = Some(String::new());
+    let _ = stringy.unwrap_or(String::new());
 
     let opt = Some(1);
     let hello = "Hello";
diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr
index 4c5938ab88b..887f23ac976 100644
--- a/tests/ui/or_fun_call.stderr
+++ b/tests/ui/or_fun_call.stderr
@@ -66,11 +66,11 @@ error: use of `unwrap_or` followed by a function call
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
 
-error: use of `unwrap_or` followed by a function call
+error: use of `unwrap_or` followed by a call to `new`
   --> $DIR/or_fun_call.rs:94:21
    |
-LL |     let _ = stringy.unwrap_or("".to_owned());
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
+LL |     let _ = stringy.unwrap_or(String::new());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
 
 error: use of `unwrap_or` followed by a function call
   --> $DIR/or_fun_call.rs:102:21
diff --git a/tests/ui/partialeq_to_none.fixed b/tests/ui/partialeq_to_none.fixed
index f3e4c58d694..4644ea8f51d 100644
--- a/tests/ui/partialeq_to_none.fixed
+++ b/tests/ui/partialeq_to_none.fixed
@@ -26,6 +26,18 @@ fn optref() -> &'static &'static Option<()> {
     &&None
 }
 
+pub fn macro_expansion() {
+    macro_rules! foo {
+        () => {
+            None::<()>
+        };
+    }
+
+    let _ = foobar() == foo!();
+    let _ = foo!() == foobar();
+    let _ = foo!() == foo!();
+}
+
 fn main() {
     let x = Some(0);
 
diff --git a/tests/ui/partialeq_to_none.rs b/tests/ui/partialeq_to_none.rs
index 767b2a38bcc..61011b3a8c5 100644
--- a/tests/ui/partialeq_to_none.rs
+++ b/tests/ui/partialeq_to_none.rs
@@ -26,6 +26,18 @@ fn optref() -> &'static &'static Option<()> {
     &&None
 }
 
+pub fn macro_expansion() {
+    macro_rules! foo {
+        () => {
+            None::<()>
+        };
+    }
+
+    let _ = foobar() == foo!();
+    let _ = foo!() == foobar();
+    let _ = foo!() == foo!();
+}
+
 fn main() {
     let x = Some(0);
 
diff --git a/tests/ui/partialeq_to_none.stderr b/tests/ui/partialeq_to_none.stderr
index de15a9f7baa..d06ab7aee55 100644
--- a/tests/ui/partialeq_to_none.stderr
+++ b/tests/ui/partialeq_to_none.stderr
@@ -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:32:13
+  --> $DIR/partialeq_to_none.rs:44: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:33:13
+  --> $DIR/partialeq_to_none.rs:45: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:34:13
+  --> $DIR/partialeq_to_none.rs:46: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:35:13
+  --> $DIR/partialeq_to_none.rs:47: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:37:8
+  --> $DIR/partialeq_to_none.rs:49: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:39:8
+  --> $DIR/partialeq_to_none.rs:51: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:41:13
+  --> $DIR/partialeq_to_none.rs:53: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:43:13
+  --> $DIR/partialeq_to_none.rs:55: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:45:13
+  --> $DIR/partialeq_to_none.rs:57:13
    |
 LL |       let _ = {
    |  _____________^
@@ -77,31 +77,31 @@ LL ~     }.is_some();
    |
 
 error: binary comparison to literal `Option::None`
-  --> $DIR/partialeq_to_none.rs:55:13
+  --> $DIR/partialeq_to_none.rs:67: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:56:13
+  --> $DIR/partialeq_to_none.rs:68: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:57:13
+  --> $DIR/partialeq_to_none.rs:69: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:58:13
+  --> $DIR/partialeq_to_none.rs:70: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:61:13
+  --> $DIR/partialeq_to_none.rs:73:13
    |
 LL |     let _ = None != *x;
    |             ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()`
diff --git a/tests/ui/positional_named_format_parameters.fixed b/tests/ui/positional_named_format_parameters.fixed
new file mode 100644
index 00000000000..4170e109820
--- /dev/null
+++ b/tests/ui/positional_named_format_parameters.fixed
@@ -0,0 +1,56 @@
+// run-rustfix
+#![allow(unused_must_use)]
+#![allow(named_arguments_used_positionally)] // Unstable at time of writing.
+#![warn(clippy::positional_named_format_parameters)]
+
+use std::io::Write;
+
+fn main() {
+    let mut v = Vec::new();
+    let hello = "Hello";
+
+    println!("{hello:.foo$}", foo = 2);
+    writeln!(v, "{hello:.foo$}", foo = 2);
+
+    // Warnings
+    println!("{zero} {one:?}", zero = 0, one = 1);
+    println!("This is a test {zero} {one:?}", zero = 0, one = 1);
+    println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01);
+    println!("Hello {one:zero$}!", zero = 5, one = 1);
+    println!("Hello {zero:one$}!", zero = 4, one = 1);
+    println!("Hello {zero:0one$}!", zero = 4, one = 1);
+    println!("Hello is {one:.zero$}", zero = 5, one = 0.01);
+    println!("Hello is {one:<6.zero$}", zero = 5, one = 0.01);
+    println!("{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello);
+    println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01);
+    println!("Hello {world} {world}!", world = 5);
+
+    writeln!(v, "{zero} {one:?}", zero = 0, one = 1);
+    writeln!(v, "This is a test {zero} {one:?}", zero = 0, one = 1);
+    writeln!(v, "Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01);
+    writeln!(v, "Hello {one:zero$}!", zero = 4, one = 1);
+    writeln!(v, "Hello {zero:one$}!", zero = 4, one = 1);
+    writeln!(v, "Hello {zero:0one$}!", zero = 4, one = 1);
+    writeln!(v, "Hello is {one:.zero$}", zero = 3, one = 0.01);
+    writeln!(v, "Hello is {one:<6.zero$}", zero = 2, one = 0.01);
+    writeln!(v, "{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello);
+    writeln!(v, "Hello {one} is {two:.zero$}", zero = 1, one = hello, two = 0.01);
+    writeln!(v, "Hello {world} {world}!", world = 0);
+
+    // Tests from other files
+    println!("{w:w$}", w = 1);
+    println!("{p:.p$}", p = 1);
+    println!("{v}", v = 1);
+    println!("{v:v$}", v = 1);
+    println!("{v:v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{v:v$.v$}", v = 1);
+    println!("{w:w$}", w = 1);
+    println!("{p:.p$}", p = 1);
+    println!("{:p$.w$}", 1, w = 1, p = 1);
+}
diff --git a/tests/ui/positional_named_format_parameters.rs b/tests/ui/positional_named_format_parameters.rs
new file mode 100644
index 00000000000..553d8494ecc
--- /dev/null
+++ b/tests/ui/positional_named_format_parameters.rs
@@ -0,0 +1,56 @@
+// run-rustfix
+#![allow(unused_must_use)]
+#![allow(named_arguments_used_positionally)] // Unstable at time of writing.
+#![warn(clippy::positional_named_format_parameters)]
+
+use std::io::Write;
+
+fn main() {
+    let mut v = Vec::new();
+    let hello = "Hello";
+
+    println!("{hello:.foo$}", foo = 2);
+    writeln!(v, "{hello:.foo$}", foo = 2);
+
+    // Warnings
+    println!("{} {1:?}", zero = 0, one = 1);
+    println!("This is a test { } {000001:?}", zero = 0, one = 1);
+    println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+    println!("Hello {1:0$}!", zero = 5, one = 1);
+    println!("Hello {0:1$}!", zero = 4, one = 1);
+    println!("Hello {0:01$}!", zero = 4, one = 1);
+    println!("Hello is {1:.*}", zero = 5, one = 0.01);
+    println!("Hello is {:<6.*}", zero = 5, one = 0.01);
+    println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
+    println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+    println!("Hello {world} {}!", world = 5);
+
+    writeln!(v, "{} {1:?}", zero = 0, one = 1);
+    writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1);
+    writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+    writeln!(v, "Hello {1:0$}!", zero = 4, one = 1);
+    writeln!(v, "Hello {0:1$}!", zero = 4, one = 1);
+    writeln!(v, "Hello {0:01$}!", zero = 4, one = 1);
+    writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01);
+    writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01);
+    writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
+    writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
+    writeln!(v, "Hello {world} {}!", world = 0);
+
+    // Tests from other files
+    println!("{:w$}", w = 1);
+    println!("{:.p$}", p = 1);
+    println!("{}", v = 1);
+    println!("{:0$}", v = 1);
+    println!("{0:0$}", v = 1);
+    println!("{:0$.0$}", v = 1);
+    println!("{0:0$.0$}", v = 1);
+    println!("{0:0$.v$}", v = 1);
+    println!("{0:v$.0$}", v = 1);
+    println!("{v:0$.0$}", v = 1);
+    println!("{v:v$.0$}", v = 1);
+    println!("{v:0$.v$}", v = 1);
+    println!("{:w$}", w = 1);
+    println!("{:.p$}", p = 1);
+    println!("{:p$.w$}", 1, w = 1, p = 1);
+}
diff --git a/tests/ui/positional_named_format_parameters.stderr b/tests/ui/positional_named_format_parameters.stderr
new file mode 100644
index 00000000000..48ddb6d67ad
--- /dev/null
+++ b/tests/ui/positional_named_format_parameters.stderr
@@ -0,0 +1,418 @@
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:16:16
+   |
+LL |     println!("{} {1:?}", zero = 0, one = 1);
+   |                ^ help: replace it with: `zero`
+   |
+   = note: `-D clippy::positional-named-format-parameters` implied by `-D warnings`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:16:19
+   |
+LL |     println!("{} {1:?}", zero = 0, one = 1);
+   |                   ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:17:31
+   |
+LL |     println!("This is a test { } {000001:?}", zero = 0, one = 1);
+   |                               ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:17:35
+   |
+LL |     println!("This is a test { } {000001:?}", zero = 0, one = 1);
+   |                                   ^^^^^^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:18:32
+   |
+LL |     println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                                ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:18:22
+   |
+LL |     println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                      ^ help: replace it with: `one`
+
+error: named parameter two is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:18:29
+   |
+LL |     println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                             ^ help: replace it with: `two`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:19:24
+   |
+LL |     println!("Hello {1:0$}!", zero = 5, one = 1);
+   |                        ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:19:22
+   |
+LL |     println!("Hello {1:0$}!", zero = 5, one = 1);
+   |                      ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:20:22
+   |
+LL |     println!("Hello {0:1$}!", zero = 4, one = 1);
+   |                      ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:20:24
+   |
+LL |     println!("Hello {0:1$}!", zero = 4, one = 1);
+   |                        ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:21:22
+   |
+LL |     println!("Hello {0:01$}!", zero = 4, one = 1);
+   |                      ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:21:25
+   |
+LL |     println!("Hello {0:01$}!", zero = 4, one = 1);
+   |                         ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:22:28
+   |
+LL |     println!("Hello is {1:.*}", zero = 5, one = 0.01);
+   |                            ^ help: replace it with: `zero$`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:22:25
+   |
+LL |     println!("Hello is {1:.*}", zero = 5, one = 0.01);
+   |                         ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:23:29
+   |
+LL |     println!("Hello is {:<6.*}", zero = 5, one = 0.01);
+   |                             ^ help: replace it with: `zero$`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:23:25
+   |
+LL |     println!("Hello is {:<6.*}", zero = 5, one = 0.01);
+   |                         ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:24:16
+   |
+LL |     println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
+   |                ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:24:28
+   |
+LL |     println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
+   |                            ^ help: replace it with: `one$`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:25:32
+   |
+LL |     println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                                ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:25:22
+   |
+LL |     println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                      ^ help: replace it with: `one`
+
+error: named parameter two is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:25:29
+   |
+LL |     println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                             ^ help: replace it with: `two`
+
+error: named parameter world is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:26:30
+   |
+LL |     println!("Hello {world} {}!", world = 5);
+   |                              ^ help: replace it with: `world`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:28:19
+   |
+LL |     writeln!(v, "{} {1:?}", zero = 0, one = 1);
+   |                   ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:28:22
+   |
+LL |     writeln!(v, "{} {1:?}", zero = 0, one = 1);
+   |                      ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:29:34
+   |
+LL |     writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1);
+   |                                  ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:29:38
+   |
+LL |     writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1);
+   |                                      ^^^^^^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:30:35
+   |
+LL |     writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                                   ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:30:25
+   |
+LL |     writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                         ^ help: replace it with: `one`
+
+error: named parameter two is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:30:32
+   |
+LL |     writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01);
+   |                                ^ help: replace it with: `two`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:31:27
+   |
+LL |     writeln!(v, "Hello {1:0$}!", zero = 4, one = 1);
+   |                           ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:31:25
+   |
+LL |     writeln!(v, "Hello {1:0$}!", zero = 4, one = 1);
+   |                         ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:32:25
+   |
+LL |     writeln!(v, "Hello {0:1$}!", zero = 4, one = 1);
+   |                         ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:32:27
+   |
+LL |     writeln!(v, "Hello {0:1$}!", zero = 4, one = 1);
+   |                           ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:33:25
+   |
+LL |     writeln!(v, "Hello {0:01$}!", zero = 4, one = 1);
+   |                         ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:33:28
+   |
+LL |     writeln!(v, "Hello {0:01$}!", zero = 4, one = 1);
+   |                            ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:34:31
+   |
+LL |     writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01);
+   |                               ^ help: replace it with: `zero$`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:34:28
+   |
+LL |     writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01);
+   |                            ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:35:32
+   |
+LL |     writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01);
+   |                                ^ help: replace it with: `zero$`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:35:28
+   |
+LL |     writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01);
+   |                            ^ help: replace it with: `one`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:36:19
+   |
+LL |     writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
+   |                   ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:36:31
+   |
+LL |     writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello);
+   |                               ^ help: replace it with: `one$`
+
+error: named parameter zero is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:37:35
+   |
+LL |     writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
+   |                                   ^ help: replace it with: `zero`
+
+error: named parameter one is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:37:25
+   |
+LL |     writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
+   |                         ^ help: replace it with: `one`
+
+error: named parameter two is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:37:32
+   |
+LL |     writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01);
+   |                                ^ help: replace it with: `two`
+
+error: named parameter world is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:38:33
+   |
+LL |     writeln!(v, "Hello {world} {}!", world = 0);
+   |                                 ^ help: replace it with: `world`
+
+error: named parameter w is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:41:16
+   |
+LL |     println!("{:w$}", w = 1);
+   |                ^ help: replace it with: `w`
+
+error: named parameter p is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:42:16
+   |
+LL |     println!("{:.p$}", p = 1);
+   |                ^ help: replace it with: `p`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:43:16
+   |
+LL |     println!("{}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:44:16
+   |
+LL |     println!("{:0$}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:44:17
+   |
+LL |     println!("{:0$}", v = 1);
+   |                 ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:45:16
+   |
+LL |     println!("{0:0$}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:45:18
+   |
+LL |     println!("{0:0$}", v = 1);
+   |                  ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:46:16
+   |
+LL |     println!("{:0$.0$}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:46:20
+   |
+LL |     println!("{:0$.0$}", v = 1);
+   |                    ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:46:17
+   |
+LL |     println!("{:0$.0$}", v = 1);
+   |                 ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:47:16
+   |
+LL |     println!("{0:0$.0$}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:47:21
+   |
+LL |     println!("{0:0$.0$}", v = 1);
+   |                     ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:47:18
+   |
+LL |     println!("{0:0$.0$}", v = 1);
+   |                  ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:48:16
+   |
+LL |     println!("{0:0$.v$}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:48:18
+   |
+LL |     println!("{0:0$.v$}", v = 1);
+   |                  ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:49:16
+   |
+LL |     println!("{0:v$.0$}", v = 1);
+   |                ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:49:21
+   |
+LL |     println!("{0:v$.0$}", v = 1);
+   |                     ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:50:21
+   |
+LL |     println!("{v:0$.0$}", v = 1);
+   |                     ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:50:18
+   |
+LL |     println!("{v:0$.0$}", v = 1);
+   |                  ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:51:21
+   |
+LL |     println!("{v:v$.0$}", v = 1);
+   |                     ^ help: replace it with: `v`
+
+error: named parameter v is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:52:18
+   |
+LL |     println!("{v:0$.v$}", v = 1);
+   |                  ^ help: replace it with: `v`
+
+error: named parameter w is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:53:16
+   |
+LL |     println!("{:w$}", w = 1);
+   |                ^ help: replace it with: `w`
+
+error: named parameter p is used as a positional parameter
+  --> $DIR/positional_named_format_parameters.rs:54:16
+   |
+LL |     println!("{:.p$}", p = 1);
+   |                ^ help: replace it with: `p`
+
+error: aborting due to 69 previous errors
+
diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed
index c4c9c821433..57f23bd1916 100644
--- a/tests/ui/question_mark.fixed
+++ b/tests/ui/question_mark.fixed
@@ -207,4 +207,19 @@ fn option_map() -> Option<bool> {
     }
 }
 
+pub struct PatternedError {
+    flag: bool,
+}
+
+// No warning
+fn pattern() -> Result<(), PatternedError> {
+    let res = Ok(());
+
+    if let Err(err @ PatternedError { flag: true }) = res {
+        return Err(err);
+    }
+
+    res
+}
+
 fn main() {}
diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs
index cdbc7b1606f..436f027c215 100644
--- a/tests/ui/question_mark.rs
+++ b/tests/ui/question_mark.rs
@@ -243,4 +243,19 @@ fn option_map() -> Option<bool> {
     }
 }
 
+pub struct PatternedError {
+    flag: bool,
+}
+
+// No warning
+fn pattern() -> Result<(), PatternedError> {
+    let res = Ok(());
+
+    if let Err(err @ PatternedError { flag: true }) = res {
+        return Err(err);
+    }
+
+    res
+}
+
 fn main() {}
diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs
index f7f3b195ccc..f0e1a8128d7 100644
--- a/tests/ui/regex.rs
+++ b/tests/ui/regex.rs
@@ -1,4 +1,4 @@
-#![allow(unused)]
+#![allow(unused, clippy::needless_borrow)]
 #![warn(clippy::invalid_regex, clippy::trivial_regex)]
 
 extern crate regex;
diff --git a/tests/ui/result_large_err.rs b/tests/ui/result_large_err.rs
new file mode 100644
index 00000000000..78d8f76fe66
--- /dev/null
+++ b/tests/ui/result_large_err.rs
@@ -0,0 +1,98 @@
+#![warn(clippy::result_large_err)]
+
+pub fn small_err() -> Result<(), u128> {
+    Ok(())
+}
+
+pub fn large_err() -> Result<(), [u8; 512]> {
+    Ok(())
+}
+
+pub struct FullyDefinedLargeError {
+    _foo: u128,
+    _bar: [u8; 100],
+    _foobar: [u8; 120],
+}
+
+impl FullyDefinedLargeError {
+    pub fn ret() -> Result<(), Self> {
+        Ok(())
+    }
+}
+
+pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
+    Ok(())
+}
+
+type Fdlr<T> = std::result::Result<T, FullyDefinedLargeError>;
+pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
+    Ok(x)
+}
+
+pub fn param_small_error<R>() -> Result<(), (R, u128)> {
+    Ok(())
+}
+
+pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeError)> {
+    Ok(())
+}
+
+pub enum LargeErrorVariants<T> {
+    _Small(u8),
+    _Omg([u8; 512]),
+    _Param(T),
+}
+
+impl LargeErrorVariants<()> {
+    pub fn large_enum_error() -> Result<(), Self> {
+        Ok(())
+    }
+}
+
+trait TraitForcesLargeError {
+    fn large_error() -> Result<(), [u8; 512]> {
+        Ok(())
+    }
+}
+
+struct TraitImpl;
+
+impl TraitForcesLargeError for TraitImpl {
+    // Should not lint
+    fn large_error() -> Result<(), [u8; 512]> {
+        Ok(())
+    }
+}
+
+pub union FullyDefinedUnionError {
+    _maybe: u8,
+    _or_even: [[u8; 16]; 32],
+}
+
+pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
+    Ok(())
+}
+
+pub union UnionError<T: Copy> {
+    _maybe: T,
+    _or_perhaps_even: (T, [u8; 512]),
+}
+
+pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
+    Ok(())
+}
+
+pub struct ArrayError<T, U> {
+    _large_array: [T; 32],
+    _other_stuff: U,
+}
+
+pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
+    Ok(())
+}
+
+pub fn array_error<T, U>() -> Result<(), ArrayError<(i32, T), U>> {
+    Ok(())
+}
+
+fn main() {}
diff --git a/tests/ui/result_large_err.stderr b/tests/ui/result_large_err.stderr
new file mode 100644
index 00000000000..0f1f39d72cb
--- /dev/null
+++ b/tests/ui/result_large_err.stderr
@@ -0,0 +1,91 @@
+error: the `Err`-variant returned from this function is very large
+  --> $DIR/result_large_err.rs:7:23
+   |
+LL | pub fn large_err() -> Result<(), [u8; 512]> {
+   |                       ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
+   |
+   = note: `-D clippy::result-large-err` implied by `-D warnings`
+   = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>`
+
+error: the `Err`-variant returned from this function is very large
+  --> $DIR/result_large_err.rs:18:21
+   |
+LL |     pub fn ret() -> Result<(), Self> {
+   |                     ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
+   |
+   = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
+
+error: the `Err`-variant returned from this function is very large
+  --> $DIR/result_large_err.rs:23:26
+   |
+LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
+   |
+   = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
+
+error: the `Err`-variant returned from this function is very large
+  --> $DIR/result_large_err.rs:28:45
+   |
+LL | pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
+   |                                             ^^^^^^^ the `Err`-variant is at least 240 bytes
+   |
+   = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
+
+error: the `Err`-variant returned from this function is very large
+  --> $DIR/result_large_err.rs:36:34
+   |
+LL | pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeError)> {
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 256 bytes
+   |
+   = help: try reducing the size of `(u128, R, FullyDefinedLargeError)`, for example by boxing large elements or replacing it with `Box<(u128, R, FullyDefinedLargeError)>`
+
+error: the `Err`-variant returned from this function is very large
+  --> $DIR/result_large_err.rs:47:34
+   |
+LL |     pub fn large_enum_error() -> Result<(), Self> {
+   |                                  ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 513 bytes
+   |
+   = help: try reducing the size of `LargeErrorVariants<()>`, for example by boxing large elements or replacing it with `Box<LargeErrorVariants<()>>`
+
+error: the `Err`-variant returned from this function is very large
+  --> $DIR/result_large_err.rs:53:25
+   |
+LL |     fn large_error() -> Result<(), [u8; 512]> {
+   |                         ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
+   |
+   = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>`
+
+error: the `Err`-variant returned from this function is very large
+  --> $DIR/result_large_err.rs:72:29
+   |
+LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
+   |
+   = help: try reducing the size of `FullyDefinedUnionError`, for example by boxing large elements or replacing it with `Box<FullyDefinedUnionError>`
+
+error: the `Err`-variant returned from this function is very large
+  --> $DIR/result_large_err.rs:81:40
+   |
+LL | pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
+   |
+   = help: try reducing the size of `UnionError<T>`, for example by boxing large elements or replacing it with `Box<UnionError<T>>`
+
+error: the `Err`-variant returned from this function is very large
+  --> $DIR/result_large_err.rs:90:34
+   |
+LL | pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes
+   |
+   = help: try reducing the size of `ArrayError<i32, U>`, for example by boxing large elements or replacing it with `Box<ArrayError<i32, U>>`
+
+error: the `Err`-variant returned from this function is very large
+  --> $DIR/result_large_err.rs:94:31
+   |
+LL | pub fn array_error<T, U>() -> Result<(), ArrayError<(i32, T), U>> {
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes
+   |
+   = help: try reducing the size of `ArrayError<(i32, T), U>`, for example by boxing large elements or replacing it with `Box<ArrayError<(i32, T), U>>`
+
+error: aborting due to 11 previous errors
+
diff --git a/tests/ui/same_item_push.rs b/tests/ui/same_item_push.rs
index 99964f0de07..af01a8df71b 100644
--- a/tests/ui/same_item_push.rs
+++ b/tests/ui/same_item_push.rs
@@ -151,6 +151,7 @@ fn main() {
 
     // Fix #6987
     let mut vec = Vec::new();
+    #[allow(clippy::needless_borrow)]
     for _ in 0..10 {
         vec.push(1);
         vec.extend(&[2]);
diff --git a/tests/ui/string_add.rs b/tests/ui/string_add.rs
index 30fd17c59e5..16673c01e63 100644
--- a/tests/ui/string_add.rs
+++ b/tests/ui/string_add.rs
@@ -7,13 +7,13 @@ extern crate macro_rules;
 #[allow(clippy::string_add_assign, unused)]
 fn main() {
     // ignores assignment distinction
-    let mut x = "".to_owned();
+    let mut x = String::new();
 
     for _ in 1..3 {
         x = x + ".";
     }
 
-    let y = "".to_owned();
+    let y = String::new();
     let z = y + "...";
 
     assert_eq!(&x, &z);
diff --git a/tests/ui/string_add_assign.fixed b/tests/ui/string_add_assign.fixed
index db71bab1e52..b687f43b254 100644
--- a/tests/ui/string_add_assign.fixed
+++ b/tests/ui/string_add_assign.fixed
@@ -4,13 +4,13 @@
 #[warn(clippy::string_add_assign)]
 fn main() {
     // ignores assignment distinction
-    let mut x = "".to_owned();
+    let mut x = String::new();
 
     for _ in 1..3 {
         x += ".";
     }
 
-    let y = "".to_owned();
+    let y = String::new();
     let z = y + "...";
 
     assert_eq!(&x, &z);
diff --git a/tests/ui/string_add_assign.rs b/tests/ui/string_add_assign.rs
index 644991945cb..e5dbde108fb 100644
--- a/tests/ui/string_add_assign.rs
+++ b/tests/ui/string_add_assign.rs
@@ -4,13 +4,13 @@
 #[warn(clippy::string_add_assign)]
 fn main() {
     // ignores assignment distinction
-    let mut x = "".to_owned();
+    let mut x = String::new();
 
     for _ in 1..3 {
         x = x + ".";
     }
 
-    let y = "".to_owned();
+    let y = String::new();
     let z = y + "...";
 
     assert_eq!(&x, &z);
diff --git a/tests/ui/suspicious_to_owned.rs b/tests/ui/suspicious_to_owned.rs
new file mode 100644
index 00000000000..cba21bf4a93
--- /dev/null
+++ b/tests/ui/suspicious_to_owned.rs
@@ -0,0 +1,62 @@
+#![warn(clippy::suspicious_to_owned)]
+#![warn(clippy::implicit_clone)]
+#![allow(clippy::redundant_clone)]
+use std::borrow::Cow;
+use std::ffi::{c_char, CStr};
+
+fn main() {
+    let moo = "Moooo";
+    let c_moo = b"Moooo\0";
+    let c_moo_ptr = c_moo.as_ptr() as *const c_char;
+    let moos = ['M', 'o', 'o'];
+    let moos_vec = moos.to_vec();
+
+    // we expect this to be linted
+    let cow = Cow::Borrowed(moo);
+    let _ = cow.to_owned();
+    // we expect no lints for this
+    let cow = Cow::Borrowed(moo);
+    let _ = cow.into_owned();
+    // we expect no lints for this
+    let cow = Cow::Borrowed(moo);
+    let _ = cow.clone();
+
+    // we expect this to be linted
+    let cow = Cow::Borrowed(&moos);
+    let _ = cow.to_owned();
+    // we expect no lints for this
+    let cow = Cow::Borrowed(&moos);
+    let _ = cow.into_owned();
+    // we expect no lints for this
+    let cow = Cow::Borrowed(&moos);
+    let _ = cow.clone();
+
+    // we expect this to be linted
+    let cow = Cow::Borrowed(&moos_vec);
+    let _ = cow.to_owned();
+    // we expect no lints for this
+    let cow = Cow::Borrowed(&moos_vec);
+    let _ = cow.into_owned();
+    // we expect no lints for this
+    let cow = Cow::Borrowed(&moos_vec);
+    let _ = cow.clone();
+
+    // we expect this to be linted
+    let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy();
+    let _ = cow.to_owned();
+    // we expect no lints for this
+    let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy();
+    let _ = cow.into_owned();
+    // we expect no lints for this
+    let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy();
+    let _ = cow.clone();
+
+    // we expect no lints for these
+    let _ = moo.to_owned();
+    let _ = c_moo.to_owned();
+    let _ = moos.to_owned();
+
+    // we expect implicit_clone lints for these
+    let _ = String::from(moo).to_owned();
+    let _ = moos_vec.to_owned();
+}
diff --git a/tests/ui/suspicious_to_owned.stderr b/tests/ui/suspicious_to_owned.stderr
new file mode 100644
index 00000000000..92e1024bf1f
--- /dev/null
+++ b/tests/ui/suspicious_to_owned.stderr
@@ -0,0 +1,42 @@
+error: this `to_owned` call clones the std::borrow::Cow<str> itself and does not cause the std::borrow::Cow<str> contents to become owned
+  --> $DIR/suspicious_to_owned.rs:16:13
+   |
+LL |     let _ = cow.to_owned();
+   |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+   |
+   = note: `-D clippy::suspicious-to-owned` implied by `-D warnings`
+
+error: this `to_owned` call clones the std::borrow::Cow<[char; 3]> itself and does not cause the std::borrow::Cow<[char; 3]> contents to become owned
+  --> $DIR/suspicious_to_owned.rs:26:13
+   |
+LL |     let _ = cow.to_owned();
+   |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+
+error: this `to_owned` call clones the std::borrow::Cow<std::vec::Vec<char>> itself and does not cause the std::borrow::Cow<std::vec::Vec<char>> contents to become owned
+  --> $DIR/suspicious_to_owned.rs:36:13
+   |
+LL |     let _ = cow.to_owned();
+   |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+
+error: this `to_owned` call clones the std::borrow::Cow<str> itself and does not cause the std::borrow::Cow<str> contents to become owned
+  --> $DIR/suspicious_to_owned.rs:46:13
+   |
+LL |     let _ = cow.to_owned();
+   |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+
+error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type
+  --> $DIR/suspicious_to_owned.rs:60:13
+   |
+LL |     let _ = String::from(moo).to_owned();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::from(moo).clone()`
+   |
+   = note: `-D clippy::implicit-clone` implied by `-D warnings`
+
+error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type
+  --> $DIR/suspicious_to_owned.rs:61:13
+   |
+LL |     let _ = moos_vec.to_owned();
+   |             ^^^^^^^^^^^^^^^^^^^ help: consider using: `moos_vec.clone()`
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed
new file mode 100644
index 00000000000..4ce5d421782
--- /dev/null
+++ b/tests/ui/trait_duplication_in_bounds.fixed
@@ -0,0 +1,112 @@
+// run-rustfix
+#![deny(clippy::trait_duplication_in_bounds)]
+#![allow(unused)]
+
+fn bad_foo<T: Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
+    unimplemented!();
+}
+
+fn bad_bar<T, U>(arg0: T, arg1: U)
+where
+    T: Clone + Copy,
+    U: Clone + Copy,
+{
+    unimplemented!();
+}
+
+fn good_bar<T: Clone + Copy, U: Clone + Copy>(arg0: T, arg1: U) {
+    unimplemented!();
+}
+
+fn good_foo<T, U>(arg0: T, arg1: U)
+where
+    T: Clone + Copy,
+    U: Clone + Copy,
+{
+    unimplemented!();
+}
+
+trait GoodSelfTraitBound: Clone + Copy {
+    fn f();
+}
+
+trait GoodSelfWhereClause {
+    fn f()
+    where
+        Self: Clone + Copy;
+}
+
+trait BadSelfTraitBound: Clone {
+    fn f();
+}
+
+trait BadSelfWhereClause {
+    fn f()
+    where
+        Self: Clone;
+}
+
+trait GoodTraitBound<T: Clone + Copy, U: Clone + Copy> {
+    fn f();
+}
+
+trait GoodWhereClause<T, U> {
+    fn f()
+    where
+        T: Clone + Copy,
+        U: Clone + Copy;
+}
+
+trait BadTraitBound<T: Clone + Copy, U: Clone + Copy> {
+    fn f();
+}
+
+trait BadWhereClause<T, U> {
+    fn f()
+    where
+        T: Clone + Copy,
+        U: Clone + Copy;
+}
+
+struct GoodStructBound<T: Clone + Copy, U: Clone + Copy> {
+    t: T,
+    u: U,
+}
+
+impl<T: Clone + Copy, U: Clone + Copy> GoodTraitBound<T, U> for GoodStructBound<T, U> {
+    // this should not warn
+    fn f() {}
+}
+
+struct GoodStructWhereClause;
+
+impl<T, U> GoodTraitBound<T, U> for GoodStructWhereClause
+where
+    T: Clone + Copy,
+    U: Clone + Copy,
+{
+    // this should not warn
+    fn f() {}
+}
+
+fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
+
+trait GenericTrait<T> {}
+
+fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
+    unimplemented!();
+}
+
+fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
+    unimplemented!();
+}
+
+mod foo {
+    pub trait Clone {}
+}
+
+fn qualified_path<T: std::clone::Clone + foo::Clone>(arg0: T) {
+    unimplemented!();
+}
+
+fn main() {}
diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs
index a5751c58aab..7f2e96a22e6 100644
--- a/tests/ui/trait_duplication_in_bounds.rs
+++ b/tests/ui/trait_duplication_in_bounds.rs
@@ -1,212 +1,112 @@
+// run-rustfix
 #![deny(clippy::trait_duplication_in_bounds)]
 #![allow(unused)]
 
-use std::collections::BTreeMap;
-use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
+fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
+    unimplemented!();
+}
 
-fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+fn bad_bar<T, U>(arg0: T, arg1: U)
 where
-    T: Clone,
-    T: Default,
+    T: Clone + Clone + Clone + Copy,
+    U: Clone + Copy,
 {
     unimplemented!();
 }
 
-fn good_bar<T: Clone + Default>(arg: T) {
+fn good_bar<T: Clone + Copy, U: Clone + Copy>(arg0: T, arg1: U) {
     unimplemented!();
 }
 
-fn good_foo<T>(arg: T)
+fn good_foo<T, U>(arg0: T, arg1: U)
 where
-    T: Clone + Default,
+    T: Clone + Copy,
+    U: Clone + Copy,
 {
     unimplemented!();
 }
 
-fn good_foobar<T: Default>(arg: T)
-where
-    T: Clone,
-{
-    unimplemented!();
+trait GoodSelfTraitBound: Clone + Copy {
+    fn f();
 }
 
-trait T: Default {
+trait GoodSelfWhereClause {
     fn f()
     where
-        Self: Default;
+        Self: Clone + Copy;
 }
 
-trait U: Default {
+trait BadSelfTraitBound: Clone + Clone + Clone {
+    fn f();
+}
+
+trait BadSelfWhereClause {
     fn f()
     where
-        Self: Clone;
+        Self: Clone + Clone + Clone;
 }
 
-trait ZZ: Default {
-    fn g();
-    fn h();
+trait GoodTraitBound<T: Clone + Copy, U: Clone + Copy> {
+    fn f();
+}
+
+trait GoodWhereClause<T, U> {
     fn f()
     where
-        Self: Default + Clone;
+        T: Clone + Copy,
+        U: Clone + Copy;
 }
 
-trait BadTrait: Default + Clone {
+trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
+    fn f();
+}
+
+trait BadWhereClause<T, U> {
     fn f()
-    where
-        Self: Default + Clone;
-    fn g()
-    where
-        Self: Default;
-    fn h()
-    where
-        Self: Copy;
-}
-
-#[derive(Default, Clone)]
-struct Life;
-
-impl T for Life {
-    // this should not warn
-    fn f() {}
-}
-
-impl U for Life {
-    // this should not warn
-    fn f() {}
-}
-
-// should not warn
-trait Iter: Iterator {
-    fn into_group_btreemap<K, V>(self) -> BTreeMap<K, Vec<V>>
-    where
-        Self: Iterator<Item = (K, V)> + Sized,
-        K: Ord + Eq,
-    {
-        unimplemented!();
-    }
-}
-
-struct Foo;
-
-trait FooIter: Iterator<Item = Foo> {
-    fn bar()
-    where
-        Self: Iterator<Item = Foo>,
-    {
-    }
-}
-
-// This should not lint
-fn impl_trait(_: impl AsRef<str>, _: impl AsRef<str>) {}
-
-mod repeated_where_clauses_or_trait_bounds {
-    fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
-        unimplemented!();
-    }
-
-    fn bad_bar<T, U>(arg0: T, arg1: U)
     where
         T: Clone + Clone + Clone + Copy,
-        U: Clone + Copy,
-    {
-        unimplemented!();
-    }
+        U: Clone + Copy;
+}
 
-    fn good_bar<T: Clone + Copy, U: Clone + Copy>(arg0: T, arg1: U) {
-        unimplemented!();
-    }
+struct GoodStructBound<T: Clone + Copy, U: Clone + Copy> {
+    t: T,
+    u: U,
+}
 
-    fn good_foo<T, U>(arg0: T, arg1: U)
-    where
-        T: Clone + Copy,
-        U: Clone + Copy,
-    {
-        unimplemented!();
-    }
+impl<T: Clone + Copy, U: Clone + Copy> GoodTraitBound<T, U> for GoodStructBound<T, U> {
+    // this should not warn
+    fn f() {}
+}
 
-    trait GoodSelfTraitBound: Clone + Copy {
-        fn f();
-    }
+struct GoodStructWhereClause;
 
-    trait GoodSelfWhereClause {
-        fn f()
-        where
-            Self: Clone + Copy;
-    }
+impl<T, U> GoodTraitBound<T, U> for GoodStructWhereClause
+where
+    T: Clone + Copy,
+    U: Clone + Copy,
+{
+    // this should not warn
+    fn f() {}
+}
 
-    trait BadSelfTraitBound: Clone + Clone + Clone {
-        fn f();
-    }
+fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
 
-    trait BadSelfWhereClause {
-        fn f()
-        where
-            Self: Clone + Clone + Clone;
-    }
+trait GenericTrait<T> {}
 
-    trait GoodTraitBound<T: Clone + Copy, U: Clone + Copy> {
-        fn f();
-    }
+fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
+    unimplemented!();
+}
 
-    trait GoodWhereClause<T, U> {
-        fn f()
-        where
-            T: Clone + Copy,
-            U: Clone + Copy;
-    }
+fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
+    unimplemented!();
+}
 
-    trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
-        fn f();
-    }
+mod foo {
+    pub trait Clone {}
+}
 
-    trait BadWhereClause<T, U> {
-        fn f()
-        where
-            T: Clone + Clone + Clone + Copy,
-            U: Clone + Copy;
-    }
-
-    struct GoodStructBound<T: Clone + Copy, U: Clone + Copy> {
-        t: T,
-        u: U,
-    }
-
-    impl<T: Clone + Copy, U: Clone + Copy> GoodTraitBound<T, U> for GoodStructBound<T, U> {
-        // this should not warn
-        fn f() {}
-    }
-
-    struct GoodStructWhereClause;
-
-    impl<T, U> GoodTraitBound<T, U> for GoodStructWhereClause
-    where
-        T: Clone + Copy,
-        U: Clone + Copy,
-    {
-        // this should not warn
-        fn f() {}
-    }
-
-    fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {}
-
-    trait GenericTrait<T> {}
-
-    // This should not warn but currently does see #8757
-    fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
-        unimplemented!();
-    }
-
-    fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
-        unimplemented!();
-    }
-
-    mod foo {
-        pub trait Clone {}
-    }
-
-    fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
-        unimplemented!();
-    }
+fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
+    unimplemented!();
 }
 
 fn main() {}
diff --git a/tests/ui/trait_duplication_in_bounds.stderr b/tests/ui/trait_duplication_in_bounds.stderr
index 7ef04e52708..af800ba7888 100644
--- a/tests/ui/trait_duplication_in_bounds.stderr
+++ b/tests/ui/trait_duplication_in_bounds.stderr
@@ -1,167 +1,56 @@
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:7:15
+error: these bounds contain repeated elements
+  --> $DIR/trait_duplication_in_bounds.rs:5:15
    |
-LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
-   |               ^^^^^
+LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
    |
 note: the lint level is defined here
-  --> $DIR/trait_duplication_in_bounds.rs:1:9
+  --> $DIR/trait_duplication_in_bounds.rs:2:9
    |
 LL | #![deny(clippy::trait_duplication_in_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:7:23
-   |
-LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
-   |                       ^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:36:15
-   |
-LL |         Self: Default;
-   |               ^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:50:15
-   |
-LL |         Self: Default + Clone;
-   |               ^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:56:15
-   |
-LL |         Self: Default + Clone;
-   |               ^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:56:25
-   |
-LL |         Self: Default + Clone;
-   |                         ^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:59:15
-   |
-LL |         Self: Default;
-   |               ^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:94:15
-   |
-LL |         Self: Iterator<Item = Foo>,
-   |               ^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:103:19
-   |
-LL |     fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
-   |                   ^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:103:19
-   |
-LL |     fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) {
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:109:12
-   |
-LL |         T: Clone + Clone + Clone + Copy,
-   |            ^^^^^
-   |
-   = help: consider removing this trait bound
 
 error: these where clauses contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:109:12
+  --> $DIR/trait_duplication_in_bounds.rs:11: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
+   |
+LL | trait BadSelfTraitBound: Clone + Clone + Clone {
+   |                          ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
+
+error: these where clauses contain repeated elements
+  --> $DIR/trait_duplication_in_bounds.rs:46:15
+   |
+LL |         Self: Clone + Clone + Clone;
+   |               ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
+
+error: these bounds contain repeated elements
+  --> $DIR/trait_duplication_in_bounds.rs:60: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
    |
 LL |         T: Clone + Clone + Clone + Copy,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
 
 error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:137:30
+  --> $DIR/trait_duplication_in_bounds.rs:100:19
    |
-LL |     trait BadSelfTraitBound: Clone + Clone + Clone {
-   |                              ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
-
-error: these where clauses contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:144:19
-   |
-LL |             Self: Clone + Clone + Clone;
-   |                   ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone`
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:158:28
-   |
-LL |     trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
-   |                            ^^^^^
-   |
-   = help: consider removing this trait bound
+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:158:28
+  --> $DIR/trait_duplication_in_bounds.rs:108:22
    |
-LL |     trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> {
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
+LL | fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone`
 
-error: these where clauses contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:165:16
-   |
-LL |             T: Clone + Clone + Clone + Copy,
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy`
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:195:24
-   |
-LL |     fn good_generic<T: GenericTrait<u64> + GenericTrait<u32>>(arg0: T) {
-   |                        ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:199:23
-   |
-LL |     fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
-   |                       ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:199:23
-   |
-LL |     fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) {
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait<u32> + GenericTrait<u64>`
-
-error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:207:26
-   |
-LL |     fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
-   |                          ^^^^^^^^^^^^^^^^^
-   |
-   = help: consider removing this trait bound
-
-error: these bounds contain repeated elements
-  --> $DIR/trait_duplication_in_bounds.rs:207:26
-   |
-LL |     fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) {
-   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + foo::Clone`
-
-error: aborting due to 22 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.rs b/tests/ui/trait_duplication_in_bounds_unfixable.rs
new file mode 100644
index 00000000000..5630a0345ad
--- /dev/null
+++ b/tests/ui/trait_duplication_in_bounds_unfixable.rs
@@ -0,0 +1,166 @@
+#![deny(clippy::trait_duplication_in_bounds)]
+
+use std::collections::BTreeMap;
+use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
+
+fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+where
+    T: Clone,
+    T: Default,
+{
+    unimplemented!();
+}
+
+fn good_bar<T: Clone + Default>(arg: T) {
+    unimplemented!();
+}
+
+fn good_foo<T>(arg: T)
+where
+    T: Clone + Default,
+{
+    unimplemented!();
+}
+
+fn good_foobar<T: Default>(arg: T)
+where
+    T: Clone,
+{
+    unimplemented!();
+}
+
+trait T: Default {
+    fn f()
+    where
+        Self: Default;
+}
+
+trait U: Default {
+    fn f()
+    where
+        Self: Clone;
+}
+
+trait ZZ: Default {
+    fn g();
+    fn h();
+    fn f()
+    where
+        Self: Default + Clone;
+}
+
+trait BadTrait: Default + Clone {
+    fn f()
+    where
+        Self: Default + Clone;
+    fn g()
+    where
+        Self: Default;
+    fn h()
+    where
+        Self: Copy;
+}
+
+#[derive(Default, Clone)]
+struct Life;
+
+impl T for Life {
+    // this should not warn
+    fn f() {}
+}
+
+impl U for Life {
+    // this should not warn
+    fn f() {}
+}
+
+// should not warn
+trait Iter: Iterator {
+    fn into_group_btreemap<K, V>(self) -> BTreeMap<K, Vec<V>>
+    where
+        Self: Iterator<Item = (K, V)> + Sized,
+        K: Ord + Eq,
+    {
+        unimplemented!();
+    }
+}
+
+struct Foo;
+
+trait FooIter: Iterator<Item = Foo> {
+    fn bar()
+    where
+        Self: Iterator<Item = Foo>,
+    {
+    }
+}
+
+// The below should not lint and exist to guard against false positives
+fn impl_trait(_: impl AsRef<str>, _: impl AsRef<str>) {}
+
+pub mod one {
+    #[derive(Clone, Debug)]
+    struct MultiProductIter<I>
+    where
+        I: Iterator + Clone,
+        I::Item: Clone,
+    {
+        _marker: I,
+    }
+
+    pub struct MultiProduct<I>(Vec<MultiProductIter<I>>)
+    where
+        I: Iterator + Clone,
+        I::Item: Clone;
+
+    pub fn multi_cartesian_product<H>(_: H) -> MultiProduct<<H::Item as IntoIterator>::IntoIter>
+    where
+        H: Iterator,
+        H::Item: IntoIterator,
+        <H::Item as IntoIterator>::IntoIter: Clone,
+        <H::Item as IntoIterator>::Item: Clone,
+    {
+        todo!()
+    }
+}
+
+pub mod two {
+    use std::iter::Peekable;
+
+    pub struct MergeBy<I, J, F>
+    where
+        I: Iterator,
+        J: Iterator<Item = I::Item>,
+    {
+        _i: Peekable<I>,
+        _j: Peekable<J>,
+        _f: F,
+    }
+
+    impl<I, J, F> Clone for MergeBy<I, J, F>
+    where
+        I: Iterator,
+        J: Iterator<Item = I::Item>,
+        std::iter::Peekable<I>: Clone,
+        std::iter::Peekable<J>: Clone,
+        F: Clone,
+    {
+        fn clone(&self) -> Self {
+            Self {
+                _i: self._i.clone(),
+                _j: self._j.clone(),
+                _f: self._f.clone(),
+            }
+        }
+    }
+}
+
+pub trait Trait {}
+
+pub fn f(_a: impl Trait, _b: impl Trait) {}
+
+pub trait ImplTrait<T> {}
+
+impl<A, B> ImplTrait<(A, B)> for Foo where Foo: ImplTrait<A> + ImplTrait<B> {}
+
+fn main() {}
diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.stderr b/tests/ui/trait_duplication_in_bounds_unfixable.stderr
new file mode 100644
index 00000000000..fbd9abb005f
--- /dev/null
+++ b/tests/ui/trait_duplication_in_bounds_unfixable.stderr
@@ -0,0 +1,71 @@
+error: this trait bound is already specified in the where clause
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:15
+   |
+LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+   |               ^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:1:9
+   |
+LL | #![deny(clippy::trait_duplication_in_bounds)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in the where clause
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:23
+   |
+LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
+   |                       ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:35:15
+   |
+LL |         Self: Default;
+   |               ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:49:15
+   |
+LL |         Self: Default + Clone;
+   |               ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:15
+   |
+LL |         Self: Default + Clone;
+   |               ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:25
+   |
+LL |         Self: Default + Clone;
+   |                         ^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:58:15
+   |
+LL |         Self: Default;
+   |               ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds_unfixable.rs:93:15
+   |
+LL |         Self: Iterator<Item = Foo>,
+   |               ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/transmute_undefined_repr.rs b/tests/ui/transmute_undefined_repr.rs
index ebcaa7a84cf..5aad0b44270 100644
--- a/tests/ui/transmute_undefined_repr.rs
+++ b/tests/ui/transmute_undefined_repr.rs
@@ -4,6 +4,7 @@
 use core::any::TypeId;
 use core::ffi::c_void;
 use core::mem::{size_of, transmute, MaybeUninit};
+use core::ptr::NonNull;
 
 fn value<T>() -> T {
     unimplemented!()
@@ -109,6 +110,17 @@ fn main() {
         let _: Ty2<u32, u32> = transmute(value::<MaybeUninit<Ty2<u32, u32>>>()); // Ok
 
         let _: Ty<&[u32]> = transmute::<&[u32], _>(value::<&Vec<u32>>()); // Ok
+
+        let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<Ty2<u32, u32>, u32>>()); // Ok
+        let _: *const Ty2C<Ty2<u32, u32>, u32> = transmute(value::<*const Ty2<u32, u32>>()); // Ok
+        let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<(), Ty2<u32, u32>>>()); // Ok
+        let _: *const Ty2C<(), Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Ok
+
+        let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>()); // Err
+        let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Err
+
+        let _: NonNull<u8> = transmute(value::<NonNull<(String, String)>>()); // Ok
+        let _: NonNull<(String, String)> = transmute(value::<NonNull<u8>>()); // Ok
     }
 }
 
diff --git a/tests/ui/transmute_undefined_repr.stderr b/tests/ui/transmute_undefined_repr.stderr
index 28bfba6c757..e50a773290e 100644
--- a/tests/ui/transmute_undefined_repr.stderr
+++ b/tests/ui/transmute_undefined_repr.stderr
@@ -1,5 +1,5 @@
 error: transmute from `Ty2<u32, i32>` which has an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:27:33
+  --> $DIR/transmute_undefined_repr.rs:28:33
    |
 LL |         let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>()); // Lint, Ty2 is unordered
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,13 +7,13 @@ LL |         let _: Ty2C<u32, i32> = transmute(value::<Ty2<u32, i32>>()); // Lin
    = note: `-D clippy::transmute-undefined-repr` implied by `-D warnings`
 
 error: transmute into `Ty2<u32, i32>` which has an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:28:32
+  --> $DIR/transmute_undefined_repr.rs:29:32
    |
 LL |         let _: Ty2<u32, i32> = transmute(value::<Ty2C<u32, i32>>()); // Lint, Ty2 is unordered
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from `Ty<Ty2<u32, i32>>` to `Ty2<u32, f32>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:33:32
+  --> $DIR/transmute_undefined_repr.rs:34:32
    |
 LL |         let _: Ty2<u32, f32> = transmute(value::<Ty<Ty2<u32, i32>>>()); // Lint, different Ty2 instances
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -21,7 +21,7 @@ LL |         let _: Ty2<u32, f32> = transmute(value::<Ty<Ty2<u32, i32>>>()); //
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `Ty2<u32, f32>` to `Ty<Ty2<u32, i32>>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:34:36
+  --> $DIR/transmute_undefined_repr.rs:35:36
    |
 LL |         let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, f32>>()); // Lint, different Ty2 instances
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL |         let _: Ty<Ty2<u32, i32>> = transmute(value::<Ty2<u32, f32>>()); //
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `Ty<&Ty2<u32, i32>>` to `&Ty2<u32, f32>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:39:33
+  --> $DIR/transmute_undefined_repr.rs:40:33
    |
 LL |         let _: &Ty2<u32, f32> = transmute(value::<Ty<&Ty2<u32, i32>>>()); // Lint, different Ty2 instances
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL |         let _: &Ty2<u32, f32> = transmute(value::<Ty<&Ty2<u32, i32>>>()); /
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `&Ty2<u32, f32>` to `Ty<&Ty2<u32, i32>>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:40:37
+  --> $DIR/transmute_undefined_repr.rs:41:37
    |
 LL |         let _: Ty<&Ty2<u32, i32>> = transmute(value::<&Ty2<u32, f32>>()); // Lint, different Ty2 instances
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL |         let _: Ty<&Ty2<u32, i32>> = transmute(value::<&Ty2<u32, f32>>()); /
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `std::boxed::Box<Ty2<u32, u32>>` to `&mut Ty2<u32, f32>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:57:45
+  --> $DIR/transmute_undefined_repr.rs:58:45
    |
 LL |         let _: &'static mut Ty2<u32, f32> = transmute(value::<Box<Ty2<u32, u32>>>()); // Lint, different Ty2 instances
    |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,15 +53,31 @@ LL |         let _: &'static mut Ty2<u32, f32> = transmute(value::<Box<Ty2<u32,
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
 error: transmute from `&mut Ty2<u32, f32>` to `std::boxed::Box<Ty2<u32, u32>>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:58:37
+  --> $DIR/transmute_undefined_repr.rs:59:37
    |
 LL |         let _: Box<Ty2<u32, u32>> = transmute(value::<&'static mut Ty2<u32, f32>>()); // Lint, different Ty2 instances
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: two instances of the same generic type (`Ty2`) may have different layouts
 
+error: transmute into `*const Ty2<u32, u32>` which has an undefined layout
+  --> $DIR/transmute_undefined_repr.rs:119:39
+   |
+LL |         let _: *const Ty2<u32, u32> = transmute(value::<*const Ty2C<u32, Ty2<u32, u32>>>()); // Err
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the contained type `Ty2<u32, u32>` has an undefined layout
+
+error: transmute from `*const Ty2<u32, u32>` which has an undefined layout
+  --> $DIR/transmute_undefined_repr.rs:120:50
+   |
+LL |         let _: *const Ty2C<u32, Ty2<u32, u32>> = transmute(value::<*const Ty2<u32, u32>>()); // Err
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the contained type `Ty2<u32, u32>` has an undefined layout
+
 error: transmute from `std::vec::Vec<Ty2<U, i32>>` to `std::vec::Vec<Ty2<T, u32>>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:138:35
+  --> $DIR/transmute_undefined_repr.rs:150:35
    |
 LL |         let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); // Err
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -69,12 +85,12 @@ LL |         let _: Vec<Ty2<T, u32>> = transmute(value::<Vec<Ty2<U, i32>>>()); /
    = note: two instances of the same generic type (`Vec`) may have different layouts
 
 error: transmute from `std::vec::Vec<Ty2<T, u32>>` to `std::vec::Vec<Ty2<U, i32>>`, both of which have an undefined layout
-  --> $DIR/transmute_undefined_repr.rs:139:35
+  --> $DIR/transmute_undefined_repr.rs:151:35
    |
 LL |         let _: Vec<Ty2<U, i32>> = transmute(value::<Vec<Ty2<T, u32>>>()); // Err
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: two instances of the same generic type (`Vec`) may have different layouts
 
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/tests/ui/unicode.fixed b/tests/ui/unicode.fixed
index 328cda369e1..94b4723452f 100644
--- a/tests/ui/unicode.fixed
+++ b/tests/ui/unicode.fixed
@@ -1,4 +1,7 @@
 // run-rustfix
+// compile-flags: --test
+#![allow(dead_code)]
+
 #[warn(clippy::invisible_characters)]
 fn zero() {
     print!("Here >\u{200B}< is a ZWS, and \u{200B}another");
@@ -15,22 +18,43 @@ fn canon() {
     print!("a\u{0300}h?"); // also ok
 }
 
-#[warn(clippy::non_ascii_literal)]
-fn uni() {
-    print!("\u{dc}ben!");
-    print!("\u{DC}ben!"); // this is ok
-}
+mod non_ascii_literal {
+    #![deny(clippy::non_ascii_literal)]
 
-// issue 8013
-#[warn(clippy::non_ascii_literal)]
-fn single_quote() {
-    const _EMPTY_BLOCK: char = '\u{25b1}';
-    const _FULL_BLOCK: char = '\u{25b0}';
+    fn uni() {
+        print!("\u{dc}ben!");
+        print!("\u{DC}ben!"); // this is ok
+    }
+
+    // issue 8013
+    fn single_quote() {
+        const _EMPTY_BLOCK: char = '\u{25b1}';
+        const _FULL_BLOCK: char = '\u{25b0}';
+    }
+
+    #[test]
+    pub fn issue_7739() {
+        // Ryū crate: https://github.com/dtolnay/ryu
+    }
+
+    mod issue_8263 {
+        #![deny(clippy::non_ascii_literal)]
+
+        // Re-allow for a single test
+        #[test]
+        #[allow(clippy::non_ascii_literal)]
+        fn allowed() {
+            let _ = "悲しいかな、ここに日本語を書くことはできない。";
+        }
+
+        #[test]
+        fn denied() {
+            let _ = "\u{60b2}\u{3057}\u{3044}\u{304b}\u{306a}\u{3001}\u{3053}\u{3053}\u{306b}\u{65e5}\u{672c}\u{8a9e}\u{3092}\u{66f8}\u{304f}\u{3053}\u{3068}\u{306f}\u{3067}\u{304d}\u{306a}\u{3044}\u{3002}";
+        }
+    }
 }
 
 fn main() {
     zero();
-    uni();
     canon();
-    single_quote();
 }
diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs
index 7828d6bcbea..6ad0b255b94 100644
--- a/tests/ui/unicode.rs
+++ b/tests/ui/unicode.rs
@@ -1,4 +1,7 @@
 // run-rustfix
+// compile-flags: --test
+#![allow(dead_code)]
+
 #[warn(clippy::invisible_characters)]
 fn zero() {
     print!("Here >​< is a ZWS, and ​another");
@@ -15,22 +18,43 @@ fn canon() {
     print!("a\u{0300}h?"); // also ok
 }
 
-#[warn(clippy::non_ascii_literal)]
-fn uni() {
-    print!("Üben!");
-    print!("\u{DC}ben!"); // this is ok
-}
+mod non_ascii_literal {
+    #![deny(clippy::non_ascii_literal)]
 
-// issue 8013
-#[warn(clippy::non_ascii_literal)]
-fn single_quote() {
-    const _EMPTY_BLOCK: char = '▱';
-    const _FULL_BLOCK: char = '▰';
+    fn uni() {
+        print!("Üben!");
+        print!("\u{DC}ben!"); // this is ok
+    }
+
+    // issue 8013
+    fn single_quote() {
+        const _EMPTY_BLOCK: char = '▱';
+        const _FULL_BLOCK: char = '▰';
+    }
+
+    #[test]
+    pub fn issue_7739() {
+        // Ryū crate: https://github.com/dtolnay/ryu
+    }
+
+    mod issue_8263 {
+        #![deny(clippy::non_ascii_literal)]
+
+        // Re-allow for a single test
+        #[test]
+        #[allow(clippy::non_ascii_literal)]
+        fn allowed() {
+            let _ = "悲しいかな、ここに日本語を書くことはできない。";
+        }
+
+        #[test]
+        fn denied() {
+            let _ = "悲しいかな、ここに日本語を書くことはできない。";
+        }
+    }
 }
 
 fn main() {
     zero();
-    uni();
     canon();
-    single_quote();
 }
diff --git a/tests/ui/unicode.stderr b/tests/ui/unicode.stderr
index 01d3f3c0296..ea74a81451e 100644
--- a/tests/ui/unicode.stderr
+++ b/tests/ui/unicode.stderr
@@ -1,5 +1,5 @@
 error: invisible character detected
-  --> $DIR/unicode.rs:4:12
+  --> $DIR/unicode.rs:7:12
    |
 LL |     print!("Here >​< is a ZWS, and ​another");
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{200B}< is a ZWS, and /u{200B}another"`
@@ -7,19 +7,19 @@ LL |     print!("Here >​< is a ZWS, and ​another");
    = note: `-D clippy::invisible-characters` implied by `-D warnings`
 
 error: invisible character detected
-  --> $DIR/unicode.rs:6:12
+  --> $DIR/unicode.rs:9:12
    |
 LL |     print!("Here >­< is a SHY, and ­another");
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{AD}< is a SHY, and /u{AD}another"`
 
 error: invisible character detected
-  --> $DIR/unicode.rs:8:12
+  --> $DIR/unicode.rs:11:12
    |
 LL |     print!("Here >⁠< is a WJ, and ⁠another");
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{2060}< is a WJ, and /u{2060}another"`
 
 error: non-NFC Unicode sequence detected
-  --> $DIR/unicode.rs:14:12
+  --> $DIR/unicode.rs:17:12
    |
 LL |     print!("̀àh?");
    |            ^^^^^ help: consider replacing the string with: `"̀àh?"`
@@ -27,24 +27,40 @@ LL |     print!("̀àh?");
    = note: `-D clippy::unicode-not-nfc` implied by `-D warnings`
 
 error: literal non-ASCII character detected
-  --> $DIR/unicode.rs:20:12
+  --> $DIR/unicode.rs:25:16
    |
-LL |     print!("Üben!");
-   |            ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"`
+LL |         print!("Üben!");
+   |                ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"`
    |
-   = note: `-D clippy::non-ascii-literal` implied by `-D warnings`
+note: the lint level is defined here
+  --> $DIR/unicode.rs:22:13
+   |
+LL |     #![deny(clippy::non_ascii_literal)]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: literal non-ASCII character detected
-  --> $DIR/unicode.rs:27:32
+  --> $DIR/unicode.rs:31:36
    |
-LL |     const _EMPTY_BLOCK: char = '▱';
-   |                                ^^^ help: consider replacing the string with: `'/u{25b1}'`
+LL |         const _EMPTY_BLOCK: char = '▱';
+   |                                    ^^^ help: consider replacing the string with: `'/u{25b1}'`
 
 error: literal non-ASCII character detected
-  --> $DIR/unicode.rs:28:31
+  --> $DIR/unicode.rs:32:35
    |
-LL |     const _FULL_BLOCK: char = '▰';
-   |                               ^^^ help: consider replacing the string with: `'/u{25b0}'`
+LL |         const _FULL_BLOCK: char = '▰';
+   |                                   ^^^ help: consider replacing the string with: `'/u{25b0}'`
 
-error: aborting due to 7 previous errors
+error: literal non-ASCII character detected
+  --> $DIR/unicode.rs:52:21
+   |
+LL |             let _ = "悲しいかな、ここに日本語を書くことはできない。";
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"/u{60b2}/u{3057}/u{3044}/u{304b}/u{306a}/u{3001}/u{3053}/u{3053}/u{306b}/u{65e5}/u{672c}/u{8a9e}/u{3092}/u{66f8}/u{304f}/u{3053}/u{3068}/u{306f}/u{3067}/u{304d}/u{306a}/u{3044}/u{3002}"`
+   |
+note: the lint level is defined here
+  --> $DIR/unicode.rs:41:17
+   |
+LL |         #![deny(clippy::non_ascii_literal)]
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed
index b352b285c86..ee9f157342d 100644
--- a/tests/ui/unnecessary_cast.fixed
+++ b/tests/ui/unnecessary_cast.fixed
@@ -88,4 +88,13 @@ mod fixable {
     }
 
     type I32Alias = i32;
+
+    fn issue_9380() {
+        let _: i32 = -1_i32;
+        let _: f32 = -(1) as f32;
+        let _: i64 = -1_i64;
+        let _: i64 = -(1.0) as i64;
+
+        let _ = -(1 + 1) as i64;
+    }
 }
diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs
index 6c8cc3effe8..5b70412424c 100644
--- a/tests/ui/unnecessary_cast.rs
+++ b/tests/ui/unnecessary_cast.rs
@@ -88,4 +88,13 @@ mod fixable {
     }
 
     type I32Alias = i32;
+
+    fn issue_9380() {
+        let _: i32 = -(1) as i32;
+        let _: f32 = -(1) as f32;
+        let _: i64 = -(1) as i64;
+        let _: i64 = -(1.0) as i64;
+
+        let _ = -(1 + 1) as i64;
+    }
 }
diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr
index bad45f0025b..f7829ff3b0e 100644
--- a/tests/ui/unnecessary_cast.stderr
+++ b/tests/ui/unnecessary_cast.stderr
@@ -150,5 +150,17 @@ error: casting float literal to `f32` is unnecessary
 LL |         let _ = -1.0 as f32;
    |                 ^^^^^^^^^^^ help: try: `-1.0_f32`
 
-error: aborting due to 25 previous errors
+error: casting integer literal to `i32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:93:22
+   |
+LL |         let _: i32 = -(1) as i32;
+   |                      ^^^^^^^^^^^ help: try: `-1_i32`
+
+error: casting integer literal to `i64` is unnecessary
+  --> $DIR/unnecessary_cast.rs:95:22
+   |
+LL |         let _: i64 = -(1) as i64;
+   |                      ^^^^^^^^^^^ help: try: `-1_i64`
+
+error: aborting due to 27 previous errors
 
diff --git a/tests/ui/unnecessary_owned_empty_strings.fixed b/tests/ui/unnecessary_owned_empty_strings.fixed
index f95f91329a2..40052c41039 100644
--- a/tests/ui/unnecessary_owned_empty_strings.fixed
+++ b/tests/ui/unnecessary_owned_empty_strings.fixed
@@ -12,6 +12,7 @@ fn main() {
     ref_str_argument("");
 
     // should be linted
+    #[allow(clippy::manual_string_new)]
     ref_str_argument("");
 
     // should not be linted
diff --git a/tests/ui/unnecessary_owned_empty_strings.rs b/tests/ui/unnecessary_owned_empty_strings.rs
index 0cbdc151ed9..2304dff5192 100644
--- a/tests/ui/unnecessary_owned_empty_strings.rs
+++ b/tests/ui/unnecessary_owned_empty_strings.rs
@@ -12,6 +12,7 @@ fn main() {
     ref_str_argument(&String::new());
 
     // should be linted
+    #[allow(clippy::manual_string_new)]
     ref_str_argument(&String::from(""));
 
     // should not be linted
diff --git a/tests/ui/unnecessary_owned_empty_strings.stderr b/tests/ui/unnecessary_owned_empty_strings.stderr
index 46bc4597b33..1eb198a8675 100644
--- a/tests/ui/unnecessary_owned_empty_strings.stderr
+++ b/tests/ui/unnecessary_owned_empty_strings.stderr
@@ -7,7 +7,7 @@ LL |     ref_str_argument(&String::new());
    = note: `-D clippy::unnecessary-owned-empty-strings` implied by `-D warnings`
 
 error: usage of `&String::from("")` for a function expecting a `&str` argument
-  --> $DIR/unnecessary_owned_empty_strings.rs:15:22
+  --> $DIR/unnecessary_owned_empty_strings.rs:16:22
    |
 LL |     ref_str_argument(&String::from(""));
    |                      ^^^^^^^^^^^^^^^^^ help: try: `""`
diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed
index f4f76cd3dd4..9cd5bc73b1e 100644
--- a/tests/ui/unnecessary_to_owned.fixed
+++ b/tests/ui/unnecessary_to_owned.fixed
@@ -329,3 +329,31 @@ mod issue_8759_variant {
         rw.set_view(&rw.default_view().to_owned());
     }
 }
+
+mod issue_9317 {
+    #![allow(dead_code)]
+
+    struct Bytes {}
+
+    impl ToString for Bytes {
+        fn to_string(&self) -> String {
+            "123".to_string()
+        }
+    }
+
+    impl AsRef<[u8]> for Bytes {
+        fn as_ref(&self) -> &[u8] {
+            &[1, 2, 3]
+        }
+    }
+
+    fn consume<C: AsRef<[u8]>>(c: C) {
+        let _ = c;
+    }
+
+    pub fn main() {
+        let b = Bytes {};
+        // Should not lint.
+        consume(b.to_string());
+    }
+}
diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs
index fe09a489ab0..7f62ba3ab5d 100644
--- a/tests/ui/unnecessary_to_owned.rs
+++ b/tests/ui/unnecessary_to_owned.rs
@@ -329,3 +329,31 @@ mod issue_8759_variant {
         rw.set_view(&rw.default_view().to_owned());
     }
 }
+
+mod issue_9317 {
+    #![allow(dead_code)]
+
+    struct Bytes {}
+
+    impl ToString for Bytes {
+        fn to_string(&self) -> String {
+            "123".to_string()
+        }
+    }
+
+    impl AsRef<[u8]> for Bytes {
+        fn as_ref(&self) -> &[u8] {
+            &[1, 2, 3]
+        }
+    }
+
+    fn consume<C: AsRef<[u8]>>(c: C) {
+        let _ = c;
+    }
+
+    pub fn main() {
+        let b = Bytes {};
+        // Should not lint.
+        consume(b.to_string());
+    }
+}
diff --git a/tests/ui/unused_peekable.rs b/tests/ui/unused_peekable.rs
new file mode 100644
index 00000000000..153457e3671
--- /dev/null
+++ b/tests/ui/unused_peekable.rs
@@ -0,0 +1,144 @@
+#![warn(clippy::unused_peekable)]
+#![allow(clippy::no_effect)]
+
+use std::iter::Empty;
+use std::iter::Peekable;
+
+fn main() {
+    invalid();
+    valid();
+}
+
+#[allow(clippy::unused_unit)]
+fn invalid() {
+    let peekable = std::iter::empty::<u32>().peekable();
+
+    // Only lint `new_local`
+    let old_local = std::iter::empty::<u32>().peekable();
+    let new_local = old_local;
+
+    // Behind mut ref
+    let mut by_mut_ref_test = std::iter::empty::<u32>().peekable();
+    let by_mut_ref = &mut by_mut_ref_test;
+
+    // Explicitly returns `Peekable`
+    fn returns_peekable() -> Peekable<Empty<u32>> {
+        std::iter::empty().peekable()
+    }
+
+    let peekable_from_fn = returns_peekable();
+
+    // Using a method not exclusive to `Peekable`
+    let mut peekable_using_iterator_method = std::iter::empty::<u32>().peekable();
+    peekable_using_iterator_method.next();
+
+    // Passed by ref to another function
+    fn takes_ref(_peek: &Peekable<Empty<u32>>) {}
+    let passed_along_ref = std::iter::empty::<u32>().peekable();
+    takes_ref(&passed_along_ref);
+
+    // `by_ref` without `peek`
+    let mut by_ref_test = std::iter::empty::<u32>().peekable();
+    let _by_ref = by_ref_test.by_ref();
+
+    let mut peekable_in_for_loop = std::iter::empty::<u32>().peekable();
+    for x in peekable_in_for_loop {}
+}
+
+fn valid() {
+    fn takes_peekable(_peek: Peekable<Empty<u32>>) {}
+
+    // Passed to another function
+    let passed_along = std::iter::empty::<u32>().peekable();
+    takes_peekable(passed_along);
+
+    // Passed to another method
+    struct PeekableConsumer;
+    impl PeekableConsumer {
+        fn consume(&self, _: Peekable<Empty<u32>>) {}
+        fn consume_mut_ref(&self, _: &mut Peekable<Empty<u32>>) {}
+    }
+
+    let peekable_consumer = PeekableConsumer;
+    let mut passed_along_to_method = std::iter::empty::<u32>().peekable();
+    peekable_consumer.consume_mut_ref(&mut passed_along_to_method);
+    peekable_consumer.consume(passed_along_to_method);
+
+    // `peek` called in another block
+    let mut peekable_in_block = std::iter::empty::<u32>().peekable();
+    {
+        peekable_in_block.peek();
+    }
+
+    // Check the other `Peekable` methods :)
+    {
+        let mut peekable_with_peek_mut = std::iter::empty::<u32>().peekable();
+        peekable_with_peek_mut.peek_mut();
+
+        let mut peekable_with_next_if = std::iter::empty::<u32>().peekable();
+        peekable_with_next_if.next_if(|_| true);
+
+        let mut peekable_with_next_if_eq = std::iter::empty::<u32>().peekable();
+        peekable_with_next_if_eq.next_if_eq(&3);
+    }
+
+    let mut peekable_in_closure = std::iter::empty::<u32>().peekable();
+    let call_peek = |p: &mut Peekable<Empty<u32>>| {
+        p.peek();
+    };
+    call_peek(&mut peekable_in_closure);
+
+    // From a macro
+    macro_rules! make_me_a_peekable_please {
+        () => {
+            std::iter::empty::<u32>().peekable()
+        };
+    }
+
+    let _unsuspecting_macro_user = make_me_a_peekable_please!();
+
+    // Generic Iterator returned
+    fn return_an_iter() -> impl Iterator<Item = u32> {
+        std::iter::empty::<u32>().peekable()
+    }
+
+    let _unsuspecting_user = return_an_iter();
+
+    // Call `peek` in a macro
+    macro_rules! peek_iter {
+        ($iter:ident) => {
+            $iter.peek();
+        };
+    }
+
+    let mut peek_in_macro = std::iter::empty::<u32>().peekable();
+    peek_iter!(peek_in_macro);
+
+    // Behind mut ref
+    let mut by_mut_ref_test = std::iter::empty::<u32>().peekable();
+    let by_mut_ref = &mut by_mut_ref_test;
+    by_mut_ref.peek();
+
+    // Behind ref
+    let mut by_ref_test = std::iter::empty::<u32>().peekable();
+    let by_ref = &by_ref_test;
+    by_ref_test.peek();
+
+    // In struct
+    struct PeekableWrapper {
+        f: Peekable<Empty<u32>>,
+    }
+
+    let struct_test = std::iter::empty::<u32>().peekable();
+    PeekableWrapper { f: struct_test };
+
+    // `by_ref` before `peek`
+    let mut by_ref_test = std::iter::empty::<u32>().peekable();
+    let peeked_val = by_ref_test.by_ref().peek();
+
+    // `peek` called in another block as the last expression
+    let mut peekable_last_expr = std::iter::empty::<u32>().peekable();
+    {
+        peekable_last_expr.peek();
+    }
+}
diff --git a/tests/ui/unused_peekable.stderr b/tests/ui/unused_peekable.stderr
new file mode 100644
index 00000000000..d557f54179d
--- /dev/null
+++ b/tests/ui/unused_peekable.stderr
@@ -0,0 +1,67 @@
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:14:9
+   |
+LL |     let peekable = std::iter::empty::<u32>().peekable();
+   |         ^^^^^^^^
+   |
+   = note: `-D clippy::unused-peekable` implied by `-D warnings`
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:18:9
+   |
+LL |     let new_local = old_local;
+   |         ^^^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:22:9
+   |
+LL |     let by_mut_ref = &mut by_mut_ref_test;
+   |         ^^^^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:29:9
+   |
+LL |     let peekable_from_fn = returns_peekable();
+   |         ^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:32:13
+   |
+LL |     let mut peekable_using_iterator_method = std::iter::empty::<u32>().peekable();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:37:9
+   |
+LL |     let passed_along_ref = std::iter::empty::<u32>().peekable();
+   |         ^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:42:9
+   |
+LL |     let _by_ref = by_ref_test.by_ref();
+   |         ^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: `peek` never called on `Peekable` iterator
+  --> $DIR/unused_peekable.rs:44:13
+   |
+LL |     let mut peekable_in_for_loop = std::iter::empty::<u32>().peekable();
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing the call to `peekable`
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/unwrap.rs b/tests/ui/unwrap.rs
index a4a3cd1d379..d9fd402e7cf 100644
--- a/tests/ui/unwrap.rs
+++ b/tests/ui/unwrap.rs
@@ -6,8 +6,9 @@ fn unwrap_option() {
 }
 
 fn unwrap_result() {
-    let res: Result<u8, ()> = Ok(0);
+    let res: Result<u8, u8> = Ok(0);
     let _ = res.unwrap();
+    let _ = res.unwrap_err();
 }
 
 fn main() {
diff --git a/tests/ui/unwrap.stderr b/tests/ui/unwrap.stderr
index 4f0858005f6..78422757819 100644
--- a/tests/ui/unwrap.stderr
+++ b/tests/ui/unwrap.stderr
@@ -15,5 +15,13 @@ LL |     let _ = res.unwrap();
    |
    = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message
 
-error: aborting due to 2 previous errors
+error: used `unwrap_err()` on `a Result` value
+  --> $DIR/unwrap.rs:11:13
+   |
+LL |     let _ = res.unwrap_err();
+   |             ^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `Ok` case gracefully, consider using `expect_err()` to provide a better panic message
+
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs
index 0d4a0504a6e..9f27fef8249 100644
--- a/tests/ui/unwrap_expect_used.rs
+++ b/tests/ui/unwrap_expect_used.rs
@@ -1,10 +1,35 @@
 #![warn(clippy::unwrap_used, clippy::expect_used)]
 
+trait OptionExt {
+    type Item;
+
+    fn unwrap_err(self) -> Self::Item;
+
+    fn expect_err(self, msg: &str) -> Self::Item;
+}
+
+impl<T> OptionExt for Option<T> {
+    type Item = T;
+    fn unwrap_err(self) -> T {
+        panic!();
+    }
+
+    fn expect_err(self, msg: &str) -> T {
+        panic!();
+    }
+}
+
 fn main() {
     Some(3).unwrap();
     Some(3).expect("Hello world!");
 
+    // Don't trigger on unwrap_err on an option
+    Some(3).unwrap_err();
+    Some(3).expect_err("Hellow none!");
+
     let a: Result<i32, i32> = Ok(3);
     a.unwrap();
     a.expect("Hello world!");
+    a.unwrap_err();
+    a.expect_err("Hello error!");
 }
diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr
index f54bfd617c4..1a19459b2c1 100644
--- a/tests/ui/unwrap_expect_used.stderr
+++ b/tests/ui/unwrap_expect_used.stderr
@@ -1,5 +1,5 @@
 error: used `unwrap()` on `an Option` value
-  --> $DIR/unwrap_expect_used.rs:4:5
+  --> $DIR/unwrap_expect_used.rs:23:5
    |
 LL |     Some(3).unwrap();
    |     ^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     Some(3).unwrap();
    = help: if this value is `None`, it will panic
 
 error: used `expect()` on `an Option` value
-  --> $DIR/unwrap_expect_used.rs:5:5
+  --> $DIR/unwrap_expect_used.rs:24:5
    |
 LL |     Some(3).expect("Hello world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     Some(3).expect("Hello world!");
    = help: if this value is `None`, it will panic
 
 error: used `unwrap()` on `a Result` value
-  --> $DIR/unwrap_expect_used.rs:8:5
+  --> $DIR/unwrap_expect_used.rs:31:5
    |
 LL |     a.unwrap();
    |     ^^^^^^^^^^
@@ -25,12 +25,28 @@ LL |     a.unwrap();
    = help: if this value is an `Err`, it will panic
 
 error: used `expect()` on `a Result` value
-  --> $DIR/unwrap_expect_used.rs:9:5
+  --> $DIR/unwrap_expect_used.rs:32:5
    |
 LL |     a.expect("Hello world!");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: if this value is an `Err`, it will panic
 
-error: aborting due to 4 previous errors
+error: used `unwrap_err()` on `a Result` value
+  --> $DIR/unwrap_expect_used.rs:33:5
+   |
+LL |     a.unwrap_err();
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: if this value is an `Ok`, it will panic
+
+error: used `expect_err()` on `a Result` value
+  --> $DIR/unwrap_expect_used.rs:34:5
+   |
+LL |     a.expect_err("Hello error!");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this value is an `Ok`, it will panic
+
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/useless_conversion_try.rs b/tests/ui/useless_conversion_try.rs
index 39f54c27bee..4acf5b5fa2d 100644
--- a/tests/ui/useless_conversion_try.rs
+++ b/tests/ui/useless_conversion_try.rs
@@ -29,10 +29,10 @@ fn main() {
     let _ = String::try_from("foo".to_string()).unwrap();
     let _ = String::try_from(format!("A: {:04}", 123)).unwrap();
     let _: String = format!("Hello {}", "world").try_into().unwrap();
-    let _: String = "".to_owned().try_into().unwrap();
+    let _: String = String::new().try_into().unwrap();
     let _: String = match String::from("_").try_into() {
         Ok(a) => a,
-        Err(_) => "".into(),
+        Err(_) => String::new(),
     };
     // FIXME this is a false negative
     #[allow(clippy::cmp_owned)]
diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr
index b691c13f7db..12e74d61471 100644
--- a/tests/ui/useless_conversion_try.stderr
+++ b/tests/ui/useless_conversion_try.stderr
@@ -62,7 +62,7 @@ LL |     let _: String = format!("Hello {}", "world").try_into().unwrap();
 error: useless conversion to the same type: `std::string::String`
   --> $DIR/useless_conversion_try.rs:32:21
    |
-LL |     let _: String = "".to_owned().try_into().unwrap();
+LL |     let _: String = String::new().try_into().unwrap();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider removing `.try_into()`
diff --git a/tests/ui/vec_resize_to_zero.rs b/tests/ui/vec_resize_to_zero.rs
index 7ed27439ec6..a8307e741cf 100644
--- a/tests/ui/vec_resize_to_zero.rs
+++ b/tests/ui/vec_resize_to_zero.rs
@@ -1,15 +1,19 @@
 #![warn(clippy::vec_resize_to_zero)]
 
 fn main() {
+    let mut v = vec![1, 2, 3, 4, 5];
+
     // applicable here
-    vec![1, 2, 3, 4, 5].resize(0, 5);
+    v.resize(0, 5);
 
     // not applicable
-    vec![1, 2, 3, 4, 5].resize(2, 5);
+    v.resize(2, 5);
+
+    let mut v = vec!["foo", "bar", "baz"];
 
     // applicable here, but only implemented for integer literals for now
-    vec!["foo", "bar", "baz"].resize(0, "bar");
+    v.resize(0, "bar");
 
     // not applicable
-    vec!["foo", "bar", "baz"].resize(2, "bar")
+    v.resize(2, "bar")
 }
diff --git a/tests/ui/vec_resize_to_zero.stderr b/tests/ui/vec_resize_to_zero.stderr
index feb846298c6..7428cf62d6c 100644
--- a/tests/ui/vec_resize_to_zero.stderr
+++ b/tests/ui/vec_resize_to_zero.stderr
@@ -1,10 +1,10 @@
 error: emptying a vector with `resize`
-  --> $DIR/vec_resize_to_zero.rs:5:5
+  --> $DIR/vec_resize_to_zero.rs:7:5
    |
-LL |     vec![1, 2, 3, 4, 5].resize(0, 5);
-   |     ^^^^^^^^^^^^^^^^^^^^------------
-   |                         |
-   |                         help: ...or you can empty the vector with: `clear()`
+LL |     v.resize(0, 5);
+   |     ^^------------
+   |       |
+   |       help: ...or you can empty the vector with: `clear()`
    |
    = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings`
    = help: the arguments may be inverted...
diff --git a/tests/ui/verbose_file_reads.rs b/tests/ui/verbose_file_reads.rs
index e0065e05ade..df267e9872a 100644
--- a/tests/ui/verbose_file_reads.rs
+++ b/tests/ui/verbose_file_reads.rs
@@ -18,7 +18,7 @@ fn main() -> std::io::Result<()> {
     s.read_to_end();
     s.read_to_string();
     // Should catch this
-    let mut f = File::open(&path)?;
+    let mut f = File::open(path)?;
     let mut buffer = Vec::new();
     f.read_to_end(&mut buffer)?;
     // ...and this
diff --git a/tests/workspace.rs b/tests/workspace.rs
index e13efb3e016..95325e06037 100644
--- a/tests/workspace.rs
+++ b/tests/workspace.rs
@@ -20,8 +20,8 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
         .current_dir(&cwd)
         .env("CARGO_TARGET_DIR", &target_dir)
         .arg("clean")
-        .args(&["-p", "subcrate"])
-        .args(&["-p", "path_dep"])
+        .args(["-p", "subcrate"])
+        .args(["-p", "path_dep"])
         .output()
         .unwrap();
 
@@ -32,11 +32,11 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
         .env("CARGO_INCREMENTAL", "0")
         .env("CARGO_TARGET_DIR", &target_dir)
         .arg("clippy")
-        .args(&["-p", "subcrate"])
+        .args(["-p", "subcrate"])
         .arg("--no-deps")
         .arg("--")
         .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
-        .args(&["--cfg", r#"feature="primary_package_test""#])
+        .args(["--cfg", r#"feature="primary_package_test""#])
         .output()
         .unwrap();
     println!("status: {}", output.status);
@@ -52,10 +52,10 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
             .env("CARGO_INCREMENTAL", "0")
             .env("CARGO_TARGET_DIR", &target_dir)
             .arg("clippy")
-            .args(&["-p", "subcrate"])
+            .args(["-p", "subcrate"])
             .arg("--")
             .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
-            .args(&["--cfg", r#"feature="primary_package_test""#])
+            .args(["--cfg", r#"feature="primary_package_test""#])
             .output()
             .unwrap();
         println!("status: {}", output.status);
@@ -79,7 +79,7 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
             .env("CARGO_INCREMENTAL", "0")
             .env("CARGO_TARGET_DIR", &target_dir)
             .arg("clippy")
-            .args(&["-p", "subcrate"])
+            .args(["-p", "subcrate"])
             .arg("--")
             .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
             .output()

From 7bd5b012c701da221b308a147a6547854f680f1a Mon Sep 17 00:00:00 2001
From: Jason Newcomb <jsnewcomb@pm.me>
Date: Wed, 31 Aug 2022 09:33:32 -0400
Subject: [PATCH 09/34] Use `CountIsStart` in clippy

---
 clippy_lints/src/write.rs  | 4 ++--
 clippy_utils/src/macros.rs | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs
index 5533840b166..347165d9704 100644
--- a/clippy_lints/src/write.rs
+++ b/clippy_lints/src/write.rs
@@ -526,7 +526,7 @@ impl SimpleFormatArgs {
         str_lit_span: Span,
         fmt_span: Span,
     ) {
-        use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam};
+        use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam, CountIsStar};
 
         let snippet = snippet_opt(cx, fmt_span);
 
@@ -540,7 +540,7 @@ impl SimpleFormatArgs {
             self.push_to_complex(span, n);
         };
 
-        if let (CountIsParam(n), Some(span)) = (arg.format.precision, arg.format.precision_span) {
+        if let (CountIsParam(n) | CountIsStar(n), Some(span)) = (arg.format.precision, arg.format.precision_span) {
             // We need to do this hack as precision spans should be converted from .* to .foo$
             let hack = if snippet.as_ref().and_then(|s| s.find('*')).is_some() {
                 0
diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs
index e5ca3545540..43e53f3feeb 100644
--- a/clippy_utils/src/macros.rs
+++ b/clippy_utils/src/macros.rs
@@ -644,7 +644,7 @@ impl<'tcx> Count<'tcx> {
                 span,
                 values,
             )?),
-            rpf::Count::CountIsParam(_) => {
+            rpf::Count::CountIsParam(_) | rpf::Count::CountIsStar(_) => {
                 Self::Param(FormatParam::new(FormatParamKind::Numbered, position?, inner?, values)?)
             },
             rpf::Count::CountImplied => Self::Implied,

From d4a0785464f567c8781f15819f8be74a95b0a3f0 Mon Sep 17 00:00:00 2001
From: Jason Newcomb <jsnewcomb@pm.me>
Date: Wed, 31 Aug 2022 23:24:29 -0400
Subject: [PATCH 10/34] Correctly handle unescape warnings

---
 clippy_dev/src/update_lints.rs   |  6 +++++-
 clippy_lints/src/write.rs        |  6 +++++-
 clippy_utils/src/macros.rs       |  6 ++++--
 tests/ui/crashes/ice-9405.rs     | 11 +++++++++++
 tests/ui/crashes/ice-9405.stderr | 11 +++++++++++
 5 files changed, 36 insertions(+), 4 deletions(-)
 create mode 100644 tests/ui/crashes/ice-9405.rs
 create mode 100644 tests/ui/crashes/ice-9405.stderr

diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs
index c503142e5e4..28bec872c08 100644
--- a/clippy_dev/src/update_lints.rs
+++ b/clippy_dev/src/update_lints.rs
@@ -977,7 +977,11 @@ fn remove_line_splices(s: &str) -> String {
         .and_then(|s| s.strip_suffix('"'))
         .unwrap_or_else(|| panic!("expected quoted string, found `{}`", s));
     let mut res = String::with_capacity(s.len());
-    unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, _| res.push_str(&s[range]));
+    unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, ch| {
+        if ch.is_ok() {
+            res.push_str(&s[range]);
+        }
+    });
     res
 }
 
diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs
index 5533840b166..abd681c5307 100644
--- a/clippy_lints/src/write.rs
+++ b/clippy_lints/src/write.rs
@@ -805,7 +805,11 @@ fn check_newlines(fmtstr: &StrLit) -> bool {
     let contents = fmtstr.symbol.as_str();
 
     let mut cb = |r: Range<usize>, c: Result<char, EscapeError>| {
-        let c = c.unwrap();
+        let c = match c {
+            Ok(c) => c,
+            Err(e) if !e.is_fatal() => return,
+            Err(e) => panic!("{:?}", e),
+        };
 
         if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline {
             should_lint = true;
diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs
index e5ca3545540..6b7d5e9aea8 100644
--- a/clippy_utils/src/macros.rs
+++ b/clippy_utils/src/macros.rs
@@ -389,8 +389,10 @@ impl FormatString {
         };
 
         let mut unescaped = String::with_capacity(inner.len());
-        unescape_literal(inner, mode, &mut |_, ch| {
-            unescaped.push(ch.unwrap());
+        unescape_literal(inner, mode, &mut |_, ch| match ch {
+            Ok(ch) => unescaped.push(ch),
+            Err(e) if !e.is_fatal() => (),
+            Err(e) => panic!("{:?}", e),
         });
 
         let mut parts = Vec::new();
diff --git a/tests/ui/crashes/ice-9405.rs b/tests/ui/crashes/ice-9405.rs
new file mode 100644
index 00000000000..e2d274aeb04
--- /dev/null
+++ b/tests/ui/crashes/ice-9405.rs
@@ -0,0 +1,11 @@
+#![warn(clippy::useless_format)]
+#![allow(clippy::print_literal)]
+
+fn main() {
+    println!(
+        "\
+
+            {}",
+        "multiple skipped lines"
+    );
+}
diff --git a/tests/ui/crashes/ice-9405.stderr b/tests/ui/crashes/ice-9405.stderr
new file mode 100644
index 00000000000..9a6e410f21e
--- /dev/null
+++ b/tests/ui/crashes/ice-9405.stderr
@@ -0,0 +1,11 @@
+warning: multiple lines skipped by escaped newline
+  --> $DIR/ice-9405.rs:6:10
+   |
+LL |           "/
+   |  __________^
+LL | |
+LL | |             {}",
+   | |____________^ skipping everything up to and including this point
+
+warning: 1 warning emitted
+

From 6e14e60af45ebc79f06eeeb75004e77de4658a80 Mon Sep 17 00:00:00 2001
From: Lukas Lueg <lukas.lueg@gmail.com>
Date: Wed, 31 Aug 2022 21:08:33 +0200
Subject: [PATCH 11/34] Fix {subopt,imprec}_float not lint const.*(const)

Fixes #9402
Fixes #9201
---
 clippy_lints/src/floating_point_arithmetic.rs | 30 +++++------
 tests/ui/floating_point_powf.fixed            |  5 ++
 tests/ui/floating_point_powf.rs               |  5 ++
 tests/ui/floating_point_powf.stderr           | 50 ++++++++++++++-----
 4 files changed, 62 insertions(+), 28 deletions(-)

diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs
index bb50e8fcabb..9120507f48c 100644
--- a/clippy_lints/src/floating_point_arithmetic.rs
+++ b/clippy_lints/src/floating_point_arithmetic.rs
@@ -238,23 +238,23 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
 fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
     // Check receiver
     if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
-        let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
-            "exp"
+        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 {
-            "exp2"
+            Some("exp2")
         } else {
-            return;
-        };
-
-        span_lint_and_sugg(
-            cx,
-            SUBOPTIMAL_FLOPS,
-            expr.span,
-            "exponent for bases 2 and e can be computed more accurately",
-            "consider using",
-            format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method),
-            Applicability::MachineApplicable,
-        );
+            None
+        } {
+            span_lint_and_sugg(
+                cx,
+                SUBOPTIMAL_FLOPS,
+                expr.span,
+                "exponent for bases 2 and e can be computed more accurately",
+                "consider using",
+                format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method),
+                Applicability::MachineApplicable,
+            );
+        }
     }
 
     // Check argument
diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed
index 7efe10a10f9..e7ef45634df 100644
--- a/tests/ui/floating_point_powf.fixed
+++ b/tests/ui/floating_point_powf.fixed
@@ -18,6 +18,11 @@ fn main() {
     let _ = x.powi(-16_777_215);
     let _ = (x as f32).powi(-16_777_215);
     let _ = (x as f32).powi(3);
+    let _ = (1.5_f32 + 1.0).cbrt();
+    let _ = 1.5_f64.cbrt();
+    let _ = 1.5_f64.sqrt();
+    let _ = 1.5_f64.powi(3);
+
     // Cases where the lint shouldn't be applied
     let _ = x.powf(2.1);
     let _ = x.powf(-2.1);
diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs
index 445080417f2..d749aa2d48a 100644
--- a/tests/ui/floating_point_powf.rs
+++ b/tests/ui/floating_point_powf.rs
@@ -18,6 +18,11 @@ fn main() {
     let _ = x.powf(-16_777_215.0);
     let _ = (x as f32).powf(-16_777_215.0);
     let _ = (x as f32).powf(3.0);
+    let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0);
+    let _ = 1.5_f64.powf(1.0 / 3.0);
+    let _ = 1.5_f64.powf(1.0 / 2.0);
+    let _ = 1.5_f64.powf(3.0);
+
     // Cases where the lint shouldn't be applied
     let _ = x.powf(2.1);
     let _ = x.powf(-2.1);
diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr
index 6ee696e6ada..e9693de8fc9 100644
--- a/tests/ui/floating_point_powf.stderr
+++ b/tests/ui/floating_point_powf.stderr
@@ -92,77 +92,101 @@ error: exponentiation with integer powers can be computed more efficiently
 LL |     let _ = (x as f32).powf(3.0);
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(3)`
 
+error: cube-root of a number can be computed more accurately
+  --> $DIR/floating_point_powf.rs:21:13
+   |
+LL |     let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(1.5_f32 + 1.0).cbrt()`
+
+error: cube-root of a number can be computed more accurately
+  --> $DIR/floating_point_powf.rs:22:13
+   |
+LL |     let _ = 1.5_f64.powf(1.0 / 3.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.cbrt()`
+
+error: square-root of a number can be computed more efficiently and accurately
+  --> $DIR/floating_point_powf.rs:23:13
+   |
+LL |     let _ = 1.5_f64.powf(1.0 / 2.0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.sqrt()`
+
+error: exponentiation with integer powers can be computed more efficiently
+  --> $DIR/floating_point_powf.rs:24:13
+   |
+LL |     let _ = 1.5_f64.powf(3.0);
+   |             ^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.powi(3)`
+
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:28:13
+  --> $DIR/floating_point_powf.rs:33:13
    |
 LL |     let _ = 2f64.powf(x);
    |             ^^^^^^^^^^^^ help: consider using: `x.exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:29:13
+  --> $DIR/floating_point_powf.rs:34:13
    |
 LL |     let _ = 2f64.powf(3.1);
    |             ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:30:13
+  --> $DIR/floating_point_powf.rs:35:13
    |
 LL |     let _ = 2f64.powf(-3.1);
    |             ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:31:13
+  --> $DIR/floating_point_powf.rs:36:13
    |
 LL |     let _ = std::f64::consts::E.powf(x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:32:13
+  --> $DIR/floating_point_powf.rs:37:13
    |
 LL |     let _ = std::f64::consts::E.powf(3.1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> $DIR/floating_point_powf.rs:33:13
+  --> $DIR/floating_point_powf.rs:38:13
    |
 LL |     let _ = std::f64::consts::E.powf(-3.1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()`
 
 error: square-root of a number can be computed more efficiently and accurately
-  --> $DIR/floating_point_powf.rs:34:13
+  --> $DIR/floating_point_powf.rs:39:13
    |
 LL |     let _ = x.powf(1.0 / 2.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()`
 
 error: cube-root of a number can be computed more accurately
-  --> $DIR/floating_point_powf.rs:35:13
+  --> $DIR/floating_point_powf.rs:40:13
    |
 LL |     let _ = x.powf(1.0 / 3.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:36:13
+  --> $DIR/floating_point_powf.rs:41:13
    |
 LL |     let _ = x.powf(3.0);
    |             ^^^^^^^^^^^ help: consider using: `x.powi(3)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:37:13
+  --> $DIR/floating_point_powf.rs:42:13
    |
 LL |     let _ = x.powf(-2.0);
    |             ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:38:13
+  --> $DIR/floating_point_powf.rs:43:13
    |
 LL |     let _ = x.powf(-2_147_483_648.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> $DIR/floating_point_powf.rs:39:13
+  --> $DIR/floating_point_powf.rs:44:13
    |
 LL |     let _ = x.powf(2_147_483_647.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)`
 
-error: aborting due to 27 previous errors
+error: aborting due to 31 previous errors
 

From b1f86a49ea0119e66ee7dced613c91824d56c6d0 Mon Sep 17 00:00:00 2001
From: Dmitrii Lavrov <d.lavrov@proscom.ru>
Date: Thu, 30 Jun 2022 16:57:15 +0300
Subject: [PATCH 12/34] New lint `bool_to_int_with_if`

---
 CHANGELOG.md                               |   1 +
 clippy_lints/src/bool_to_int_with_if.rs    | 125 +++++++++++++++++++++
 clippy_lints/src/lib.register_all.rs       |   1 +
 clippy_lints/src/lib.register_lints.rs     |   1 +
 clippy_lints/src/lib.register_style.rs     |   1 +
 clippy_lints/src/lib.rs                    |   2 +
 clippy_lints/src/matches/single_match.rs   |   8 +-
 clippy_lints/src/only_used_in_recursion.rs |  12 +-
 tests/ui/author/struct.rs                  |   7 +-
 tests/ui/bool_to_int_with_if.fixed         |  85 ++++++++++++++
 tests/ui/bool_to_int_with_if.rs            | 109 ++++++++++++++++++
 tests/ui/bool_to_int_with_if.stderr        |  84 ++++++++++++++
 12 files changed, 419 insertions(+), 17 deletions(-)
 create mode 100644 clippy_lints/src/bool_to_int_with_if.rs
 create mode 100644 tests/ui/bool_to_int_with_if.fixed
 create mode 100644 tests/ui/bool_to_int_with_if.rs
 create mode 100644 tests/ui/bool_to_int_with_if.stderr

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c488c142e46..257add86b6e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3603,6 +3603,7 @@ Released 2018-09-13
 [`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions
 [`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison
 [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
+[`bool_to_int_with_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_to_int_with_if
 [`borrow_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr
 [`borrow_deref_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_deref_ref
 [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs
new file mode 100644
index 00000000000..a4b8cbb0d82
--- /dev/null
+++ b/clippy_lints/src/bool_to_int_with_if.rs
@@ -0,0 +1,125 @@
+use rustc_ast::{ExprPrecedence, LitKind};
+use rustc_hir::{Block, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, source::snippet_block_with_applicability};
+use rustc_errors::Applicability;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Instead of using an if statement to convert a bool to an int,
+    /// this lint suggests using a `from()` function or an `as` coercion.
+    ///
+    /// ### Why is this bad?
+    /// Coercion or `from()` is idiomatic way to convert bool to a number.
+    /// Both methods are guaranteed to return 1 for true, and 0 for false.
+    ///
+    /// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let condition = false;
+    /// if condition {
+    ///     1_i64
+    /// } else {
+    ///     0
+    /// };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # let condition = false;
+    /// i64::from(condition);
+    /// ```
+    /// or
+    /// ```rust
+    /// # let condition = false;
+    /// condition as i64;
+    /// ```
+    #[clippy::version = "1.65.0"]
+    pub BOOL_TO_INT_WITH_IF,
+    style,
+    "using if to convert bool to int"
+}
+declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
+
+impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
+    fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+        if !expr.span.from_expansion() {
+            check_if_else(ctx, expr);
+        }
+    }
+}
+
+fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
+    if let ExprKind::If(check, then, Some(else_)) = expr.kind
+        && let Some(then_lit) = int_literal(then)
+        && let Some(else_lit) = int_literal(else_)
+        && check_int_literal_equals_val(then_lit, 1)
+        && check_int_literal_equals_val(else_lit, 0)
+    {
+        let mut applicability = Applicability::MachineApplicable;
+        let snippet = snippet_block_with_applicability(ctx, check.span, "..", None, &mut applicability);
+        let snippet_with_braces = {
+            let need_parens = should_have_parentheses(check);
+            let (left_paren, right_paren) = if need_parens {("(", ")")} else {("", "")};
+            format!("{left_paren}{snippet}{right_paren}")
+        };
+
+        let ty = ctx.typeck_results().expr_ty(then_lit); // then and else must be of same type
+
+        let suggestion = {
+            let wrap_in_curly = is_else_clause(ctx.tcx, expr);
+            let (left_curly, right_curly) = if wrap_in_curly {("{", "}")} else {("", "")};
+            format!(
+                "{left_curly}{ty}::from({snippet}){right_curly}"
+            )
+        }; // when used in else clause if statement should be wrapped in curly braces
+
+        span_lint_and_then(ctx,
+            BOOL_TO_INT_WITH_IF,
+            expr.span,
+            "boolean to int conversion using if",
+            |diag| {
+            diag.span_suggestion(
+                expr.span,
+                "replace with from",
+                suggestion,
+                applicability,
+            );
+            diag.note(format!("`{snippet_with_braces} as {ty}` or `{snippet_with_braces}.into()` can also be valid options"));
+        });
+    };
+}
+
+// If block contains only a int literal expression, return literal expression
+fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> {
+    if let ExprKind::Block(block, _) = expr.kind
+        && let Block {
+            stmts: [],       // Shouldn't lint if statements with side effects
+            expr: Some(expr),
+            ..
+        } = block
+        && let ExprKind::Lit(lit) = &expr.kind
+        && let LitKind::Int(_, _) = lit.node
+    {
+        Some(expr)
+    } else {
+        None
+    }
+}
+
+fn check_int_literal_equals_val<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>, expected_value: u128) -> bool {
+    if let ExprKind::Lit(lit) = &expr.kind
+        && let LitKind::Int(val, _) = lit.node
+        && val == expected_value
+    {
+        true
+    } else {
+        false
+    }
+}
+
+fn should_have_parentheses<'tcx>(check: &'tcx rustc_hir::Expr<'tcx>) -> bool {
+    check.precedence().order() < ExprPrecedence::Cast.order()
+}
diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs
index 134cbbf7b5c..1f85382347a 100644
--- a/clippy_lints/src/lib.register_all.rs
+++ b/clippy_lints/src/lib.register_all.rs
@@ -17,6 +17,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
     LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
+    LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
     LintId::of(booleans::NONMINIMAL_BOOL),
     LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
     LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index fd20e016578..13b573beea1 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -56,6 +56,7 @@ store.register_lints(&[
     await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
     blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
     bool_assert_comparison::BOOL_ASSERT_COMPARISON,
+    bool_to_int_with_if::BOOL_TO_INT_WITH_IF,
     booleans::NONMINIMAL_BOOL,
     booleans::OVERLY_COMPLEX_BOOL_EXPR,
     borrow_deref_ref::BORROW_DEREF_REF,
diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs
index b5cb078e7a3..05d2ec2e9e1 100644
--- a/clippy_lints/src/lib.register_style.rs
+++ b/clippy_lints/src/lib.register_style.rs
@@ -6,6 +6,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
     LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
+    LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF),
     LintId::of(casts::FN_TO_NUMERIC_CAST),
     LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
     LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 178e57aaf61..a26e129f094 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -178,6 +178,7 @@ mod attrs;
 mod await_holding_invalid;
 mod blocks_in_if_conditions;
 mod bool_assert_comparison;
+mod bool_to_int_with_if;
 mod booleans;
 mod borrow_deref_ref;
 mod cargo;
@@ -900,6 +901,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(manual_string_new::ManualStringNew));
     store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable));
     store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments));
+    store.register_late_pass(|| Box::new(bool_to_int_with_if::BoolToIntWithIf));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs
index 92091a0c339..52632e88b1b 100644
--- a/clippy_lints/src/matches/single_match.rs
+++ b/clippy_lints/src/matches/single_match.rs
@@ -201,12 +201,8 @@ fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>,
             // in the arms, so we need to evaluate the correct offsets here in order to iterate in
             // both arms at the same time.
             let len = max(
-                left_in.len() + {
-                    if left_pos.is_some() { 1 } else { 0 }
-                },
-                right_in.len() + {
-                    if right_pos.is_some() { 1 } else { 0 }
-                },
+                left_in.len() + usize::from(left_pos.is_some()),
+                right_in.len() + usize::from(right_pos.is_some()),
             );
             let mut left_pos = left_pos.unwrap_or(usize::MAX);
             let mut right_pos = right_pos.unwrap_or(usize::MAX);
diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs
index 774a3540d1e..c55478b3441 100644
--- a/clippy_lints/src/only_used_in_recursion.rs
+++ b/clippy_lints/src/only_used_in_recursion.rs
@@ -234,11 +234,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
             })) => (
                 def_id.to_def_id(),
                 FnKind::TraitFn,
-                if sig.decl.implicit_self.has_implicit_self() {
-                    1
-                } else {
-                    0
-                },
+                usize::from(sig.decl.implicit_self.has_implicit_self()),
             ),
             Some(Node::ImplItem(&ImplItem {
                 kind: ImplItemKind::Fn(ref sig, _),
@@ -253,11 +249,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                     (
                         trait_item_id,
                         FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const _ as usize),
-                        if sig.decl.implicit_self.has_implicit_self() {
-                            1
-                        } else {
-                            0
-                        },
+                        usize::from(sig.decl.implicit_self.has_implicit_self()),
                     )
                 } else {
                     (def_id.to_def_id(), FnKind::Fn, 0)
diff --git a/tests/ui/author/struct.rs b/tests/ui/author/struct.rs
index 5fdf3433a37..a99bdfc1313 100644
--- a/tests/ui/author/struct.rs
+++ b/tests/ui/author/struct.rs
@@ -1,4 +1,9 @@
-#[allow(clippy::unnecessary_operation, clippy::single_match)]
+#![allow(
+    clippy::unnecessary_operation,
+    clippy::single_match,
+    clippy::no_effect,
+    clippy::bool_to_int_with_if
+)]
 fn main() {
     struct Test {
         field: u32,
diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed
new file mode 100644
index 00000000000..9c1098dc4c1
--- /dev/null
+++ b/tests/ui/bool_to_int_with_if.fixed
@@ -0,0 +1,85 @@
+// run-rustfix
+
+#![warn(clippy::bool_to_int_with_if)]
+#![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
+
+fn main() {
+    let a = true;
+    let b = false;
+
+    let x = 1;
+    let y = 2;
+
+    // Should lint
+    // precedence
+    i32::from(a);
+    i32::from(!a);
+    i32::from(a || b);
+    i32::from(cond(a, b));
+    i32::from(x + y < 4);
+
+    // if else if
+    if a {
+        123
+    } else {i32::from(b)};
+
+    // Shouldn't lint
+
+    if a {
+        1
+    } else if b {
+        0
+    } else {
+        3
+    };
+
+    if a {
+        3
+    } else if b {
+        1
+    } else {
+        -2
+    };
+
+    if a {
+        3
+    } else {
+        0
+    };
+    if a {
+        side_effect();
+        1
+    } else {
+        0
+    };
+    if a {
+        1
+    } else {
+        side_effect();
+        0
+    };
+
+    // multiple else ifs
+    if a {
+        123
+    } else if b {
+        1
+    } else if a | b {
+        0
+    } else {
+        123
+    };
+
+    some_fn(a);
+}
+
+// Lint returns and type inference
+fn some_fn(a: bool) -> u8 {
+    u8::from(a)
+}
+
+fn side_effect() {}
+
+fn cond(a: bool, b: bool) -> bool {
+    a || b
+}
diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs
new file mode 100644
index 00000000000..0c967dac6e2
--- /dev/null
+++ b/tests/ui/bool_to_int_with_if.rs
@@ -0,0 +1,109 @@
+// run-rustfix
+
+#![warn(clippy::bool_to_int_with_if)]
+#![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)]
+
+fn main() {
+    let a = true;
+    let b = false;
+
+    let x = 1;
+    let y = 2;
+
+    // Should lint
+    // precedence
+    if a {
+        1
+    } else {
+        0
+    };
+    if !a {
+        1
+    } else {
+        0
+    };
+    if a || b {
+        1
+    } else {
+        0
+    };
+    if cond(a, b) {
+        1
+    } else {
+        0
+    };
+    if x + y < 4 {
+        1
+    } else {
+        0
+    };
+
+    // if else if
+    if a {
+        123
+    } else if b {
+        1
+    } else {
+        0
+    };
+
+    // Shouldn't lint
+
+    if a {
+        1
+    } else if b {
+        0
+    } else {
+        3
+    };
+
+    if a {
+        3
+    } else if b {
+        1
+    } else {
+        -2
+    };
+
+    if a {
+        3
+    } else {
+        0
+    };
+    if a {
+        side_effect();
+        1
+    } else {
+        0
+    };
+    if a {
+        1
+    } else {
+        side_effect();
+        0
+    };
+
+    // multiple else ifs
+    if a {
+        123
+    } else if b {
+        1
+    } else if a | b {
+        0
+    } else {
+        123
+    };
+
+    some_fn(a);
+}
+
+// Lint returns and type inference
+fn some_fn(a: bool) -> u8 {
+    if a { 1 } else { 0 }
+}
+
+fn side_effect() {}
+
+fn cond(a: bool, b: bool) -> bool {
+    a || b
+}
diff --git a/tests/ui/bool_to_int_with_if.stderr b/tests/ui/bool_to_int_with_if.stderr
new file mode 100644
index 00000000000..8647a9cffbe
--- /dev/null
+++ b/tests/ui/bool_to_int_with_if.stderr
@@ -0,0 +1,84 @@
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:15:5
+   |
+LL | /     if a {
+LL | |         1
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^ help: replace with from: `i32::from(a)`
+   |
+   = note: `-D clippy::bool-to-int-with-if` implied by `-D warnings`
+   = note: `a as i32` or `a.into()` can also be valid options
+
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:20:5
+   |
+LL | /     if !a {
+LL | |         1
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^ help: replace with from: `i32::from(!a)`
+   |
+   = note: `!a as i32` or `!a.into()` can also be valid options
+
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:25:5
+   |
+LL | /     if a || b {
+LL | |         1
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^ help: replace with from: `i32::from(a || b)`
+   |
+   = note: `(a || b) as i32` or `(a || b).into()` can also be valid options
+
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:30:5
+   |
+LL | /     if cond(a, b) {
+LL | |         1
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^ help: replace with from: `i32::from(cond(a, b))`
+   |
+   = note: `cond(a, b) as i32` or `cond(a, b).into()` can also be valid options
+
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:35:5
+   |
+LL | /     if x + y < 4 {
+LL | |         1
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^ help: replace with from: `i32::from(x + y < 4)`
+   |
+   = note: `(x + y < 4) as i32` or `(x + y < 4).into()` can also be valid options
+
+error: boolean to int conversion using if
+  --> $DIR/bool_to_int_with_if.rs:44:12
+   |
+LL |       } else if b {
+   |  ____________^
+LL | |         1
+LL | |     } else {
+LL | |         0
+LL | |     };
+   | |_____^ help: replace with from: `{i32::from(b)}`
+   |
+   = 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:102:5
+   |
+LL |     if a { 1 } else { 0 }
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)`
+   |
+   = note: `a as u8` or `a.into()` can also be valid options
+
+error: aborting due to 7 previous errors
+

From bd70ccf915482503b193d8d53e00dcdc6197676a Mon Sep 17 00:00:00 2001
From: Jason Newcomb <jsnewcomb@pm.me>
Date: Fri, 2 Sep 2022 13:40:35 -0400
Subject: [PATCH 13/34] Don't use `hir_ty_to_ty` in `result_large_err` as it
 sometimes leaves late-bound lifetimes.

---
 clippy_lints/src/functions/result.rs | 10 +++++-----
 tests/ui/crashes/ice-9414.rs         |  8 ++++++++
 2 files changed, 13 insertions(+), 5 deletions(-)
 create mode 100644 tests/ui/crashes/ice-9414.rs

diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs
index af520a493ed..9591405cb06 100644
--- a/clippy_lints/src/functions/result.rs
+++ b/clippy_lints/src/functions/result.rs
@@ -4,7 +4,6 @@ use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{sym, Span};
-use rustc_typeck::hir_ty_to_ty;
 
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
 use clippy_utils::trait_ref_of_method;
@@ -17,11 +16,12 @@ use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR};
 fn result_err_ty<'tcx>(
     cx: &LateContext<'tcx>,
     decl: &hir::FnDecl<'tcx>,
+    id: hir::def_id::LocalDefId,
     item_span: Span,
 ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
     if !in_external_macro(cx.sess(), item_span)
         && let hir::FnRetTy::Return(hir_ty) = decl.output
-        && let ty = hir_ty_to_ty(cx.tcx, hir_ty)
+        && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).output())
         && is_type_diagnostic_item(cx, ty, sym::Result)
         && let ty::Adt(_, substs) = ty.kind()
     {
@@ -34,7 +34,7 @@ fn result_err_ty<'tcx>(
 
 pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) {
     if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind
-        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span)
+        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span)
     {
         if cx.access_levels.is_exported(item.def_id) {
             let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@@ -47,7 +47,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, l
 pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) {
     // Don't lint if method is a trait's implementation, we can't do anything about those
     if let hir::ImplItemKind::Fn(ref sig, _) = item.kind
-        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span)
+        && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span)
         && trait_ref_of_method(cx, item.def_id).is_none()
     {
         if cx.access_levels.is_exported(item.def_id) {
@@ -61,7 +61,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) {
     if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) {
+        if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) {
             if cx.access_levels.is_exported(item.def_id) {
                 check_result_unit_err(cx, err_ty, fn_header_span);
             }
diff --git a/tests/ui/crashes/ice-9414.rs b/tests/ui/crashes/ice-9414.rs
new file mode 100644
index 00000000000..02cf5d5c240
--- /dev/null
+++ b/tests/ui/crashes/ice-9414.rs
@@ -0,0 +1,8 @@
+#![warn(clippy::result_large_err)]
+
+trait T {}
+fn f(_: &u32) -> Result<(), *const (dyn '_ + T)> {
+    Ok(())
+}
+
+fn main() {}

From e5f30f4dfa3b9311273b2546897b23ddafd17133 Mon Sep 17 00:00:00 2001
From: Cameron Steffen <cam.steffen94@gmail.com>
Date: Tue, 30 Aug 2022 17:36:53 -0500
Subject: [PATCH 14/34] clippy: BindingAnnotation change

---
 clippy_lints/src/dereference.rs               |  2 +-
 clippy_lints/src/explicit_write.rs            |  2 +-
 clippy_lints/src/index_refutable_slice.rs     | 16 ++++++++-------
 clippy_lints/src/let_if_seq.rs                |  4 ++--
 clippy_lints/src/loops/manual_find.rs         |  2 +-
 clippy_lints/src/loops/mut_range_bound.rs     |  2 +-
 clippy_lints/src/loops/same_item_push.rs      |  4 ++--
 clippy_lints/src/matches/manual_map.rs        |  2 +-
 clippy_lints/src/matches/match_as_ref.rs      | 20 +++++++++----------
 clippy_lints/src/matches/needless_match.rs    |  5 ++---
 clippy_lints/src/matches/single_match.rs      |  2 +-
 clippy_lints/src/methods/clone_on_copy.rs     |  9 ++-------
 clippy_lints/src/methods/iter_skip_next.rs    |  2 +-
 clippy_lints/src/methods/map_clone.rs         |  4 ++--
 clippy_lints/src/methods/str_splitn.rs        | 11 +++++-----
 clippy_lints/src/misc.rs                      | 11 +++++-----
 .../src/misc_early/redundant_pattern.rs       | 12 +++--------
 .../src/needless_arbitrary_self_type.rs       |  6 +++---
 clippy_lints/src/needless_borrowed_ref.rs     |  2 +-
 clippy_lints/src/needless_late_init.rs        |  2 +-
 clippy_lints/src/needless_pass_by_value.rs    | 10 ++++------
 clippy_lints/src/option_if_let_else.rs        |  4 ++--
 clippy_lints/src/pass_by_ref_or_value.rs      |  2 +-
 clippy_lints/src/ptr.rs                       |  4 ++--
 clippy_lints/src/question_mark.rs             |  7 +++----
 .../src/slow_vector_initialization.rs         |  2 +-
 clippy_lints/src/unnested_or_patterns.rs      |  4 ++--
 clippy_lints/src/utils/author.rs              | 14 ++++++++++---
 clippy_lints/src/vec_init_then_push.rs        |  2 +-
 clippy_utils/src/hir_utils.rs                 | 11 +++++-----
 clippy_utils/src/lib.rs                       |  2 +-
 tests/ui/author.stdout                        |  2 +-
 tests/ui/author/blocks.stdout                 |  6 +++---
 tests/ui/author/loop.stdout                   |  4 ++--
 tests/ui/author/matches.stdout                |  4 ++--
 35 files changed, 95 insertions(+), 103 deletions(-)

diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index 1506ea604f0..3de188d96ce 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -503,7 +503,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
     }
 
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
-        if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
+        if let PatKind::Binding(BindingAnnotation::REF, id, name, _) = pat.kind {
             if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
                 // This binding id has been seen before. Add this pattern to the list of changes.
                 if let Some(prev_pat) = opt_prev_pat {
diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs
index 5bf4313b41a..502f0b583c4 100644
--- a/clippy_lints/src/explicit_write.rs
+++ b/clippy_lints/src/explicit_write.rs
@@ -128,7 +128,7 @@ fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>)
         if let Some(Node::Pat(res_pat)) = cx.tcx.hir().find(expr_res);
 
         // Find id of the local we found in the block
-        if let PatKind::Binding(BindingAnnotation::Unannotated, local_hir_id, _ident, None) = local.pat.kind;
+        if let PatKind::Binding(BindingAnnotation::NONE, local_hir_id, _ident, None) = local.pat.kind;
 
         // If those two are the same hir id
         if res_pat.hir_id == local_hir_id;
diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs
index d0c6495e35a..0dd7f5bf000 100644
--- a/clippy_lints/src/index_refutable_slice.rs
+++ b/clippy_lints/src/index_refutable_slice.rs
@@ -95,12 +95,14 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
     let mut removed_pat: FxHashSet<hir::HirId> = FxHashSet::default();
     let mut slices: FxIndexMap<hir::HirId, SliceLintInformation> = FxIndexMap::default();
     pat.walk_always(|pat| {
-        if let hir::PatKind::Binding(binding, value_hir_id, ident, sub_pat) = pat.kind {
-            // We'll just ignore mut and ref mut for simplicity sake right now
-            if let hir::BindingAnnotation::Mutable | hir::BindingAnnotation::RefMut = binding {
-                return;
-            }
-
+        // We'll just ignore mut and ref mut for simplicity sake right now
+        if let hir::PatKind::Binding(
+            hir::BindingAnnotation(by_ref, hir::Mutability::Not),
+            value_hir_id,
+            ident,
+            sub_pat,
+        ) = pat.kind
+        {
             // This block catches bindings with sub patterns. It would be hard to build a correct suggestion
             // for them and it's likely that the user knows what they are doing in such a case.
             if removed_pat.contains(&value_hir_id) {
@@ -116,7 +118,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
             if let ty::Slice(inner_ty) | ty::Array(inner_ty, _) = bound_ty.peel_refs().kind() {
                 // The values need to use the `ref` keyword if they can't be copied.
                 // This will need to be adjusted if the lint want to support mutable access in the future
-                let src_is_ref = bound_ty.is_ref() && binding != hir::BindingAnnotation::Ref;
+                let src_is_ref = bound_ty.is_ref() && by_ref != hir::ByRef::Yes;
                 let needs_ref = !(src_is_ref || is_copy(cx, *inner_ty));
 
                 let slice_info = slices
diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs
index 56bbbbbc819..10fc0f4018e 100644
--- a/clippy_lints/src/let_if_seq.rs
+++ b/clippy_lints/src/let_if_seq.rs
@@ -4,7 +4,7 @@ use clippy_utils::{path_to_local_id, visitors::is_local_used};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir::BindingAnnotation;
+use rustc_hir::{BindingAnnotation, Mutability};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
                     };
 
                     let mutability = match mode {
-                        BindingAnnotation::RefMut | BindingAnnotation::Mutable => "<mut> ",
+                        BindingAnnotation(_, Mutability::Mut) => "<mut> ",
                         _ => "",
                     };
 
diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs
index 215c83a7edf..09b2376d5c0 100644
--- a/clippy_lints/src/loops/manual_find.rs
+++ b/clippy_lints/src/loops/manual_find.rs
@@ -106,7 +106,7 @@ fn get_binding(pat: &Pat<'_>) -> Option<HirId> {
             hir_id = None;
             return;
         }
-        if let BindingAnnotation::Unannotated = annotation {
+        if let BindingAnnotation::NONE = annotation {
             hir_id = Some(id);
         }
     });
diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs
index aedf3810b23..fce2d54639c 100644
--- a/clippy_lints/src/loops/mut_range_bound.rs
+++ b/clippy_lints/src/loops/mut_range_bound.rs
@@ -44,7 +44,7 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId>
     if_chain! {
         if let Some(hir_id) = path_to_local(bound);
         if let Node::Pat(pat) = cx.tcx.hir().get(hir_id);
-        if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind;
+        if let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind;
         then {
             return Some(hir_id);
         }
diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs
index 1439f1f4c75..98f73c428eb 100644
--- a/clippy_lints/src/loops/same_item_push.rs
+++ b/clippy_lints/src/loops/same_item_push.rs
@@ -7,7 +7,7 @@ use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind};
 use rustc_lint::LateContext;
 use rustc_span::symbol::sym;
 use std::iter::Iterator;
@@ -65,7 +65,7 @@ pub(super) fn check<'tcx>(
                             if_chain! {
                                 if let Node::Pat(pat) = node;
                                 if let PatKind::Binding(bind_ann, ..) = pat.kind;
-                                if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
+                                if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut));
                                 let parent_node = cx.tcx.hir().get_parent_node(hir_id);
                                 if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node);
                                 if let Some(init) = parent_let_expr.init;
diff --git a/clippy_lints/src/matches/manual_map.rs b/clippy_lints/src/matches/manual_map.rs
index 8f98b43b9e5..b0198e856d5 100644
--- a/clippy_lints/src/matches/manual_map.rs
+++ b/clippy_lints/src/matches/manual_map.rs
@@ -165,7 +165,7 @@ fn check<'tcx>(
                 }
 
                 // `ref` and `ref mut` annotations were handled earlier.
-                let annotation = if matches!(annotation, BindingAnnotation::Mutable) {
+                let annotation = if matches!(annotation, BindingAnnotation::MUT) {
                     "mut "
                 } else {
                     ""
diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs
index a0efdecec67..91d17f481e2 100644
--- a/clippy_lints/src/matches/match_as_ref.rs
+++ b/clippy_lints/src/matches/match_as_ref.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_lang_ctor, peel_blocks};
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, LangItem, PatKind, QPath};
+use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 
@@ -10,18 +10,17 @@ use super::MATCH_AS_REF;
 
 pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
     if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
-        let arm_ref: Option<BindingAnnotation> = if is_none_arm(cx, &arms[0]) {
+        let arm_ref_mut = if is_none_arm(cx, &arms[0]) {
             is_ref_some_arm(cx, &arms[1])
         } else if is_none_arm(cx, &arms[1]) {
             is_ref_some_arm(cx, &arms[0])
         } else {
             None
         };
-        if let Some(rb) = arm_ref {
-            let suggestion = if rb == BindingAnnotation::Ref {
-                "as_ref"
-            } else {
-                "as_mut"
+        if let Some(rb) = arm_ref_mut {
+            let suggestion = match rb {
+                Mutability::Not => "as_ref",
+                Mutability::Mut => "as_mut",
             };
 
             let output_ty = cx.typeck_results().expr_ty(expr);
@@ -66,19 +65,18 @@ fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
 }
 
 // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
-fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotation> {
+fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<Mutability> {
     if_chain! {
         if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
         if is_lang_ctor(cx, qpath, LangItem::OptionSome);
-        if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
-        if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
+        if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind;
         if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind;
         if let ExprKind::Path(ref some_path) = e.kind;
         if is_lang_ctor(cx, some_path, LangItem::OptionSome);
         if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind;
         if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
         then {
-            return Some(rb)
+            return Some(mutabl)
         }
     }
     None
diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs
index 6f037339ec7..634eef82e53 100644
--- a/clippy_lints/src/matches/needless_match.rs
+++ b/clippy_lints/src/matches/needless_match.rs
@@ -8,7 +8,7 @@ use clippy_utils::{
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath};
+use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath};
 use rustc_lint::LateContext;
 use rustc_span::sym;
 use rustc_typeck::hir_ty_to_ty;
@@ -189,8 +189,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
                 },
             )),
         ) => {
-            return !matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut)
-                && pat_ident.name == first_seg.ident.name;
+            return !matches!(annot, BindingAnnotation(ByRef::Yes, _)) && pat_ident.name == first_seg.ident.name;
         },
         // Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
         (PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {
diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs
index 92091a0c339..95478af45b4 100644
--- a/clippy_lints/src/matches/single_match.rs
+++ b/clippy_lints/src/matches/single_match.rs
@@ -175,7 +175,7 @@ fn collect_pat_paths<'a>(acc: &mut Vec<Ty<'a>>, cx: &LateContext<'a>, pat: &Pat<
             let p_ty = cx.typeck_results().pat_ty(p);
             collect_pat_paths(acc, cx, p, p_ty);
         }),
-        PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::Unannotated, .., None) | PatKind::Path(_) => {
+        PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::NONE, .., None) | PatKind::Path(_) => {
             acc.push(ty);
         },
         _ => {},
diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs
index 60e1355f9b9..2c3683a09e3 100644
--- a/clippy_lints/src/methods/clone_on_copy.rs
+++ b/clippy_lints/src/methods/clone_on_copy.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg;
 use clippy_utils::ty::is_copy;
 use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
+use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, adjustment::Adjust};
 use rustc_span::symbol::{sym, Symbol};
@@ -98,12 +98,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
                 _ => false,
             },
             // local binding capturing a reference
-            Some(Node::Local(l))
-                if matches!(
-                    l.pat.kind,
-                    PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..)
-                ) =>
-            {
+            Some(Node::Local(l)) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => {
                 return;
             },
             _ => false,
diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs
index 43e9451f7d3..beb772100af 100644
--- a/clippy_lints/src/methods/iter_skip_next.rs
+++ b/clippy_lints/src/methods/iter_skip_next.rs
@@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
                     if let Some(id) = path_to_local(recv);
                     if let Node::Pat(pat) = cx.tcx.hir().get(id);
                     if let PatKind::Binding(ann, _, _, _)  = pat.kind;
-                    if ann != BindingAnnotation::Mutable;
+                    if ann != BindingAnnotation::MUT;
                     then {
                         application = Applicability::Unspecified;
                         diag.span_help(
diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs
index ffedda95ff8..a13541ad48d 100644
--- a/clippy_lints/src/methods/map_clone.rs
+++ b/clippy_lints/src/methods/map_clone.rs
@@ -33,13 +33,13 @@ pub(super) fn check<'tcx>(
             let closure_expr = peel_blocks(&closure_body.value);
             match closure_body.params[0].pat.kind {
                 hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding(
-                    hir::BindingAnnotation::Unannotated, .., name, None
+                    hir::BindingAnnotation::NONE, .., name, None
                 ) = inner.kind {
                     if ident_eq(name, closure_expr) {
                         lint_explicit_closure(cx, e.span, recv.span, true, msrv);
                     }
                 },
-                hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
+                hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => {
                     match closure_expr.kind {
                         hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
                             if ident_eq(name, inner) {
diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs
index 4ac738272d0..c5da8c8b0fe 100644
--- a/clippy_lints/src/methods/str_splitn.rs
+++ b/clippy_lints/src/methods/str_splitn.rs
@@ -130,7 +130,7 @@ fn check_manual_split_once_indirect(
     let ctxt = expr.span.ctxt();
     let mut parents = cx.tcx.hir().parent_iter(expr.hir_id);
     if let (_, Node::Local(local)) = parents.next()?
-        && let PatKind::Binding(BindingAnnotation::Mutable, iter_binding_id, iter_ident, None) = local.pat.kind
+        && let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind
         && let (iter_stmt_id, Node::Stmt(_)) = parents.next()?
         && let (_, Node::Block(enclosing_block)) = parents.next()?
 
@@ -212,11 +212,10 @@ fn indirect_usage<'tcx>(
     ctxt: SyntaxContext,
 ) -> Option<IndirectUsage<'tcx>> {
     if let StmtKind::Local(Local {
-        pat:
-            Pat {
-                kind: PatKind::Binding(BindingAnnotation::Unannotated, _, ident, None),
-                ..
-            },
+        pat: Pat {
+            kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None),
+            ..
+        },
         init: Some(init_expr),
         hir_id: local_hir_id,
         ..
diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs
index 8224e80c9cc..ea245edd770 100644
--- a/clippy_lints/src/misc.rs
+++ b/clippy_lints/src/misc.rs
@@ -5,8 +5,8 @@ use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt,
-    StmtKind, TyKind,
+    self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind,
+    Stmt, StmtKind, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
@@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
             return;
         }
         for arg in iter_input_pats(decl, body) {
-            if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind {
+            if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind {
                 span_lint(
                     cx,
                     TOPLEVEL_REF_ARG,
@@ -162,9 +162,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
         if_chain! {
             if !in_external_macro(cx.tcx.sess, stmt.span);
             if let StmtKind::Local(local) = stmt.kind;
-            if let PatKind::Binding(an, .., name, None) = local.pat.kind;
+            if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind;
             if let Some(init) = local.init;
-            if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut;
             then {
                 // use the macro callsite when the init span (but not the whole local span)
                 // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];`
@@ -173,7 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
                 } else {
                     Sugg::hir(cx, init, "..")
                 };
-                let (mutopt, initref) = if an == BindingAnnotation::RefMut {
+                let (mutopt, initref) = if mutabl == Mutability::Mut {
                     ("mut ", sugg_init.mut_addr())
                 } else {
                     ("", sugg_init.addr())
diff --git a/clippy_lints/src/misc_early/redundant_pattern.rs b/clippy_lints/src/misc_early/redundant_pattern.rs
index 525dbf7757c..d7bb0616acb 100644
--- a/clippy_lints/src/misc_early/redundant_pattern.rs
+++ b/clippy_lints/src/misc_early/redundant_pattern.rs
@@ -1,18 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use rustc_ast::ast::{BindingMode, Mutability, Pat, PatKind};
+use rustc_ast::ast::{Pat, PatKind};
 use rustc_errors::Applicability;
 use rustc_lint::EarlyContext;
 
 use super::REDUNDANT_PATTERN;
 
 pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
-    if let PatKind::Ident(left, ident, Some(ref right)) = pat.kind {
-        let left_binding = match left {
-            BindingMode::ByRef(Mutability::Mut) => "ref mut ",
-            BindingMode::ByRef(Mutability::Not) => "ref ",
-            BindingMode::ByValue(..) => "",
-        };
-
+    if let PatKind::Ident(ann, ident, Some(ref right)) = pat.kind {
         if let PatKind::Wild = right.kind {
             span_lint_and_sugg(
                 cx,
@@ -23,7 +17,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
                     ident.name, ident.name,
                 ),
                 "try",
-                format!("{}{}", left_binding, ident.name),
+                format!("{}{}", ann.prefix_str(), ident.name),
                 Applicability::MachineApplicable,
             );
         }
diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs
index 9838d3cad9f..f2ffac85bf4 100644
--- a/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use if_chain::if_chain;
-use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
+use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -120,14 +120,14 @@ impl EarlyLintPass for NeedlessArbitrarySelfType {
 
         match &p.ty.kind {
             TyKind::Path(None, path) => {
-                if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
+                if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), _, _) = p.pat.kind {
                     check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
                 }
             },
             TyKind::Rptr(lifetime, mut_ty) => {
                 if_chain! {
                 if let TyKind::Path(None, path) = &mut_ty.ty.kind;
-                if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
+                if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind;
                     then {
                         check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
                     }
diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs
index 05c012b92e8..b8855e5adbf 100644
--- a/clippy_lints/src/needless_borrowed_ref.rs
+++ b/clippy_lints/src/needless_borrowed_ref.rs
@@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef {
             if let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind;
 
             // Check sub_pat got a `ref` keyword (excluding `ref mut`).
-            if let PatKind::Binding(BindingAnnotation::Ref, .., spanned_name, _) = sub_pat.kind;
+            if let PatKind::Binding(BindingAnnotation::REF, .., spanned_name, _) = sub_pat.kind;
             let parent_id = cx.tcx.hir().get_parent_node(pat.hir_id);
             if let Some(parent_node) = cx.tcx.hir().find(parent_id);
             then {
diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs
index ff2999b1f4a..de99f1d7078 100644
--- a/clippy_lints/src/needless_late_init.rs
+++ b/clippy_lints/src/needless_late_init.rs
@@ -373,7 +373,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
             if let Local {
                 init: None,
                 pat: &Pat {
-                    kind: PatKind::Binding(BindingAnnotation::Unannotated, binding_id, _, None),
+                    kind: PatKind::Binding(BindingAnnotation::NONE, binding_id, _, None),
                     ..
                 },
                 source: LocalSource::Normal,
diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs
index 0cbef1c95fe..6d17c7a7346 100644
--- a/clippy_lints/src/needless_pass_by_value.rs
+++ b/clippy_lints/src/needless_pass_by_value.rs
@@ -8,7 +8,9 @@ use rustc_ast::ast::Attribute;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Node, PatKind, QPath, TyKind};
+use rustc_hir::{
+    BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind,
+};
 use rustc_hir::{HirIdMap, HirIdSet};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
@@ -188,13 +190,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                 if !implements_borrow_trait;
                 if !all_borrowable_trait;
 
-                if let PatKind::Binding(mode, canonical_id, ..) = arg.pat.kind;
+                if let PatKind::Binding(BindingAnnotation(_, Mutability::Not), canonical_id, ..) = arg.pat.kind;
                 if !moved_vars.contains(&canonical_id);
                 then {
-                    if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut {
-                        continue;
-                    }
-
                     // Dereference suggestion
                     let sugg = |diag: &mut Diagnostic| {
                         if let ty::Adt(def, ..) = ty.kind() {
diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs
index 9602d0d1d2e..0315678bf97 100644
--- a/clippy_lints/src/option_if_let_else.rs
+++ b/clippy_lints/src/option_if_let_else.rs
@@ -130,7 +130,7 @@ fn try_get_option_occurence<'tcx>(
             .filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2)))
             .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref());
         then {
-            let capture_mut = if bind_annotation == BindingAnnotation::Mutable { "mut " } else { "" };
+            let capture_mut = if bind_annotation == BindingAnnotation::MUT { "mut " } else { "" };
             let some_body = peel_blocks(if_then);
             let none_body = peel_blocks(if_else);
             let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" };
@@ -138,7 +138,7 @@ fn try_get_option_occurence<'tcx>(
             let (as_ref, as_mut) = match &expr.kind {
                 ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
                 ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
-                _ => (bind_annotation == BindingAnnotation::Ref, bind_annotation == BindingAnnotation::RefMut),
+                _ => (bind_annotation == BindingAnnotation::REF, bind_annotation == BindingAnnotation::REF_MUT),
             };
 
             // Check if captures the closure will need conflict with borrows made in the scrutinee.
diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs
index 5fa4fd74853..0960b050c24 100644
--- a/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/clippy_lints/src/pass_by_ref_or_value.rs
@@ -221,7 +221,7 @@ impl<'tcx> PassByRefOrValue {
                     // if function has a body and parameter is annotated with mut, ignore
                     if let Some(param) = fn_body.and_then(|body| body.params.get(index)) {
                         match param.pat.kind {
-                            PatKind::Binding(BindingAnnotation::Unannotated, _, _, _) => {},
+                            PatKind::Binding(BindingAnnotation::NONE, _, _, _) => {},
                             _ => continue,
                         }
                     }
diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs
index 3c5ea2d9414..47b5ff7e0f0 100644
--- a/clippy_lints/src/ptr.rs
+++ b/clippy_lints/src/ptr.rs
@@ -571,7 +571,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
                 Some((Node::Stmt(_), _)) => (),
                 Some((Node::Local(l), _)) => {
                     // Only trace simple bindings. e.g `let x = y;`
-                    if let PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) = l.pat.kind {
+                    if let PatKind::Binding(BindingAnnotation::NONE, id, _, None) = l.pat.kind {
                         self.bindings.insert(id, args_idx);
                     } else {
                         set_skip_flag();
@@ -644,7 +644,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
             .filter_map(|(i, arg)| {
                 let param = &body.params[arg.idx];
                 match param.pat.kind {
-                    PatKind::Binding(BindingAnnotation::Unannotated, id, _, None)
+                    PatKind::Binding(BindingAnnotation::NONE, id, _, None)
                         if !is_lint_allowed(cx, PTR_ARG, param.hir_id) =>
                     {
                         Some((id, i))
diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs
index b432ccb1ee3..98a62e1b867 100644
--- a/clippy_lints/src/question_mark.rs
+++ b/clippy_lints/src/question_mark.rs
@@ -9,7 +9,7 @@ use clippy_utils::{
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
-use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, PathSegment, QPath};
+use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, Node, PatKind, PathSegment, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -123,7 +123,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
         if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr);
         if !is_else_clause(cx.tcx, expr);
         if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind;
-        if let PatKind::Binding(annot, bind_id, ident, None) = field.kind;
+        if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind;
         let caller_ty = cx.typeck_results().expr_ty(let_expr);
         let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else);
         if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id))
@@ -132,12 +132,11 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr:
         then {
             let mut applicability = Applicability::MachineApplicable;
             let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
-            let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
             let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_)));
             let sugg = format!(
                 "{}{}?{}",
                 receiver_str,
-                if by_ref { ".as_ref()" } else { "" },
+                if by_ref == ByRef::Yes { ".as_ref()" } else { "" },
                 if requires_semi { ";" } else { "" }
             );
             span_lint_and_sugg(
diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs
index b59a25e3a40..3437d196b5d 100644
--- a/clippy_lints/src/slow_vector_initialization.rs
+++ b/clippy_lints/src/slow_vector_initialization.rs
@@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
         // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
         if_chain! {
             if let StmtKind::Local(local) = stmt.kind;
-            if let PatKind::Binding(BindingAnnotation::Mutable, local_id, _, None) = local.pat.kind;
+            if let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind;
             if let Some(init) = local.init;
             if let Some(len_arg) = Self::is_vec_with_capacity(cx, init);
 
diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs
index 04e2f301bfd..fb73c386640 100644
--- a/clippy_lints/src/unnested_or_patterns.rs
+++ b/clippy_lints/src/unnested_or_patterns.rs
@@ -137,12 +137,12 @@ fn insert_necessary_parens(pat: &mut P<Pat>) {
     struct Visitor;
     impl MutVisitor for Visitor {
         fn visit_pat(&mut self, pat: &mut P<Pat>) {
-            use ast::{BindingMode::*, Mutability::*};
+            use ast::BindingAnnotation;
             noop_visit_pat(pat, self);
             let target = match &mut pat.kind {
                 // `i @ a | b`, `box a | b`, and `& mut? a | b`.
                 Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p,
-                Ref(p, Not) if matches!(p.kind, Ident(ByValue(Mut), ..)) => p, // `&(mut x)`
+                Ref(p, Mutability::Not) if matches!(p.kind, Ident(BindingAnnotation::MUT, ..)) => p, // `&(mut x)`
                 _ => return,
             };
             target.kind = Paren(P(take_pat(target)));
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index 429c64ac156..a298c00caed 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -6,7 +6,9 @@ use rustc_ast::ast::{LitFloatType, LitKind};
 use rustc_ast::LitIntType;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
-use rustc_hir::{ArrayLen, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
+use rustc_hir::{
+    ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
+};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::{Ident, Symbol};
@@ -609,10 +611,16 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
         match pat.value.kind {
             PatKind::Wild => kind!("Wild"),
-            PatKind::Binding(anno, .., name, sub) => {
+            PatKind::Binding(ann, _, name, sub) => {
                 bind!(self, name);
                 opt_bind!(self, sub);
-                kind!("Binding(BindingAnnotation::{anno:?}, _, {name}, {sub})");
+                let ann = match ann {
+                    BindingAnnotation::NONE => "NONE",
+                    BindingAnnotation::REF => "REF",
+                    BindingAnnotation::MUT => "MUT",
+                    BindingAnnotation::REF_MUT => "REF_MUT",
+                };
+                kind!("Binding(BindingAnnotation::{ann}, _, {name}, {sub})");
                 self.ident(name);
                 sub.if_some(|p| self.pat(p));
             },
diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs
index 35db45e2b0c..627f6510700 100644
--- a/clippy_lints/src/vec_init_then_push.rs
+++ b/clippy_lints/src/vec_init_then_push.rs
@@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
 
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
         if let Some(init_expr) = local.init
-            && let PatKind::Binding(BindingAnnotation::Mutable, id, name, None) = local.pat.kind
+            && let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind
             && !in_external_macro(cx.sess(), local.span)
             && let Some(init) = get_vec_init_kind(cx, init_expr)
             && !matches!(init, VecInitKind::WithExprCapacity(_))
diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs
index 1834e2a2de8..e531dc29dcc 100644
--- a/clippy_utils/src/hir_utils.rs
+++ b/clippy_utils/src/hir_utils.rs
@@ -6,9 +6,9 @@ use rustc_data_structures::fx::FxHasher;
 use rustc_hir::def::Res;
 use rustc_hir::HirIdMap;
 use rustc_hir::{
-    ArrayLen, BinOpKind, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard,
-    HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath,
-    Stmt, StmtKind, Ty, TyKind, TypeBinding,
+    ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
+    GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path,
+    PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::LateContext;
@@ -815,8 +815,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
     pub fn hash_pat(&mut self, pat: &Pat<'_>) {
         std::mem::discriminant(&pat.kind).hash(&mut self.s);
         match pat.kind {
-            PatKind::Binding(ann, _, _, pat) => {
-                std::mem::discriminant(&ann).hash(&mut self.s);
+            PatKind::Binding(BindingAnnotation(by_ref, mutability), _, _, pat) => {
+                std::mem::discriminant(&by_ref).hash(&mut self.s);
+                std::mem::discriminant(&mutability).hash(&mut self.s);
                 if let Some(pat) = pat {
                     self.hash_pat(pat);
                 }
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 997e773b5da..839e6292f38 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -192,7 +192,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
     let hir = cx.tcx.hir();
     if_chain! {
         if let Some(Node::Pat(pat)) = hir.find(hir_id);
-        if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..));
+        if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..));
         let parent = hir.get_parent_node(hir_id);
         if let Some(Node::Local(local)) = hir.find(parent);
         then {
diff --git a/tests/ui/author.stdout b/tests/ui/author.stdout
index 3125863036b..597318a556b 100644
--- a/tests/ui/author.stdout
+++ b/tests/ui/author.stdout
@@ -6,7 +6,7 @@ if_chain! {
     if match_qpath(qpath, &["char"]);
     if let ExprKind::Lit(ref lit) = expr.kind;
     if let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node;
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind;
     if name.as_str() == "x";
     then {
         // report your lint here
diff --git a/tests/ui/author/blocks.stdout b/tests/ui/author/blocks.stdout
index 2fc4a7d1f7f..a529981e2e6 100644
--- a/tests/ui/author/blocks.stdout
+++ b/tests/ui/author/blocks.stdout
@@ -5,13 +5,13 @@ if_chain! {
     if let Some(init) = local.init;
     if let ExprKind::Lit(ref lit) = init.kind;
     if let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node;
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind;
     if name.as_str() == "x";
     if let StmtKind::Local(local1) = block.stmts[1].kind;
     if let Some(init1) = local1.init;
     if let ExprKind::Lit(ref lit1) = init1.kind;
     if let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node;
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local1.pat.kind;
     if name1.as_str() == "_t";
     if let StmtKind::Semi(e) = block.stmts[2].kind;
     if let ExprKind::Unary(UnOp::Neg, inner) = e.kind;
@@ -31,7 +31,7 @@ if_chain! {
     if let ExprKind::Path(ref qpath) = func.kind;
     if match_qpath(qpath, &["String", "new"]);
     if args.is_empty();
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind;
     if name.as_str() == "expr";
     if let Some(trailing_expr) = block.expr;
     if let ExprKind::Call(func1, args1) = trailing_expr.kind;
diff --git a/tests/ui/author/loop.stdout b/tests/ui/author/loop.stdout
index 3d9560f697a..ceb53fcd496 100644
--- a/tests/ui/author/loop.stdout
+++ b/tests/ui/author/loop.stdout
@@ -1,6 +1,6 @@
 if_chain! {
     if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr);
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind;
     if name.as_str() == "y";
     if let ExprKind::Struct(qpath, fields, None) = arg.kind;
     if matches!(qpath, QPath::LangItem(LangItem::Range, _));
@@ -17,7 +17,7 @@ if_chain! {
     if let Some(init) = local.init;
     if let ExprKind::Path(ref qpath1) = init.kind;
     if match_qpath(qpath1, &["y"]);
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind;
     if name1.as_str() == "z";
     if block.expr.is_none();
     then {
diff --git a/tests/ui/author/matches.stdout b/tests/ui/author/matches.stdout
index 38444a0094c..2cf69a035b4 100644
--- a/tests/ui/author/matches.stdout
+++ b/tests/ui/author/matches.stdout
@@ -21,7 +21,7 @@ if_chain! {
     if let Some(init1) = local1.init;
     if let ExprKind::Lit(ref lit4) = init1.kind;
     if let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node;
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local1.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local1.pat.kind;
     if name.as_str() == "x";
     if let Some(trailing_expr) = block.expr;
     if let ExprKind::Path(ref qpath) = trailing_expr.kind;
@@ -30,7 +30,7 @@ if_chain! {
     if arms[2].guard.is_none();
     if let ExprKind::Lit(ref lit5) = arms[2].body.kind;
     if let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node;
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
+    if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind;
     if name1.as_str() == "a";
     then {
         // report your lint here

From ffc75af4cd01740e9daac43ff24d777525e506c1 Mon Sep 17 00:00:00 2001
From: Lukas Lueg <lukas.lueg@gmail.com>
Date: Fri, 2 Sep 2022 20:28:00 +0200
Subject: [PATCH 15/34] Fix `mut_mutex_lock` for Mutex behind imm deref

Fixes #9415
---
 clippy_lints/src/methods/mut_mutex_lock.rs | 3 ++-
 tests/ui/mut_mutex_lock.fixed              | 7 +++++++
 tests/ui/mut_mutex_lock.rs                 | 7 +++++++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs
index bd8458a222e..b9593b3687d 100644
--- a/clippy_lints/src/methods/mut_mutex_lock.rs
+++ b/clippy_lints/src/methods/mut_mutex_lock.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{expr_custom_deref_adjustment, ty::is_type_diagnostic_item};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability};
@@ -11,6 +11,7 @@ use super::MUT_MUTEX_LOCK;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) {
     if_chain! {
+        if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut));
         if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind();
         if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id);
         if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
diff --git a/tests/ui/mut_mutex_lock.fixed b/tests/ui/mut_mutex_lock.fixed
index 36bc52e3374..ecad10a8290 100644
--- a/tests/ui/mut_mutex_lock.fixed
+++ b/tests/ui/mut_mutex_lock.fixed
@@ -18,4 +18,11 @@ fn no_owned_mutex_lock() {
     *value += 1;
 }
 
+fn issue9415() {
+    let mut arc_mutex = Arc::new(Mutex::new(42_u8));
+    let arc_mutex: &mut Arc<Mutex<u8>> = &mut arc_mutex;
+    let mut guard = arc_mutex.lock().unwrap();
+    *guard += 1;
+}
+
 fn main() {}
diff --git a/tests/ui/mut_mutex_lock.rs b/tests/ui/mut_mutex_lock.rs
index ea60df5ae1b..f2b1d6fbfbc 100644
--- a/tests/ui/mut_mutex_lock.rs
+++ b/tests/ui/mut_mutex_lock.rs
@@ -18,4 +18,11 @@ fn no_owned_mutex_lock() {
     *value += 1;
 }
 
+fn issue9415() {
+    let mut arc_mutex = Arc::new(Mutex::new(42_u8));
+    let arc_mutex: &mut Arc<Mutex<u8>> = &mut arc_mutex;
+    let mut guard = arc_mutex.lock().unwrap();
+    *guard += 1;
+}
+
 fn main() {}

From ad72aee93c80cf2e207e1f728ff0c87336ead695 Mon Sep 17 00:00:00 2001
From: Andre Bogus <bogusandre@gmail.com>
Date: Sun, 5 Jun 2022 10:44:14 +0200
Subject: [PATCH 16/34] add `--explain` subcommand

---
 clippy_dev/src/update_lints.rs                | 188 +++++-
 src/docs.rs                                   | 596 ++++++++++++++++++
 src/docs/absurd_extreme_comparisons.txt       |  25 +
 src/docs/alloc_instead_of_core.txt            |  18 +
 src/docs/allow_attributes_without_reason.txt  |  22 +
 src/docs/almost_complete_letter_range.txt     |  15 +
 src/docs/almost_swapped.txt                   |  15 +
 src/docs/approx_constant.txt                  |  24 +
 src/docs/arithmetic.txt                       |  28 +
 src/docs/as_conversions.txt                   |  32 +
 src/docs/as_underscore.txt                    |  21 +
 src/docs/assertions_on_constants.txt          |  14 +
 src/docs/assertions_on_result_states.txt      |  14 +
 src/docs/assign_op_pattern.txt                |  28 +
 src/docs/async_yields_async.txt               |  28 +
 src/docs/await_holding_invalid_type.txt       |  29 +
 src/docs/await_holding_lock.txt               |  51 ++
 src/docs/await_holding_refcell_ref.txt        |  47 ++
 src/docs/bad_bit_mask.txt                     |  30 +
 src/docs/bind_instead_of_map.txt              |  22 +
 src/docs/blanket_clippy_restriction_lints.txt |  16 +
 src/docs/blocks_in_if_conditions.txt          |  21 +
 src/docs/bool_assert_comparison.txt           |  16 +
 src/docs/bool_comparison.txt                  |  18 +
 src/docs/bool_to_int_with_if.txt              |  26 +
 src/docs/borrow_as_ptr.txt                    |  26 +
 src/docs/borrow_deref_ref.txt                 |  27 +
 src/docs/borrow_interior_mutable_const.txt    |  40 ++
 src/docs/borrowed_box.txt                     |  19 +
 src/docs/box_collection.txt                   |  23 +
 src/docs/boxed_local.txt                      |  18 +
 src/docs/branches_sharing_code.txt            |  32 +
 src/docs/builtin_type_shadow.txt              |  15 +
 src/docs/bytes_count_to_len.txt               |  18 +
 src/docs/bytes_nth.txt                        |  16 +
 src/docs/cargo_common_metadata.txt            |  33 +
 ...e_sensitive_file_extension_comparisons.txt |  21 +
 src/docs/cast_abs_to_unsigned.txt             |  16 +
 src/docs/cast_enum_constructor.txt            |  11 +
 src/docs/cast_enum_truncation.txt             |  12 +
 src/docs/cast_lossless.txt                    |  26 +
 src/docs/cast_possible_truncation.txt         |  16 +
 src/docs/cast_possible_wrap.txt               |  17 +
 src/docs/cast_precision_loss.txt              |  19 +
 src/docs/cast_ptr_alignment.txt               |  21 +
 src/docs/cast_ref_to_mut.txt                  |  28 +
 src/docs/cast_sign_loss.txt                   |  15 +
 src/docs/cast_slice_different_sizes.txt       |  38 ++
 src/docs/cast_slice_from_raw_parts.txt        |  20 +
 src/docs/char_lit_as_u8.txt                   |  21 +
 src/docs/chars_last_cmp.txt                   |  17 +
 src/docs/chars_next_cmp.txt                   |  19 +
 src/docs/checked_conversions.txt              |  15 +
 src/docs/clone_double_ref.txt                 |  16 +
 src/docs/clone_on_copy.txt                    |  11 +
 src/docs/clone_on_ref_ptr.txt                 |  21 +
 src/docs/cloned_instead_of_copied.txt         |  16 +
 src/docs/cmp_nan.txt                          |  16 +
 src/docs/cmp_null.txt                         |  23 +
 src/docs/cmp_owned.txt                        |  18 +
 src/docs/cognitive_complexity.txt             |  13 +
 src/docs/collapsible_else_if.txt              |  29 +
 src/docs/collapsible_if.txt                   |  23 +
 src/docs/collapsible_match.txt                |  31 +
 src/docs/collapsible_str_replace.txt          |  19 +
 src/docs/comparison_chain.txt                 |  36 ++
 src/docs/comparison_to_empty.txt              |  31 +
 src/docs/copy_iterator.txt                    |  20 +
 src/docs/crate_in_macro_def.txt               |  35 +
 src/docs/create_dir.txt                       |  15 +
 src/docs/crosspointer_transmute.txt           |  12 +
 src/docs/dbg_macro.txt                        |  16 +
 src/docs/debug_assert_with_mut_call.txt       |  18 +
 src/docs/decimal_literal_representation.txt   |  13 +
 src/docs/declare_interior_mutable_const.txt   |  46 ++
 src/docs/default_instead_of_iter_empty.txt    |  15 +
 src/docs/default_numeric_fallback.txt         |  28 +
 src/docs/default_trait_access.txt             |  16 +
 src/docs/default_union_representation.txt     |  36 ++
 src/docs/deprecated_cfg_attr.txt              |  24 +
 src/docs/deprecated_semver.txt                |  13 +
 src/docs/deref_addrof.txt                     |  22 +
 src/docs/deref_by_slicing.txt                 |  17 +
 src/docs/derivable_impls.txt                  |  35 +
 src/docs/derive_hash_xor_eq.txt               |  23 +
 src/docs/derive_ord_xor_partial_ord.txt       |  44 ++
 src/docs/derive_partial_eq_without_eq.txt     |  25 +
 src/docs/disallowed_methods.txt               |  41 ++
 src/docs/disallowed_names.txt                 |  12 +
 src/docs/disallowed_script_idents.txt         |  32 +
 src/docs/disallowed_types.txt                 |  33 +
 src/docs/diverging_sub_expression.txt         |  19 +
 src/docs/doc_link_with_quotes.txt             |  16 +
 src/docs/doc_markdown.txt                     |  35 +
 src/docs/double_comparisons.txt               |  17 +
 src/docs/double_must_use.txt                  |  17 +
 src/docs/double_neg.txt                       |  12 +
 src/docs/double_parens.txt                    |  24 +
 src/docs/drop_copy.txt                        |  15 +
 src/docs/drop_non_drop.txt                    |  13 +
 src/docs/drop_ref.txt                         |  17 +
 src/docs/duplicate_mod.txt                    |  31 +
 src/docs/duplicate_underscore_argument.txt    |  16 +
 src/docs/duration_subsec.txt                  |  19 +
 src/docs/else_if_without_else.txt             |  27 +
 src/docs/empty_drop.txt                       |  20 +
 src/docs/empty_enum.txt                       |  27 +
 src/docs/empty_line_after_outer_attr.txt      |  35 +
 src/docs/empty_loop.txt                       |  27 +
 src/docs/empty_structs_with_brackets.txt      |  14 +
 src/docs/enum_clike_unportable_variant.txt    |  16 +
 src/docs/enum_glob_use.txt                    |  24 +
 src/docs/enum_variant_names.txt               |  30 +
 src/docs/eq_op.txt                            |  22 +
 src/docs/equatable_if_let.txt                 |  23 +
 src/docs/erasing_op.txt                       |  15 +
 src/docs/err_expect.txt                       |  16 +
 src/docs/excessive_precision.txt              |  18 +
 src/docs/exhaustive_enums.txt                 |  23 +
 src/docs/exhaustive_structs.txt               |  23 +
 src/docs/exit.txt                             |  12 +
 src/docs/expect_fun_call.txt                  |  24 +
 src/docs/expect_used.txt                      |  26 +
 src/docs/expl_impl_clone_on_copy.txt          |  20 +
 src/docs/explicit_auto_deref.txt              |  16 +
 src/docs/explicit_counter_loop.txt            |  21 +
 src/docs/explicit_deref_methods.txt           |  24 +
 src/docs/explicit_into_iter_loop.txt          |  20 +
 src/docs/explicit_iter_loop.txt               |  25 +
 src/docs/explicit_write.txt                   |  18 +
 src/docs/extend_with_drain.txt                |  21 +
 src/docs/extra_unused_lifetimes.txt           |  23 +
 src/docs/fallible_impl_from.txt               |  32 +
 src/docs/field_reassign_with_default.txt      |  23 +
 src/docs/filetype_is_file.txt                 |  29 +
 src/docs/filter_map_identity.txt              |  14 +
 src/docs/filter_map_next.txt                  |  16 +
 src/docs/filter_next.txt                      |  16 +
 src/docs/flat_map_identity.txt                |  14 +
 src/docs/flat_map_option.txt                  |  16 +
 src/docs/float_arithmetic.txt                 |  11 +
 src/docs/float_cmp.txt                        |  28 +
 src/docs/float_cmp_const.txt                  |  26 +
 src/docs/float_equality_without_abs.txt       |  26 +
 src/docs/fn_address_comparisons.txt           |  17 +
 src/docs/fn_params_excessive_bools.txt        |  31 +
 src/docs/fn_to_numeric_cast.txt               |  21 +
 src/docs/fn_to_numeric_cast_any.txt           |  35 +
 .../fn_to_numeric_cast_with_truncation.txt    |  26 +
 src/docs/for_kv_map.txt                       |  22 +
 src/docs/for_loops_over_fallibles.txt         |  32 +
 src/docs/forget_copy.txt                      |  21 +
 src/docs/forget_non_drop.txt                  |  13 +
 src/docs/forget_ref.txt                       |  15 +
 src/docs/format_in_format_args.txt            |  16 +
 src/docs/format_push_string.txt               |  26 +
 src/docs/from_iter_instead_of_collect.txt     |  24 +
 src/docs/from_over_into.txt                   |  26 +
 src/docs/from_str_radix_10.txt                |  25 +
 src/docs/future_not_send.txt                  |  29 +
 src/docs/get_first.txt                        |  19 +
 src/docs/get_last_with_len.txt                |  26 +
 src/docs/get_unwrap.txt                       |  30 +
 src/docs/identity_op.txt                      |  11 +
 src/docs/if_let_mutex.txt                     |  25 +
 src/docs/if_not_else.txt                      |  25 +
 src/docs/if_same_then_else.txt                |  15 +
 src/docs/if_then_some_else_none.txt           |  26 +
 src/docs/ifs_same_cond.txt                    |  25 +
 src/docs/implicit_clone.txt                   |  19 +
 src/docs/implicit_hasher.txt                  |  26 +
 src/docs/implicit_return.txt                  |  22 +
 src/docs/implicit_saturating_sub.txt          |  21 +
 src/docs/imprecise_flops.txt                  |  23 +
 src/docs/inconsistent_digit_grouping.txt      |  17 +
 src/docs/inconsistent_struct_constructor.txt  |  40 ++
 src/docs/index_refutable_slice.txt            |  29 +
 src/docs/indexing_slicing.txt                 |  33 +
 src/docs/ineffective_bit_mask.txt             |  25 +
 src/docs/inefficient_to_string.txt            |  17 +
 src/docs/infallible_destructuring_match.txt   |  29 +
 src/docs/infinite_iter.txt                    |  13 +
 src/docs/inherent_to_string.txt               |  29 +
 .../inherent_to_string_shadow_display.txt     |  37 ++
 src/docs/init_numbered_fields.txt             |  24 +
 src/docs/inline_always.txt                    |  23 +
 src/docs/inline_asm_x86_att_syntax.txt        |  16 +
 src/docs/inline_asm_x86_intel_syntax.txt      |  16 +
 src/docs/inline_fn_without_body.txt           |  14 +
 src/docs/inspect_for_each.txt                 |  23 +
 src/docs/int_plus_one.txt                     |  15 +
 src/docs/integer_arithmetic.txt               |  18 +
 src/docs/integer_division.txt                 |  19 +
 src/docs/into_iter_on_ref.txt                 |  18 +
 src/docs/invalid_null_ptr_usage.txt           |  16 +
 src/docs/invalid_regex.txt                    |  12 +
 src/docs/invalid_upcast_comparisons.txt       |  18 +
 src/docs/invalid_utf8_in_unchecked.txt        |  12 +
 src/docs/invisible_characters.txt             |  10 +
 src/docs/is_digit_ascii_radix.txt             |  20 +
 src/docs/items_after_statements.txt           |  37 ++
 src/docs/iter_cloned_collect.txt              |  17 +
 src/docs/iter_count.txt                       |  22 +
 src/docs/iter_next_loop.txt                   |  17 +
 src/docs/iter_next_slice.txt                  |  16 +
 src/docs/iter_not_returning_iterator.txt      |  26 +
 src/docs/iter_nth.txt                         |  20 +
 src/docs/iter_nth_zero.txt                    |  17 +
 src/docs/iter_on_empty_collections.txt        |  25 +
 src/docs/iter_on_single_items.txt             |  24 +
 src/docs/iter_overeager_cloned.txt            |  22 +
 src/docs/iter_skip_next.txt                   |  18 +
 src/docs/iter_with_drain.txt                  |  16 +
 src/docs/iterator_step_by_zero.txt            |  13 +
 src/docs/just_underscores_and_digits.txt      |  14 +
 src/docs/large_const_arrays.txt               |  17 +
 src/docs/large_digit_groups.txt               |  12 +
 src/docs/large_enum_variant.txt               |  40 ++
 src/docs/large_include_file.txt               |  21 +
 src/docs/large_stack_arrays.txt               |  10 +
 src/docs/large_types_passed_by_value.txt      |  24 +
 src/docs/len_without_is_empty.txt             |  19 +
 src/docs/len_zero.txt                         |  28 +
 src/docs/let_and_return.txt                   |  21 +
 src/docs/let_underscore_drop.txt              |  29 +
 src/docs/let_underscore_lock.txt              |  20 +
 src/docs/let_underscore_must_use.txt          |  17 +
 src/docs/let_unit_value.txt                   |  13 +
 src/docs/linkedlist.txt                       |  32 +
 src/docs/lossy_float_literal.txt              |  18 +
 src/docs/macro_use_imports.txt                |  12 +
 src/docs/main_recursion.txt                   |  13 +
 src/docs/manual_assert.txt                    |  18 +
 src/docs/manual_async_fn.txt                  |  16 +
 src/docs/manual_bits.txt                      |  15 +
 src/docs/manual_filter_map.txt                |  19 +
 src/docs/manual_find.txt                      |  24 +
 src/docs/manual_find_map.txt                  |  19 +
 src/docs/manual_flatten.txt                   |  25 +
 src/docs/manual_instant_elapsed.txt           |  21 +
 src/docs/manual_map.txt                       |  17 +
 src/docs/manual_memcpy.txt                    |  18 +
 src/docs/manual_non_exhaustive.txt            |  41 ++
 src/docs/manual_ok_or.txt                     |  19 +
 src/docs/manual_range_contains.txt            |  19 +
 src/docs/manual_rem_euclid.txt                |  17 +
 src/docs/manual_retain.txt                    |  15 +
 src/docs/manual_saturating_arithmetic.txt     |  18 +
 src/docs/manual_split_once.txt                |  29 +
 src/docs/manual_str_repeat.txt                |  15 +
 src/docs/manual_string_new.txt                |  20 +
 src/docs/manual_strip.txt                     |  24 +
 src/docs/manual_swap.txt                      |  22 +
 src/docs/manual_unwrap_or.txt                 |  20 +
 src/docs/many_single_char_names.txt           |  12 +
 src/docs/map_clone.txt                        |  22 +
 src/docs/map_collect_result_unit.txt          |  14 +
 src/docs/map_entry.txt                        |  28 +
 src/docs/map_err_ignore.txt                   |  93 +++
 src/docs/map_flatten.txt                      |  21 +
 src/docs/map_identity.txt                     |  16 +
 src/docs/map_unwrap_or.txt                    |  22 +
 src/docs/match_as_ref.txt                     |  23 +
 src/docs/match_bool.txt                       |  24 +
 src/docs/match_like_matches_macro.txt         |  32 +
 src/docs/match_on_vec_items.txt               |  29 +
 src/docs/match_overlapping_arm.txt            |  16 +
 src/docs/match_ref_pats.txt                   |  26 +
 src/docs/match_result_ok.txt                  |  27 +
 src/docs/match_same_arms.txt                  |  38 ++
 src/docs/match_single_binding.txt             |  23 +
 src/docs/match_str_case_mismatch.txt          |  22 +
 src/docs/match_wild_err_arm.txt               |  16 +
 .../match_wildcard_for_single_variants.txt    |  27 +
 src/docs/maybe_infinite_iter.txt              |  16 +
 src/docs/mem_forget.txt                       |  12 +
 src/docs/mem_replace_option_with_none.txt     |  21 +
 src/docs/mem_replace_with_default.txt         |  18 +
 src/docs/mem_replace_with_uninit.txt          |  24 +
 src/docs/min_max.txt                          |  18 +
 src/docs/mismatched_target_os.txt             |  24 +
 src/docs/mismatching_type_param_order.txt     |  33 +
 src/docs/misrefactored_assign_op.txt          |  20 +
 src/docs/missing_const_for_fn.txt             |  40 ++
 src/docs/missing_docs_in_private_items.txt    |   9 +
 src/docs/missing_enforced_import_renames.txt  |  22 +
 src/docs/missing_errors_doc.txt               |  21 +
 src/docs/missing_inline_in_public_items.txt   |  45 ++
 src/docs/missing_panics_doc.txt               |  24 +
 src/docs/missing_safety_doc.txt               |  26 +
 src/docs/missing_spin_loop.txt                |  27 +
 src/docs/mistyped_literal_suffixes.txt        |  15 +
 src/docs/mixed_case_hex_literals.txt          |  16 +
 src/docs/mixed_read_write_in_expression.txt   |  32 +
 src/docs/mod_module_files.txt                 |  22 +
 src/docs/module_inception.txt                 |  24 +
 src/docs/module_name_repetitions.txt          |  20 +
 src/docs/modulo_arithmetic.txt                |  15 +
 src/docs/modulo_one.txt                       |  16 +
 src/docs/multi_assignments.txt                |  17 +
 src/docs/multiple_crate_versions.txt          |  19 +
 src/docs/multiple_inherent_impl.txt           |  26 +
 src/docs/must_use_candidate.txt               |  23 +
 src/docs/must_use_unit.txt                    |  13 +
 src/docs/mut_from_ref.txt                     |  26 +
 src/docs/mut_mut.txt                          |  12 +
 src/docs/mut_mutex_lock.txt                   |  29 +
 src/docs/mut_range_bound.txt                  |  29 +
 src/docs/mutable_key_type.txt                 |  61 ++
 src/docs/mutex_atomic.txt                     |  22 +
 src/docs/mutex_integer.txt                    |  22 +
 src/docs/naive_bytecount.txt                  |  22 +
 src/docs/needless_arbitrary_self_type.txt     |  44 ++
 src/docs/needless_bitwise_bool.txt            |  22 +
 src/docs/needless_bool.txt                    |  26 +
 src/docs/needless_borrow.txt                  |  21 +
 src/docs/needless_borrowed_reference.txt      |  30 +
 src/docs/needless_collect.txt                 |  14 +
 src/docs/needless_continue.txt                |  61 ++
 src/docs/needless_doctest_main.txt            |  22 +
 src/docs/needless_for_each.txt                |  24 +
 src/docs/needless_late_init.txt               |  42 ++
 src/docs/needless_lifetimes.txt               |  29 +
 src/docs/needless_match.txt                   |  36 ++
 src/docs/needless_option_as_deref.txt         |  18 +
 src/docs/needless_option_take.txt             |  17 +
 .../needless_parens_on_range_literals.txt     |  23 +
 src/docs/needless_pass_by_value.txt           |  27 +
 src/docs/needless_question_mark.txt           |  43 ++
 src/docs/needless_range_loop.txt              |  23 +
 src/docs/needless_return.txt                  |  19 +
 src/docs/needless_splitn.txt                  |  16 +
 src/docs/needless_update.txt                  |  30 +
 src/docs/neg_cmp_op_on_partial_ord.txt        |  26 +
 src/docs/neg_multiply.txt                     |  18 +
 src/docs/negative_feature_names.txt           |  22 +
 src/docs/never_loop.txt                       |  15 +
 src/docs/new_ret_no_self.txt                  |  47 ++
 src/docs/new_without_default.txt              |  32 +
 src/docs/no_effect.txt                        |  12 +
 src/docs/no_effect_replace.txt                |  11 +
 src/docs/no_effect_underscore_binding.txt     |  16 +
 src/docs/non_ascii_literal.txt                |  19 +
 src/docs/non_octal_unix_permissions.txt       |  23 +
 src/docs/non_send_fields_in_send_ty.txt       |  36 ++
 src/docs/nonminimal_bool.txt                  |  23 +
 src/docs/nonsensical_open_options.txt         |  14 +
 src/docs/nonstandard_macro_braces.txt         |  15 +
 src/docs/not_unsafe_ptr_arg_deref.txt         |  30 +
 src/docs/obfuscated_if_else.txt               |  21 +
 src/docs/octal_escapes.txt                    |  33 +
 src/docs/ok_expect.txt                        |  19 +
 src/docs/only_used_in_recursion.txt           |  58 ++
 src/docs/op_ref.txt                           |  17 +
 src/docs/option_as_ref_deref.txt              |  15 +
 src/docs/option_env_unwrap.txt                |  19 +
 src/docs/option_filter_map.txt                |  15 +
 src/docs/option_if_let_else.txt               |  46 ++
 src/docs/option_map_or_none.txt               |  19 +
 src/docs/option_map_unit_fn.txt               |  27 +
 src/docs/option_option.txt                    |  32 +
 src/docs/or_fun_call.txt                      |  26 +
 src/docs/or_then_unwrap.txt                   |  22 +
 src/docs/out_of_bounds_indexing.txt           |  22 +
 src/docs/overflow_check_conditional.txt       |  11 +
 src/docs/overly_complex_bool_expr.txt         |  20 +
 src/docs/panic.txt                            |  10 +
 src/docs/panic_in_result_fn.txt               |  22 +
 src/docs/panicking_unwrap.txt                 |  18 +
 src/docs/partialeq_ne_impl.txt                |  18 +
 src/docs/partialeq_to_none.txt                |  24 +
 src/docs/path_buf_push_overwrite.txt          |  25 +
 src/docs/pattern_type_mismatch.txt            |  64 ++
 .../positional_named_format_parameters.txt    |  15 +
 src/docs/possible_missing_comma.txt           |  14 +
 src/docs/precedence.txt                       |  17 +
 src/docs/print_in_format_impl.txt             |  34 +
 src/docs/print_literal.txt                    |  20 +
 src/docs/print_stderr.txt                     |  21 +
 src/docs/print_stdout.txt                     |  21 +
 src/docs/print_with_newline.txt               |  16 +
 src/docs/println_empty_string.txt             |  16 +
 src/docs/ptr_arg.txt                          |  29 +
 src/docs/ptr_as_ptr.txt                       |  22 +
 src/docs/ptr_eq.txt                           |  22 +
 src/docs/ptr_offset_with_cast.txt             |  30 +
 src/docs/pub_use.txt                          |  28 +
 src/docs/question_mark.txt                    |  18 +
 src/docs/range_minus_one.txt                  |  27 +
 src/docs/range_plus_one.txt                   |  36 ++
 src/docs/range_zip_with_len.txt               |  16 +
 src/docs/rc_buffer.txt                        |  27 +
 src/docs/rc_clone_in_vec_init.txt             |  29 +
 src/docs/rc_mutex.txt                         |  26 +
 src/docs/read_zero_byte_vec.txt               |  30 +
 src/docs/recursive_format_impl.txt            |  32 +
 src/docs/redundant_allocation.txt             |  17 +
 src/docs/redundant_clone.txt                  |  23 +
 src/docs/redundant_closure.txt                |  25 +
 src/docs/redundant_closure_call.txt           |  17 +
 .../redundant_closure_for_method_calls.txt    |  15 +
 src/docs/redundant_else.txt                   |  30 +
 src/docs/redundant_feature_names.txt          |  23 +
 src/docs/redundant_field_names.txt            |  22 +
 src/docs/redundant_pattern.txt                |  22 +
 src/docs/redundant_pattern_matching.txt       |  45 ++
 src/docs/redundant_pub_crate.txt              |  21 +
 src/docs/redundant_slicing.txt                |  24 +
 src/docs/redundant_static_lifetimes.txt       |  19 +
 src/docs/ref_binding_to_reference.txt         |  21 +
 src/docs/ref_option_ref.txt                   |  19 +
 src/docs/repeat_once.txt                      |  25 +
 src/docs/rest_pat_in_fully_bound_structs.txt  |  24 +
 src/docs/result_large_err.txt                 |  36 ++
 src/docs/result_map_or_into_option.txt        |  16 +
 src/docs/result_map_unit_fn.txt               |  26 +
 src/docs/result_unit_err.txt                  |  40 ++
 src/docs/return_self_not_must_use.txt         |  46 ++
 src/docs/reversed_empty_ranges.txt            |  26 +
 src/docs/same_functions_in_if_condition.txt   |  41 ++
 src/docs/same_item_push.txt                   |  29 +
 src/docs/same_name_method.txt                 |  23 +
 src/docs/search_is_some.txt                   |  24 +
 src/docs/self_assignment.txt                  |  32 +
 src/docs/self_named_constructors.txt          |  26 +
 src/docs/self_named_module_files.txt          |  22 +
 src/docs/semicolon_if_nothing_returned.txt    |  20 +
 src/docs/separated_literal_suffix.txt         |  17 +
 src/docs/serde_api_misuse.txt                 |  10 +
 src/docs/shadow_reuse.txt                     |  20 +
 src/docs/shadow_same.txt                      |  18 +
 src/docs/shadow_unrelated.txt                 |  22 +
 src/docs/short_circuit_statement.txt          |  14 +
 src/docs/should_implement_trait.txt           |  22 +
 src/docs/significant_drop_in_scrutinee.txt    |  43 ++
 src/docs/similar_names.txt                    |  12 +
 src/docs/single_char_add_str.txt              |  18 +
 src/docs/single_char_lifetime_names.txt       |  28 +
 src/docs/single_char_pattern.txt              |  20 +
 src/docs/single_component_path_imports.txt    |  21 +
 src/docs/single_element_loop.txt              |  21 +
 src/docs/single_match.txt                     |  21 +
 src/docs/single_match_else.txt                |  29 +
 src/docs/size_of_in_element_count.txt         |  16 +
 src/docs/skip_while_next.txt                  |  16 +
 src/docs/slow_vector_initialization.txt       |  24 +
 src/docs/stable_sort_primitive.txt            |  31 +
 src/docs/std_instead_of_alloc.txt             |  18 +
 src/docs/std_instead_of_core.txt              |  18 +
 src/docs/str_to_string.txt                    |  18 +
 src/docs/string_add.txt                       |  27 +
 src/docs/string_add_assign.txt                |  17 +
 src/docs/string_extend_chars.txt              |  23 +
 src/docs/string_from_utf8_as_bytes.txt        |  15 +
 src/docs/string_lit_as_bytes.txt              |  39 ++
 src/docs/string_slice.txt                     |  17 +
 src/docs/string_to_string.txt                 |  19 +
 src/docs/strlen_on_c_strings.txt              |  20 +
 src/docs/struct_excessive_bools.txt           |  29 +
 src/docs/suboptimal_flops.txt                 |  50 ++
 src/docs/suspicious_arithmetic_impl.txt       |  17 +
 src/docs/suspicious_assignment_formatting.txt |  12 +
 src/docs/suspicious_else_formatting.txt       |  30 +
 src/docs/suspicious_map.txt                   |  13 +
 src/docs/suspicious_op_assign_impl.txt        |  15 +
 src/docs/suspicious_operation_groupings.txt   |  41 ++
 src/docs/suspicious_splitn.txt                |  22 +
 src/docs/suspicious_to_owned.txt              |  39 ++
 src/docs/suspicious_unary_op_formatting.txt   |  18 +
 src/docs/swap_ptr_to_ref.txt                  |  23 +
 src/docs/tabs_in_doc_comments.txt             |  44 ++
 src/docs/temporary_assignment.txt             |  12 +
 src/docs/to_digit_is_some.txt                 |  15 +
 src/docs/to_string_in_format_args.txt         |  17 +
 src/docs/todo.txt                             |  10 +
 src/docs/too_many_arguments.txt               |  14 +
 src/docs/too_many_lines.txt                   |  17 +
 src/docs/toplevel_ref_arg.txt                 |  28 +
 src/docs/trailing_empty_array.txt             |  22 +
 src/docs/trait_duplication_in_bounds.txt      |  37 ++
 src/docs/transmute_bytes_to_str.txt           |  27 +
 src/docs/transmute_float_to_int.txt           |  16 +
 src/docs/transmute_int_to_bool.txt            |  16 +
 src/docs/transmute_int_to_char.txt            |  27 +
 src/docs/transmute_int_to_float.txt           |  16 +
 src/docs/transmute_num_to_bytes.txt           |  16 +
 src/docs/transmute_ptr_to_ptr.txt             |  21 +
 src/docs/transmute_ptr_to_ref.txt             |  21 +
 src/docs/transmute_undefined_repr.txt         |  22 +
 .../transmutes_expressible_as_ptr_casts.txt   |  16 +
 src/docs/transmuting_null.txt                 |  15 +
 src/docs/trim_split_whitespace.txt            |  14 +
 src/docs/trivial_regex.txt                    |  18 +
 src/docs/trivially_copy_pass_by_ref.txt       |  43 ++
 src/docs/try_err.txt                          |  28 +
 src/docs/type_complexity.txt                  |  14 +
 src/docs/type_repetition_in_bounds.txt        |  16 +
 src/docs/undocumented_unsafe_blocks.txt       |  43 ++
 src/docs/undropped_manually_drops.txt         |  22 +
 src/docs/unicode_not_nfc.txt                  |  12 +
 src/docs/unimplemented.txt                    |  10 +
 src/docs/uninit_assumed_init.txt              |  28 +
 src/docs/uninit_vec.txt                       |  41 ++
 src/docs/unit_arg.txt                         |  14 +
 src/docs/unit_cmp.txt                         |  33 +
 src/docs/unit_hash.txt                        |  20 +
 src/docs/unit_return_expecting_ord.txt        |  20 +
 src/docs/unnecessary_cast.txt                 |  19 +
 src/docs/unnecessary_filter_map.txt           |  23 +
 src/docs/unnecessary_find_map.txt             |  23 +
 src/docs/unnecessary_fold.txt                 |  17 +
 src/docs/unnecessary_join.txt                 |  25 +
 src/docs/unnecessary_lazy_evaluations.txt     |  32 +
 src/docs/unnecessary_mut_passed.txt           |  17 +
 src/docs/unnecessary_operation.txt            |  12 +
 src/docs/unnecessary_owned_empty_strings.txt  |  16 +
 src/docs/unnecessary_self_imports.txt         |  19 +
 src/docs/unnecessary_sort_by.txt              |  21 +
 src/docs/unnecessary_to_owned.txt             |  24 +
 src/docs/unnecessary_unwrap.txt               |  20 +
 src/docs/unnecessary_wraps.txt                |  36 ++
 src/docs/unneeded_field_pattern.txt           |  26 +
 src/docs/unneeded_wildcard_pattern.txt        |  28 +
 src/docs/unnested_or_patterns.txt             |  22 +
 src/docs/unreachable.txt                      |  10 +
 src/docs/unreadable_literal.txt               |  16 +
 src/docs/unsafe_derive_deserialize.txt        |  27 +
 src/docs/unsafe_removed_from_name.txt         |  15 +
 src/docs/unseparated_literal_suffix.txt       |  18 +
 src/docs/unsound_collection_transmute.txt     |  25 +
 src/docs/unused_async.txt                     |  23 +
 src/docs/unused_io_amount.txt                 |  31 +
 src/docs/unused_peekable.txt                  |  26 +
 src/docs/unused_rounding.txt                  |  17 +
 src/docs/unused_self.txt                      |  23 +
 src/docs/unused_unit.txt                      |  18 +
 src/docs/unusual_byte_groupings.txt           |  12 +
 src/docs/unwrap_in_result.txt                 |  39 ++
 src/docs/unwrap_or_else_default.txt           |  18 +
 src/docs/unwrap_used.txt                      |  37 ++
 src/docs/upper_case_acronyms.txt              |  25 +
 src/docs/use_debug.txt                        |  12 +
 src/docs/use_self.txt                         |  31 +
 src/docs/used_underscore_binding.txt          |  19 +
 src/docs/useless_asref.txt                    |  17 +
 src/docs/useless_attribute.txt                |  36 ++
 src/docs/useless_conversion.txt               |  17 +
 src/docs/useless_format.txt                   |  22 +
 src/docs/useless_let_if_seq.txt               |  39 ++
 src/docs/useless_transmute.txt                |  12 +
 src/docs/useless_vec.txt                      |  18 +
 src/docs/vec_box.txt                          |  26 +
 src/docs/vec_init_then_push.txt               |  23 +
 src/docs/vec_resize_to_zero.txt               |  15 +
 src/docs/verbose_bit_mask.txt                 |  15 +
 src/docs/verbose_file_reads.txt               |  17 +
 src/docs/vtable_address_comparisons.txt       |  17 +
 src/docs/while_immutable_condition.txt        |  20 +
 src/docs/while_let_loop.txt                   |  25 +
 src/docs/while_let_on_iterator.txt            |  20 +
 src/docs/wildcard_dependencies.txt            |  13 +
 src/docs/wildcard_enum_match_arm.txt          |  25 +
 src/docs/wildcard_imports.txt                 |  45 ++
 src/docs/wildcard_in_or_patterns.txt          |  22 +
 src/docs/write_literal.txt                    |  21 +
 src/docs/write_with_newline.txt               |  18 +
 src/docs/writeln_empty_string.txt             |  16 +
 src/docs/wrong_self_convention.txt            |  39 ++
 src/docs/wrong_transmute.txt                  |  15 +
 src/docs/zero_divided_by_zero.txt             |  15 +
 src/docs/zero_prefixed_literal.txt            |  32 +
 src/docs/zero_ptr.txt                         |  16 +
 src/docs/zero_sized_map_values.txt            |  24 +
 src/docs/zst_offset.txt                       |  11 +
 src/main.rs                                   |  13 +
 575 files changed, 13817 insertions(+), 28 deletions(-)
 create mode 100644 src/docs.rs
 create mode 100644 src/docs/absurd_extreme_comparisons.txt
 create mode 100644 src/docs/alloc_instead_of_core.txt
 create mode 100644 src/docs/allow_attributes_without_reason.txt
 create mode 100644 src/docs/almost_complete_letter_range.txt
 create mode 100644 src/docs/almost_swapped.txt
 create mode 100644 src/docs/approx_constant.txt
 create mode 100644 src/docs/arithmetic.txt
 create mode 100644 src/docs/as_conversions.txt
 create mode 100644 src/docs/as_underscore.txt
 create mode 100644 src/docs/assertions_on_constants.txt
 create mode 100644 src/docs/assertions_on_result_states.txt
 create mode 100644 src/docs/assign_op_pattern.txt
 create mode 100644 src/docs/async_yields_async.txt
 create mode 100644 src/docs/await_holding_invalid_type.txt
 create mode 100644 src/docs/await_holding_lock.txt
 create mode 100644 src/docs/await_holding_refcell_ref.txt
 create mode 100644 src/docs/bad_bit_mask.txt
 create mode 100644 src/docs/bind_instead_of_map.txt
 create mode 100644 src/docs/blanket_clippy_restriction_lints.txt
 create mode 100644 src/docs/blocks_in_if_conditions.txt
 create mode 100644 src/docs/bool_assert_comparison.txt
 create mode 100644 src/docs/bool_comparison.txt
 create mode 100644 src/docs/bool_to_int_with_if.txt
 create mode 100644 src/docs/borrow_as_ptr.txt
 create mode 100644 src/docs/borrow_deref_ref.txt
 create mode 100644 src/docs/borrow_interior_mutable_const.txt
 create mode 100644 src/docs/borrowed_box.txt
 create mode 100644 src/docs/box_collection.txt
 create mode 100644 src/docs/boxed_local.txt
 create mode 100644 src/docs/branches_sharing_code.txt
 create mode 100644 src/docs/builtin_type_shadow.txt
 create mode 100644 src/docs/bytes_count_to_len.txt
 create mode 100644 src/docs/bytes_nth.txt
 create mode 100644 src/docs/cargo_common_metadata.txt
 create mode 100644 src/docs/case_sensitive_file_extension_comparisons.txt
 create mode 100644 src/docs/cast_abs_to_unsigned.txt
 create mode 100644 src/docs/cast_enum_constructor.txt
 create mode 100644 src/docs/cast_enum_truncation.txt
 create mode 100644 src/docs/cast_lossless.txt
 create mode 100644 src/docs/cast_possible_truncation.txt
 create mode 100644 src/docs/cast_possible_wrap.txt
 create mode 100644 src/docs/cast_precision_loss.txt
 create mode 100644 src/docs/cast_ptr_alignment.txt
 create mode 100644 src/docs/cast_ref_to_mut.txt
 create mode 100644 src/docs/cast_sign_loss.txt
 create mode 100644 src/docs/cast_slice_different_sizes.txt
 create mode 100644 src/docs/cast_slice_from_raw_parts.txt
 create mode 100644 src/docs/char_lit_as_u8.txt
 create mode 100644 src/docs/chars_last_cmp.txt
 create mode 100644 src/docs/chars_next_cmp.txt
 create mode 100644 src/docs/checked_conversions.txt
 create mode 100644 src/docs/clone_double_ref.txt
 create mode 100644 src/docs/clone_on_copy.txt
 create mode 100644 src/docs/clone_on_ref_ptr.txt
 create mode 100644 src/docs/cloned_instead_of_copied.txt
 create mode 100644 src/docs/cmp_nan.txt
 create mode 100644 src/docs/cmp_null.txt
 create mode 100644 src/docs/cmp_owned.txt
 create mode 100644 src/docs/cognitive_complexity.txt
 create mode 100644 src/docs/collapsible_else_if.txt
 create mode 100644 src/docs/collapsible_if.txt
 create mode 100644 src/docs/collapsible_match.txt
 create mode 100644 src/docs/collapsible_str_replace.txt
 create mode 100644 src/docs/comparison_chain.txt
 create mode 100644 src/docs/comparison_to_empty.txt
 create mode 100644 src/docs/copy_iterator.txt
 create mode 100644 src/docs/crate_in_macro_def.txt
 create mode 100644 src/docs/create_dir.txt
 create mode 100644 src/docs/crosspointer_transmute.txt
 create mode 100644 src/docs/dbg_macro.txt
 create mode 100644 src/docs/debug_assert_with_mut_call.txt
 create mode 100644 src/docs/decimal_literal_representation.txt
 create mode 100644 src/docs/declare_interior_mutable_const.txt
 create mode 100644 src/docs/default_instead_of_iter_empty.txt
 create mode 100644 src/docs/default_numeric_fallback.txt
 create mode 100644 src/docs/default_trait_access.txt
 create mode 100644 src/docs/default_union_representation.txt
 create mode 100644 src/docs/deprecated_cfg_attr.txt
 create mode 100644 src/docs/deprecated_semver.txt
 create mode 100644 src/docs/deref_addrof.txt
 create mode 100644 src/docs/deref_by_slicing.txt
 create mode 100644 src/docs/derivable_impls.txt
 create mode 100644 src/docs/derive_hash_xor_eq.txt
 create mode 100644 src/docs/derive_ord_xor_partial_ord.txt
 create mode 100644 src/docs/derive_partial_eq_without_eq.txt
 create mode 100644 src/docs/disallowed_methods.txt
 create mode 100644 src/docs/disallowed_names.txt
 create mode 100644 src/docs/disallowed_script_idents.txt
 create mode 100644 src/docs/disallowed_types.txt
 create mode 100644 src/docs/diverging_sub_expression.txt
 create mode 100644 src/docs/doc_link_with_quotes.txt
 create mode 100644 src/docs/doc_markdown.txt
 create mode 100644 src/docs/double_comparisons.txt
 create mode 100644 src/docs/double_must_use.txt
 create mode 100644 src/docs/double_neg.txt
 create mode 100644 src/docs/double_parens.txt
 create mode 100644 src/docs/drop_copy.txt
 create mode 100644 src/docs/drop_non_drop.txt
 create mode 100644 src/docs/drop_ref.txt
 create mode 100644 src/docs/duplicate_mod.txt
 create mode 100644 src/docs/duplicate_underscore_argument.txt
 create mode 100644 src/docs/duration_subsec.txt
 create mode 100644 src/docs/else_if_without_else.txt
 create mode 100644 src/docs/empty_drop.txt
 create mode 100644 src/docs/empty_enum.txt
 create mode 100644 src/docs/empty_line_after_outer_attr.txt
 create mode 100644 src/docs/empty_loop.txt
 create mode 100644 src/docs/empty_structs_with_brackets.txt
 create mode 100644 src/docs/enum_clike_unportable_variant.txt
 create mode 100644 src/docs/enum_glob_use.txt
 create mode 100644 src/docs/enum_variant_names.txt
 create mode 100644 src/docs/eq_op.txt
 create mode 100644 src/docs/equatable_if_let.txt
 create mode 100644 src/docs/erasing_op.txt
 create mode 100644 src/docs/err_expect.txt
 create mode 100644 src/docs/excessive_precision.txt
 create mode 100644 src/docs/exhaustive_enums.txt
 create mode 100644 src/docs/exhaustive_structs.txt
 create mode 100644 src/docs/exit.txt
 create mode 100644 src/docs/expect_fun_call.txt
 create mode 100644 src/docs/expect_used.txt
 create mode 100644 src/docs/expl_impl_clone_on_copy.txt
 create mode 100644 src/docs/explicit_auto_deref.txt
 create mode 100644 src/docs/explicit_counter_loop.txt
 create mode 100644 src/docs/explicit_deref_methods.txt
 create mode 100644 src/docs/explicit_into_iter_loop.txt
 create mode 100644 src/docs/explicit_iter_loop.txt
 create mode 100644 src/docs/explicit_write.txt
 create mode 100644 src/docs/extend_with_drain.txt
 create mode 100644 src/docs/extra_unused_lifetimes.txt
 create mode 100644 src/docs/fallible_impl_from.txt
 create mode 100644 src/docs/field_reassign_with_default.txt
 create mode 100644 src/docs/filetype_is_file.txt
 create mode 100644 src/docs/filter_map_identity.txt
 create mode 100644 src/docs/filter_map_next.txt
 create mode 100644 src/docs/filter_next.txt
 create mode 100644 src/docs/flat_map_identity.txt
 create mode 100644 src/docs/flat_map_option.txt
 create mode 100644 src/docs/float_arithmetic.txt
 create mode 100644 src/docs/float_cmp.txt
 create mode 100644 src/docs/float_cmp_const.txt
 create mode 100644 src/docs/float_equality_without_abs.txt
 create mode 100644 src/docs/fn_address_comparisons.txt
 create mode 100644 src/docs/fn_params_excessive_bools.txt
 create mode 100644 src/docs/fn_to_numeric_cast.txt
 create mode 100644 src/docs/fn_to_numeric_cast_any.txt
 create mode 100644 src/docs/fn_to_numeric_cast_with_truncation.txt
 create mode 100644 src/docs/for_kv_map.txt
 create mode 100644 src/docs/for_loops_over_fallibles.txt
 create mode 100644 src/docs/forget_copy.txt
 create mode 100644 src/docs/forget_non_drop.txt
 create mode 100644 src/docs/forget_ref.txt
 create mode 100644 src/docs/format_in_format_args.txt
 create mode 100644 src/docs/format_push_string.txt
 create mode 100644 src/docs/from_iter_instead_of_collect.txt
 create mode 100644 src/docs/from_over_into.txt
 create mode 100644 src/docs/from_str_radix_10.txt
 create mode 100644 src/docs/future_not_send.txt
 create mode 100644 src/docs/get_first.txt
 create mode 100644 src/docs/get_last_with_len.txt
 create mode 100644 src/docs/get_unwrap.txt
 create mode 100644 src/docs/identity_op.txt
 create mode 100644 src/docs/if_let_mutex.txt
 create mode 100644 src/docs/if_not_else.txt
 create mode 100644 src/docs/if_same_then_else.txt
 create mode 100644 src/docs/if_then_some_else_none.txt
 create mode 100644 src/docs/ifs_same_cond.txt
 create mode 100644 src/docs/implicit_clone.txt
 create mode 100644 src/docs/implicit_hasher.txt
 create mode 100644 src/docs/implicit_return.txt
 create mode 100644 src/docs/implicit_saturating_sub.txt
 create mode 100644 src/docs/imprecise_flops.txt
 create mode 100644 src/docs/inconsistent_digit_grouping.txt
 create mode 100644 src/docs/inconsistent_struct_constructor.txt
 create mode 100644 src/docs/index_refutable_slice.txt
 create mode 100644 src/docs/indexing_slicing.txt
 create mode 100644 src/docs/ineffective_bit_mask.txt
 create mode 100644 src/docs/inefficient_to_string.txt
 create mode 100644 src/docs/infallible_destructuring_match.txt
 create mode 100644 src/docs/infinite_iter.txt
 create mode 100644 src/docs/inherent_to_string.txt
 create mode 100644 src/docs/inherent_to_string_shadow_display.txt
 create mode 100644 src/docs/init_numbered_fields.txt
 create mode 100644 src/docs/inline_always.txt
 create mode 100644 src/docs/inline_asm_x86_att_syntax.txt
 create mode 100644 src/docs/inline_asm_x86_intel_syntax.txt
 create mode 100644 src/docs/inline_fn_without_body.txt
 create mode 100644 src/docs/inspect_for_each.txt
 create mode 100644 src/docs/int_plus_one.txt
 create mode 100644 src/docs/integer_arithmetic.txt
 create mode 100644 src/docs/integer_division.txt
 create mode 100644 src/docs/into_iter_on_ref.txt
 create mode 100644 src/docs/invalid_null_ptr_usage.txt
 create mode 100644 src/docs/invalid_regex.txt
 create mode 100644 src/docs/invalid_upcast_comparisons.txt
 create mode 100644 src/docs/invalid_utf8_in_unchecked.txt
 create mode 100644 src/docs/invisible_characters.txt
 create mode 100644 src/docs/is_digit_ascii_radix.txt
 create mode 100644 src/docs/items_after_statements.txt
 create mode 100644 src/docs/iter_cloned_collect.txt
 create mode 100644 src/docs/iter_count.txt
 create mode 100644 src/docs/iter_next_loop.txt
 create mode 100644 src/docs/iter_next_slice.txt
 create mode 100644 src/docs/iter_not_returning_iterator.txt
 create mode 100644 src/docs/iter_nth.txt
 create mode 100644 src/docs/iter_nth_zero.txt
 create mode 100644 src/docs/iter_on_empty_collections.txt
 create mode 100644 src/docs/iter_on_single_items.txt
 create mode 100644 src/docs/iter_overeager_cloned.txt
 create mode 100644 src/docs/iter_skip_next.txt
 create mode 100644 src/docs/iter_with_drain.txt
 create mode 100644 src/docs/iterator_step_by_zero.txt
 create mode 100644 src/docs/just_underscores_and_digits.txt
 create mode 100644 src/docs/large_const_arrays.txt
 create mode 100644 src/docs/large_digit_groups.txt
 create mode 100644 src/docs/large_enum_variant.txt
 create mode 100644 src/docs/large_include_file.txt
 create mode 100644 src/docs/large_stack_arrays.txt
 create mode 100644 src/docs/large_types_passed_by_value.txt
 create mode 100644 src/docs/len_without_is_empty.txt
 create mode 100644 src/docs/len_zero.txt
 create mode 100644 src/docs/let_and_return.txt
 create mode 100644 src/docs/let_underscore_drop.txt
 create mode 100644 src/docs/let_underscore_lock.txt
 create mode 100644 src/docs/let_underscore_must_use.txt
 create mode 100644 src/docs/let_unit_value.txt
 create mode 100644 src/docs/linkedlist.txt
 create mode 100644 src/docs/lossy_float_literal.txt
 create mode 100644 src/docs/macro_use_imports.txt
 create mode 100644 src/docs/main_recursion.txt
 create mode 100644 src/docs/manual_assert.txt
 create mode 100644 src/docs/manual_async_fn.txt
 create mode 100644 src/docs/manual_bits.txt
 create mode 100644 src/docs/manual_filter_map.txt
 create mode 100644 src/docs/manual_find.txt
 create mode 100644 src/docs/manual_find_map.txt
 create mode 100644 src/docs/manual_flatten.txt
 create mode 100644 src/docs/manual_instant_elapsed.txt
 create mode 100644 src/docs/manual_map.txt
 create mode 100644 src/docs/manual_memcpy.txt
 create mode 100644 src/docs/manual_non_exhaustive.txt
 create mode 100644 src/docs/manual_ok_or.txt
 create mode 100644 src/docs/manual_range_contains.txt
 create mode 100644 src/docs/manual_rem_euclid.txt
 create mode 100644 src/docs/manual_retain.txt
 create mode 100644 src/docs/manual_saturating_arithmetic.txt
 create mode 100644 src/docs/manual_split_once.txt
 create mode 100644 src/docs/manual_str_repeat.txt
 create mode 100644 src/docs/manual_string_new.txt
 create mode 100644 src/docs/manual_strip.txt
 create mode 100644 src/docs/manual_swap.txt
 create mode 100644 src/docs/manual_unwrap_or.txt
 create mode 100644 src/docs/many_single_char_names.txt
 create mode 100644 src/docs/map_clone.txt
 create mode 100644 src/docs/map_collect_result_unit.txt
 create mode 100644 src/docs/map_entry.txt
 create mode 100644 src/docs/map_err_ignore.txt
 create mode 100644 src/docs/map_flatten.txt
 create mode 100644 src/docs/map_identity.txt
 create mode 100644 src/docs/map_unwrap_or.txt
 create mode 100644 src/docs/match_as_ref.txt
 create mode 100644 src/docs/match_bool.txt
 create mode 100644 src/docs/match_like_matches_macro.txt
 create mode 100644 src/docs/match_on_vec_items.txt
 create mode 100644 src/docs/match_overlapping_arm.txt
 create mode 100644 src/docs/match_ref_pats.txt
 create mode 100644 src/docs/match_result_ok.txt
 create mode 100644 src/docs/match_same_arms.txt
 create mode 100644 src/docs/match_single_binding.txt
 create mode 100644 src/docs/match_str_case_mismatch.txt
 create mode 100644 src/docs/match_wild_err_arm.txt
 create mode 100644 src/docs/match_wildcard_for_single_variants.txt
 create mode 100644 src/docs/maybe_infinite_iter.txt
 create mode 100644 src/docs/mem_forget.txt
 create mode 100644 src/docs/mem_replace_option_with_none.txt
 create mode 100644 src/docs/mem_replace_with_default.txt
 create mode 100644 src/docs/mem_replace_with_uninit.txt
 create mode 100644 src/docs/min_max.txt
 create mode 100644 src/docs/mismatched_target_os.txt
 create mode 100644 src/docs/mismatching_type_param_order.txt
 create mode 100644 src/docs/misrefactored_assign_op.txt
 create mode 100644 src/docs/missing_const_for_fn.txt
 create mode 100644 src/docs/missing_docs_in_private_items.txt
 create mode 100644 src/docs/missing_enforced_import_renames.txt
 create mode 100644 src/docs/missing_errors_doc.txt
 create mode 100644 src/docs/missing_inline_in_public_items.txt
 create mode 100644 src/docs/missing_panics_doc.txt
 create mode 100644 src/docs/missing_safety_doc.txt
 create mode 100644 src/docs/missing_spin_loop.txt
 create mode 100644 src/docs/mistyped_literal_suffixes.txt
 create mode 100644 src/docs/mixed_case_hex_literals.txt
 create mode 100644 src/docs/mixed_read_write_in_expression.txt
 create mode 100644 src/docs/mod_module_files.txt
 create mode 100644 src/docs/module_inception.txt
 create mode 100644 src/docs/module_name_repetitions.txt
 create mode 100644 src/docs/modulo_arithmetic.txt
 create mode 100644 src/docs/modulo_one.txt
 create mode 100644 src/docs/multi_assignments.txt
 create mode 100644 src/docs/multiple_crate_versions.txt
 create mode 100644 src/docs/multiple_inherent_impl.txt
 create mode 100644 src/docs/must_use_candidate.txt
 create mode 100644 src/docs/must_use_unit.txt
 create mode 100644 src/docs/mut_from_ref.txt
 create mode 100644 src/docs/mut_mut.txt
 create mode 100644 src/docs/mut_mutex_lock.txt
 create mode 100644 src/docs/mut_range_bound.txt
 create mode 100644 src/docs/mutable_key_type.txt
 create mode 100644 src/docs/mutex_atomic.txt
 create mode 100644 src/docs/mutex_integer.txt
 create mode 100644 src/docs/naive_bytecount.txt
 create mode 100644 src/docs/needless_arbitrary_self_type.txt
 create mode 100644 src/docs/needless_bitwise_bool.txt
 create mode 100644 src/docs/needless_bool.txt
 create mode 100644 src/docs/needless_borrow.txt
 create mode 100644 src/docs/needless_borrowed_reference.txt
 create mode 100644 src/docs/needless_collect.txt
 create mode 100644 src/docs/needless_continue.txt
 create mode 100644 src/docs/needless_doctest_main.txt
 create mode 100644 src/docs/needless_for_each.txt
 create mode 100644 src/docs/needless_late_init.txt
 create mode 100644 src/docs/needless_lifetimes.txt
 create mode 100644 src/docs/needless_match.txt
 create mode 100644 src/docs/needless_option_as_deref.txt
 create mode 100644 src/docs/needless_option_take.txt
 create mode 100644 src/docs/needless_parens_on_range_literals.txt
 create mode 100644 src/docs/needless_pass_by_value.txt
 create mode 100644 src/docs/needless_question_mark.txt
 create mode 100644 src/docs/needless_range_loop.txt
 create mode 100644 src/docs/needless_return.txt
 create mode 100644 src/docs/needless_splitn.txt
 create mode 100644 src/docs/needless_update.txt
 create mode 100644 src/docs/neg_cmp_op_on_partial_ord.txt
 create mode 100644 src/docs/neg_multiply.txt
 create mode 100644 src/docs/negative_feature_names.txt
 create mode 100644 src/docs/never_loop.txt
 create mode 100644 src/docs/new_ret_no_self.txt
 create mode 100644 src/docs/new_without_default.txt
 create mode 100644 src/docs/no_effect.txt
 create mode 100644 src/docs/no_effect_replace.txt
 create mode 100644 src/docs/no_effect_underscore_binding.txt
 create mode 100644 src/docs/non_ascii_literal.txt
 create mode 100644 src/docs/non_octal_unix_permissions.txt
 create mode 100644 src/docs/non_send_fields_in_send_ty.txt
 create mode 100644 src/docs/nonminimal_bool.txt
 create mode 100644 src/docs/nonsensical_open_options.txt
 create mode 100644 src/docs/nonstandard_macro_braces.txt
 create mode 100644 src/docs/not_unsafe_ptr_arg_deref.txt
 create mode 100644 src/docs/obfuscated_if_else.txt
 create mode 100644 src/docs/octal_escapes.txt
 create mode 100644 src/docs/ok_expect.txt
 create mode 100644 src/docs/only_used_in_recursion.txt
 create mode 100644 src/docs/op_ref.txt
 create mode 100644 src/docs/option_as_ref_deref.txt
 create mode 100644 src/docs/option_env_unwrap.txt
 create mode 100644 src/docs/option_filter_map.txt
 create mode 100644 src/docs/option_if_let_else.txt
 create mode 100644 src/docs/option_map_or_none.txt
 create mode 100644 src/docs/option_map_unit_fn.txt
 create mode 100644 src/docs/option_option.txt
 create mode 100644 src/docs/or_fun_call.txt
 create mode 100644 src/docs/or_then_unwrap.txt
 create mode 100644 src/docs/out_of_bounds_indexing.txt
 create mode 100644 src/docs/overflow_check_conditional.txt
 create mode 100644 src/docs/overly_complex_bool_expr.txt
 create mode 100644 src/docs/panic.txt
 create mode 100644 src/docs/panic_in_result_fn.txt
 create mode 100644 src/docs/panicking_unwrap.txt
 create mode 100644 src/docs/partialeq_ne_impl.txt
 create mode 100644 src/docs/partialeq_to_none.txt
 create mode 100644 src/docs/path_buf_push_overwrite.txt
 create mode 100644 src/docs/pattern_type_mismatch.txt
 create mode 100644 src/docs/positional_named_format_parameters.txt
 create mode 100644 src/docs/possible_missing_comma.txt
 create mode 100644 src/docs/precedence.txt
 create mode 100644 src/docs/print_in_format_impl.txt
 create mode 100644 src/docs/print_literal.txt
 create mode 100644 src/docs/print_stderr.txt
 create mode 100644 src/docs/print_stdout.txt
 create mode 100644 src/docs/print_with_newline.txt
 create mode 100644 src/docs/println_empty_string.txt
 create mode 100644 src/docs/ptr_arg.txt
 create mode 100644 src/docs/ptr_as_ptr.txt
 create mode 100644 src/docs/ptr_eq.txt
 create mode 100644 src/docs/ptr_offset_with_cast.txt
 create mode 100644 src/docs/pub_use.txt
 create mode 100644 src/docs/question_mark.txt
 create mode 100644 src/docs/range_minus_one.txt
 create mode 100644 src/docs/range_plus_one.txt
 create mode 100644 src/docs/range_zip_with_len.txt
 create mode 100644 src/docs/rc_buffer.txt
 create mode 100644 src/docs/rc_clone_in_vec_init.txt
 create mode 100644 src/docs/rc_mutex.txt
 create mode 100644 src/docs/read_zero_byte_vec.txt
 create mode 100644 src/docs/recursive_format_impl.txt
 create mode 100644 src/docs/redundant_allocation.txt
 create mode 100644 src/docs/redundant_clone.txt
 create mode 100644 src/docs/redundant_closure.txt
 create mode 100644 src/docs/redundant_closure_call.txt
 create mode 100644 src/docs/redundant_closure_for_method_calls.txt
 create mode 100644 src/docs/redundant_else.txt
 create mode 100644 src/docs/redundant_feature_names.txt
 create mode 100644 src/docs/redundant_field_names.txt
 create mode 100644 src/docs/redundant_pattern.txt
 create mode 100644 src/docs/redundant_pattern_matching.txt
 create mode 100644 src/docs/redundant_pub_crate.txt
 create mode 100644 src/docs/redundant_slicing.txt
 create mode 100644 src/docs/redundant_static_lifetimes.txt
 create mode 100644 src/docs/ref_binding_to_reference.txt
 create mode 100644 src/docs/ref_option_ref.txt
 create mode 100644 src/docs/repeat_once.txt
 create mode 100644 src/docs/rest_pat_in_fully_bound_structs.txt
 create mode 100644 src/docs/result_large_err.txt
 create mode 100644 src/docs/result_map_or_into_option.txt
 create mode 100644 src/docs/result_map_unit_fn.txt
 create mode 100644 src/docs/result_unit_err.txt
 create mode 100644 src/docs/return_self_not_must_use.txt
 create mode 100644 src/docs/reversed_empty_ranges.txt
 create mode 100644 src/docs/same_functions_in_if_condition.txt
 create mode 100644 src/docs/same_item_push.txt
 create mode 100644 src/docs/same_name_method.txt
 create mode 100644 src/docs/search_is_some.txt
 create mode 100644 src/docs/self_assignment.txt
 create mode 100644 src/docs/self_named_constructors.txt
 create mode 100644 src/docs/self_named_module_files.txt
 create mode 100644 src/docs/semicolon_if_nothing_returned.txt
 create mode 100644 src/docs/separated_literal_suffix.txt
 create mode 100644 src/docs/serde_api_misuse.txt
 create mode 100644 src/docs/shadow_reuse.txt
 create mode 100644 src/docs/shadow_same.txt
 create mode 100644 src/docs/shadow_unrelated.txt
 create mode 100644 src/docs/short_circuit_statement.txt
 create mode 100644 src/docs/should_implement_trait.txt
 create mode 100644 src/docs/significant_drop_in_scrutinee.txt
 create mode 100644 src/docs/similar_names.txt
 create mode 100644 src/docs/single_char_add_str.txt
 create mode 100644 src/docs/single_char_lifetime_names.txt
 create mode 100644 src/docs/single_char_pattern.txt
 create mode 100644 src/docs/single_component_path_imports.txt
 create mode 100644 src/docs/single_element_loop.txt
 create mode 100644 src/docs/single_match.txt
 create mode 100644 src/docs/single_match_else.txt
 create mode 100644 src/docs/size_of_in_element_count.txt
 create mode 100644 src/docs/skip_while_next.txt
 create mode 100644 src/docs/slow_vector_initialization.txt
 create mode 100644 src/docs/stable_sort_primitive.txt
 create mode 100644 src/docs/std_instead_of_alloc.txt
 create mode 100644 src/docs/std_instead_of_core.txt
 create mode 100644 src/docs/str_to_string.txt
 create mode 100644 src/docs/string_add.txt
 create mode 100644 src/docs/string_add_assign.txt
 create mode 100644 src/docs/string_extend_chars.txt
 create mode 100644 src/docs/string_from_utf8_as_bytes.txt
 create mode 100644 src/docs/string_lit_as_bytes.txt
 create mode 100644 src/docs/string_slice.txt
 create mode 100644 src/docs/string_to_string.txt
 create mode 100644 src/docs/strlen_on_c_strings.txt
 create mode 100644 src/docs/struct_excessive_bools.txt
 create mode 100644 src/docs/suboptimal_flops.txt
 create mode 100644 src/docs/suspicious_arithmetic_impl.txt
 create mode 100644 src/docs/suspicious_assignment_formatting.txt
 create mode 100644 src/docs/suspicious_else_formatting.txt
 create mode 100644 src/docs/suspicious_map.txt
 create mode 100644 src/docs/suspicious_op_assign_impl.txt
 create mode 100644 src/docs/suspicious_operation_groupings.txt
 create mode 100644 src/docs/suspicious_splitn.txt
 create mode 100644 src/docs/suspicious_to_owned.txt
 create mode 100644 src/docs/suspicious_unary_op_formatting.txt
 create mode 100644 src/docs/swap_ptr_to_ref.txt
 create mode 100644 src/docs/tabs_in_doc_comments.txt
 create mode 100644 src/docs/temporary_assignment.txt
 create mode 100644 src/docs/to_digit_is_some.txt
 create mode 100644 src/docs/to_string_in_format_args.txt
 create mode 100644 src/docs/todo.txt
 create mode 100644 src/docs/too_many_arguments.txt
 create mode 100644 src/docs/too_many_lines.txt
 create mode 100644 src/docs/toplevel_ref_arg.txt
 create mode 100644 src/docs/trailing_empty_array.txt
 create mode 100644 src/docs/trait_duplication_in_bounds.txt
 create mode 100644 src/docs/transmute_bytes_to_str.txt
 create mode 100644 src/docs/transmute_float_to_int.txt
 create mode 100644 src/docs/transmute_int_to_bool.txt
 create mode 100644 src/docs/transmute_int_to_char.txt
 create mode 100644 src/docs/transmute_int_to_float.txt
 create mode 100644 src/docs/transmute_num_to_bytes.txt
 create mode 100644 src/docs/transmute_ptr_to_ptr.txt
 create mode 100644 src/docs/transmute_ptr_to_ref.txt
 create mode 100644 src/docs/transmute_undefined_repr.txt
 create mode 100644 src/docs/transmutes_expressible_as_ptr_casts.txt
 create mode 100644 src/docs/transmuting_null.txt
 create mode 100644 src/docs/trim_split_whitespace.txt
 create mode 100644 src/docs/trivial_regex.txt
 create mode 100644 src/docs/trivially_copy_pass_by_ref.txt
 create mode 100644 src/docs/try_err.txt
 create mode 100644 src/docs/type_complexity.txt
 create mode 100644 src/docs/type_repetition_in_bounds.txt
 create mode 100644 src/docs/undocumented_unsafe_blocks.txt
 create mode 100644 src/docs/undropped_manually_drops.txt
 create mode 100644 src/docs/unicode_not_nfc.txt
 create mode 100644 src/docs/unimplemented.txt
 create mode 100644 src/docs/uninit_assumed_init.txt
 create mode 100644 src/docs/uninit_vec.txt
 create mode 100644 src/docs/unit_arg.txt
 create mode 100644 src/docs/unit_cmp.txt
 create mode 100644 src/docs/unit_hash.txt
 create mode 100644 src/docs/unit_return_expecting_ord.txt
 create mode 100644 src/docs/unnecessary_cast.txt
 create mode 100644 src/docs/unnecessary_filter_map.txt
 create mode 100644 src/docs/unnecessary_find_map.txt
 create mode 100644 src/docs/unnecessary_fold.txt
 create mode 100644 src/docs/unnecessary_join.txt
 create mode 100644 src/docs/unnecessary_lazy_evaluations.txt
 create mode 100644 src/docs/unnecessary_mut_passed.txt
 create mode 100644 src/docs/unnecessary_operation.txt
 create mode 100644 src/docs/unnecessary_owned_empty_strings.txt
 create mode 100644 src/docs/unnecessary_self_imports.txt
 create mode 100644 src/docs/unnecessary_sort_by.txt
 create mode 100644 src/docs/unnecessary_to_owned.txt
 create mode 100644 src/docs/unnecessary_unwrap.txt
 create mode 100644 src/docs/unnecessary_wraps.txt
 create mode 100644 src/docs/unneeded_field_pattern.txt
 create mode 100644 src/docs/unneeded_wildcard_pattern.txt
 create mode 100644 src/docs/unnested_or_patterns.txt
 create mode 100644 src/docs/unreachable.txt
 create mode 100644 src/docs/unreadable_literal.txt
 create mode 100644 src/docs/unsafe_derive_deserialize.txt
 create mode 100644 src/docs/unsafe_removed_from_name.txt
 create mode 100644 src/docs/unseparated_literal_suffix.txt
 create mode 100644 src/docs/unsound_collection_transmute.txt
 create mode 100644 src/docs/unused_async.txt
 create mode 100644 src/docs/unused_io_amount.txt
 create mode 100644 src/docs/unused_peekable.txt
 create mode 100644 src/docs/unused_rounding.txt
 create mode 100644 src/docs/unused_self.txt
 create mode 100644 src/docs/unused_unit.txt
 create mode 100644 src/docs/unusual_byte_groupings.txt
 create mode 100644 src/docs/unwrap_in_result.txt
 create mode 100644 src/docs/unwrap_or_else_default.txt
 create mode 100644 src/docs/unwrap_used.txt
 create mode 100644 src/docs/upper_case_acronyms.txt
 create mode 100644 src/docs/use_debug.txt
 create mode 100644 src/docs/use_self.txt
 create mode 100644 src/docs/used_underscore_binding.txt
 create mode 100644 src/docs/useless_asref.txt
 create mode 100644 src/docs/useless_attribute.txt
 create mode 100644 src/docs/useless_conversion.txt
 create mode 100644 src/docs/useless_format.txt
 create mode 100644 src/docs/useless_let_if_seq.txt
 create mode 100644 src/docs/useless_transmute.txt
 create mode 100644 src/docs/useless_vec.txt
 create mode 100644 src/docs/vec_box.txt
 create mode 100644 src/docs/vec_init_then_push.txt
 create mode 100644 src/docs/vec_resize_to_zero.txt
 create mode 100644 src/docs/verbose_bit_mask.txt
 create mode 100644 src/docs/verbose_file_reads.txt
 create mode 100644 src/docs/vtable_address_comparisons.txt
 create mode 100644 src/docs/while_immutable_condition.txt
 create mode 100644 src/docs/while_let_loop.txt
 create mode 100644 src/docs/while_let_on_iterator.txt
 create mode 100644 src/docs/wildcard_dependencies.txt
 create mode 100644 src/docs/wildcard_enum_match_arm.txt
 create mode 100644 src/docs/wildcard_imports.txt
 create mode 100644 src/docs/wildcard_in_or_patterns.txt
 create mode 100644 src/docs/write_literal.txt
 create mode 100644 src/docs/write_with_newline.txt
 create mode 100644 src/docs/writeln_empty_string.txt
 create mode 100644 src/docs/wrong_self_convention.txt
 create mode 100644 src/docs/wrong_transmute.txt
 create mode 100644 src/docs/zero_divided_by_zero.txt
 create mode 100644 src/docs/zero_prefixed_literal.txt
 create mode 100644 src/docs/zero_ptr.txt
 create mode 100644 src/docs/zero_sized_map_values.txt
 create mode 100644 src/docs/zst_offset.txt

diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs
index 28bec872c08..b95061bf81a 100644
--- a/clippy_dev/src/update_lints.rs
+++ b/clippy_dev/src/update_lints.rs
@@ -3,7 +3,7 @@ use aho_corasick::AhoCorasickBuilder;
 use indoc::writedoc;
 use itertools::Itertools;
 use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
-use std::collections::{HashMap, HashSet};
+use std::collections::{BTreeSet, HashMap, HashSet};
 use std::ffi::OsStr;
 use std::fmt::Write;
 use std::fs::{self, OpenOptions};
@@ -124,6 +124,8 @@ fn generate_lint_files(
     let content = gen_lint_group_list("all", all_group_lints);
     process_file("clippy_lints/src/lib.register_all.rs", update_mode, &content);
 
+    update_docs(update_mode, &usable_lints);
+
     for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) {
         let content = gen_lint_group_list(&lint_group, lints.iter());
         process_file(
@@ -140,6 +142,62 @@ fn generate_lint_files(
     process_file("tests/ui/rename.rs", update_mode, &content);
 }
 
+fn update_docs(update_mode: UpdateMode, usable_lints: &[Lint]) {
+    replace_region_in_file(update_mode, Path::new("src/docs.rs"), "docs! {\n", "\n}\n", |res| {
+        for name in usable_lints.iter().map(|lint| lint.name.clone()).sorted() {
+            writeln!(res, r#"    "{name}","#).unwrap();
+        }
+    });
+
+    if update_mode == UpdateMode::Check {
+        let mut extra = BTreeSet::new();
+        let mut lint_names = usable_lints
+            .iter()
+            .map(|lint| lint.name.clone())
+            .collect::<BTreeSet<_>>();
+        for file in std::fs::read_dir("src/docs").unwrap() {
+            let filename = file.unwrap().file_name().into_string().unwrap();
+            if let Some(name) = filename.strip_suffix(".txt") {
+                if !lint_names.remove(name) {
+                    extra.insert(name.to_string());
+                }
+            }
+        }
+
+        let failed = print_lint_names("extra lint docs:", &extra) | print_lint_names("missing lint docs:", &lint_names);
+
+        if failed {
+            exit_with_failure();
+        }
+    } else {
+        if std::fs::remove_dir_all("src/docs").is_err() {
+            eprintln!("could not remove src/docs directory");
+        }
+        if std::fs::create_dir("src/docs").is_err() {
+            eprintln!("could not recreate src/docs directory");
+        }
+    }
+    for lint in usable_lints {
+        process_file(
+            Path::new("src/docs").join(lint.name.clone() + ".txt"),
+            update_mode,
+            &lint.documentation,
+        );
+    }
+}
+
+fn print_lint_names(header: &str, lints: &BTreeSet<String>) -> bool {
+    if lints.is_empty() {
+        return false;
+    }
+    println!("{}", header);
+    for lint in lints.iter().sorted() {
+        println!("    {}", lint);
+    }
+    println!();
+    true
+}
+
 pub fn print_lints() {
     let (lint_list, _, _) = gather_all();
     let usable_lints = Lint::usable_lints(&lint_list);
@@ -589,17 +647,26 @@ struct Lint {
     desc: String,
     module: String,
     declaration_range: Range<usize>,
+    documentation: String,
 }
 
 impl Lint {
     #[must_use]
-    fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Range<usize>) -> Self {
+    fn new(
+        name: &str,
+        group: &str,
+        desc: &str,
+        module: &str,
+        declaration_range: Range<usize>,
+        documentation: String,
+    ) -> Self {
         Self {
             name: name.to_lowercase(),
             group: group.into(),
             desc: remove_line_splices(desc),
             module: module.into(),
             declaration_range,
+            documentation,
         }
     }
 
@@ -852,27 +919,35 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
          }| token_kind == &TokenKind::Ident && *content == "declare_clippy_lint",
     ) {
         let start = range.start;
-
-        let mut iter = iter
-            .by_ref()
-            .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
+        let mut docs = String::with_capacity(128);
+        let mut iter = iter.by_ref().filter(|t| !matches!(t.token_kind, TokenKind::Whitespace));
         // matches `!{`
         match_tokens!(iter, Bang OpenBrace);
-        match iter.next() {
-            // #[clippy::version = "version"] pub
-            Some(LintDeclSearchResult {
-                token_kind: TokenKind::Pound,
-                ..
-            }) => {
-                match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident);
-            },
-            // pub
-            Some(LintDeclSearchResult {
-                token_kind: TokenKind::Ident,
-                ..
-            }) => (),
-            _ => continue,
+        let mut in_code = false;
+        while let Some(t) = iter.next() {
+            match t.token_kind {
+                TokenKind::LineComment { .. } => {
+                    if let Some(line) = t.content.strip_prefix("/// ").or_else(|| t.content.strip_prefix("///")) {
+                        if line.starts_with("```") {
+                            docs += "```\n";
+                            in_code = !in_code;
+                        } else if !(in_code && line.starts_with("# ")) {
+                            docs += line;
+                            docs.push('\n');
+                        }
+                    }
+                },
+                TokenKind::Pound => {
+                    match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident);
+                    break;
+                },
+                TokenKind::Ident => {
+                    break;
+                },
+                _ => {},
+            }
         }
+        docs.pop(); // remove final newline
 
         let (name, group, desc) = match_tokens!(
             iter,
@@ -890,7 +965,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
             ..
         }) = iter.next()
         {
-            lints.push(Lint::new(name, group, desc, module, start..range.end));
+            lints.push(Lint::new(name, group, desc, module, start..range.end, docs));
         }
     }
 }
@@ -1120,6 +1195,7 @@ mod tests {
                 "\"really long text\"",
                 "module_name",
                 Range::default(),
+                String::new(),
             ),
             Lint::new(
                 "doc_markdown",
@@ -1127,6 +1203,7 @@ mod tests {
                 "\"single line\"",
                 "module_name",
                 Range::default(),
+                String::new(),
             ),
         ];
         assert_eq!(expected, result);
@@ -1166,6 +1243,7 @@ mod tests {
                 "\"abc\"",
                 "module_name",
                 Range::default(),
+                String::new(),
             ),
             Lint::new(
                 "should_assert_eq2",
@@ -1173,6 +1251,7 @@ mod tests {
                 "\"abc\"",
                 "module_name",
                 Range::default(),
+                String::new(),
             ),
             Lint::new(
                 "should_assert_eq2",
@@ -1180,6 +1259,7 @@ mod tests {
                 "\"abc\"",
                 "module_name",
                 Range::default(),
+                String::new(),
             ),
         ];
         let expected = vec![Lint::new(
@@ -1188,6 +1268,7 @@ mod tests {
             "\"abc\"",
             "module_name",
             Range::default(),
+            String::new(),
         )];
         assert_eq!(expected, Lint::usable_lints(&lints));
     }
@@ -1195,22 +1276,51 @@ mod tests {
     #[test]
     fn test_by_lint_group() {
         let lints = vec![
-            Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
+            Lint::new(
+                "should_assert_eq",
+                "group1",
+                "\"abc\"",
+                "module_name",
+                Range::default(),
+                String::new(),
+            ),
             Lint::new(
                 "should_assert_eq2",
                 "group2",
                 "\"abc\"",
                 "module_name",
                 Range::default(),
+                String::new(),
+            ),
+            Lint::new(
+                "incorrect_match",
+                "group1",
+                "\"abc\"",
+                "module_name",
+                Range::default(),
+                String::new(),
             ),
-            Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
         ];
         let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
         expected.insert(
             "group1".to_string(),
             vec![
-                Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
-                Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
+                Lint::new(
+                    "should_assert_eq",
+                    "group1",
+                    "\"abc\"",
+                    "module_name",
+                    Range::default(),
+                    String::new(),
+                ),
+                Lint::new(
+                    "incorrect_match",
+                    "group1",
+                    "\"abc\"",
+                    "module_name",
+                    Range::default(),
+                    String::new(),
+                ),
             ],
         );
         expected.insert(
@@ -1221,6 +1331,7 @@ mod tests {
                 "\"abc\"",
                 "module_name",
                 Range::default(),
+                String::new(),
             )],
         );
         assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
@@ -1259,9 +1370,30 @@ mod tests {
     #[test]
     fn test_gen_lint_group_list() {
         let lints = vec![
-            Lint::new("abc", "group1", "\"abc\"", "module_name", Range::default()),
-            Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
-            Lint::new("internal", "internal_style", "\"abc\"", "module_name", Range::default()),
+            Lint::new(
+                "abc",
+                "group1",
+                "\"abc\"",
+                "module_name",
+                Range::default(),
+                String::new(),
+            ),
+            Lint::new(
+                "should_assert_eq",
+                "group1",
+                "\"abc\"",
+                "module_name",
+                Range::default(),
+                String::new(),
+            ),
+            Lint::new(
+                "internal",
+                "internal_style",
+                "\"abc\"",
+                "module_name",
+                Range::default(),
+                String::new(),
+            ),
         ];
         let expected = GENERATED_FILE_COMMENT.to_string()
             + &[
diff --git a/src/docs.rs b/src/docs.rs
new file mode 100644
index 00000000000..69243bf4d9c
--- /dev/null
+++ b/src/docs.rs
@@ -0,0 +1,596 @@
+// autogenerated. Please look at /clippy_dev/src/update_lints.rs
+
+macro_rules! include_lint {
+    ($file_name: expr) => {
+        include_str!($file_name)
+    };
+}
+
+macro_rules! docs {
+    ($($lint_name: expr,)*) => {
+        pub fn explain(lint: &str) {
+            println!("{}", match lint {
+                $(
+                    $lint_name => include_lint!(concat!("docs/", concat!($lint_name, ".txt"))),
+                )*
+                _ => "unknown lint",
+            })
+        }
+    }
+}
+
+docs! {
+    "absurd_extreme_comparisons",
+    "alloc_instead_of_core",
+    "allow_attributes_without_reason",
+    "almost_complete_letter_range",
+    "almost_swapped",
+    "approx_constant",
+    "arithmetic",
+    "as_conversions",
+    "as_underscore",
+    "assertions_on_constants",
+    "assertions_on_result_states",
+    "assign_op_pattern",
+    "async_yields_async",
+    "await_holding_invalid_type",
+    "await_holding_lock",
+    "await_holding_refcell_ref",
+    "bad_bit_mask",
+    "bind_instead_of_map",
+    "blanket_clippy_restriction_lints",
+    "blocks_in_if_conditions",
+    "bool_assert_comparison",
+    "bool_comparison",
+    "bool_to_int_with_if",
+    "borrow_as_ptr",
+    "borrow_deref_ref",
+    "borrow_interior_mutable_const",
+    "borrowed_box",
+    "box_collection",
+    "boxed_local",
+    "branches_sharing_code",
+    "builtin_type_shadow",
+    "bytes_count_to_len",
+    "bytes_nth",
+    "cargo_common_metadata",
+    "case_sensitive_file_extension_comparisons",
+    "cast_abs_to_unsigned",
+    "cast_enum_constructor",
+    "cast_enum_truncation",
+    "cast_lossless",
+    "cast_possible_truncation",
+    "cast_possible_wrap",
+    "cast_precision_loss",
+    "cast_ptr_alignment",
+    "cast_ref_to_mut",
+    "cast_sign_loss",
+    "cast_slice_different_sizes",
+    "cast_slice_from_raw_parts",
+    "char_lit_as_u8",
+    "chars_last_cmp",
+    "chars_next_cmp",
+    "checked_conversions",
+    "clone_double_ref",
+    "clone_on_copy",
+    "clone_on_ref_ptr",
+    "cloned_instead_of_copied",
+    "cmp_nan",
+    "cmp_null",
+    "cmp_owned",
+    "cognitive_complexity",
+    "collapsible_else_if",
+    "collapsible_if",
+    "collapsible_match",
+    "collapsible_str_replace",
+    "comparison_chain",
+    "comparison_to_empty",
+    "copy_iterator",
+    "crate_in_macro_def",
+    "create_dir",
+    "crosspointer_transmute",
+    "dbg_macro",
+    "debug_assert_with_mut_call",
+    "decimal_literal_representation",
+    "declare_interior_mutable_const",
+    "default_instead_of_iter_empty",
+    "default_numeric_fallback",
+    "default_trait_access",
+    "default_union_representation",
+    "deprecated_cfg_attr",
+    "deprecated_semver",
+    "deref_addrof",
+    "deref_by_slicing",
+    "derivable_impls",
+    "derive_hash_xor_eq",
+    "derive_ord_xor_partial_ord",
+    "derive_partial_eq_without_eq",
+    "disallowed_methods",
+    "disallowed_names",
+    "disallowed_script_idents",
+    "disallowed_types",
+    "diverging_sub_expression",
+    "doc_link_with_quotes",
+    "doc_markdown",
+    "double_comparisons",
+    "double_must_use",
+    "double_neg",
+    "double_parens",
+    "drop_copy",
+    "drop_non_drop",
+    "drop_ref",
+    "duplicate_mod",
+    "duplicate_underscore_argument",
+    "duration_subsec",
+    "else_if_without_else",
+    "empty_drop",
+    "empty_enum",
+    "empty_line_after_outer_attr",
+    "empty_loop",
+    "empty_structs_with_brackets",
+    "enum_clike_unportable_variant",
+    "enum_glob_use",
+    "enum_variant_names",
+    "eq_op",
+    "equatable_if_let",
+    "erasing_op",
+    "err_expect",
+    "excessive_precision",
+    "exhaustive_enums",
+    "exhaustive_structs",
+    "exit",
+    "expect_fun_call",
+    "expect_used",
+    "expl_impl_clone_on_copy",
+    "explicit_auto_deref",
+    "explicit_counter_loop",
+    "explicit_deref_methods",
+    "explicit_into_iter_loop",
+    "explicit_iter_loop",
+    "explicit_write",
+    "extend_with_drain",
+    "extra_unused_lifetimes",
+    "fallible_impl_from",
+    "field_reassign_with_default",
+    "filetype_is_file",
+    "filter_map_identity",
+    "filter_map_next",
+    "filter_next",
+    "flat_map_identity",
+    "flat_map_option",
+    "float_arithmetic",
+    "float_cmp",
+    "float_cmp_const",
+    "float_equality_without_abs",
+    "fn_address_comparisons",
+    "fn_params_excessive_bools",
+    "fn_to_numeric_cast",
+    "fn_to_numeric_cast_any",
+    "fn_to_numeric_cast_with_truncation",
+    "for_kv_map",
+    "for_loops_over_fallibles",
+    "forget_copy",
+    "forget_non_drop",
+    "forget_ref",
+    "format_in_format_args",
+    "format_push_string",
+    "from_iter_instead_of_collect",
+    "from_over_into",
+    "from_str_radix_10",
+    "future_not_send",
+    "get_first",
+    "get_last_with_len",
+    "get_unwrap",
+    "identity_op",
+    "if_let_mutex",
+    "if_not_else",
+    "if_same_then_else",
+    "if_then_some_else_none",
+    "ifs_same_cond",
+    "implicit_clone",
+    "implicit_hasher",
+    "implicit_return",
+    "implicit_saturating_sub",
+    "imprecise_flops",
+    "inconsistent_digit_grouping",
+    "inconsistent_struct_constructor",
+    "index_refutable_slice",
+    "indexing_slicing",
+    "ineffective_bit_mask",
+    "inefficient_to_string",
+    "infallible_destructuring_match",
+    "infinite_iter",
+    "inherent_to_string",
+    "inherent_to_string_shadow_display",
+    "init_numbered_fields",
+    "inline_always",
+    "inline_asm_x86_att_syntax",
+    "inline_asm_x86_intel_syntax",
+    "inline_fn_without_body",
+    "inspect_for_each",
+    "int_plus_one",
+    "integer_arithmetic",
+    "integer_division",
+    "into_iter_on_ref",
+    "invalid_null_ptr_usage",
+    "invalid_regex",
+    "invalid_upcast_comparisons",
+    "invalid_utf8_in_unchecked",
+    "invisible_characters",
+    "is_digit_ascii_radix",
+    "items_after_statements",
+    "iter_cloned_collect",
+    "iter_count",
+    "iter_next_loop",
+    "iter_next_slice",
+    "iter_not_returning_iterator",
+    "iter_nth",
+    "iter_nth_zero",
+    "iter_on_empty_collections",
+    "iter_on_single_items",
+    "iter_overeager_cloned",
+    "iter_skip_next",
+    "iter_with_drain",
+    "iterator_step_by_zero",
+    "just_underscores_and_digits",
+    "large_const_arrays",
+    "large_digit_groups",
+    "large_enum_variant",
+    "large_include_file",
+    "large_stack_arrays",
+    "large_types_passed_by_value",
+    "len_without_is_empty",
+    "len_zero",
+    "let_and_return",
+    "let_underscore_drop",
+    "let_underscore_lock",
+    "let_underscore_must_use",
+    "let_unit_value",
+    "linkedlist",
+    "lossy_float_literal",
+    "macro_use_imports",
+    "main_recursion",
+    "manual_assert",
+    "manual_async_fn",
+    "manual_bits",
+    "manual_filter_map",
+    "manual_find",
+    "manual_find_map",
+    "manual_flatten",
+    "manual_instant_elapsed",
+    "manual_map",
+    "manual_memcpy",
+    "manual_non_exhaustive",
+    "manual_ok_or",
+    "manual_range_contains",
+    "manual_rem_euclid",
+    "manual_retain",
+    "manual_saturating_arithmetic",
+    "manual_split_once",
+    "manual_str_repeat",
+    "manual_string_new",
+    "manual_strip",
+    "manual_swap",
+    "manual_unwrap_or",
+    "many_single_char_names",
+    "map_clone",
+    "map_collect_result_unit",
+    "map_entry",
+    "map_err_ignore",
+    "map_flatten",
+    "map_identity",
+    "map_unwrap_or",
+    "match_as_ref",
+    "match_bool",
+    "match_like_matches_macro",
+    "match_on_vec_items",
+    "match_overlapping_arm",
+    "match_ref_pats",
+    "match_result_ok",
+    "match_same_arms",
+    "match_single_binding",
+    "match_str_case_mismatch",
+    "match_wild_err_arm",
+    "match_wildcard_for_single_variants",
+    "maybe_infinite_iter",
+    "mem_forget",
+    "mem_replace_option_with_none",
+    "mem_replace_with_default",
+    "mem_replace_with_uninit",
+    "min_max",
+    "mismatched_target_os",
+    "mismatching_type_param_order",
+    "misrefactored_assign_op",
+    "missing_const_for_fn",
+    "missing_docs_in_private_items",
+    "missing_enforced_import_renames",
+    "missing_errors_doc",
+    "missing_inline_in_public_items",
+    "missing_panics_doc",
+    "missing_safety_doc",
+    "missing_spin_loop",
+    "mistyped_literal_suffixes",
+    "mixed_case_hex_literals",
+    "mixed_read_write_in_expression",
+    "mod_module_files",
+    "module_inception",
+    "module_name_repetitions",
+    "modulo_arithmetic",
+    "modulo_one",
+    "multi_assignments",
+    "multiple_crate_versions",
+    "multiple_inherent_impl",
+    "must_use_candidate",
+    "must_use_unit",
+    "mut_from_ref",
+    "mut_mut",
+    "mut_mutex_lock",
+    "mut_range_bound",
+    "mutable_key_type",
+    "mutex_atomic",
+    "mutex_integer",
+    "naive_bytecount",
+    "needless_arbitrary_self_type",
+    "needless_bitwise_bool",
+    "needless_bool",
+    "needless_borrow",
+    "needless_borrowed_reference",
+    "needless_collect",
+    "needless_continue",
+    "needless_doctest_main",
+    "needless_for_each",
+    "needless_late_init",
+    "needless_lifetimes",
+    "needless_match",
+    "needless_option_as_deref",
+    "needless_option_take",
+    "needless_parens_on_range_literals",
+    "needless_pass_by_value",
+    "needless_question_mark",
+    "needless_range_loop",
+    "needless_return",
+    "needless_splitn",
+    "needless_update",
+    "neg_cmp_op_on_partial_ord",
+    "neg_multiply",
+    "negative_feature_names",
+    "never_loop",
+    "new_ret_no_self",
+    "new_without_default",
+    "no_effect",
+    "no_effect_replace",
+    "no_effect_underscore_binding",
+    "non_ascii_literal",
+    "non_octal_unix_permissions",
+    "non_send_fields_in_send_ty",
+    "nonminimal_bool",
+    "nonsensical_open_options",
+    "nonstandard_macro_braces",
+    "not_unsafe_ptr_arg_deref",
+    "obfuscated_if_else",
+    "octal_escapes",
+    "ok_expect",
+    "only_used_in_recursion",
+    "op_ref",
+    "option_as_ref_deref",
+    "option_env_unwrap",
+    "option_filter_map",
+    "option_if_let_else",
+    "option_map_or_none",
+    "option_map_unit_fn",
+    "option_option",
+    "or_fun_call",
+    "or_then_unwrap",
+    "out_of_bounds_indexing",
+    "overflow_check_conditional",
+    "overly_complex_bool_expr",
+    "panic",
+    "panic_in_result_fn",
+    "panicking_unwrap",
+    "partialeq_ne_impl",
+    "partialeq_to_none",
+    "path_buf_push_overwrite",
+    "pattern_type_mismatch",
+    "positional_named_format_parameters",
+    "possible_missing_comma",
+    "precedence",
+    "print_in_format_impl",
+    "print_literal",
+    "print_stderr",
+    "print_stdout",
+    "print_with_newline",
+    "println_empty_string",
+    "ptr_arg",
+    "ptr_as_ptr",
+    "ptr_eq",
+    "ptr_offset_with_cast",
+    "pub_use",
+    "question_mark",
+    "range_minus_one",
+    "range_plus_one",
+    "range_zip_with_len",
+    "rc_buffer",
+    "rc_clone_in_vec_init",
+    "rc_mutex",
+    "read_zero_byte_vec",
+    "recursive_format_impl",
+    "redundant_allocation",
+    "redundant_clone",
+    "redundant_closure",
+    "redundant_closure_call",
+    "redundant_closure_for_method_calls",
+    "redundant_else",
+    "redundant_feature_names",
+    "redundant_field_names",
+    "redundant_pattern",
+    "redundant_pattern_matching",
+    "redundant_pub_crate",
+    "redundant_slicing",
+    "redundant_static_lifetimes",
+    "ref_binding_to_reference",
+    "ref_option_ref",
+    "repeat_once",
+    "rest_pat_in_fully_bound_structs",
+    "result_large_err",
+    "result_map_or_into_option",
+    "result_map_unit_fn",
+    "result_unit_err",
+    "return_self_not_must_use",
+    "reversed_empty_ranges",
+    "same_functions_in_if_condition",
+    "same_item_push",
+    "same_name_method",
+    "search_is_some",
+    "self_assignment",
+    "self_named_constructors",
+    "self_named_module_files",
+    "semicolon_if_nothing_returned",
+    "separated_literal_suffix",
+    "serde_api_misuse",
+    "shadow_reuse",
+    "shadow_same",
+    "shadow_unrelated",
+    "short_circuit_statement",
+    "should_implement_trait",
+    "significant_drop_in_scrutinee",
+    "similar_names",
+    "single_char_add_str",
+    "single_char_lifetime_names",
+    "single_char_pattern",
+    "single_component_path_imports",
+    "single_element_loop",
+    "single_match",
+    "single_match_else",
+    "size_of_in_element_count",
+    "skip_while_next",
+    "slow_vector_initialization",
+    "stable_sort_primitive",
+    "std_instead_of_alloc",
+    "std_instead_of_core",
+    "str_to_string",
+    "string_add",
+    "string_add_assign",
+    "string_extend_chars",
+    "string_from_utf8_as_bytes",
+    "string_lit_as_bytes",
+    "string_slice",
+    "string_to_string",
+    "strlen_on_c_strings",
+    "struct_excessive_bools",
+    "suboptimal_flops",
+    "suspicious_arithmetic_impl",
+    "suspicious_assignment_formatting",
+    "suspicious_else_formatting",
+    "suspicious_map",
+    "suspicious_op_assign_impl",
+    "suspicious_operation_groupings",
+    "suspicious_splitn",
+    "suspicious_to_owned",
+    "suspicious_unary_op_formatting",
+    "swap_ptr_to_ref",
+    "tabs_in_doc_comments",
+    "temporary_assignment",
+    "to_digit_is_some",
+    "to_string_in_format_args",
+    "todo",
+    "too_many_arguments",
+    "too_many_lines",
+    "toplevel_ref_arg",
+    "trailing_empty_array",
+    "trait_duplication_in_bounds",
+    "transmute_bytes_to_str",
+    "transmute_float_to_int",
+    "transmute_int_to_bool",
+    "transmute_int_to_char",
+    "transmute_int_to_float",
+    "transmute_num_to_bytes",
+    "transmute_ptr_to_ptr",
+    "transmute_ptr_to_ref",
+    "transmute_undefined_repr",
+    "transmutes_expressible_as_ptr_casts",
+    "transmuting_null",
+    "trim_split_whitespace",
+    "trivial_regex",
+    "trivially_copy_pass_by_ref",
+    "try_err",
+    "type_complexity",
+    "type_repetition_in_bounds",
+    "undocumented_unsafe_blocks",
+    "undropped_manually_drops",
+    "unicode_not_nfc",
+    "unimplemented",
+    "uninit_assumed_init",
+    "uninit_vec",
+    "unit_arg",
+    "unit_cmp",
+    "unit_hash",
+    "unit_return_expecting_ord",
+    "unnecessary_cast",
+    "unnecessary_filter_map",
+    "unnecessary_find_map",
+    "unnecessary_fold",
+    "unnecessary_join",
+    "unnecessary_lazy_evaluations",
+    "unnecessary_mut_passed",
+    "unnecessary_operation",
+    "unnecessary_owned_empty_strings",
+    "unnecessary_self_imports",
+    "unnecessary_sort_by",
+    "unnecessary_to_owned",
+    "unnecessary_unwrap",
+    "unnecessary_wraps",
+    "unneeded_field_pattern",
+    "unneeded_wildcard_pattern",
+    "unnested_or_patterns",
+    "unreachable",
+    "unreadable_literal",
+    "unsafe_derive_deserialize",
+    "unsafe_removed_from_name",
+    "unseparated_literal_suffix",
+    "unsound_collection_transmute",
+    "unused_async",
+    "unused_io_amount",
+    "unused_peekable",
+    "unused_rounding",
+    "unused_self",
+    "unused_unit",
+    "unusual_byte_groupings",
+    "unwrap_in_result",
+    "unwrap_or_else_default",
+    "unwrap_used",
+    "upper_case_acronyms",
+    "use_debug",
+    "use_self",
+    "used_underscore_binding",
+    "useless_asref",
+    "useless_attribute",
+    "useless_conversion",
+    "useless_format",
+    "useless_let_if_seq",
+    "useless_transmute",
+    "useless_vec",
+    "vec_box",
+    "vec_init_then_push",
+    "vec_resize_to_zero",
+    "verbose_bit_mask",
+    "verbose_file_reads",
+    "vtable_address_comparisons",
+    "while_immutable_condition",
+    "while_let_loop",
+    "while_let_on_iterator",
+    "wildcard_dependencies",
+    "wildcard_enum_match_arm",
+    "wildcard_imports",
+    "wildcard_in_or_patterns",
+    "write_literal",
+    "write_with_newline",
+    "writeln_empty_string",
+    "wrong_self_convention",
+    "wrong_transmute",
+    "zero_divided_by_zero",
+    "zero_prefixed_literal",
+    "zero_ptr",
+    "zero_sized_map_values",
+    "zst_offset",
+
+}
diff --git a/src/docs/absurd_extreme_comparisons.txt b/src/docs/absurd_extreme_comparisons.txt
new file mode 100644
index 00000000000..590bee28aa2
--- /dev/null
+++ b/src/docs/absurd_extreme_comparisons.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for comparisons where one side of the relation is
+either the minimum or maximum value for its type and warns if it involves a
+case that is always true or always false. Only integer and boolean types are
+checked.
+
+### Why is this bad?
+An expression like `min <= x` may misleadingly imply
+that it is possible for `x` to be less than the minimum. Expressions like
+`max < x` are probably mistakes.
+
+### Known problems
+For `usize` the size of the current compile target will
+be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
+a comparison to detect target pointer width will trigger this lint. One can
+use `mem::sizeof` and compare its value or conditional compilation
+attributes
+like `#[cfg(target_pointer_width = "64")] ..` instead.
+
+### Example
+```
+let vec: Vec<isize> = Vec::new();
+if vec.len() <= 0 {}
+if 100 > i32::MAX {}
+```
\ No newline at end of file
diff --git a/src/docs/alloc_instead_of_core.txt b/src/docs/alloc_instead_of_core.txt
new file mode 100644
index 00000000000..488a36e9276
--- /dev/null
+++ b/src/docs/alloc_instead_of_core.txt
@@ -0,0 +1,18 @@
+### What it does
+
+Finds items imported through `alloc` when available through `core`.
+
+### Why is this bad?
+
+Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are
+imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint
+is also useful for crates migrating to become `no_std` compatible.
+
+### Example
+```
+use alloc::slice::from_ref;
+```
+Use instead:
+```
+use core::slice::from_ref;
+```
\ No newline at end of file
diff --git a/src/docs/allow_attributes_without_reason.txt b/src/docs/allow_attributes_without_reason.txt
new file mode 100644
index 00000000000..fcc4f49b08b
--- /dev/null
+++ b/src/docs/allow_attributes_without_reason.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for attributes that allow lints without a reason.
+
+(This requires the `lint_reasons` feature)
+
+### Why is this bad?
+Allowing a lint should always have a reason. This reason should be documented to
+ensure that others understand the reasoning
+
+### Example
+```
+#![feature(lint_reasons)]
+
+#![allow(clippy::some_lint)]
+```
+
+Use instead:
+```
+#![feature(lint_reasons)]
+
+#![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")]
+```
\ No newline at end of file
diff --git a/src/docs/almost_complete_letter_range.txt b/src/docs/almost_complete_letter_range.txt
new file mode 100644
index 00000000000..01cbaf9eae2
--- /dev/null
+++ b/src/docs/almost_complete_letter_range.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for ranges which almost include the entire range of letters from 'a' to 'z', but
+don't because they're a half open range.
+
+### Why is this bad?
+This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
+
+### Example
+```
+let _ = 'a'..'z';
+```
+Use instead:
+```
+let _ = 'a'..='z';
+```
\ No newline at end of file
diff --git a/src/docs/almost_swapped.txt b/src/docs/almost_swapped.txt
new file mode 100644
index 00000000000..cd10a8d5409
--- /dev/null
+++ b/src/docs/almost_swapped.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for `foo = bar; bar = foo` sequences.
+
+### Why is this bad?
+This looks like a failed attempt to swap.
+
+### Example
+```
+a = b;
+b = a;
+```
+If swapping is intended, use `swap()` instead:
+```
+std::mem::swap(&mut a, &mut b);
+```
\ No newline at end of file
diff --git a/src/docs/approx_constant.txt b/src/docs/approx_constant.txt
new file mode 100644
index 00000000000..393fa4b5ef7
--- /dev/null
+++ b/src/docs/approx_constant.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for floating point literals that approximate
+constants which are defined in
+[`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants)
+or
+[`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants),
+respectively, suggesting to use the predefined constant.
+
+### Why is this bad?
+Usually, the definition in the standard library is more
+precise than what people come up with. If you find that your definition is
+actually more precise, please [file a Rust
+issue](https://github.com/rust-lang/rust/issues).
+
+### Example
+```
+let x = 3.14;
+let y = 1_f64 / x;
+```
+Use instead:
+```
+let x = std::f32::consts::PI;
+let y = std::f64::consts::FRAC_1_PI;
+```
\ No newline at end of file
diff --git a/src/docs/arithmetic.txt b/src/docs/arithmetic.txt
new file mode 100644
index 00000000000..0b3f07d9505
--- /dev/null
+++ b/src/docs/arithmetic.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for any kind of arithmetic operation of any type.
+
+Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
+Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
+or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered
+away.
+
+### 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
+```
+a + 1;
+```
+
+Third-party types also tend to overflow.
+
+#### Example
+```
+use rust_decimal::Decimal;
+let _n = Decimal::MAX + Decimal::MAX;
+```
+
+### Allowed types
+Custom allowed types can be specified through the "arithmetic-allowed" filter.
\ No newline at end of file
diff --git a/src/docs/as_conversions.txt b/src/docs/as_conversions.txt
new file mode 100644
index 00000000000..4af479bd811
--- /dev/null
+++ b/src/docs/as_conversions.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for usage of `as` conversions.
+
+Note that this lint is specialized in linting *every single* use of `as`
+regardless of whether good alternatives exist or not.
+If you want more precise lints for `as`, please consider using these separate lints:
+`unnecessary_cast`, `cast_lossless/cast_possible_truncation/cast_possible_wrap/cast_precision_loss/cast_sign_loss`,
+`fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`.
+There is a good explanation the reason why this lint should work in this way and how it is useful
+[in this issue](https://github.com/rust-lang/rust-clippy/issues/5122).
+
+### Why is this bad?
+`as` conversions will perform many kinds of
+conversions, including silently lossy conversions and dangerous coercions.
+There are cases when it makes sense to use `as`, so the lint is
+Allow by default.
+
+### Example
+```
+let a: u32;
+...
+f(a as u16);
+```
+
+Use instead:
+```
+f(a.try_into()?);
+
+// or
+
+f(a.try_into().expect("Unexpected u16 overflow in f"));
+```
\ No newline at end of file
diff --git a/src/docs/as_underscore.txt b/src/docs/as_underscore.txt
new file mode 100644
index 00000000000..2d9b0c35893
--- /dev/null
+++ b/src/docs/as_underscore.txt
@@ -0,0 +1,21 @@
+### What it does
+Check for the usage of `as _` conversion using inferred type.
+
+### Why is this bad?
+The conversion might include lossy conversion and dangerous cast that might go
+undetected due to the type being inferred.
+
+The lint is allowed by default as using `_` is less wordy than always specifying the type.
+
+### Example
+```
+fn foo(n: usize) {}
+let n: u16 = 256;
+foo(n as _);
+```
+Use instead:
+```
+fn foo(n: usize) {}
+let n: u16 = 256;
+foo(n as usize);
+```
\ No newline at end of file
diff --git a/src/docs/assertions_on_constants.txt b/src/docs/assertions_on_constants.txt
new file mode 100644
index 00000000000..270c1e3b639
--- /dev/null
+++ b/src/docs/assertions_on_constants.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for `assert!(true)` and `assert!(false)` calls.
+
+### Why is this bad?
+Will be optimized out by the compiler or should probably be replaced by a
+`panic!()` or `unreachable!()`
+
+### Example
+```
+assert!(false)
+assert!(true)
+const B: bool = false;
+assert!(B)
+```
\ No newline at end of file
diff --git a/src/docs/assertions_on_result_states.txt b/src/docs/assertions_on_result_states.txt
new file mode 100644
index 00000000000..0889084fd3a
--- /dev/null
+++ b/src/docs/assertions_on_result_states.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls.
+
+### Why is this bad?
+An assertion failure cannot output an useful message of the error.
+
+### Known problems
+The suggested replacement decreases the readability of code and log output.
+
+### Example
+```
+assert!(r.is_ok());
+assert!(r.is_err());
+```
\ No newline at end of file
diff --git a/src/docs/assign_op_pattern.txt b/src/docs/assign_op_pattern.txt
new file mode 100644
index 00000000000..f355c0cc18d
--- /dev/null
+++ b/src/docs/assign_op_pattern.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for `a = a op b` or `a = b commutative_op a`
+patterns.
+
+### Why is this bad?
+These can be written as the shorter `a op= b`.
+
+### Known problems
+While forbidden by the spec, `OpAssign` traits may have
+implementations that differ from the regular `Op` impl.
+
+### Example
+```
+let mut a = 5;
+let b = 0;
+// ...
+
+a = a + b;
+```
+
+Use instead:
+```
+let mut a = 5;
+let b = 0;
+// ...
+
+a += b;
+```
\ No newline at end of file
diff --git a/src/docs/async_yields_async.txt b/src/docs/async_yields_async.txt
new file mode 100644
index 00000000000..a40de6d2e47
--- /dev/null
+++ b/src/docs/async_yields_async.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for async blocks that yield values of types
+that can themselves be awaited.
+
+### Why is this bad?
+An await is likely missing.
+
+### Example
+```
+async fn foo() {}
+
+fn bar() {
+  let x = async {
+    foo()
+  };
+}
+```
+
+Use instead:
+```
+async fn foo() {}
+
+fn bar() {
+  let x = async {
+    foo().await
+  };
+}
+```
\ No newline at end of file
diff --git a/src/docs/await_holding_invalid_type.txt b/src/docs/await_holding_invalid_type.txt
new file mode 100644
index 00000000000..e9c768772ff
--- /dev/null
+++ b/src/docs/await_holding_invalid_type.txt
@@ -0,0 +1,29 @@
+### What it does
+Allows users to configure types which should not be held across `await`
+suspension points.
+
+### Why is this bad?
+There are some types which are perfectly "safe" to be used concurrently
+from a memory access perspective but will cause bugs at runtime if they
+are held in such a way.
+
+### Example
+
+```
+await-holding-invalid-types = [
+  # You can specify a type name
+  "CustomLockType",
+  # You can (optionally) specify a reason
+  { path = "OtherCustomLockType", reason = "Relies on a thread local" }
+]
+```
+
+```
+struct CustomLockType;
+struct OtherCustomLockType;
+async fn foo() {
+  let _x = CustomLockType;
+  let _y = OtherCustomLockType;
+  baz().await; // Lint violation
+}
+```
\ No newline at end of file
diff --git a/src/docs/await_holding_lock.txt b/src/docs/await_holding_lock.txt
new file mode 100644
index 00000000000..0f450a11160
--- /dev/null
+++ b/src/docs/await_holding_lock.txt
@@ -0,0 +1,51 @@
+### What it does
+Checks for calls to await while holding a non-async-aware MutexGuard.
+
+### Why is this bad?
+The Mutex types found in std::sync and parking_lot
+are not designed to operate in an async context across await points.
+
+There are two potential solutions. One is to use an async-aware Mutex
+type. Many asynchronous foundation crates provide such a Mutex type. The
+other solution is to ensure the mutex is unlocked before calling await,
+either by introducing a scope or an explicit call to Drop::drop.
+
+### Known problems
+Will report false positive for explicitly dropped guards
+([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is
+to wrap the `.lock()` call in a block instead of explicitly dropping the guard.
+
+### Example
+```
+async fn foo(x: &Mutex<u32>) {
+  let mut guard = x.lock().unwrap();
+  *guard += 1;
+  baz().await;
+}
+
+async fn bar(x: &Mutex<u32>) {
+  let mut guard = x.lock().unwrap();
+  *guard += 1;
+  drop(guard); // explicit drop
+  baz().await;
+}
+```
+
+Use instead:
+```
+async fn foo(x: &Mutex<u32>) {
+  {
+    let mut guard = x.lock().unwrap();
+    *guard += 1;
+  }
+  baz().await;
+}
+
+async fn bar(x: &Mutex<u32>) {
+  {
+    let mut guard = x.lock().unwrap();
+    *guard += 1;
+  } // guard dropped here at end of scope
+  baz().await;
+}
+```
\ No newline at end of file
diff --git a/src/docs/await_holding_refcell_ref.txt b/src/docs/await_holding_refcell_ref.txt
new file mode 100644
index 00000000000..226a261b9cc
--- /dev/null
+++ b/src/docs/await_holding_refcell_ref.txt
@@ -0,0 +1,47 @@
+### What it does
+Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`.
+
+### Why is this bad?
+`RefCell` refs only check for exclusive mutable access
+at runtime. Holding onto a `RefCell` ref across an `await` suspension point
+risks panics from a mutable ref shared while other refs are outstanding.
+
+### Known problems
+Will report false positive for explicitly dropped refs
+([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)). A workaround for this is
+to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref.
+
+### Example
+```
+async fn foo(x: &RefCell<u32>) {
+  let mut y = x.borrow_mut();
+  *y += 1;
+  baz().await;
+}
+
+async fn bar(x: &RefCell<u32>) {
+  let mut y = x.borrow_mut();
+  *y += 1;
+  drop(y); // explicit drop
+  baz().await;
+}
+```
+
+Use instead:
+```
+async fn foo(x: &RefCell<u32>) {
+  {
+     let mut y = x.borrow_mut();
+     *y += 1;
+  }
+  baz().await;
+}
+
+async fn bar(x: &RefCell<u32>) {
+  {
+    let mut y = x.borrow_mut();
+    *y += 1;
+  } // y dropped here at end of scope
+  baz().await;
+}
+```
\ No newline at end of file
diff --git a/src/docs/bad_bit_mask.txt b/src/docs/bad_bit_mask.txt
new file mode 100644
index 00000000000..d40024ee562
--- /dev/null
+++ b/src/docs/bad_bit_mask.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for incompatible bit masks in comparisons.
+
+The formula for detecting if an expression of the type `_ <bit_op> m
+<cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
+{`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
+table:
+
+|Comparison  |Bit Op|Example      |is always|Formula               |
+|------------|------|-------------|---------|----------------------|
+|`==` or `!=`| `&`  |`x & 2 == 3` |`false`  |`c & m != c`          |
+|`<`  or `>=`| `&`  |`x & 2 < 3`  |`true`   |`m < c`               |
+|`>`  or `<=`| `&`  |`x & 1 > 1`  |`false`  |`m <= c`              |
+|`==` or `!=`| `\|` |`x \| 1 == 0`|`false`  |`c \| m != c`         |
+|`<`  or `>=`| `\|` |`x \| 1 < 1` |`false`  |`m >= c`              |
+|`<=` or `>` | `\|` |`x \| 1 > 0` |`true`   |`m > c`               |
+
+### Why is this bad?
+If the bits that the comparison cares about are always
+set to zero or one by the bit mask, the comparison is constant `true` or
+`false` (depending on mask, compared value, and operators).
+
+So the code is actively misleading, and the only reason someone would write
+this intentionally is to win an underhanded Rust contest or create a
+test-case for this lint.
+
+### Example
+```
+if (x & 1 == 2) { }
+```
\ No newline at end of file
diff --git a/src/docs/bind_instead_of_map.txt b/src/docs/bind_instead_of_map.txt
new file mode 100644
index 00000000000..148575803d3
--- /dev/null
+++ b/src/docs/bind_instead_of_map.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
+`_.or_else(|x| Err(y))`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.map(|x| y)` or `_.map_err(|x| y)`.
+
+### Example
+```
+let _ = opt().and_then(|s| Some(s.len()));
+let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) });
+let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) });
+```
+
+The correct use would be:
+
+```
+let _ = opt().map(|s| s.len());
+let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 });
+let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 });
+```
\ No newline at end of file
diff --git a/src/docs/blanket_clippy_restriction_lints.txt b/src/docs/blanket_clippy_restriction_lints.txt
new file mode 100644
index 00000000000..28a4ebf7169
--- /dev/null
+++ b/src/docs/blanket_clippy_restriction_lints.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
+
+### Why is this bad?
+Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust.
+These lints should only be enabled on a lint-by-lint basis and with careful consideration.
+
+### Example
+```
+#![deny(clippy::restriction)]
+```
+
+Use instead:
+```
+#![deny(clippy::as_conversions)]
+```
\ No newline at end of file
diff --git a/src/docs/blocks_in_if_conditions.txt b/src/docs/blocks_in_if_conditions.txt
new file mode 100644
index 00000000000..3afa14853fd
--- /dev/null
+++ b/src/docs/blocks_in_if_conditions.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for `if` conditions that use blocks containing an
+expression, statements or conditions that use closures with blocks.
+
+### Why is this bad?
+Style, using blocks in the condition makes it hard to read.
+
+### Examples
+```
+if { true } { /* ... */ }
+
+if { let x = somefunc(); x } { /* ... */ }
+```
+
+Use instead:
+```
+if true { /* ... */ }
+
+let res = { let x = somefunc(); x };
+if res { /* ... */ }
+```
\ No newline at end of file
diff --git a/src/docs/bool_assert_comparison.txt b/src/docs/bool_assert_comparison.txt
new file mode 100644
index 00000000000..df7ca00cc2b
--- /dev/null
+++ b/src/docs/bool_assert_comparison.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint warns about boolean comparisons in assert-like macros.
+
+### Why is this bad?
+It is shorter to use the equivalent.
+
+### Example
+```
+assert_eq!("a".is_empty(), false);
+assert_ne!("a".is_empty(), true);
+```
+
+Use instead:
+```
+assert!(!"a".is_empty());
+```
\ No newline at end of file
diff --git a/src/docs/bool_comparison.txt b/src/docs/bool_comparison.txt
new file mode 100644
index 00000000000..0996f60cec4
--- /dev/null
+++ b/src/docs/bool_comparison.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for expressions of the form `x == true`,
+`x != true` and order comparisons such as `x < true` (or vice versa) and
+suggest using the variable directly.
+
+### Why is this bad?
+Unnecessary code.
+
+### Example
+```
+if x == true {}
+if y == false {}
+```
+use `x` directly:
+```
+if x {}
+if !y {}
+```
\ No newline at end of file
diff --git a/src/docs/bool_to_int_with_if.txt b/src/docs/bool_to_int_with_if.txt
new file mode 100644
index 00000000000..63535b454c9
--- /dev/null
+++ b/src/docs/bool_to_int_with_if.txt
@@ -0,0 +1,26 @@
+### What it does
+Instead of using an if statement to convert a bool to an int,
+this lint suggests using a `from()` function or an `as` coercion.
+
+### Why is this bad?
+Coercion or `from()` is idiomatic way to convert bool to a number.
+Both methods are guaranteed to return 1 for true, and 0 for false.
+
+See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
+
+### Example
+```
+if condition {
+    1_i64
+} else {
+    0
+};
+```
+Use instead:
+```
+i64::from(condition);
+```
+or
+```
+condition as i64;
+```
\ No newline at end of file
diff --git a/src/docs/borrow_as_ptr.txt b/src/docs/borrow_as_ptr.txt
new file mode 100644
index 00000000000..0be865abd57
--- /dev/null
+++ b/src/docs/borrow_as_ptr.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for the usage of `&expr as *const T` or
+`&mut expr as *mut T`, and suggest using `ptr::addr_of` or
+`ptr::addr_of_mut` instead.
+
+### Why is this bad?
+This would improve readability and avoid creating a reference
+that points to an uninitialized value or unaligned place.
+Read the `ptr::addr_of` docs for more information.
+
+### Example
+```
+let val = 1;
+let p = &val as *const i32;
+
+let mut val_mut = 1;
+let p_mut = &mut val_mut as *mut i32;
+```
+Use instead:
+```
+let val = 1;
+let p = std::ptr::addr_of!(val);
+
+let mut val_mut = 1;
+let p_mut = std::ptr::addr_of_mut!(val_mut);
+```
\ No newline at end of file
diff --git a/src/docs/borrow_deref_ref.txt b/src/docs/borrow_deref_ref.txt
new file mode 100644
index 00000000000..352480d3f26
--- /dev/null
+++ b/src/docs/borrow_deref_ref.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for `&*(&T)`.
+
+### Why is this bad?
+Dereferencing and then borrowing a reference value has no effect in most cases.
+
+### Known problems
+False negative on such code:
+```
+let x = &12;
+let addr_x = &x as *const _ as usize;
+let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggered.
+                                        // But if we fix it, assert will fail.
+assert_ne!(addr_x, addr_y);
+```
+
+### Example
+```
+let s = &String::new();
+
+let a: &String = &* s;
+```
+
+Use instead:
+```
+let a: &String = s;
+```
\ No newline at end of file
diff --git a/src/docs/borrow_interior_mutable_const.txt b/src/docs/borrow_interior_mutable_const.txt
new file mode 100644
index 00000000000..e55b6a77e66
--- /dev/null
+++ b/src/docs/borrow_interior_mutable_const.txt
@@ -0,0 +1,40 @@
+### What it does
+Checks if `const` items which is interior mutable (e.g.,
+contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
+
+### Why is this bad?
+Consts are copied everywhere they are referenced, i.e.,
+every time you refer to the const a fresh instance of the `Cell` or `Mutex`
+or `AtomicXxxx` will be created, which defeats the whole purpose of using
+these types in the first place.
+
+The `const` value should be stored inside a `static` item.
+
+### Known problems
+When an enum has variants with interior mutability, use of its non
+interior mutable variants can generate false positives. See issue
+[#3962](https://github.com/rust-lang/rust-clippy/issues/3962)
+
+Types that have underlying or potential interior mutability trigger the lint whether
+the interior mutable field is used or not. See issues
+[#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
+[#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
+
+### Example
+```
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
+
+CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
+assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
+```
+
+Use instead:
+```
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
+
+static STATIC_ATOM: AtomicUsize = CONST_ATOM;
+STATIC_ATOM.store(9, SeqCst);
+assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
+```
\ No newline at end of file
diff --git a/src/docs/borrowed_box.txt b/src/docs/borrowed_box.txt
new file mode 100644
index 00000000000..d7089be662a
--- /dev/null
+++ b/src/docs/borrowed_box.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for use of `&Box<T>` anywhere in the code.
+Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
+
+### Why is this bad?
+A `&Box<T>` parameter requires the function caller to box `T` first before passing it to a function.
+Using `&T` defines a concrete type for the parameter and generalizes the function, this would also
+auto-deref to `&T` at the function call site if passed a `&Box<T>`.
+
+### Example
+```
+fn foo(bar: &Box<T>) { ... }
+```
+
+Better:
+
+```
+fn foo(bar: &T) { ... }
+```
\ No newline at end of file
diff --git a/src/docs/box_collection.txt b/src/docs/box_collection.txt
new file mode 100644
index 00000000000..053f24c4628
--- /dev/null
+++ b/src/docs/box_collection.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for use of `Box<T>` where T is a collection such as Vec anywhere in the code.
+Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
+
+### Why is this bad?
+Collections already keeps their contents in a separate area on
+the heap. So if you `Box` them, you just add another level of indirection
+without any benefit whatsoever.
+
+### Example
+```
+struct X {
+    values: Box<Vec<Foo>>,
+}
+```
+
+Better:
+
+```
+struct X {
+    values: Vec<Foo>,
+}
+```
\ No newline at end of file
diff --git a/src/docs/boxed_local.txt b/src/docs/boxed_local.txt
new file mode 100644
index 00000000000..8b1febf1455
--- /dev/null
+++ b/src/docs/boxed_local.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for usage of `Box<T>` where an unboxed `T` would
+work fine.
+
+### Why is this bad?
+This is an unnecessary allocation, and bad for
+performance. It is only necessary to allocate if you wish to move the box
+into something.
+
+### Example
+```
+fn foo(x: Box<u32>) {}
+```
+
+Use instead:
+```
+fn foo(x: u32) {}
+```
\ No newline at end of file
diff --git a/src/docs/branches_sharing_code.txt b/src/docs/branches_sharing_code.txt
new file mode 100644
index 00000000000..79be6124798
--- /dev/null
+++ b/src/docs/branches_sharing_code.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks if the `if` and `else` block contain shared code that can be
+moved out of the blocks.
+
+### Why is this bad?
+Duplicate code is less maintainable.
+
+### Known problems
+* The lint doesn't check if the moved expressions modify values that are being used in
+  the if condition. The suggestion can in that case modify the behavior of the program.
+  See [rust-clippy#7452](https://github.com/rust-lang/rust-clippy/issues/7452)
+
+### Example
+```
+let foo = if … {
+    println!("Hello World");
+    13
+} else {
+    println!("Hello World");
+    42
+};
+```
+
+Use instead:
+```
+println!("Hello World");
+let foo = if … {
+    13
+} else {
+    42
+};
+```
\ No newline at end of file
diff --git a/src/docs/builtin_type_shadow.txt b/src/docs/builtin_type_shadow.txt
new file mode 100644
index 00000000000..15b1c9df7ba
--- /dev/null
+++ b/src/docs/builtin_type_shadow.txt
@@ -0,0 +1,15 @@
+### What it does
+Warns if a generic shadows a built-in type.
+
+### Why is this bad?
+This gives surprising type errors.
+
+### Example
+
+```
+impl<u32> Foo<u32> {
+    fn impl_func(&self) -> u32 {
+        42
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/bytes_count_to_len.txt b/src/docs/bytes_count_to_len.txt
new file mode 100644
index 00000000000..ca7bf9a38da
--- /dev/null
+++ b/src/docs/bytes_count_to_len.txt
@@ -0,0 +1,18 @@
+### What it does
+It checks for `str::bytes().count()` and suggests replacing it with
+`str::len()`.
+
+### Why is this bad?
+`str::bytes().count()` is longer and may not be as performant as using
+`str::len()`.
+
+### Example
+```
+"hello".bytes().count();
+String::from("hello").bytes().count();
+```
+Use instead:
+```
+"hello".len();
+String::from("hello").len();
+```
\ No newline at end of file
diff --git a/src/docs/bytes_nth.txt b/src/docs/bytes_nth.txt
new file mode 100644
index 00000000000..260de343353
--- /dev/null
+++ b/src/docs/bytes_nth.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for the use of `.bytes().nth()`.
+
+### Why is this bad?
+`.as_bytes().get()` is more efficient and more
+readable.
+
+### Example
+```
+"Hello".bytes().nth(3);
+```
+
+Use instead:
+```
+"Hello".as_bytes().get(3);
+```
\ No newline at end of file
diff --git a/src/docs/cargo_common_metadata.txt b/src/docs/cargo_common_metadata.txt
new file mode 100644
index 00000000000..1998647a927
--- /dev/null
+++ b/src/docs/cargo_common_metadata.txt
@@ -0,0 +1,33 @@
+### What it does
+Checks to see if all common metadata is defined in
+`Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata
+
+### Why is this bad?
+It will be more difficult for users to discover the
+purpose of the crate, and key information related to it.
+
+### Example
+```
+[package]
+name = "clippy"
+version = "0.0.212"
+repository = "https://github.com/rust-lang/rust-clippy"
+readme = "README.md"
+license = "MIT OR Apache-2.0"
+keywords = ["clippy", "lint", "plugin"]
+categories = ["development-tools", "development-tools::cargo-plugins"]
+```
+
+Should include a description field like:
+
+```
+[package]
+name = "clippy"
+version = "0.0.212"
+description = "A bunch of helpful lints to avoid common pitfalls in Rust"
+repository = "https://github.com/rust-lang/rust-clippy"
+readme = "README.md"
+license = "MIT OR Apache-2.0"
+keywords = ["clippy", "lint", "plugin"]
+categories = ["development-tools", "development-tools::cargo-plugins"]
+```
\ No newline at end of file
diff --git a/src/docs/case_sensitive_file_extension_comparisons.txt b/src/docs/case_sensitive_file_extension_comparisons.txt
new file mode 100644
index 00000000000..8e6e18ed4e2
--- /dev/null
+++ b/src/docs/case_sensitive_file_extension_comparisons.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for calls to `ends_with` with possible file extensions
+and suggests to use a case-insensitive approach instead.
+
+### Why is this bad?
+`ends_with` is case-sensitive and may not detect files with a valid extension.
+
+### Example
+```
+fn is_rust_file(filename: &str) -> bool {
+    filename.ends_with(".rs")
+}
+```
+Use instead:
+```
+fn is_rust_file(filename: &str) -> bool {
+    let filename = std::path::Path::new(filename);
+    filename.extension()
+        .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
+}
+```
\ No newline at end of file
diff --git a/src/docs/cast_abs_to_unsigned.txt b/src/docs/cast_abs_to_unsigned.txt
new file mode 100644
index 00000000000..c5d8ee034ce
--- /dev/null
+++ b/src/docs/cast_abs_to_unsigned.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for uses of the `abs()` method that cast the result to unsigned.
+
+### Why is this bad?
+The `unsigned_abs()` method avoids panic when called on the MIN value.
+
+### Example
+```
+let x: i32 = -42;
+let y: u32 = x.abs() as u32;
+```
+Use instead:
+```
+let x: i32 = -42;
+let y: u32 = x.unsigned_abs();
+```
\ No newline at end of file
diff --git a/src/docs/cast_enum_constructor.txt b/src/docs/cast_enum_constructor.txt
new file mode 100644
index 00000000000..675c03a42bc
--- /dev/null
+++ b/src/docs/cast_enum_constructor.txt
@@ -0,0 +1,11 @@
+### What it does
+Checks for casts from an enum tuple constructor to an integer.
+
+### Why is this bad?
+The cast is easily confused with casting a c-like enum value to an integer.
+
+### Example
+```
+enum E { X(i32) };
+let _ = E::X as usize;
+```
\ No newline at end of file
diff --git a/src/docs/cast_enum_truncation.txt b/src/docs/cast_enum_truncation.txt
new file mode 100644
index 00000000000..abe32a8296d
--- /dev/null
+++ b/src/docs/cast_enum_truncation.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for casts from an enum type to an integral type which will definitely truncate the
+value.
+
+### Why is this bad?
+The resulting integral value will not match the value of the variant it came from.
+
+### Example
+```
+enum E { X = 256 };
+let _ = E::X as u8;
+```
\ No newline at end of file
diff --git a/src/docs/cast_lossless.txt b/src/docs/cast_lossless.txt
new file mode 100644
index 00000000000..c3a61dd470f
--- /dev/null
+++ b/src/docs/cast_lossless.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for casts between numerical types that may
+be replaced by safe conversion functions.
+
+### Why is this bad?
+Rust's `as` keyword will perform many kinds of
+conversions, including silently lossy conversions. Conversion functions such
+as `i32::from` will only perform lossless conversions. Using the conversion
+functions prevents conversions from turning into silent lossy conversions if
+the types of the input expressions ever change, and make it easier for
+people reading the code to know that the conversion is lossless.
+
+### Example
+```
+fn as_u64(x: u8) -> u64 {
+    x as u64
+}
+```
+
+Using `::from` would look like this:
+
+```
+fn as_u64(x: u8) -> u64 {
+    u64::from(x)
+}
+```
\ No newline at end of file
diff --git a/src/docs/cast_possible_truncation.txt b/src/docs/cast_possible_truncation.txt
new file mode 100644
index 00000000000..0b164848cc7
--- /dev/null
+++ b/src/docs/cast_possible_truncation.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for casts between numerical types that may
+truncate large values. This is expected behavior, so the cast is `Allow` by
+default.
+
+### Why is this bad?
+In some problem domains, it is good practice to avoid
+truncation. This lint can be activated to help assess where additional
+checks could be beneficial.
+
+### Example
+```
+fn as_u8(x: u64) -> u8 {
+    x as u8
+}
+```
\ No newline at end of file
diff --git a/src/docs/cast_possible_wrap.txt b/src/docs/cast_possible_wrap.txt
new file mode 100644
index 00000000000..f883fc9cfb9
--- /dev/null
+++ b/src/docs/cast_possible_wrap.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for casts from an unsigned type to a signed type of
+the same size. Performing such a cast is a 'no-op' for the compiler,
+i.e., nothing is changed at the bit level, and the binary representation of
+the value is reinterpreted. This can cause wrapping if the value is too big
+for the target signed type. However, the cast works as defined, so this lint
+is `Allow` by default.
+
+### Why is this bad?
+While such a cast is not bad in itself, the results can
+be surprising when this is not the intended behavior, as demonstrated by the
+example below.
+
+### Example
+```
+u32::MAX as i32; // will yield a value of `-1`
+```
\ No newline at end of file
diff --git a/src/docs/cast_precision_loss.txt b/src/docs/cast_precision_loss.txt
new file mode 100644
index 00000000000..f915d9f8a6d
--- /dev/null
+++ b/src/docs/cast_precision_loss.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for casts from any numerical to a float type where
+the receiving type cannot store all values from the original type without
+rounding errors. This possible rounding is to be expected, so this lint is
+`Allow` by default.
+
+Basically, this warns on casting any integer with 32 or more bits to `f32`
+or any 64-bit integer to `f64`.
+
+### Why is this bad?
+It's not bad at all. But in some applications it can be
+helpful to know where precision loss can take place. This lint can help find
+those places in the code.
+
+### Example
+```
+let x = u64::MAX;
+x as f64;
+```
\ No newline at end of file
diff --git a/src/docs/cast_ptr_alignment.txt b/src/docs/cast_ptr_alignment.txt
new file mode 100644
index 00000000000..6a6d4dcaa2a
--- /dev/null
+++ b/src/docs/cast_ptr_alignment.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for casts, using `as` or `pointer::cast`,
+from a less-strictly-aligned pointer to a more-strictly-aligned pointer
+
+### Why is this bad?
+Dereferencing the resulting pointer may be undefined
+behavior.
+
+### Known problems
+Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
+on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
+u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
+
+### Example
+```
+let _ = (&1u8 as *const u8) as *const u16;
+let _ = (&mut 1u8 as *mut u8) as *mut u16;
+
+(&1u8 as *const u8).cast::<u16>();
+(&mut 1u8 as *mut u8).cast::<u16>();
+```
\ No newline at end of file
diff --git a/src/docs/cast_ref_to_mut.txt b/src/docs/cast_ref_to_mut.txt
new file mode 100644
index 00000000000..fb5b4dbb62d
--- /dev/null
+++ b/src/docs/cast_ref_to_mut.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for casts of `&T` to `&mut T` anywhere in the code.
+
+### Why is this bad?
+It’s basically guaranteed to be undefined behavior.
+`UnsafeCell` is the only way to obtain aliasable data that is considered
+mutable.
+
+### Example
+```
+fn x(r: &i32) {
+    unsafe {
+        *(r as *const _ as *mut _) += 1;
+    }
+}
+```
+
+Instead consider using interior mutability types.
+
+```
+use std::cell::UnsafeCell;
+
+fn x(r: &UnsafeCell<i32>) {
+    unsafe {
+        *r.get() += 1;
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/cast_sign_loss.txt b/src/docs/cast_sign_loss.txt
new file mode 100644
index 00000000000..d64fe1b07f4
--- /dev/null
+++ b/src/docs/cast_sign_loss.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for casts from a signed to an unsigned numerical
+type. In this case, negative values wrap around to large positive values,
+which can be quite surprising in practice. However, as the cast works as
+defined, this lint is `Allow` by default.
+
+### Why is this bad?
+Possibly surprising results. You can activate this lint
+as a one-time check to see where numerical wrapping can arise.
+
+### Example
+```
+let y: i8 = -1;
+y as u128; // will return 18446744073709551615
+```
\ No newline at end of file
diff --git a/src/docs/cast_slice_different_sizes.txt b/src/docs/cast_slice_different_sizes.txt
new file mode 100644
index 00000000000..c01ef0ba92c
--- /dev/null
+++ b/src/docs/cast_slice_different_sizes.txt
@@ -0,0 +1,38 @@
+### What it does
+Checks for `as` casts between raw pointers to slices with differently sized elements.
+
+### Why is this bad?
+The produced raw pointer to a slice does not update its length metadata. The produced
+pointer will point to a different number of bytes than the original pointer because the
+length metadata of a raw slice pointer is in elements rather than bytes.
+Producing a slice reference from the raw pointer will either create a slice with
+less data (which can be surprising) or create a slice with more data and cause Undefined Behavior.
+
+### Example
+// Missing data
+```
+let a = [1_i32, 2, 3, 4];
+let p = &a as *const [i32] as *const [u8];
+unsafe {
+    println!("{:?}", &*p);
+}
+```
+// Undefined Behavior (note: also potential alignment issues)
+```
+let a = [1_u8, 2, 3, 4];
+let p = &a as *const [u8] as *const [u32];
+unsafe {
+    println!("{:?}", &*p);
+}
+```
+Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length
+```
+let a = [1_i32, 2, 3, 4];
+let old_ptr = &a as *const [i32];
+// The data pointer is cast to a pointer to the target `u8` not `[u8]`
+// The length comes from the known length of 4 i32s times the 4 bytes per i32
+let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16);
+unsafe {
+    println!("{:?}", &*new_ptr);
+}
+```
\ No newline at end of file
diff --git a/src/docs/cast_slice_from_raw_parts.txt b/src/docs/cast_slice_from_raw_parts.txt
new file mode 100644
index 00000000000..b58c739766a
--- /dev/null
+++ b/src/docs/cast_slice_from_raw_parts.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for a raw slice being cast to a slice pointer
+
+### Why is this bad?
+This can result in multiple `&mut` references to the same location when only a pointer is
+required.
+`ptr::slice_from_raw_parts` is a safe alternative that doesn't require
+the same [safety requirements] to be upheld.
+
+### Example
+```
+let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _;
+let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _;
+```
+Use instead:
+```
+let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len);
+let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
+```
+[safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety
\ No newline at end of file
diff --git a/src/docs/char_lit_as_u8.txt b/src/docs/char_lit_as_u8.txt
new file mode 100644
index 00000000000..00d60b9a451
--- /dev/null
+++ b/src/docs/char_lit_as_u8.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for expressions where a character literal is cast
+to `u8` and suggests using a byte literal instead.
+
+### Why is this bad?
+In general, casting values to smaller types is
+error-prone and should be avoided where possible. In the particular case of
+converting a character literal to u8, it is easy to avoid by just using a
+byte literal instead. As an added bonus, `b'a'` is even slightly shorter
+than `'a' as u8`.
+
+### Example
+```
+'x' as u8
+```
+
+A better version, using the byte literal:
+
+```
+b'x'
+```
\ No newline at end of file
diff --git a/src/docs/chars_last_cmp.txt b/src/docs/chars_last_cmp.txt
new file mode 100644
index 00000000000..4c1d8838973
--- /dev/null
+++ b/src/docs/chars_last_cmp.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for usage of `_.chars().last()` or
+`_.chars().next_back()` on a `str` to check if it ends with a given char.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.ends_with(_)`.
+
+### Example
+```
+name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
+```
+
+Use instead:
+```
+name.ends_with('_') || name.ends_with('-');
+```
\ No newline at end of file
diff --git a/src/docs/chars_next_cmp.txt b/src/docs/chars_next_cmp.txt
new file mode 100644
index 00000000000..77cbce2de00
--- /dev/null
+++ b/src/docs/chars_next_cmp.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `.chars().next()` on a `str` to check
+if it starts with a given char.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.starts_with(_)`.
+
+### Example
+```
+let name = "foo";
+if name.chars().next() == Some('_') {};
+```
+
+Use instead:
+```
+let name = "foo";
+if name.starts_with('_') {};
+```
\ No newline at end of file
diff --git a/src/docs/checked_conversions.txt b/src/docs/checked_conversions.txt
new file mode 100644
index 00000000000..536b01294ee
--- /dev/null
+++ b/src/docs/checked_conversions.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for explicit bounds checking when casting.
+
+### Why is this bad?
+Reduces the readability of statements & is error prone.
+
+### Example
+```
+foo <= i32::MAX as u32;
+```
+
+Use instead:
+```
+i32::try_from(foo).is_ok();
+```
\ No newline at end of file
diff --git a/src/docs/clone_double_ref.txt b/src/docs/clone_double_ref.txt
new file mode 100644
index 00000000000..2729635bd24
--- /dev/null
+++ b/src/docs/clone_double_ref.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `.clone()` on an `&&T`.
+
+### Why is this bad?
+Cloning an `&&T` copies the inner `&T`, instead of
+cloning the underlying `T`.
+
+### Example
+```
+fn main() {
+    let x = vec![1];
+    let y = &&x;
+    let z = y.clone();
+    println!("{:p} {:p}", *y, z); // prints out the same pointer
+}
+```
\ No newline at end of file
diff --git a/src/docs/clone_on_copy.txt b/src/docs/clone_on_copy.txt
new file mode 100644
index 00000000000..99a0bdb4c4a
--- /dev/null
+++ b/src/docs/clone_on_copy.txt
@@ -0,0 +1,11 @@
+### What it does
+Checks for usage of `.clone()` on a `Copy` type.
+
+### Why is this bad?
+The only reason `Copy` types implement `Clone` is for
+generics, not for using the `clone` method on a concrete type.
+
+### Example
+```
+42u64.clone();
+```
\ No newline at end of file
diff --git a/src/docs/clone_on_ref_ptr.txt b/src/docs/clone_on_ref_ptr.txt
new file mode 100644
index 00000000000..2d83f8fefc1
--- /dev/null
+++ b/src/docs/clone_on_ref_ptr.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for usage of `.clone()` on a ref-counted pointer,
+(`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified
+function syntax instead (e.g., `Rc::clone(foo)`).
+
+### Why is this bad?
+Calling '.clone()' on an Rc, Arc, or Weak
+can obscure the fact that only the pointer is being cloned, not the underlying
+data.
+
+### Example
+```
+let x = Rc::new(1);
+
+x.clone();
+```
+
+Use instead:
+```
+Rc::clone(&x);
+```
\ No newline at end of file
diff --git a/src/docs/cloned_instead_of_copied.txt b/src/docs/cloned_instead_of_copied.txt
new file mode 100644
index 00000000000..2f2014d5fd2
--- /dev/null
+++ b/src/docs/cloned_instead_of_copied.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usages of `cloned()` on an `Iterator` or `Option` where
+`copied()` could be used instead.
+
+### Why is this bad?
+`copied()` is better because it guarantees that the type being cloned
+implements `Copy`.
+
+### Example
+```
+[1, 2, 3].iter().cloned();
+```
+Use instead:
+```
+[1, 2, 3].iter().copied();
+```
\ No newline at end of file
diff --git a/src/docs/cmp_nan.txt b/src/docs/cmp_nan.txt
new file mode 100644
index 00000000000..e2ad04d9323
--- /dev/null
+++ b/src/docs/cmp_nan.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for comparisons to NaN.
+
+### Why is this bad?
+NaN does not compare meaningfully to anything – not
+even itself – so those comparisons are simply wrong.
+
+### Example
+```
+if x == f32::NAN { }
+```
+
+Use instead:
+```
+if x.is_nan() { }
+```
\ No newline at end of file
diff --git a/src/docs/cmp_null.txt b/src/docs/cmp_null.txt
new file mode 100644
index 00000000000..02fd15124f0
--- /dev/null
+++ b/src/docs/cmp_null.txt
@@ -0,0 +1,23 @@
+### What it does
+This lint checks for equality comparisons with `ptr::null`
+
+### Why is this bad?
+It's easier and more readable to use the inherent
+`.is_null()`
+method instead
+
+### Example
+```
+use std::ptr;
+
+if x == ptr::null {
+    // ..
+}
+```
+
+Use instead:
+```
+if x.is_null() {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/cmp_owned.txt b/src/docs/cmp_owned.txt
new file mode 100644
index 00000000000..f8d4956ff1d
--- /dev/null
+++ b/src/docs/cmp_owned.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for conversions to owned values just for the sake
+of a comparison.
+
+### Why is this bad?
+The comparison can operate on a reference, so creating
+an owned value effectively throws it away directly afterwards, which is
+needlessly consuming code and heap space.
+
+### Example
+```
+if x.to_owned() == y {}
+```
+
+Use instead:
+```
+if x == y {}
+```
\ No newline at end of file
diff --git a/src/docs/cognitive_complexity.txt b/src/docs/cognitive_complexity.txt
new file mode 100644
index 00000000000..fdd75f6479c
--- /dev/null
+++ b/src/docs/cognitive_complexity.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for methods with high cognitive complexity.
+
+### Why is this bad?
+Methods of high cognitive complexity tend to be hard to
+both read and maintain. Also LLVM will tend to optimize small methods better.
+
+### Known problems
+Sometimes it's hard to find a way to reduce the
+complexity.
+
+### Example
+You'll see it when you get the warning.
\ No newline at end of file
diff --git a/src/docs/collapsible_else_if.txt b/src/docs/collapsible_else_if.txt
new file mode 100644
index 00000000000..4ddfca17731
--- /dev/null
+++ b/src/docs/collapsible_else_if.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for collapsible `else { if ... }` expressions
+that can be collapsed to `else if ...`.
+
+### Why is this bad?
+Each `if`-statement adds one level of nesting, which
+makes code look more complex than it really is.
+
+### Example
+```
+
+if x {
+    …
+} else {
+    if y {
+        …
+    }
+}
+```
+
+Should be written:
+
+```
+if x {
+    …
+} else if y {
+    …
+}
+```
\ No newline at end of file
diff --git a/src/docs/collapsible_if.txt b/src/docs/collapsible_if.txt
new file mode 100644
index 00000000000..e1264ee062e
--- /dev/null
+++ b/src/docs/collapsible_if.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for nested `if` statements which can be collapsed
+by `&&`-combining their conditions.
+
+### Why is this bad?
+Each `if`-statement adds one level of nesting, which
+makes code look more complex than it really is.
+
+### Example
+```
+if x {
+    if y {
+        // …
+    }
+}
+```
+
+Use instead:
+```
+if x && y {
+    // …
+}
+```
\ No newline at end of file
diff --git a/src/docs/collapsible_match.txt b/src/docs/collapsible_match.txt
new file mode 100644
index 00000000000..0d59594a03a
--- /dev/null
+++ b/src/docs/collapsible_match.txt
@@ -0,0 +1,31 @@
+### What it does
+Finds nested `match` or `if let` expressions where the patterns may be "collapsed" together
+without adding any branches.
+
+Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only
+cases where merging would most likely make the code more readable.
+
+### Why is this bad?
+It is unnecessarily verbose and complex.
+
+### Example
+```
+fn func(opt: Option<Result<u64, String>>) {
+    let n = match opt {
+        Some(n) => match n {
+            Ok(n) => n,
+            _ => return,
+        }
+        None => return,
+    };
+}
+```
+Use instead:
+```
+fn func(opt: Option<Result<u64, String>>) {
+    let n = match opt {
+        Some(Ok(n)) => n,
+        _ => return,
+    };
+}
+```
\ No newline at end of file
diff --git a/src/docs/collapsible_str_replace.txt b/src/docs/collapsible_str_replace.txt
new file mode 100644
index 00000000000..c24c25a3028
--- /dev/null
+++ b/src/docs/collapsible_str_replace.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for consecutive calls to `str::replace` (2 or more)
+that can be collapsed into a single call.
+
+### Why is this bad?
+Consecutive `str::replace` calls scan the string multiple times
+with repetitive code.
+
+### Example
+```
+let hello = "hesuo worpd"
+    .replace('s', "l")
+    .replace("u", "l")
+    .replace('p', "l");
+```
+Use instead:
+```
+let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l");
+```
\ No newline at end of file
diff --git a/src/docs/comparison_chain.txt b/src/docs/comparison_chain.txt
new file mode 100644
index 00000000000..43b09f31ff4
--- /dev/null
+++ b/src/docs/comparison_chain.txt
@@ -0,0 +1,36 @@
+### What it does
+Checks comparison chains written with `if` that can be
+rewritten with `match` and `cmp`.
+
+### Why is this bad?
+`if` is not guaranteed to be exhaustive and conditionals can get
+repetitive
+
+### Known problems
+The match statement may be slower due to the compiler
+not inlining the call to cmp. See issue [#5354](https://github.com/rust-lang/rust-clippy/issues/5354)
+
+### Example
+```
+fn f(x: u8, y: u8) {
+    if x > y {
+        a()
+    } else if x < y {
+        b()
+    } else {
+        c()
+    }
+}
+```
+
+Use instead:
+```
+use std::cmp::Ordering;
+fn f(x: u8, y: u8) {
+     match x.cmp(&y) {
+         Ordering::Greater => a(),
+         Ordering::Less => b(),
+         Ordering::Equal => c()
+     }
+}
+```
\ No newline at end of file
diff --git a/src/docs/comparison_to_empty.txt b/src/docs/comparison_to_empty.txt
new file mode 100644
index 00000000000..db6f74fe270
--- /dev/null
+++ b/src/docs/comparison_to_empty.txt
@@ -0,0 +1,31 @@
+### What it does
+Checks for comparing to an empty slice such as `""` or `[]`,
+and suggests using `.is_empty()` where applicable.
+
+### Why is this bad?
+Some structures can answer `.is_empty()` much faster
+than checking for equality. So it is good to get into the habit of using
+`.is_empty()`, and having it is cheap.
+Besides, it makes the intent clearer than a manual comparison in some contexts.
+
+### Example
+
+```
+if s == "" {
+    ..
+}
+
+if arr == [] {
+    ..
+}
+```
+Use instead:
+```
+if s.is_empty() {
+    ..
+}
+
+if arr.is_empty() {
+    ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/copy_iterator.txt b/src/docs/copy_iterator.txt
new file mode 100644
index 00000000000..5f9a2a015b8
--- /dev/null
+++ b/src/docs/copy_iterator.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for types that implement `Copy` as well as
+`Iterator`.
+
+### Why is this bad?
+Implicit copies can be confusing when working with
+iterator combinators.
+
+### Example
+```
+#[derive(Copy, Clone)]
+struct Countdown(u8);
+
+impl Iterator for Countdown {
+    // ...
+}
+
+let a: Vec<_> = my_iterator.take(1).collect();
+let b: Vec<_> = my_iterator.collect();
+```
\ No newline at end of file
diff --git a/src/docs/crate_in_macro_def.txt b/src/docs/crate_in_macro_def.txt
new file mode 100644
index 00000000000..047e986dee7
--- /dev/null
+++ b/src/docs/crate_in_macro_def.txt
@@ -0,0 +1,35 @@
+### What it does
+Checks for use of `crate` as opposed to `$crate` in a macro definition.
+
+### Why is this bad?
+`crate` refers to the macro call's crate, whereas `$crate` refers to the macro definition's
+crate. Rarely is the former intended. See:
+https://doc.rust-lang.org/reference/macros-by-example.html#hygiene
+
+### Example
+```
+#[macro_export]
+macro_rules! print_message {
+    () => {
+        println!("{}", crate::MESSAGE);
+    };
+}
+pub const MESSAGE: &str = "Hello!";
+```
+Use instead:
+```
+#[macro_export]
+macro_rules! print_message {
+    () => {
+        println!("{}", $crate::MESSAGE);
+    };
+}
+pub const MESSAGE: &str = "Hello!";
+```
+
+Note that if the use of `crate` is intentional, an `allow` attribute can be applied to the
+macro definition, e.g.:
+```
+#[allow(clippy::crate_in_macro_def)]
+macro_rules! ok { ... crate::foo ... }
+```
\ No newline at end of file
diff --git a/src/docs/create_dir.txt b/src/docs/create_dir.txt
new file mode 100644
index 00000000000..e4e7937684e
--- /dev/null
+++ b/src/docs/create_dir.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead.
+
+### Why is this bad?
+Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`.
+
+### Example
+```
+std::fs::create_dir("foo");
+```
+
+Use instead:
+```
+std::fs::create_dir_all("foo");
+```
\ No newline at end of file
diff --git a/src/docs/crosspointer_transmute.txt b/src/docs/crosspointer_transmute.txt
new file mode 100644
index 00000000000..49dea154970
--- /dev/null
+++ b/src/docs/crosspointer_transmute.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for transmutes between a type `T` and `*T`.
+
+### Why is this bad?
+It's easy to mistakenly transmute between a type and a
+pointer to that type.
+
+### Example
+```
+core::intrinsics::transmute(t) // where the result type is the same as
+                               // `*t` or `&t`'s
+```
\ No newline at end of file
diff --git a/src/docs/dbg_macro.txt b/src/docs/dbg_macro.txt
new file mode 100644
index 00000000000..3e1a9a043f9
--- /dev/null
+++ b/src/docs/dbg_macro.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of dbg!() macro.
+
+### Why is this bad?
+`dbg!` macro is intended as a debugging tool. It
+should not be in version control.
+
+### Example
+```
+dbg!(true)
+```
+
+Use instead:
+```
+true
+```
\ No newline at end of file
diff --git a/src/docs/debug_assert_with_mut_call.txt b/src/docs/debug_assert_with_mut_call.txt
new file mode 100644
index 00000000000..2c44abe1f05
--- /dev/null
+++ b/src/docs/debug_assert_with_mut_call.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for function/method calls with a mutable
+parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros.
+
+### Why is this bad?
+In release builds `debug_assert!` macros are optimized out by the
+compiler.
+Therefore mutating something in a `debug_assert!` macro results in different behavior
+between a release and debug build.
+
+### Example
+```
+debug_assert_eq!(vec![3].pop(), Some(3));
+
+// or
+
+debug_assert!(takes_a_mut_parameter(&mut x));
+```
\ No newline at end of file
diff --git a/src/docs/decimal_literal_representation.txt b/src/docs/decimal_literal_representation.txt
new file mode 100644
index 00000000000..daca9bbb3a8
--- /dev/null
+++ b/src/docs/decimal_literal_representation.txt
@@ -0,0 +1,13 @@
+### What it does
+Warns if there is a better representation for a numeric literal.
+
+### Why is this bad?
+Especially for big powers of 2 a hexadecimal representation is more
+readable than a decimal representation.
+
+### Example
+```
+`255` => `0xFF`
+`65_535` => `0xFFFF`
+`4_042_322_160` => `0xF0F0_F0F0`
+```
\ No newline at end of file
diff --git a/src/docs/declare_interior_mutable_const.txt b/src/docs/declare_interior_mutable_const.txt
new file mode 100644
index 00000000000..2801b5ccff8
--- /dev/null
+++ b/src/docs/declare_interior_mutable_const.txt
@@ -0,0 +1,46 @@
+### What it does
+Checks for declaration of `const` items which is interior
+mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
+
+### Why is this bad?
+Consts are copied everywhere they are referenced, i.e.,
+every time you refer to the const a fresh instance of the `Cell` or `Mutex`
+or `AtomicXxxx` will be created, which defeats the whole purpose of using
+these types in the first place.
+
+The `const` should better be replaced by a `static` item if a global
+variable is wanted, or replaced by a `const fn` if a constructor is wanted.
+
+### Known problems
+A "non-constant" const item is a legacy way to supply an
+initialized value to downstream `static` items (e.g., the
+`std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
+and this lint should be suppressed.
+
+Even though the lint avoids triggering on a constant whose type has enums that have variants
+with interior mutability, and its value uses non interior mutable variants (see
+[#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and
+[#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples);
+it complains about associated constants without default values only based on its types;
+which might not be preferable.
+There're other enums plus associated constants cases that the lint cannot handle.
+
+Types that have underlying or potential interior mutability trigger the lint whether
+the interior mutable field is used or not. See issues
+[#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
+
+### Example
+```
+use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+
+const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
+CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged
+assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct
+```
+
+Use instead:
+```
+static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15);
+STATIC_ATOM.store(9, SeqCst);
+assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
+```
\ No newline at end of file
diff --git a/src/docs/default_instead_of_iter_empty.txt b/src/docs/default_instead_of_iter_empty.txt
new file mode 100644
index 00000000000..b63ef3d18fc
--- /dev/null
+++ b/src/docs/default_instead_of_iter_empty.txt
@@ -0,0 +1,15 @@
+### What it does
+It checks for `std::iter::Empty::default()` and suggests replacing it with
+`std::iter::empty()`.
+### Why is this bad?
+`std::iter::empty()` is the more idiomatic way.
+### Example
+```
+let _ = std::iter::Empty::<usize>::default();
+let iter: std::iter::Empty<usize> = std::iter::Empty::default();
+```
+Use instead:
+```
+let _ = std::iter::empty::<usize>();
+let iter: std::iter::Empty<usize> = std::iter::empty();
+```
\ No newline at end of file
diff --git a/src/docs/default_numeric_fallback.txt b/src/docs/default_numeric_fallback.txt
new file mode 100644
index 00000000000..15076a0a68b
--- /dev/null
+++ b/src/docs/default_numeric_fallback.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type
+inference.
+
+Default numeric fallback means that if numeric types have not yet been bound to concrete
+types at the end of type inference, then integer type is bound to `i32`, and similarly
+floating type is bound to `f64`.
+
+See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback.
+
+### Why is this bad?
+For those who are very careful about types, default numeric fallback
+can be a pitfall that cause unexpected runtime behavior.
+
+### Known problems
+This lint can only be allowed at the function level or above.
+
+### Example
+```
+let i = 10;
+let f = 1.23;
+```
+
+Use instead:
+```
+let i = 10i32;
+let f = 1.23f64;
+```
\ No newline at end of file
diff --git a/src/docs/default_trait_access.txt b/src/docs/default_trait_access.txt
new file mode 100644
index 00000000000..e69298969c8
--- /dev/null
+++ b/src/docs/default_trait_access.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for literal calls to `Default::default()`.
+
+### Why is this bad?
+It's easier for the reader if the name of the type is used, rather than the
+generic `Default`.
+
+### Example
+```
+let s: String = Default::default();
+```
+
+Use instead:
+```
+let s = String::default();
+```
\ No newline at end of file
diff --git a/src/docs/default_union_representation.txt b/src/docs/default_union_representation.txt
new file mode 100644
index 00000000000..f79ff9760e5
--- /dev/null
+++ b/src/docs/default_union_representation.txt
@@ -0,0 +1,36 @@
+### What it does
+Displays a warning when a union is declared with the default representation (without a `#[repr(C)]` attribute).
+
+### Why is this bad?
+Unions in Rust have unspecified layout by default, despite many people thinking that they
+lay out each field at the start of the union (like C does). That is, there are no guarantees
+about the offset of the fields for unions with multiple non-ZST fields without an explicitly
+specified layout. These cases may lead to undefined behavior in unsafe blocks.
+
+### Example
+```
+union Foo {
+    a: i32,
+    b: u32,
+}
+
+fn main() {
+    let _x: u32 = unsafe {
+        Foo { a: 0_i32 }.b // Undefined behavior: `b` is allowed to be padding
+    };
+}
+```
+Use instead:
+```
+#[repr(C)]
+union Foo {
+    a: i32,
+    b: u32,
+}
+
+fn main() {
+    let _x: u32 = unsafe {
+        Foo { a: 0_i32 }.b // Now defined behavior, this is just an i32 -> u32 transmute
+    };
+}
+```
\ No newline at end of file
diff --git a/src/docs/deprecated_cfg_attr.txt b/src/docs/deprecated_cfg_attr.txt
new file mode 100644
index 00000000000..9f264887a05
--- /dev/null
+++ b/src/docs/deprecated_cfg_attr.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it
+with `#[rustfmt::skip]`.
+
+### Why is this bad?
+Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690))
+are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes.
+
+### Known problems
+This lint doesn't detect crate level inner attributes, because they get
+processed before the PreExpansionPass lints get executed. See
+[#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765)
+
+### Example
+```
+#[cfg_attr(rustfmt, rustfmt_skip)]
+fn main() { }
+```
+
+Use instead:
+```
+#[rustfmt::skip]
+fn main() { }
+```
\ No newline at end of file
diff --git a/src/docs/deprecated_semver.txt b/src/docs/deprecated_semver.txt
new file mode 100644
index 00000000000..c9574a99b2b
--- /dev/null
+++ b/src/docs/deprecated_semver.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for `#[deprecated]` annotations with a `since`
+field that is not a valid semantic version.
+
+### Why is this bad?
+For checking the version of the deprecation, it must be
+a valid semver. Failing that, the contained information is useless.
+
+### Example
+```
+#[deprecated(since = "forever")]
+fn something_else() { /* ... */ }
+```
\ No newline at end of file
diff --git a/src/docs/deref_addrof.txt b/src/docs/deref_addrof.txt
new file mode 100644
index 00000000000..fa711b924d4
--- /dev/null
+++ b/src/docs/deref_addrof.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `*&` and `*&mut` in expressions.
+
+### Why is this bad?
+Immediately dereferencing a reference is no-op and
+makes the code less clear.
+
+### Known problems
+Multiple dereference/addrof pairs are not handled so
+the suggested fix for `x = **&&y` is `x = *&y`, which is still incorrect.
+
+### Example
+```
+let a = f(*&mut b);
+let c = *&d;
+```
+
+Use instead:
+```
+let a = f(b);
+let c = d;
+```
\ No newline at end of file
diff --git a/src/docs/deref_by_slicing.txt b/src/docs/deref_by_slicing.txt
new file mode 100644
index 00000000000..4dad24ac00c
--- /dev/null
+++ b/src/docs/deref_by_slicing.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for slicing expressions which are equivalent to dereferencing the
+value.
+
+### Why is this bad?
+Some people may prefer to dereference rather than slice.
+
+### Example
+```
+let vec = vec![1, 2, 3];
+let slice = &vec[..];
+```
+Use instead:
+```
+let vec = vec![1, 2, 3];
+let slice = &*vec;
+```
\ No newline at end of file
diff --git a/src/docs/derivable_impls.txt b/src/docs/derivable_impls.txt
new file mode 100644
index 00000000000..8e4a80a672c
--- /dev/null
+++ b/src/docs/derivable_impls.txt
@@ -0,0 +1,35 @@
+### What it does
+Detects manual `std::default::Default` implementations that are identical to a derived implementation.
+
+### Why is this bad?
+It is less concise.
+
+### Example
+```
+struct Foo {
+    bar: bool
+}
+
+impl Default for Foo {
+    fn default() -> Self {
+        Self {
+            bar: false
+        }
+    }
+}
+```
+
+Use instead:
+```
+#[derive(Default)]
+struct Foo {
+    bar: bool
+}
+```
+
+### Known problems
+Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925)
+in generic types and the user defined `impl` maybe is more generalized or
+specialized than what derive will produce. This lint can't detect the manual `impl`
+has exactly equal bounds, and therefore this lint is disabled for types with
+generic parameters.
\ No newline at end of file
diff --git a/src/docs/derive_hash_xor_eq.txt b/src/docs/derive_hash_xor_eq.txt
new file mode 100644
index 00000000000..fbf623d5adb
--- /dev/null
+++ b/src/docs/derive_hash_xor_eq.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for deriving `Hash` but implementing `PartialEq`
+explicitly or vice versa.
+
+### Why is this bad?
+The implementation of these traits must agree (for
+example for use with `HashMap`) so it’s probably a bad idea to use a
+default-generated `Hash` implementation with an explicitly defined
+`PartialEq`. In particular, the following must hold for any type:
+
+```
+k1 == k2 ⇒ hash(k1) == hash(k2)
+```
+
+### Example
+```
+#[derive(Hash)]
+struct Foo;
+
+impl PartialEq for Foo {
+    ...
+}
+```
\ No newline at end of file
diff --git a/src/docs/derive_ord_xor_partial_ord.txt b/src/docs/derive_ord_xor_partial_ord.txt
new file mode 100644
index 00000000000..f2107a5f69e
--- /dev/null
+++ b/src/docs/derive_ord_xor_partial_ord.txt
@@ -0,0 +1,44 @@
+### What it does
+Checks for deriving `Ord` but implementing `PartialOrd`
+explicitly or vice versa.
+
+### Why is this bad?
+The implementation of these traits must agree (for
+example for use with `sort`) so it’s probably a bad idea to use a
+default-generated `Ord` implementation with an explicitly defined
+`PartialOrd`. In particular, the following must hold for any type
+implementing `Ord`:
+
+```
+k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()
+```
+
+### Example
+```
+#[derive(Ord, PartialEq, Eq)]
+struct Foo;
+
+impl PartialOrd for Foo {
+    ...
+}
+```
+Use instead:
+```
+#[derive(PartialEq, Eq)]
+struct Foo;
+
+impl PartialOrd for Foo {
+    fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
+       Some(self.cmp(other))
+    }
+}
+
+impl Ord for Foo {
+    ...
+}
+```
+or, if you don't need a custom ordering:
+```
+#[derive(Ord, PartialOrd, PartialEq, Eq)]
+struct Foo;
+```
\ No newline at end of file
diff --git a/src/docs/derive_partial_eq_without_eq.txt b/src/docs/derive_partial_eq_without_eq.txt
new file mode 100644
index 00000000000..932fabad666
--- /dev/null
+++ b/src/docs/derive_partial_eq_without_eq.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for types that derive `PartialEq` and could implement `Eq`.
+
+### Why is this bad?
+If a type `T` derives `PartialEq` and all of its members implement `Eq`,
+then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used
+in APIs that require `Eq` types. It also allows structs containing `T` to derive
+`Eq` themselves.
+
+### Example
+```
+#[derive(PartialEq)]
+struct Foo {
+    i_am_eq: i32,
+    i_am_eq_too: Vec<String>,
+}
+```
+Use instead:
+```
+#[derive(PartialEq, Eq)]
+struct Foo {
+    i_am_eq: i32,
+    i_am_eq_too: Vec<String>,
+}
+```
\ No newline at end of file
diff --git a/src/docs/disallowed_methods.txt b/src/docs/disallowed_methods.txt
new file mode 100644
index 00000000000..d8ad5b6a667
--- /dev/null
+++ b/src/docs/disallowed_methods.txt
@@ -0,0 +1,41 @@
+### What it does
+Denies the configured methods and functions in clippy.toml
+
+Note: Even though this lint is warn-by-default, it will only trigger if
+methods are defined in the clippy.toml file.
+
+### Why is this bad?
+Some methods are undesirable in certain contexts, and it's beneficial to
+lint for them as needed.
+
+### Example
+An example clippy.toml configuration:
+```
+disallowed-methods = [
+    # Can use a string as the path of the disallowed method.
+    "std::boxed::Box::new",
+    # Can also use an inline table with a `path` key.
+    { path = "std::time::Instant::now" },
+    # When using an inline table, can add a `reason` for why the method
+    # is disallowed.
+    { path = "std::vec::Vec::leak", reason = "no leaking memory" },
+]
+```
+
+```
+// Example code where clippy issues a warning
+let xs = vec![1, 2, 3, 4];
+xs.leak(); // Vec::leak is disallowed in the config.
+// The diagnostic contains the message "no leaking memory".
+
+let _now = Instant::now(); // Instant::now is disallowed in the config.
+
+let _box = Box::new(3); // Box::new is disallowed in the config.
+```
+
+Use instead:
+```
+// Example code which does not raise clippy warning
+let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config.
+xs.push(123); // Vec::push is _not_ disallowed in the config.
+```
\ No newline at end of file
diff --git a/src/docs/disallowed_names.txt b/src/docs/disallowed_names.txt
new file mode 100644
index 00000000000..f4aaee9c77b
--- /dev/null
+++ b/src/docs/disallowed_names.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for usage of disallowed names for variables, such
+as `foo`.
+
+### Why is this bad?
+These names are usually placeholder names and should be
+avoided.
+
+### Example
+```
+let foo = 3.14;
+```
\ No newline at end of file
diff --git a/src/docs/disallowed_script_idents.txt b/src/docs/disallowed_script_idents.txt
new file mode 100644
index 00000000000..2151b7a20de
--- /dev/null
+++ b/src/docs/disallowed_script_idents.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for usage of unicode scripts other than those explicitly allowed
+by the lint config.
+
+This lint doesn't take into account non-text scripts such as `Unknown` and `Linear_A`.
+It also ignores the `Common` script type.
+While configuring, be sure to use official script name [aliases] from
+[the list of supported scripts][supported_scripts].
+
+See also: [`non_ascii_idents`].
+
+[aliases]: http://www.unicode.org/reports/tr24/tr24-31.html#Script_Value_Aliases
+[supported_scripts]: https://www.unicode.org/iso15924/iso15924-codes.html
+
+### Why is this bad?
+It may be not desired to have many different scripts for
+identifiers in the codebase.
+
+Note that if you only want to allow plain English, you might want to use
+built-in [`non_ascii_idents`] lint instead.
+
+[`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents
+
+### Example
+```
+// Assuming that `clippy.toml` contains the following line:
+// allowed-locales = ["Latin", "Cyrillic"]
+let counter = 10; // OK, latin is allowed.
+let счётчик = 10; // OK, cyrillic is allowed.
+let zähler = 10; // OK, it's still latin.
+let カウンタ = 10; // Will spawn the lint.
+```
\ No newline at end of file
diff --git a/src/docs/disallowed_types.txt b/src/docs/disallowed_types.txt
new file mode 100644
index 00000000000..2bcbcddee56
--- /dev/null
+++ b/src/docs/disallowed_types.txt
@@ -0,0 +1,33 @@
+### What it does
+Denies the configured types in clippy.toml.
+
+Note: Even though this lint is warn-by-default, it will only trigger if
+types are defined in the clippy.toml file.
+
+### Why is this bad?
+Some types are undesirable in certain contexts.
+
+### Example:
+An example clippy.toml configuration:
+```
+disallowed-types = [
+    # Can use a string as the path of the disallowed type.
+    "std::collections::BTreeMap",
+    # Can also use an inline table with a `path` key.
+    { path = "std::net::TcpListener" },
+    # When using an inline table, can add a `reason` for why the type
+    # is disallowed.
+    { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
+]
+```
+
+```
+use std::collections::BTreeMap;
+// or its use
+let x = std::collections::BTreeMap::new();
+```
+Use instead:
+```
+// A similar type that is allowed by the config
+use std::collections::HashMap;
+```
\ No newline at end of file
diff --git a/src/docs/diverging_sub_expression.txt b/src/docs/diverging_sub_expression.txt
new file mode 100644
index 00000000000..19436221802
--- /dev/null
+++ b/src/docs/diverging_sub_expression.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for diverging calls that are not match arms or
+statements.
+
+### Why is this bad?
+It is often confusing to read. In addition, the
+sub-expression evaluation order for Rust is not well documented.
+
+### Known problems
+Someone might want to use `some_bool || panic!()` as a
+shorthand.
+
+### Example
+```
+let a = b() || panic!() || c();
+// `c()` is dead, `panic!()` is only called if `b()` returns `false`
+let x = (a, b, c, panic!());
+// can simply be replaced by `panic!()`
+```
\ No newline at end of file
diff --git a/src/docs/doc_link_with_quotes.txt b/src/docs/doc_link_with_quotes.txt
new file mode 100644
index 00000000000..107c8ac116d
--- /dev/null
+++ b/src/docs/doc_link_with_quotes.txt
@@ -0,0 +1,16 @@
+### What it does
+Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks)
+outside of code blocks
+### Why is this bad?
+It is likely a typo when defining an intra-doc link
+
+### Example
+```
+/// See also: ['foo']
+fn bar() {}
+```
+Use instead:
+```
+/// See also: [`foo`]
+fn bar() {}
+```
\ No newline at end of file
diff --git a/src/docs/doc_markdown.txt b/src/docs/doc_markdown.txt
new file mode 100644
index 00000000000..94f54c587e3
--- /dev/null
+++ b/src/docs/doc_markdown.txt
@@ -0,0 +1,35 @@
+### What it does
+Checks for the presence of `_`, `::` or camel-case words
+outside ticks in documentation.
+
+### Why is this bad?
+*Rustdoc* supports markdown formatting, `_`, `::` and
+camel-case probably indicates some code which should be included between
+ticks. `_` can also be used for emphasis in markdown, this lint tries to
+consider that.
+
+### Known problems
+Lots of bad docs won’t be fixed, what the lint checks
+for is limited, and there are still false positives. HTML elements and their
+content are not linted.
+
+In addition, when writing documentation comments, including `[]` brackets
+inside a link text would trip the parser. Therefore, documenting link with
+`[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec
+would fail.
+
+### Examples
+```
+/// Do something with the foo_bar parameter. See also
+/// that::other::module::foo.
+// ^ `foo_bar` and `that::other::module::foo` should be ticked.
+fn doit(foo_bar: usize) {}
+```
+
+```
+// Link text with `[]` brackets should be written as following:
+/// Consume the array and return the inner
+/// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec].
+/// [SmallVec]: SmallVec
+fn main() {}
+```
\ No newline at end of file
diff --git a/src/docs/double_comparisons.txt b/src/docs/double_comparisons.txt
new file mode 100644
index 00000000000..7dc6818779f
--- /dev/null
+++ b/src/docs/double_comparisons.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for double comparisons that could be simplified to a single expression.
+
+
+### Why is this bad?
+Readability.
+
+### Example
+```
+if x == y || x < y {}
+```
+
+Use instead:
+
+```
+if x <= y {}
+```
\ No newline at end of file
diff --git a/src/docs/double_must_use.txt b/src/docs/double_must_use.txt
new file mode 100644
index 00000000000..0017d10d40d
--- /dev/null
+++ b/src/docs/double_must_use.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for a `#[must_use]` attribute without
+further information on functions and methods that return a type already
+marked as `#[must_use]`.
+
+### Why is this bad?
+The attribute isn't needed. Not using the result
+will already be reported. Alternatively, one can add some text to the
+attribute to improve the lint message.
+
+### Examples
+```
+#[must_use]
+fn double_must_use() -> Result<(), ()> {
+    unimplemented!();
+}
+```
\ No newline at end of file
diff --git a/src/docs/double_neg.txt b/src/docs/double_neg.txt
new file mode 100644
index 00000000000..a07f67496d7
--- /dev/null
+++ b/src/docs/double_neg.txt
@@ -0,0 +1,12 @@
+### What it does
+Detects expressions of the form `--x`.
+
+### Why is this bad?
+It can mislead C/C++ programmers to think `x` was
+decremented.
+
+### Example
+```
+let mut x = 3;
+--x;
+```
\ No newline at end of file
diff --git a/src/docs/double_parens.txt b/src/docs/double_parens.txt
new file mode 100644
index 00000000000..260d7dd575e
--- /dev/null
+++ b/src/docs/double_parens.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for unnecessary double parentheses.
+
+### Why is this bad?
+This makes code harder to read and might indicate a
+mistake.
+
+### Example
+```
+fn simple_double_parens() -> i32 {
+    ((0))
+}
+
+foo((0));
+```
+
+Use instead:
+```
+fn simple_no_parens() -> i32 {
+    0
+}
+
+foo(0);
+```
\ No newline at end of file
diff --git a/src/docs/drop_copy.txt b/src/docs/drop_copy.txt
new file mode 100644
index 00000000000..f917ca8ed21
--- /dev/null
+++ b/src/docs/drop_copy.txt
@@ -0,0 +1,15 @@
+### 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
+```
+let x: i32 = 42; // i32 implements Copy
+std::mem::drop(x) // A copy of x is passed to the function, leaving the
+                  // original unaffected
+```
\ No newline at end of file
diff --git a/src/docs/drop_non_drop.txt b/src/docs/drop_non_drop.txt
new file mode 100644
index 00000000000..ee1e3a6c216
--- /dev/null
+++ b/src/docs/drop_non_drop.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for calls to `std::mem::drop` with a value that does not implement `Drop`.
+
+### Why is this bad?
+Calling `std::mem::drop` is no different than dropping such a type. A different value may
+have been intended.
+
+### Example
+```
+struct Foo;
+let x = Foo;
+std::mem::drop(x);
+```
\ No newline at end of file
diff --git a/src/docs/drop_ref.txt b/src/docs/drop_ref.txt
new file mode 100644
index 00000000000..c4f7adf0cfa
--- /dev/null
+++ b/src/docs/drop_ref.txt
@@ -0,0 +1,17 @@
+### 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
+```
+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();
+```
\ No newline at end of file
diff --git a/src/docs/duplicate_mod.txt b/src/docs/duplicate_mod.txt
new file mode 100644
index 00000000000..709a9aba03a
--- /dev/null
+++ b/src/docs/duplicate_mod.txt
@@ -0,0 +1,31 @@
+### What it does
+Checks for files that are included as modules multiple times.
+
+### Why is this bad?
+Loading a file as a module more than once causes it to be compiled
+multiple times, taking longer and putting duplicate content into the
+module tree.
+
+### Example
+```
+// lib.rs
+mod a;
+mod b;
+```
+```
+// a.rs
+#[path = "./b.rs"]
+mod b;
+```
+
+Use instead:
+
+```
+// lib.rs
+mod a;
+mod b;
+```
+```
+// a.rs
+use crate::b;
+```
\ No newline at end of file
diff --git a/src/docs/duplicate_underscore_argument.txt b/src/docs/duplicate_underscore_argument.txt
new file mode 100644
index 00000000000..a8fcd6a9fbe
--- /dev/null
+++ b/src/docs/duplicate_underscore_argument.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for function arguments having the similar names
+differing by an underscore.
+
+### Why is this bad?
+It affects code readability.
+
+### Example
+```
+fn foo(a: i32, _a: i32) {}
+```
+
+Use instead:
+```
+fn bar(a: i32, _b: i32) {}
+```
\ No newline at end of file
diff --git a/src/docs/duration_subsec.txt b/src/docs/duration_subsec.txt
new file mode 100644
index 00000000000..e7e0ca88745
--- /dev/null
+++ b/src/docs/duration_subsec.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for calculation of subsecond microseconds or milliseconds
+from other `Duration` methods.
+
+### Why is this bad?
+It's more concise to call `Duration::subsec_micros()` or
+`Duration::subsec_millis()` than to calculate them.
+
+### Example
+```
+let micros = duration.subsec_nanos() / 1_000;
+let millis = duration.subsec_nanos() / 1_000_000;
+```
+
+Use instead:
+```
+let micros = duration.subsec_micros();
+let millis = duration.subsec_millis();
+```
\ No newline at end of file
diff --git a/src/docs/else_if_without_else.txt b/src/docs/else_if_without_else.txt
new file mode 100644
index 00000000000..33f5d0f9185
--- /dev/null
+++ b/src/docs/else_if_without_else.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for usage of if expressions with an `else if` branch,
+but without a final `else` branch.
+
+### Why is this bad?
+Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10).
+
+### Example
+```
+if x.is_positive() {
+    a();
+} else if x.is_negative() {
+    b();
+}
+```
+
+Use instead:
+
+```
+if x.is_positive() {
+    a();
+} else if x.is_negative() {
+    b();
+} else {
+    // We don't care about zero.
+}
+```
\ No newline at end of file
diff --git a/src/docs/empty_drop.txt b/src/docs/empty_drop.txt
new file mode 100644
index 00000000000..d0c0c24a9c8
--- /dev/null
+++ b/src/docs/empty_drop.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for empty `Drop` implementations.
+
+### Why is this bad?
+Empty `Drop` implementations have no effect when dropping an instance of the type. They are
+most likely useless. However, an empty `Drop` implementation prevents a type from being
+destructured, which might be the intention behind adding the implementation as a marker.
+
+### Example
+```
+struct S;
+
+impl Drop for S {
+    fn drop(&mut self) {}
+}
+```
+Use instead:
+```
+struct S;
+```
\ No newline at end of file
diff --git a/src/docs/empty_enum.txt b/src/docs/empty_enum.txt
new file mode 100644
index 00000000000..f7b41c41ee5
--- /dev/null
+++ b/src/docs/empty_enum.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for `enum`s with no variants.
+
+As of this writing, the `never_type` is still a
+nightly-only experimental API. Therefore, this lint is only triggered
+if the `never_type` is enabled.
+
+### Why is this bad?
+If you want to introduce a type which
+can't be instantiated, you should use `!` (the primitive type "never"),
+or a wrapper around it, because `!` has more extensive
+compiler support (type inference, etc...) and wrappers
+around it are the conventional way to define an uninhabited type.
+For further information visit [never type documentation](https://doc.rust-lang.org/std/primitive.never.html)
+
+
+### Example
+```
+enum Test {}
+```
+
+Use instead:
+```
+#![feature(never_type)]
+
+struct Test(!);
+```
\ No newline at end of file
diff --git a/src/docs/empty_line_after_outer_attr.txt b/src/docs/empty_line_after_outer_attr.txt
new file mode 100644
index 00000000000..c85242bbee0
--- /dev/null
+++ b/src/docs/empty_line_after_outer_attr.txt
@@ -0,0 +1,35 @@
+### What it does
+Checks for empty lines after outer attributes
+
+### Why is this bad?
+Most likely the attribute was meant to be an inner attribute using a '!'.
+If it was meant to be an outer attribute, then the following item
+should not be separated by empty lines.
+
+### Known problems
+Can cause false positives.
+
+From the clippy side it's difficult to detect empty lines between an attributes and the
+following item because empty lines and comments are not part of the AST. The parsing
+currently works for basic cases but is not perfect.
+
+### Example
+```
+#[allow(dead_code)]
+
+fn not_quite_good_code() { }
+```
+
+Use instead:
+```
+// Good (as inner attribute)
+#![allow(dead_code)]
+
+fn this_is_fine() { }
+
+// or
+
+// Good (as outer attribute)
+#[allow(dead_code)]
+fn this_is_fine_too() { }
+```
\ No newline at end of file
diff --git a/src/docs/empty_loop.txt b/src/docs/empty_loop.txt
new file mode 100644
index 00000000000..fea49a74d04
--- /dev/null
+++ b/src/docs/empty_loop.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for empty `loop` expressions.
+
+### Why is this bad?
+These busy loops burn CPU cycles without doing
+anything. It is _almost always_ a better idea to `panic!` than to have
+a busy loop.
+
+If panicking isn't possible, think of the environment and either:
+  - block on something
+  - sleep the thread for some microseconds
+  - yield or pause the thread
+
+For `std` targets, this can be done with
+[`std::thread::sleep`](https://doc.rust-lang.org/std/thread/fn.sleep.html)
+or [`std::thread::yield_now`](https://doc.rust-lang.org/std/thread/fn.yield_now.html).
+
+For `no_std` targets, doing this is more complicated, especially because
+`#[panic_handler]`s can't panic. To stop/pause the thread, you will
+probably need to invoke some target-specific intrinsic. Examples include:
+  - [`x86_64::instructions::hlt`](https://docs.rs/x86_64/0.12.2/x86_64/instructions/fn.hlt.html)
+  - [`cortex_m::asm::wfi`](https://docs.rs/cortex-m/0.6.3/cortex_m/asm/fn.wfi.html)
+
+### Example
+```
+loop {}
+```
\ No newline at end of file
diff --git a/src/docs/empty_structs_with_brackets.txt b/src/docs/empty_structs_with_brackets.txt
new file mode 100644
index 00000000000..ab5e35ae2ad
--- /dev/null
+++ b/src/docs/empty_structs_with_brackets.txt
@@ -0,0 +1,14 @@
+### What it does
+Finds structs without fields (a so-called "empty struct") that are declared with brackets.
+
+### Why is this bad?
+Empty brackets after a struct declaration can be omitted.
+
+### Example
+```
+struct Cookie {}
+```
+Use instead:
+```
+struct Cookie;
+```
\ No newline at end of file
diff --git a/src/docs/enum_clike_unportable_variant.txt b/src/docs/enum_clike_unportable_variant.txt
new file mode 100644
index 00000000000..d30a973a5a1
--- /dev/null
+++ b/src/docs/enum_clike_unportable_variant.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for C-like enumerations that are
+`repr(isize/usize)` and have values that don't fit into an `i32`.
+
+### Why is this bad?
+This will truncate the variant value on 32 bit
+architectures, but works fine on 64 bit.
+
+### Example
+```
+#[repr(usize)]
+enum NonPortable {
+    X = 0x1_0000_0000,
+    Y = 0,
+}
+```
\ No newline at end of file
diff --git a/src/docs/enum_glob_use.txt b/src/docs/enum_glob_use.txt
new file mode 100644
index 00000000000..3776822c35b
--- /dev/null
+++ b/src/docs/enum_glob_use.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for `use Enum::*`.
+
+### Why is this bad?
+It is usually better style to use the prefixed name of
+an enumeration variant, rather than importing variants.
+
+### Known problems
+Old-style enumerations that prefix the variants are
+still around.
+
+### Example
+```
+use std::cmp::Ordering::*;
+
+foo(Less);
+```
+
+Use instead:
+```
+use std::cmp::Ordering;
+
+foo(Ordering::Less)
+```
\ No newline at end of file
diff --git a/src/docs/enum_variant_names.txt b/src/docs/enum_variant_names.txt
new file mode 100644
index 00000000000..e726925edda
--- /dev/null
+++ b/src/docs/enum_variant_names.txt
@@ -0,0 +1,30 @@
+### What it does
+Detects enumeration variants that are prefixed or suffixed
+by the same characters.
+
+### Why is this bad?
+Enumeration variant names should specify their variant,
+not repeat the enumeration name.
+
+### Limitations
+Characters with no casing will be considered when comparing prefixes/suffixes
+This applies to numbers and non-ascii characters without casing
+e.g. `Foo1` and `Foo2` is considered to have different prefixes
+(the prefixes are `Foo1` and `Foo2` respectively), as also `Bar螃`, `Bar蟹`
+
+### Example
+```
+enum Cake {
+    BlackForestCake,
+    HummingbirdCake,
+    BattenbergCake,
+}
+```
+Use instead:
+```
+enum Cake {
+    BlackForest,
+    Hummingbird,
+    Battenberg,
+}
+```
\ No newline at end of file
diff --git a/src/docs/eq_op.txt b/src/docs/eq_op.txt
new file mode 100644
index 00000000000..2d75a0ec546
--- /dev/null
+++ b/src/docs/eq_op.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for equal operands to comparison, logical and
+bitwise, difference and division binary operators (`==`, `>`, etc., `&&`,
+`||`, `&`, `|`, `^`, `-` and `/`).
+
+### Why is this bad?
+This is usually just a typo or a copy and paste error.
+
+### Known problems
+False negatives: We had some false positives regarding
+calls (notably [racer](https://github.com/phildawes/racer) had one instance
+of `x.pop() && x.pop()`), so we removed matching any function or method
+calls. We may introduce a list of known pure functions in the future.
+
+### Example
+```
+if x + 1 == x + 1 {}
+
+// or
+
+assert_eq!(a, a);
+```
\ No newline at end of file
diff --git a/src/docs/equatable_if_let.txt b/src/docs/equatable_if_let.txt
new file mode 100644
index 00000000000..9997046954c
--- /dev/null
+++ b/src/docs/equatable_if_let.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for pattern matchings that can be expressed using equality.
+
+### Why is this bad?
+
+* It reads better and has less cognitive load because equality won't cause binding.
+* It is a [Yoda condition](https://en.wikipedia.org/wiki/Yoda_conditions). Yoda conditions are widely
+criticized for increasing the cognitive load of reading the code.
+* Equality is a simple bool expression and can be merged with `&&` and `||` and
+reuse if blocks
+
+### Example
+```
+if let Some(2) = x {
+    do_thing();
+}
+```
+Use instead:
+```
+if x == Some(2) {
+    do_thing();
+}
+```
\ No newline at end of file
diff --git a/src/docs/erasing_op.txt b/src/docs/erasing_op.txt
new file mode 100644
index 00000000000..3d285a6d86e
--- /dev/null
+++ b/src/docs/erasing_op.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for erasing operations, e.g., `x * 0`.
+
+### Why is this bad?
+The whole expression can be replaced by zero.
+This is most likely not the intended outcome and should probably be
+corrected
+
+### Example
+```
+let x = 1;
+0 / x;
+0 * x;
+x & 0;
+```
\ No newline at end of file
diff --git a/src/docs/err_expect.txt b/src/docs/err_expect.txt
new file mode 100644
index 00000000000..1dc83c5ce0e
--- /dev/null
+++ b/src/docs/err_expect.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for `.err().expect()` calls on the `Result` type.
+
+### Why is this bad?
+`.expect_err()` can be called directly to avoid the extra type conversion from `err()`.
+
+### Example
+```
+let x: Result<u32, &str> = Ok(10);
+x.err().expect("Testing err().expect()");
+```
+Use instead:
+```
+let x: Result<u32, &str> = Ok(10);
+x.expect_err("Testing expect_err");
+```
\ No newline at end of file
diff --git a/src/docs/excessive_precision.txt b/src/docs/excessive_precision.txt
new file mode 100644
index 00000000000..517879c4715
--- /dev/null
+++ b/src/docs/excessive_precision.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for float literals with a precision greater
+than that supported by the underlying type.
+
+### Why is this bad?
+Rust will truncate the literal silently.
+
+### Example
+```
+let v: f32 = 0.123_456_789_9;
+println!("{}", v); //  0.123_456_789
+```
+
+Use instead:
+```
+let v: f64 = 0.123_456_789_9;
+println!("{}", v); //  0.123_456_789_9
+```
\ No newline at end of file
diff --git a/src/docs/exhaustive_enums.txt b/src/docs/exhaustive_enums.txt
new file mode 100644
index 00000000000..d1032a7a29a
--- /dev/null
+++ b/src/docs/exhaustive_enums.txt
@@ -0,0 +1,23 @@
+### What it does
+Warns on any exported `enum`s that are not tagged `#[non_exhaustive]`
+
+### Why is this bad?
+Exhaustive enums are typically fine, but a project which does
+not wish to make a stability commitment around exported enums may wish to
+disable them by default.
+
+### Example
+```
+enum Foo {
+    Bar,
+    Baz
+}
+```
+Use instead:
+```
+#[non_exhaustive]
+enum Foo {
+    Bar,
+    Baz
+}
+```
\ No newline at end of file
diff --git a/src/docs/exhaustive_structs.txt b/src/docs/exhaustive_structs.txt
new file mode 100644
index 00000000000..fd6e4f5caf1
--- /dev/null
+++ b/src/docs/exhaustive_structs.txt
@@ -0,0 +1,23 @@
+### What it does
+Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`
+
+### Why is this bad?
+Exhaustive structs are typically fine, but a project which does
+not wish to make a stability commitment around exported structs may wish to
+disable them by default.
+
+### Example
+```
+struct Foo {
+    bar: u8,
+    baz: String,
+}
+```
+Use instead:
+```
+#[non_exhaustive]
+struct Foo {
+    bar: u8,
+    baz: String,
+}
+```
\ No newline at end of file
diff --git a/src/docs/exit.txt b/src/docs/exit.txt
new file mode 100644
index 00000000000..1e6154d43e0
--- /dev/null
+++ b/src/docs/exit.txt
@@ -0,0 +1,12 @@
+### What it does
+`exit()`  terminates the program and doesn't provide a
+stack trace.
+
+### Why is this bad?
+Ideally a program is terminated by finishing
+the main function.
+
+### Example
+```
+std::process::exit(0)
+```
\ No newline at end of file
diff --git a/src/docs/expect_fun_call.txt b/src/docs/expect_fun_call.txt
new file mode 100644
index 00000000000..d82d9aa9baf
--- /dev/null
+++ b/src/docs/expect_fun_call.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,
+etc., and suggests to use `unwrap_or_else` instead
+
+### Why is this bad?
+The function will always be called.
+
+### Known problems
+If the function has side-effects, not calling it will
+change the semantics of the program, but you shouldn't rely on that anyway.
+
+### Example
+```
+foo.expect(&format!("Err {}: {}", err_code, err_msg));
+
+// or
+
+foo.expect(format!("Err {}: {}", err_code, err_msg).as_str());
+```
+
+Use instead:
+```
+foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg));
+```
\ No newline at end of file
diff --git a/src/docs/expect_used.txt b/src/docs/expect_used.txt
new file mode 100644
index 00000000000..4a6981e334f
--- /dev/null
+++ b/src/docs/expect_used.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s.
+
+### Why is this bad?
+Usually it is better to handle the `None` or `Err` case.
+Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why
+this lint is `Allow` by default.
+
+`result.expect()` will let the thread panic on `Err`
+values. Normally, you want to implement more sophisticated error handling,
+and propagate errors upwards with `?` operator.
+
+### Examples
+```
+option.expect("one");
+result.expect("one");
+```
+
+Use instead:
+```
+option?;
+
+// or
+
+result?;
+```
\ No newline at end of file
diff --git a/src/docs/expl_impl_clone_on_copy.txt b/src/docs/expl_impl_clone_on_copy.txt
new file mode 100644
index 00000000000..391d93b6713
--- /dev/null
+++ b/src/docs/expl_impl_clone_on_copy.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for explicit `Clone` implementations for `Copy`
+types.
+
+### Why is this bad?
+To avoid surprising behavior, these traits should
+agree and the behavior of `Copy` cannot be overridden. In almost all
+situations a `Copy` type should have a `Clone` implementation that does
+nothing more than copy the object, which is what `#[derive(Copy, Clone)]`
+gets you.
+
+### Example
+```
+#[derive(Copy)]
+struct Foo;
+
+impl Clone for Foo {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/explicit_auto_deref.txt b/src/docs/explicit_auto_deref.txt
new file mode 100644
index 00000000000..65b25631772
--- /dev/null
+++ b/src/docs/explicit_auto_deref.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for dereferencing expressions which would be covered by auto-deref.
+
+### Why is this bad?
+This unnecessarily complicates the code.
+
+### Example
+```
+let x = String::new();
+let y: &str = &*x;
+```
+Use instead:
+```
+let x = String::new();
+let y: &str = &x;
+```
\ No newline at end of file
diff --git a/src/docs/explicit_counter_loop.txt b/src/docs/explicit_counter_loop.txt
new file mode 100644
index 00000000000..2661a43e103
--- /dev/null
+++ b/src/docs/explicit_counter_loop.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks `for` loops over slices with an explicit counter
+and suggests the use of `.enumerate()`.
+
+### Why is this bad?
+Using `.enumerate()` makes the intent more clear,
+declutters the code and may be faster in some instances.
+
+### Example
+```
+let mut i = 0;
+for item in &v {
+    bar(i, *item);
+    i += 1;
+}
+```
+
+Use instead:
+```
+for (i, item) in v.iter().enumerate() { bar(i, *item); }
+```
\ No newline at end of file
diff --git a/src/docs/explicit_deref_methods.txt b/src/docs/explicit_deref_methods.txt
new file mode 100644
index 00000000000..e14e981c707
--- /dev/null
+++ b/src/docs/explicit_deref_methods.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for explicit `deref()` or `deref_mut()` method calls.
+
+### Why is this bad?
+Dereferencing by `&*x` or `&mut *x` is clearer and more concise,
+when not part of a method chain.
+
+### Example
+```
+use std::ops::Deref;
+let a: &mut String = &mut String::from("foo");
+let b: &str = a.deref();
+```
+
+Use instead:
+```
+let a: &mut String = &mut String::from("foo");
+let b = &*a;
+```
+
+This lint excludes:
+```
+let _ = d.unwrap().deref();
+```
\ No newline at end of file
diff --git a/src/docs/explicit_into_iter_loop.txt b/src/docs/explicit_into_iter_loop.txt
new file mode 100644
index 00000000000..3931dfd69a3
--- /dev/null
+++ b/src/docs/explicit_into_iter_loop.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for loops on `y.into_iter()` where `y` will do, and
+suggests the latter.
+
+### Why is this bad?
+Readability.
+
+### Example
+```
+// with `y` a `Vec` or slice:
+for x in y.into_iter() {
+    // ..
+}
+```
+can be rewritten to
+```
+for x in y {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/explicit_iter_loop.txt b/src/docs/explicit_iter_loop.txt
new file mode 100644
index 00000000000..cabe72e91d0
--- /dev/null
+++ b/src/docs/explicit_iter_loop.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for loops on `x.iter()` where `&x` will do, and
+suggests the latter.
+
+### Why is this bad?
+Readability.
+
+### Known problems
+False negatives. We currently only warn on some known
+types.
+
+### Example
+```
+// with `y` a `Vec` or slice:
+for x in y.iter() {
+    // ..
+}
+```
+
+Use instead:
+```
+for x in &y {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/explicit_write.txt b/src/docs/explicit_write.txt
new file mode 100644
index 00000000000..eafed5d39e5
--- /dev/null
+++ b/src/docs/explicit_write.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for usage of `write!()` / `writeln()!` which can be
+replaced with `(e)print!()` / `(e)println!()`
+
+### Why is this bad?
+Using `(e)println! is clearer and more concise
+
+### Example
+```
+writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap();
+writeln!(&mut std::io::stdout(), "foo: {:?}", bar).unwrap();
+```
+
+Use instead:
+```
+eprintln!("foo: {:?}", bar);
+println!("foo: {:?}", bar);
+```
\ No newline at end of file
diff --git a/src/docs/extend_with_drain.txt b/src/docs/extend_with_drain.txt
new file mode 100644
index 00000000000..2f31dcf5f74
--- /dev/null
+++ b/src/docs/extend_with_drain.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for occurrences where one vector gets extended instead of append
+
+### Why is this bad?
+Using `append` instead of `extend` is more concise and faster
+
+### Example
+```
+let mut a = vec![1, 2, 3];
+let mut b = vec![4, 5, 6];
+
+a.extend(b.drain(..));
+```
+
+Use instead:
+```
+let mut a = vec![1, 2, 3];
+let mut b = vec![4, 5, 6];
+
+a.append(&mut b);
+```
\ No newline at end of file
diff --git a/src/docs/extra_unused_lifetimes.txt b/src/docs/extra_unused_lifetimes.txt
new file mode 100644
index 00000000000..bc1814aa475
--- /dev/null
+++ b/src/docs/extra_unused_lifetimes.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for lifetimes in generics that are never used
+anywhere else.
+
+### Why is this bad?
+The additional lifetimes make the code look more
+complicated, while there is nothing out of the ordinary going on. Removing
+them leads to more readable code.
+
+### Example
+```
+// unnecessary lifetimes
+fn unused_lifetime<'a>(x: u8) {
+    // ..
+}
+```
+
+Use instead:
+```
+fn no_lifetime(x: u8) {
+    // ...
+}
+```
\ No newline at end of file
diff --git a/src/docs/fallible_impl_from.txt b/src/docs/fallible_impl_from.txt
new file mode 100644
index 00000000000..588a5bb103d
--- /dev/null
+++ b/src/docs/fallible_impl_from.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`
+
+### Why is this bad?
+`TryFrom` should be used if there's a possibility of failure.
+
+### Example
+```
+struct Foo(i32);
+
+impl From<String> for Foo {
+    fn from(s: String) -> Self {
+        Foo(s.parse().unwrap())
+    }
+}
+```
+
+Use instead:
+```
+struct Foo(i32);
+
+impl TryFrom<String> for Foo {
+    type Error = ();
+    fn try_from(s: String) -> Result<Self, Self::Error> {
+        if let Ok(parsed) = s.parse() {
+            Ok(Foo(parsed))
+        } else {
+            Err(())
+        }
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/field_reassign_with_default.txt b/src/docs/field_reassign_with_default.txt
new file mode 100644
index 00000000000..e58b7239fde
--- /dev/null
+++ b/src/docs/field_reassign_with_default.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for immediate reassignment of fields initialized
+with Default::default().
+
+### Why is this bad?
+It's more idiomatic to use the [functional update syntax](https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax).
+
+### Known problems
+Assignments to patterns that are of tuple type are not linted.
+
+### Example
+```
+let mut a: A = Default::default();
+a.i = 42;
+```
+
+Use instead:
+```
+let a = A {
+    i: 42,
+    .. Default::default()
+};
+```
\ No newline at end of file
diff --git a/src/docs/filetype_is_file.txt b/src/docs/filetype_is_file.txt
new file mode 100644
index 00000000000..ad14bd62c4d
--- /dev/null
+++ b/src/docs/filetype_is_file.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for `FileType::is_file()`.
+
+### Why is this bad?
+When people testing a file type with `FileType::is_file`
+they are testing whether a path is something they can get bytes from. But
+`is_file` doesn't cover special file types in unix-like systems, and doesn't cover
+symlink in windows. Using `!FileType::is_dir()` is a better way to that intention.
+
+### Example
+```
+let metadata = std::fs::metadata("foo.txt")?;
+let filetype = metadata.file_type();
+
+if filetype.is_file() {
+    // read file
+}
+```
+
+should be written as:
+
+```
+let metadata = std::fs::metadata("foo.txt")?;
+let filetype = metadata.file_type();
+
+if !filetype.is_dir() {
+    // read file
+}
+```
\ No newline at end of file
diff --git a/src/docs/filter_map_identity.txt b/src/docs/filter_map_identity.txt
new file mode 100644
index 00000000000..83b666f2e27
--- /dev/null
+++ b/src/docs/filter_map_identity.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for usage of `filter_map(|x| x)`.
+
+### Why is this bad?
+Readability, this can be written more concisely by using `flatten`.
+
+### Example
+```
+iter.filter_map(|x| x);
+```
+Use instead:
+```
+iter.flatten();
+```
\ No newline at end of file
diff --git a/src/docs/filter_map_next.txt b/src/docs/filter_map_next.txt
new file mode 100644
index 00000000000..b38620b56a5
--- /dev/null
+++ b/src/docs/filter_map_next.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `_.filter_map(_).next()`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.find_map(_)`.
+
+### Example
+```
+ (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();
+```
+Can be written as
+
+```
+ (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
+```
\ No newline at end of file
diff --git a/src/docs/filter_next.txt b/src/docs/filter_next.txt
new file mode 100644
index 00000000000..898a74166dc
--- /dev/null
+++ b/src/docs/filter_next.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `_.filter(_).next()`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.find(_)`.
+
+### Example
+```
+vec.iter().filter(|x| **x == 0).next();
+```
+
+Use instead:
+```
+vec.iter().find(|x| **x == 0);
+```
\ No newline at end of file
diff --git a/src/docs/flat_map_identity.txt b/src/docs/flat_map_identity.txt
new file mode 100644
index 00000000000..a5ee79b4982
--- /dev/null
+++ b/src/docs/flat_map_identity.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for usage of `flat_map(|x| x)`.
+
+### Why is this bad?
+Readability, this can be written more concisely by using `flatten`.
+
+### Example
+```
+iter.flat_map(|x| x);
+```
+Can be written as
+```
+iter.flatten();
+```
\ No newline at end of file
diff --git a/src/docs/flat_map_option.txt b/src/docs/flat_map_option.txt
new file mode 100644
index 00000000000..d50b9156d36
--- /dev/null
+++ b/src/docs/flat_map_option.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usages of `Iterator::flat_map()` where `filter_map()` could be
+used instead.
+
+### Why is this bad?
+When applicable, `filter_map()` is more clear since it shows that
+`Option` is used to produce 0 or 1 items.
+
+### Example
+```
+let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect();
+```
+Use instead:
+```
+let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect();
+```
\ No newline at end of file
diff --git a/src/docs/float_arithmetic.txt b/src/docs/float_arithmetic.txt
new file mode 100644
index 00000000000..1f9bce5abd5
--- /dev/null
+++ b/src/docs/float_arithmetic.txt
@@ -0,0 +1,11 @@
+### What it does
+Checks for float arithmetic.
+
+### Why is this bad?
+For some embedded systems or kernel development, it
+can be useful to rule out floating-point numbers.
+
+### Example
+```
+a + 1.0;
+```
\ No newline at end of file
diff --git a/src/docs/float_cmp.txt b/src/docs/float_cmp.txt
new file mode 100644
index 00000000000..c19907c903e
--- /dev/null
+++ b/src/docs/float_cmp.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for (in-)equality comparisons on floating-point
+values (apart from zero), except in functions called `*eq*` (which probably
+implement equality for a type involving floats).
+
+### Why is this bad?
+Floating point calculations are usually imprecise, so
+asking if two values are *exactly* equal is asking for trouble. For a good
+guide on what to do, see [the floating point
+guide](http://www.floating-point-gui.de/errors/comparison).
+
+### Example
+```
+let x = 1.2331f64;
+let y = 1.2332f64;
+
+if y == 1.23f64 { }
+if y != x {} // where both are floats
+```
+
+Use instead:
+```
+let error_margin = f64::EPSILON; // Use an epsilon for comparison
+// Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
+// let error_margin = std::f64::EPSILON;
+if (y - 1.23f64).abs() < error_margin { }
+if (y - x).abs() > error_margin { }
+```
\ No newline at end of file
diff --git a/src/docs/float_cmp_const.txt b/src/docs/float_cmp_const.txt
new file mode 100644
index 00000000000..9208feaacd8
--- /dev/null
+++ b/src/docs/float_cmp_const.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for (in-)equality comparisons on floating-point
+value and constant, except in functions called `*eq*` (which probably
+implement equality for a type involving floats).
+
+### Why is this bad?
+Floating point calculations are usually imprecise, so
+asking if two values are *exactly* equal is asking for trouble. For a good
+guide on what to do, see [the floating point
+guide](http://www.floating-point-gui.de/errors/comparison).
+
+### Example
+```
+let x: f64 = 1.0;
+const ONE: f64 = 1.00;
+
+if x == ONE { } // where both are floats
+```
+
+Use instead:
+```
+let error_margin = f64::EPSILON; // Use an epsilon for comparison
+// Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
+// let error_margin = std::f64::EPSILON;
+if (x - ONE).abs() < error_margin { }
+```
\ No newline at end of file
diff --git a/src/docs/float_equality_without_abs.txt b/src/docs/float_equality_without_abs.txt
new file mode 100644
index 00000000000..556b574e15d
--- /dev/null
+++ b/src/docs/float_equality_without_abs.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for statements of the form `(a - b) < f32::EPSILON` or
+`(a - b) < f64::EPSILON`. Notes the missing `.abs()`.
+
+### Why is this bad?
+The code without `.abs()` is more likely to have a bug.
+
+### Known problems
+If the user can ensure that b is larger than a, the `.abs()` is
+technically unnecessary. However, it will make the code more robust and doesn't have any
+large performance implications. If the abs call was deliberately left out for performance
+reasons, it is probably better to state this explicitly in the code, which then can be done
+with an allow.
+
+### Example
+```
+pub fn is_roughly_equal(a: f32, b: f32) -> bool {
+    (a - b) < f32::EPSILON
+}
+```
+Use instead:
+```
+pub fn is_roughly_equal(a: f32, b: f32) -> bool {
+    (a - b).abs() < f32::EPSILON
+}
+```
\ No newline at end of file
diff --git a/src/docs/fn_address_comparisons.txt b/src/docs/fn_address_comparisons.txt
new file mode 100644
index 00000000000..7d2b7b681de
--- /dev/null
+++ b/src/docs/fn_address_comparisons.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for comparisons with an address of a function item.
+
+### Why is this bad?
+Function item address is not guaranteed to be unique and could vary
+between different code generation units. Furthermore different function items could have
+the same address after being merged together.
+
+### Example
+```
+type F = fn();
+fn a() {}
+let f: F = a;
+if f == a {
+    // ...
+}
+```
\ No newline at end of file
diff --git a/src/docs/fn_params_excessive_bools.txt b/src/docs/fn_params_excessive_bools.txt
new file mode 100644
index 00000000000..2eae0563368
--- /dev/null
+++ b/src/docs/fn_params_excessive_bools.txt
@@ -0,0 +1,31 @@
+### What it does
+Checks for excessive use of
+bools in function definitions.
+
+### Why is this bad?
+Calls to such functions
+are confusing and error prone, because it's
+hard to remember argument order and you have
+no type system support to back you up. Using
+two-variant enums instead of bools often makes
+API easier to use.
+
+### Example
+```
+fn f(is_round: bool, is_hot: bool) { ... }
+```
+
+Use instead:
+```
+enum Shape {
+    Round,
+    Spiky,
+}
+
+enum Temperature {
+    Hot,
+    IceCold,
+}
+
+fn f(shape: Shape, temperature: Temperature) { ... }
+```
\ No newline at end of file
diff --git a/src/docs/fn_to_numeric_cast.txt b/src/docs/fn_to_numeric_cast.txt
new file mode 100644
index 00000000000..1f587f6d717
--- /dev/null
+++ b/src/docs/fn_to_numeric_cast.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for casts of function pointers to something other than usize
+
+### Why is this bad?
+Casting a function pointer to anything other than usize/isize is not portable across
+architectures, because you end up losing bits if the target type is too small or end up with a
+bunch of extra bits that waste space and add more instructions to the final binary than
+strictly necessary for the problem
+
+Casting to isize also doesn't make sense since there are no signed addresses.
+
+### Example
+```
+fn fun() -> i32 { 1 }
+let _ = fun as i64;
+```
+
+Use instead:
+```
+let _ = fun as usize;
+```
\ No newline at end of file
diff --git a/src/docs/fn_to_numeric_cast_any.txt b/src/docs/fn_to_numeric_cast_any.txt
new file mode 100644
index 00000000000..ee3c33d2372
--- /dev/null
+++ b/src/docs/fn_to_numeric_cast_any.txt
@@ -0,0 +1,35 @@
+### What it does
+Checks for casts of a function pointer to any integer type.
+
+### Why is this bad?
+Casting a function pointer to an integer can have surprising results and can occur
+accidentally if parentheses are omitted from a function call. If you aren't doing anything
+low-level with function pointers then you can opt-out of casting functions to integers in
+order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
+pointer casts in your code.
+
+### Example
+```
+// fn1 is cast as `usize`
+fn fn1() -> u16 {
+    1
+};
+let _ = fn1 as usize;
+```
+
+Use instead:
+```
+// maybe you intended to call the function?
+fn fn2() -> u16 {
+    1
+};
+let _ = fn2() as usize;
+
+// or
+
+// maybe you intended to cast it to a function type?
+fn fn3() -> u16 {
+    1
+}
+let _ = fn3 as fn() -> u16;
+```
\ No newline at end of file
diff --git a/src/docs/fn_to_numeric_cast_with_truncation.txt b/src/docs/fn_to_numeric_cast_with_truncation.txt
new file mode 100644
index 00000000000..69f12fa319f
--- /dev/null
+++ b/src/docs/fn_to_numeric_cast_with_truncation.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for casts of a function pointer to a numeric type not wide enough to
+store address.
+
+### Why is this bad?
+Such a cast discards some bits of the function's address. If this is intended, it would be more
+clearly expressed by casting to usize first, then casting the usize to the intended type (with
+a comment) to perform the truncation.
+
+### Example
+```
+fn fn1() -> i16 {
+    1
+};
+let _ = fn1 as i32;
+```
+
+Use instead:
+```
+// Cast to usize first, then comment with the reason for the truncation
+fn fn1() -> i16 {
+    1
+};
+let fn_ptr = fn1 as usize;
+let fn_ptr_truncated = fn_ptr as i32;
+```
\ No newline at end of file
diff --git a/src/docs/for_kv_map.txt b/src/docs/for_kv_map.txt
new file mode 100644
index 00000000000..a9a2ffee9c7
--- /dev/null
+++ b/src/docs/for_kv_map.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for iterating a map (`HashMap` or `BTreeMap`) and
+ignoring either the keys or values.
+
+### Why is this bad?
+Readability. There are `keys` and `values` methods that
+can be used to express that don't need the values or keys.
+
+### Example
+```
+for (k, _) in &map {
+    ..
+}
+```
+
+could be replaced by
+
+```
+for k in map.keys() {
+    ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/for_loops_over_fallibles.txt b/src/docs/for_loops_over_fallibles.txt
new file mode 100644
index 00000000000..c5a7508e45d
--- /dev/null
+++ b/src/docs/for_loops_over_fallibles.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for `for` loops over `Option` or `Result` values.
+
+### Why is this bad?
+Readability. This is more clearly expressed as an `if
+let`.
+
+### Example
+```
+for x in opt {
+    // ..
+}
+
+for x in &res {
+    // ..
+}
+
+for x in res.iter() {
+    // ..
+}
+```
+
+Use instead:
+```
+if let Some(x) = opt {
+    // ..
+}
+
+if let Ok(x) = res {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/forget_copy.txt b/src/docs/forget_copy.txt
new file mode 100644
index 00000000000..1d100912e9a
--- /dev/null
+++ b/src/docs/forget_copy.txt
@@ -0,0 +1,21 @@
+### 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
+```
+let x: i32 = 42; // i32 implements Copy
+std::mem::forget(x) // A copy of x is passed to the function, leaving the
+                    // original unaffected
+```
\ No newline at end of file
diff --git a/src/docs/forget_non_drop.txt b/src/docs/forget_non_drop.txt
new file mode 100644
index 00000000000..3307d654c17
--- /dev/null
+++ b/src/docs/forget_non_drop.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for calls to `std::mem::forget` with a value that does not implement `Drop`.
+
+### Why is this bad?
+Calling `std::mem::forget` is no different than dropping such a type. A different value may
+have been intended.
+
+### Example
+```
+struct Foo;
+let x = Foo;
+std::mem::forget(x);
+```
\ No newline at end of file
diff --git a/src/docs/forget_ref.txt b/src/docs/forget_ref.txt
new file mode 100644
index 00000000000..874fb878606
--- /dev/null
+++ b/src/docs/forget_ref.txt
@@ -0,0 +1,15 @@
+### 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
+```
+let x = Box::new(1);
+std::mem::forget(&x) // Should have been forget(x), x will still be dropped
+```
\ No newline at end of file
diff --git a/src/docs/format_in_format_args.txt b/src/docs/format_in_format_args.txt
new file mode 100644
index 00000000000..ac498472f01
--- /dev/null
+++ b/src/docs/format_in_format_args.txt
@@ -0,0 +1,16 @@
+### What it does
+Detects `format!` within the arguments of another macro that does
+formatting such as `format!` itself, `write!` or `println!`. Suggests
+inlining the `format!` call.
+
+### Why is this bad?
+The recommended code is both shorter and avoids a temporary allocation.
+
+### Example
+```
+println!("error: {}", format!("something failed at {}", Location::caller()));
+```
+Use instead:
+```
+println!("error: something failed at {}", Location::caller());
+```
\ No newline at end of file
diff --git a/src/docs/format_push_string.txt b/src/docs/format_push_string.txt
new file mode 100644
index 00000000000..ca409ebc7ec
--- /dev/null
+++ b/src/docs/format_push_string.txt
@@ -0,0 +1,26 @@
+### What it does
+Detects cases where the result of a `format!` call is
+appended to an existing `String`.
+
+### Why is this bad?
+Introduces an extra, avoidable heap allocation.
+
+### Known problems
+`format!` returns a `String` but `write!` returns a `Result`.
+Thus you are forced to ignore the `Err` variant to achieve the same API.
+
+While using `write!` in the suggested way should never fail, this isn't necessarily clear to the programmer.
+
+### Example
+```
+let mut s = String::new();
+s += &format!("0x{:X}", 1024);
+s.push_str(&format!("0x{:X}", 1024));
+```
+Use instead:
+```
+use std::fmt::Write as _; // import without risk of name clashing
+
+let mut s = String::new();
+let _ = write!(s, "0x{:X}", 1024);
+```
\ No newline at end of file
diff --git a/src/docs/from_iter_instead_of_collect.txt b/src/docs/from_iter_instead_of_collect.txt
new file mode 100644
index 00000000000..f3fd2759726
--- /dev/null
+++ b/src/docs/from_iter_instead_of_collect.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for `from_iter()` function calls on types that implement the `FromIterator`
+trait.
+
+### Why is this bad?
+It is recommended style to use collect. See
+[FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
+
+### Example
+```
+let five_fives = std::iter::repeat(5).take(5);
+
+let v = Vec::from_iter(five_fives);
+
+assert_eq!(v, vec![5, 5, 5, 5, 5]);
+```
+Use instead:
+```
+let five_fives = std::iter::repeat(5).take(5);
+
+let v: Vec<i32> = five_fives.collect();
+
+assert_eq!(v, vec![5, 5, 5, 5, 5]);
+```
\ No newline at end of file
diff --git a/src/docs/from_over_into.txt b/src/docs/from_over_into.txt
new file mode 100644
index 00000000000..0770bcc42c2
--- /dev/null
+++ b/src/docs/from_over_into.txt
@@ -0,0 +1,26 @@
+### What it does
+Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead.
+
+### Why is this bad?
+According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true.
+
+### Example
+```
+struct StringWrapper(String);
+
+impl Into<StringWrapper> for String {
+    fn into(self) -> StringWrapper {
+        StringWrapper(self)
+    }
+}
+```
+Use instead:
+```
+struct StringWrapper(String);
+
+impl From<String> for StringWrapper {
+    fn from(s: String) -> StringWrapper {
+        StringWrapper(s)
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/from_str_radix_10.txt b/src/docs/from_str_radix_10.txt
new file mode 100644
index 00000000000..f6f319d3eaa
--- /dev/null
+++ b/src/docs/from_str_radix_10.txt
@@ -0,0 +1,25 @@
+### What it does
+
+Checks for function invocations of the form `primitive::from_str_radix(s, 10)`
+
+### Why is this bad?
+
+This specific common use case can be rewritten as `s.parse::<primitive>()`
+(and in most cases, the turbofish can be removed), which reduces code length
+and complexity.
+
+### Known problems
+
+This lint may suggest using (&<expression>).parse() instead of <expression>.parse() directly
+in some cases, which is correct but adds unnecessary complexity to the code.
+
+### Example
+```
+let input: &str = get_input();
+let num = u16::from_str_radix(input, 10)?;
+```
+Use instead:
+```
+let input: &str = get_input();
+let num: u16 = input.parse()?;
+```
\ No newline at end of file
diff --git a/src/docs/future_not_send.txt b/src/docs/future_not_send.txt
new file mode 100644
index 00000000000..0aa048d2735
--- /dev/null
+++ b/src/docs/future_not_send.txt
@@ -0,0 +1,29 @@
+### What it does
+This lint requires Future implementations returned from
+functions and methods to implement the `Send` marker trait. It is mostly
+used by library authors (public and internal) that target an audience where
+multithreaded executors are likely to be used for running these Futures.
+
+### Why is this bad?
+A Future implementation captures some state that it
+needs to eventually produce its final value. When targeting a multithreaded
+executor (which is the norm on non-embedded devices) this means that this
+state may need to be transported to other threads, in other words the
+whole Future needs to implement the `Send` marker trait. If it does not,
+then the resulting Future cannot be submitted to a thread pool in the
+end user’s code.
+
+Especially for generic functions it can be confusing to leave the
+discovery of this problem to the end user: the reported error location
+will be far from its cause and can in many cases not even be fixed without
+modifying the library where the offending Future implementation is
+produced.
+
+### Example
+```
+async fn not_send(bytes: std::rc::Rc<[u8]>) {}
+```
+Use instead:
+```
+async fn is_send(bytes: std::sync::Arc<[u8]>) {}
+```
\ No newline at end of file
diff --git a/src/docs/get_first.txt b/src/docs/get_first.txt
new file mode 100644
index 00000000000..c905a737ddf
--- /dev/null
+++ b/src/docs/get_first.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for using `x.get(0)` instead of
+`x.first()`.
+
+### Why is this bad?
+Using `x.first()` is easier to read and has the same
+result.
+
+### Example
+```
+let x = vec![2, 3, 5];
+let first_element = x.get(0);
+```
+
+Use instead:
+```
+let x = vec![2, 3, 5];
+let first_element = x.first();
+```
\ No newline at end of file
diff --git a/src/docs/get_last_with_len.txt b/src/docs/get_last_with_len.txt
new file mode 100644
index 00000000000..31c7f269586
--- /dev/null
+++ b/src/docs/get_last_with_len.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for using `x.get(x.len() - 1)` instead of
+`x.last()`.
+
+### Why is this bad?
+Using `x.last()` is easier to read and has the same
+result.
+
+Note that using `x[x.len() - 1]` is semantically different from
+`x.last()`.  Indexing into the array will panic on out-of-bounds
+accesses, while `x.get()` and `x.last()` will return `None`.
+
+There is another lint (get_unwrap) that covers the case of using
+`x.get(index).unwrap()` instead of `x[index]`.
+
+### Example
+```
+let x = vec![2, 3, 5];
+let last_element = x.get(x.len() - 1);
+```
+
+Use instead:
+```
+let x = vec![2, 3, 5];
+let last_element = x.last();
+```
\ No newline at end of file
diff --git a/src/docs/get_unwrap.txt b/src/docs/get_unwrap.txt
new file mode 100644
index 00000000000..8defc222441
--- /dev/null
+++ b/src/docs/get_unwrap.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for use of `.get().unwrap()` (or
+`.get_mut().unwrap`) on a standard library type which implements `Index`
+
+### Why is this bad?
+Using the Index trait (`[]`) is more clear and more
+concise.
+
+### Known problems
+Not a replacement for error handling: Using either
+`.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic`
+if the value being accessed is `None`. If the use of `.get().unwrap()` is a
+temporary placeholder for dealing with the `Option` type, then this does
+not mitigate the need for error handling. If there is a chance that `.get()`
+will be `None` in your program, then it is advisable that the `None` case
+is handled in a future refactor instead of using `.unwrap()` or the Index
+trait.
+
+### Example
+```
+let mut some_vec = vec![0, 1, 2, 3];
+let last = some_vec.get(3).unwrap();
+*some_vec.get_mut(0).unwrap() = 1;
+```
+The correct use would be:
+```
+let mut some_vec = vec![0, 1, 2, 3];
+let last = some_vec[3];
+some_vec[0] = 1;
+```
\ No newline at end of file
diff --git a/src/docs/identity_op.txt b/src/docs/identity_op.txt
new file mode 100644
index 00000000000..a8e40bb43e9
--- /dev/null
+++ b/src/docs/identity_op.txt
@@ -0,0 +1,11 @@
+### What it does
+Checks for identity operations, e.g., `x + 0`.
+
+### Why is this bad?
+This code can be removed without changing the
+meaning. So it just obscures what's going on. Delete it mercilessly.
+
+### Example
+```
+x / 1 + 0 * 1 - 0 | 0;
+```
\ No newline at end of file
diff --git a/src/docs/if_let_mutex.txt b/src/docs/if_let_mutex.txt
new file mode 100644
index 00000000000..4d873ade9ac
--- /dev/null
+++ b/src/docs/if_let_mutex.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for `Mutex::lock` calls in `if let` expression
+with lock calls in any of the else blocks.
+
+### Why is this bad?
+The Mutex lock remains held for the whole
+`if let ... else` block and deadlocks.
+
+### Example
+```
+if let Ok(thing) = mutex.lock() {
+    do_thing();
+} else {
+    mutex.lock();
+}
+```
+Should be written
+```
+let locked = mutex.lock();
+if let Ok(thing) = locked {
+    do_thing(thing);
+} else {
+    use_locked(locked);
+}
+```
\ No newline at end of file
diff --git a/src/docs/if_not_else.txt b/src/docs/if_not_else.txt
new file mode 100644
index 00000000000..0e5ac4ce6bb
--- /dev/null
+++ b/src/docs/if_not_else.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for usage of `!` or `!=` in an if condition with an
+else branch.
+
+### Why is this bad?
+Negations reduce the readability of statements.
+
+### Example
+```
+if !v.is_empty() {
+    a()
+} else {
+    b()
+}
+```
+
+Could be written:
+
+```
+if v.is_empty() {
+    b()
+} else {
+    a()
+}
+```
\ No newline at end of file
diff --git a/src/docs/if_same_then_else.txt b/src/docs/if_same_then_else.txt
new file mode 100644
index 00000000000..75127016bb8
--- /dev/null
+++ b/src/docs/if_same_then_else.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for `if/else` with the same body as the *then* part
+and the *else* part.
+
+### Why is this bad?
+This is probably a copy & paste error.
+
+### Example
+```
+let foo = if … {
+    42
+} else {
+    42
+};
+```
\ No newline at end of file
diff --git a/src/docs/if_then_some_else_none.txt b/src/docs/if_then_some_else_none.txt
new file mode 100644
index 00000000000..13744f920e3
--- /dev/null
+++ b/src/docs/if_then_some_else_none.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for if-else that could be written using either `bool::then` or `bool::then_some`.
+
+### Why is this bad?
+Looks a little redundant. Using `bool::then` is more concise and incurs no loss of clarity.
+For simple calculations and known values, use `bool::then_some`, which is eagerly evaluated
+in comparison to `bool::then`.
+
+### Example
+```
+let a = if v.is_empty() {
+    println!("true!");
+    Some(42)
+} else {
+    None
+};
+```
+
+Could be written:
+
+```
+let a = v.is_empty().then(|| {
+    println!("true!");
+    42
+});
+```
\ No newline at end of file
diff --git a/src/docs/ifs_same_cond.txt b/src/docs/ifs_same_cond.txt
new file mode 100644
index 00000000000..024ba5df93a
--- /dev/null
+++ b/src/docs/ifs_same_cond.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for consecutive `if`s with the same condition.
+
+### Why is this bad?
+This is probably a copy & paste error.
+
+### Example
+```
+if a == b {
+    …
+} else if a == b {
+    …
+}
+```
+
+Note that this lint ignores all conditions with a function call as it could
+have side effects:
+
+```
+if foo() {
+    …
+} else if foo() { // not linted
+    …
+}
+```
\ No newline at end of file
diff --git a/src/docs/implicit_clone.txt b/src/docs/implicit_clone.txt
new file mode 100644
index 00000000000..f5aa112c52c
--- /dev/null
+++ b/src/docs/implicit_clone.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer.
+
+### Why is this bad?
+These methods do the same thing as `_.clone()` but may be confusing as
+to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned.
+
+### Example
+```
+let a = vec![1, 2, 3];
+let b = a.to_vec();
+let c = a.to_owned();
+```
+Use instead:
+```
+let a = vec![1, 2, 3];
+let b = a.clone();
+let c = a.clone();
+```
\ No newline at end of file
diff --git a/src/docs/implicit_hasher.txt b/src/docs/implicit_hasher.txt
new file mode 100644
index 00000000000..0c1f76620f5
--- /dev/null
+++ b/src/docs/implicit_hasher.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for public `impl` or `fn` missing generalization
+over different hashers and implicitly defaulting to the default hashing
+algorithm (`SipHash`).
+
+### Why is this bad?
+`HashMap` or `HashSet` with custom hashers cannot be
+used with them.
+
+### Known problems
+Suggestions for replacing constructors can contain
+false-positives. Also applying suggestions can require modification of other
+pieces of code, possibly including external crates.
+
+### Example
+```
+impl<K: Hash + Eq, V> Serialize for HashMap<K, V> { }
+
+pub fn foo(map: &mut HashMap<i32, i32>) { }
+```
+could be rewritten as
+```
+impl<K: Hash + Eq, V, S: BuildHasher> Serialize for HashMap<K, V, S> { }
+
+pub fn foo<S: BuildHasher>(map: &mut HashMap<i32, i32, S>) { }
+```
\ No newline at end of file
diff --git a/src/docs/implicit_return.txt b/src/docs/implicit_return.txt
new file mode 100644
index 00000000000..ee65a636b38
--- /dev/null
+++ b/src/docs/implicit_return.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for missing return statements at the end of a block.
+
+### Why is this bad?
+Actually omitting the return keyword is idiomatic Rust code. Programmers
+coming from other languages might prefer the expressiveness of `return`. It's possible to miss
+the last returning statement because the only difference is a missing `;`. Especially in bigger
+code with multiple return paths having a `return` keyword makes it easier to find the
+corresponding statements.
+
+### Example
+```
+fn foo(x: usize) -> usize {
+    x
+}
+```
+add return
+```
+fn foo(x: usize) -> usize {
+    return x;
+}
+```
\ No newline at end of file
diff --git a/src/docs/implicit_saturating_sub.txt b/src/docs/implicit_saturating_sub.txt
new file mode 100644
index 00000000000..03b47905a21
--- /dev/null
+++ b/src/docs/implicit_saturating_sub.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for implicit saturating subtraction.
+
+### Why is this bad?
+Simplicity and readability. Instead we can easily use an builtin function.
+
+### Example
+```
+let mut i: u32 = end - start;
+
+if i != 0 {
+    i -= 1;
+}
+```
+
+Use instead:
+```
+let mut i: u32 = end - start;
+
+i = i.saturating_sub(1);
+```
\ No newline at end of file
diff --git a/src/docs/imprecise_flops.txt b/src/docs/imprecise_flops.txt
new file mode 100644
index 00000000000..e84d81cea98
--- /dev/null
+++ b/src/docs/imprecise_flops.txt
@@ -0,0 +1,23 @@
+### What it does
+Looks for floating-point expressions that
+can be expressed using built-in methods to improve accuracy
+at the cost of performance.
+
+### Why is this bad?
+Negatively impacts accuracy.
+
+### Example
+```
+let a = 3f32;
+let _ = a.powf(1.0 / 3.0);
+let _ = (1.0 + a).ln();
+let _ = a.exp() - 1.0;
+```
+
+Use instead:
+```
+let a = 3f32;
+let _ = a.cbrt();
+let _ = a.ln_1p();
+let _ = a.exp_m1();
+```
\ No newline at end of file
diff --git a/src/docs/inconsistent_digit_grouping.txt b/src/docs/inconsistent_digit_grouping.txt
new file mode 100644
index 00000000000..aa0b072de1c
--- /dev/null
+++ b/src/docs/inconsistent_digit_grouping.txt
@@ -0,0 +1,17 @@
+### What it does
+Warns if an integral or floating-point constant is
+grouped inconsistently with underscores.
+
+### Why is this bad?
+Readers may incorrectly interpret inconsistently
+grouped digits.
+
+### Example
+```
+618_64_9189_73_511
+```
+
+Use instead:
+```
+61_864_918_973_511
+```
\ No newline at end of file
diff --git a/src/docs/inconsistent_struct_constructor.txt b/src/docs/inconsistent_struct_constructor.txt
new file mode 100644
index 00000000000..eb682109a54
--- /dev/null
+++ b/src/docs/inconsistent_struct_constructor.txt
@@ -0,0 +1,40 @@
+### What it does
+Checks for struct constructors where all fields are shorthand and
+the order of the field init shorthand in the constructor is inconsistent
+with the order in the struct definition.
+
+### Why is this bad?
+Since the order of fields in a constructor doesn't affect the
+resulted instance as the below example indicates,
+
+```
+#[derive(Debug, PartialEq, Eq)]
+struct Foo {
+    x: i32,
+    y: i32,
+}
+let x = 1;
+let y = 2;
+
+// This assertion never fails:
+assert_eq!(Foo { x, y }, Foo { y, x });
+```
+
+inconsistent order can be confusing and decreases readability and consistency.
+
+### Example
+```
+struct Foo {
+    x: i32,
+    y: i32,
+}
+let x = 1;
+let y = 2;
+
+Foo { y, x };
+```
+
+Use instead:
+```
+Foo { x, y };
+```
\ No newline at end of file
diff --git a/src/docs/index_refutable_slice.txt b/src/docs/index_refutable_slice.txt
new file mode 100644
index 00000000000..8a7d52761af
--- /dev/null
+++ b/src/docs/index_refutable_slice.txt
@@ -0,0 +1,29 @@
+### What it does
+The lint checks for slice bindings in patterns that are only used to
+access individual slice values.
+
+### Why is this bad?
+Accessing slice values using indices can lead to panics. Using refutable
+patterns can avoid these. Binding to individual values also improves the
+readability as they can be named.
+
+### Limitations
+This lint currently only checks for immutable access inside `if let`
+patterns.
+
+### Example
+```
+let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+
+if let Some(slice) = slice {
+    println!("{}", slice[0]);
+}
+```
+Use instead:
+```
+let slice: Option<&[u32]> = Some(&[1, 2, 3]);
+
+if let Some(&[first, ..]) = slice {
+    println!("{}", first);
+}
+```
\ No newline at end of file
diff --git a/src/docs/indexing_slicing.txt b/src/docs/indexing_slicing.txt
new file mode 100644
index 00000000000..76ca6ed318b
--- /dev/null
+++ b/src/docs/indexing_slicing.txt
@@ -0,0 +1,33 @@
+### What it does
+Checks for usage of indexing or slicing. Arrays are special cases, this lint
+does report on arrays if we can tell that slicing operations are in bounds and does not
+lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint.
+
+### Why is this bad?
+Indexing and slicing can panic at runtime and there are
+safe alternatives.
+
+### Example
+```
+// Vector
+let x = vec![0; 5];
+
+x[2];
+&x[2..100];
+
+// Array
+let y = [0, 1, 2, 3];
+
+&y[10..100];
+&y[10..];
+```
+
+Use instead:
+```
+
+x.get(2);
+x.get(2..100);
+
+y.get(10);
+y.get(10..100);
+```
\ No newline at end of file
diff --git a/src/docs/ineffective_bit_mask.txt b/src/docs/ineffective_bit_mask.txt
new file mode 100644
index 00000000000..f6e7ef55621
--- /dev/null
+++ b/src/docs/ineffective_bit_mask.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for bit masks in comparisons which can be removed
+without changing the outcome. The basic structure can be seen in the
+following table:
+
+|Comparison| Bit Op   |Example     |equals |
+|----------|----------|------------|-------|
+|`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`|
+|`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`|
+
+### Why is this bad?
+Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
+but still a bit misleading, because the bit mask is ineffective.
+
+### Known problems
+False negatives: This lint will only match instances
+where we have figured out the math (which is for a power-of-two compared
+value). This means things like `x | 1 >= 7` (which would be better written
+as `x >= 6`) will not be reported (but bit masks like this are fairly
+uncommon).
+
+### Example
+```
+if (x | 1 > 3) {  }
+```
\ No newline at end of file
diff --git a/src/docs/inefficient_to_string.txt b/src/docs/inefficient_to_string.txt
new file mode 100644
index 00000000000..f7061d1ce7b
--- /dev/null
+++ b/src/docs/inefficient_to_string.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for usage of `.to_string()` on an `&&T` where
+`T` implements `ToString` directly (like `&&str` or `&&String`).
+
+### Why is this bad?
+This bypasses the specialized implementation of
+`ToString` and instead goes through the more expensive string formatting
+facilities.
+
+### Example
+```
+// Generic implementation for `T: Display` is used (slow)
+["foo", "bar"].iter().map(|s| s.to_string());
+
+// OK, the specialized impl is used
+["foo", "bar"].iter().map(|&s| s.to_string());
+```
\ No newline at end of file
diff --git a/src/docs/infallible_destructuring_match.txt b/src/docs/infallible_destructuring_match.txt
new file mode 100644
index 00000000000..4b5d3c4ba6c
--- /dev/null
+++ b/src/docs/infallible_destructuring_match.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for matches being used to destructure a single-variant enum
+or tuple struct where a `let` will suffice.
+
+### Why is this bad?
+Just readability – `let` doesn't nest, whereas a `match` does.
+
+### Example
+```
+enum Wrapper {
+    Data(i32),
+}
+
+let wrapper = Wrapper::Data(42);
+
+let data = match wrapper {
+    Wrapper::Data(i) => i,
+};
+```
+
+The correct use would be:
+```
+enum Wrapper {
+    Data(i32),
+}
+
+let wrapper = Wrapper::Data(42);
+let Wrapper::Data(data) = wrapper;
+```
\ No newline at end of file
diff --git a/src/docs/infinite_iter.txt b/src/docs/infinite_iter.txt
new file mode 100644
index 00000000000..8a22fabc549
--- /dev/null
+++ b/src/docs/infinite_iter.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for iteration that is guaranteed to be infinite.
+
+### Why is this bad?
+While there may be places where this is acceptable
+(e.g., in event streams), in most cases this is simply an error.
+
+### Example
+```
+use std::iter;
+
+iter::repeat(1_u8).collect::<Vec<_>>();
+```
\ No newline at end of file
diff --git a/src/docs/inherent_to_string.txt b/src/docs/inherent_to_string.txt
new file mode 100644
index 00000000000..b18e600e9e6
--- /dev/null
+++ b/src/docs/inherent_to_string.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`.
+
+### Why is this bad?
+This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred.
+
+### Example
+```
+pub struct A;
+
+impl A {
+    pub fn to_string(&self) -> String {
+        "I am A".to_string()
+    }
+}
+```
+
+Use instead:
+```
+use std::fmt;
+
+pub struct A;
+
+impl fmt::Display for A {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "I am A")
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/inherent_to_string_shadow_display.txt b/src/docs/inherent_to_string_shadow_display.txt
new file mode 100644
index 00000000000..a4bd0b622c4
--- /dev/null
+++ b/src/docs/inherent_to_string_shadow_display.txt
@@ -0,0 +1,37 @@
+### What it does
+Checks for the definition of inherent methods with a signature of `to_string(&self) -> String` and if the type implementing this method also implements the `Display` trait.
+
+### Why is this bad?
+This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`.
+
+### Example
+```
+use std::fmt;
+
+pub struct A;
+
+impl A {
+    pub fn to_string(&self) -> String {
+        "I am A".to_string()
+    }
+}
+
+impl fmt::Display for A {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "I am A, too")
+    }
+}
+```
+
+Use instead:
+```
+use std::fmt;
+
+pub struct A;
+
+impl fmt::Display for A {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "I am A")
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/init_numbered_fields.txt b/src/docs/init_numbered_fields.txt
new file mode 100644
index 00000000000..ba40af6a5fa
--- /dev/null
+++ b/src/docs/init_numbered_fields.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for tuple structs initialized with field syntax.
+It will however not lint if a base initializer is present.
+The lint will also ignore code in macros.
+
+### Why is this bad?
+This may be confusing to the uninitiated and adds no
+benefit as opposed to tuple initializers
+
+### Example
+```
+struct TupleStruct(u8, u16);
+
+let _ = TupleStruct {
+    0: 1,
+    1: 23,
+};
+
+// should be written as
+let base = TupleStruct(1, 23);
+
+// This is OK however
+let _ = TupleStruct { 0: 42, ..base };
+```
\ No newline at end of file
diff --git a/src/docs/inline_always.txt b/src/docs/inline_always.txt
new file mode 100644
index 00000000000..7721da4c4cc
--- /dev/null
+++ b/src/docs/inline_always.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for items annotated with `#[inline(always)]`,
+unless the annotated function is empty or simply panics.
+
+### Why is this bad?
+While there are valid uses of this annotation (and once
+you know when to use it, by all means `allow` this lint), it's a common
+newbie-mistake to pepper one's code with it.
+
+As a rule of thumb, before slapping `#[inline(always)]` on a function,
+measure if that additional function call really affects your runtime profile
+sufficiently to make up for the increase in compile time.
+
+### Known problems
+False positives, big time. This lint is meant to be
+deactivated by everyone doing serious performance work. This means having
+done the measurement.
+
+### Example
+```
+#[inline(always)]
+fn not_quite_hot_code(..) { ... }
+```
\ No newline at end of file
diff --git a/src/docs/inline_asm_x86_att_syntax.txt b/src/docs/inline_asm_x86_att_syntax.txt
new file mode 100644
index 00000000000..8eb49d122d8
--- /dev/null
+++ b/src/docs/inline_asm_x86_att_syntax.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of AT&T x86 assembly syntax.
+
+### Why is this bad?
+The lint has been enabled to indicate a preference
+for Intel x86 assembly syntax.
+
+### Example
+
+```
+asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
+```
+Use instead:
+```
+asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
+```
\ No newline at end of file
diff --git a/src/docs/inline_asm_x86_intel_syntax.txt b/src/docs/inline_asm_x86_intel_syntax.txt
new file mode 100644
index 00000000000..5aa22c8ed23
--- /dev/null
+++ b/src/docs/inline_asm_x86_intel_syntax.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of Intel x86 assembly syntax.
+
+### Why is this bad?
+The lint has been enabled to indicate a preference
+for AT&T x86 assembly syntax.
+
+### Example
+
+```
+asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
+```
+Use instead:
+```
+asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
+```
\ No newline at end of file
diff --git a/src/docs/inline_fn_without_body.txt b/src/docs/inline_fn_without_body.txt
new file mode 100644
index 00000000000..127c161aaa2
--- /dev/null
+++ b/src/docs/inline_fn_without_body.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for `#[inline]` on trait methods without bodies
+
+### Why is this bad?
+Only implementations of trait methods may be inlined.
+The inline attribute is ignored for trait methods without bodies.
+
+### Example
+```
+trait Animal {
+    #[inline]
+    fn name(&self) -> &'static str;
+}
+```
\ No newline at end of file
diff --git a/src/docs/inspect_for_each.txt b/src/docs/inspect_for_each.txt
new file mode 100644
index 00000000000..01a46d6c451
--- /dev/null
+++ b/src/docs/inspect_for_each.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for usage of `inspect().for_each()`.
+
+### Why is this bad?
+It is the same as performing the computation
+inside `inspect` at the beginning of the closure in `for_each`.
+
+### Example
+```
+[1,2,3,4,5].iter()
+.inspect(|&x| println!("inspect the number: {}", x))
+.for_each(|&x| {
+    assert!(x >= 0);
+});
+```
+Can be written as
+```
+[1,2,3,4,5].iter()
+.for_each(|&x| {
+    println!("inspect the number: {}", x);
+    assert!(x >= 0);
+});
+```
\ No newline at end of file
diff --git a/src/docs/int_plus_one.txt b/src/docs/int_plus_one.txt
new file mode 100644
index 00000000000..1b68f3eeb64
--- /dev/null
+++ b/src/docs/int_plus_one.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
+
+### Why is this bad?
+Readability -- better to use `> y` instead of `>= y + 1`.
+
+### Example
+```
+if x >= y + 1 {}
+```
+
+Use instead:
+```
+if x > y {}
+```
\ No newline at end of file
diff --git a/src/docs/integer_arithmetic.txt b/src/docs/integer_arithmetic.txt
new file mode 100644
index 00000000000..ea57a2ef97b
--- /dev/null
+++ b/src/docs/integer_arithmetic.txt
@@ -0,0 +1,18 @@
+### 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
+```
+a + 1;
+```
\ No newline at end of file
diff --git a/src/docs/integer_division.txt b/src/docs/integer_division.txt
new file mode 100644
index 00000000000..f6d3349810e
--- /dev/null
+++ b/src/docs/integer_division.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for division of integers
+
+### Why is this bad?
+When outside of some very specific algorithms,
+integer division is very often a mistake because it discards the
+remainder.
+
+### Example
+```
+let x = 3 / 2;
+println!("{}", x);
+```
+
+Use instead:
+```
+let x = 3f32 / 2f32;
+println!("{}", x);
+```
\ No newline at end of file
diff --git a/src/docs/into_iter_on_ref.txt b/src/docs/into_iter_on_ref.txt
new file mode 100644
index 00000000000..acb6bd474eb
--- /dev/null
+++ b/src/docs/into_iter_on_ref.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for `into_iter` calls on references which should be replaced by `iter`
+or `iter_mut`.
+
+### Why is this bad?
+Readability. Calling `into_iter` on a reference will not move out its
+content into the resulting iterator, which is confusing. It is better just call `iter` or
+`iter_mut` directly.
+
+### Example
+```
+(&vec).into_iter();
+```
+
+Use instead:
+```
+(&vec).iter();
+```
\ No newline at end of file
diff --git a/src/docs/invalid_null_ptr_usage.txt b/src/docs/invalid_null_ptr_usage.txt
new file mode 100644
index 00000000000..6fb3fa3f83d
--- /dev/null
+++ b/src/docs/invalid_null_ptr_usage.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint checks for invalid usages of `ptr::null`.
+
+### Why is this bad?
+This causes undefined behavior.
+
+### Example
+```
+// Undefined behavior
+unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
+```
+
+Use instead:
+```
+unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
+```
\ No newline at end of file
diff --git a/src/docs/invalid_regex.txt b/src/docs/invalid_regex.txt
new file mode 100644
index 00000000000..6c9969b6e1a
--- /dev/null
+++ b/src/docs/invalid_regex.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks [regex](https://crates.io/crates/regex) creation
+(with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct
+regex syntax.
+
+### Why is this bad?
+This will lead to a runtime panic.
+
+### Example
+```
+Regex::new("(")
+```
\ No newline at end of file
diff --git a/src/docs/invalid_upcast_comparisons.txt b/src/docs/invalid_upcast_comparisons.txt
new file mode 100644
index 00000000000..77cb0330803
--- /dev/null
+++ b/src/docs/invalid_upcast_comparisons.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for comparisons where the relation is always either
+true or false, but where one side has been upcast so that the comparison is
+necessary. Only integer types are checked.
+
+### Why is this bad?
+An expression like `let x : u8 = ...; (x as u32) > 300`
+will mistakenly imply that it is possible for `x` to be outside the range of
+`u8`.
+
+### Known problems
+https://github.com/rust-lang/rust-clippy/issues/886
+
+### Example
+```
+let x: u8 = 1;
+(x as u32) > 300;
+```
\ No newline at end of file
diff --git a/src/docs/invalid_utf8_in_unchecked.txt b/src/docs/invalid_utf8_in_unchecked.txt
new file mode 100644
index 00000000000..afb5acbe9c5
--- /dev/null
+++ b/src/docs/invalid_utf8_in_unchecked.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for `std::str::from_utf8_unchecked` with an invalid UTF-8 literal
+
+### Why is this bad?
+Creating such a `str` would result in undefined behavior
+
+### Example
+```
+unsafe {
+    std::str::from_utf8_unchecked(b"cl\x82ippy");
+}
+```
\ No newline at end of file
diff --git a/src/docs/invisible_characters.txt b/src/docs/invisible_characters.txt
new file mode 100644
index 00000000000..3dda380911f
--- /dev/null
+++ b/src/docs/invisible_characters.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for invisible Unicode characters in the code.
+
+### Why is this bad?
+Having an invisible character in the code makes for all
+sorts of April fools, but otherwise is very much frowned upon.
+
+### Example
+You don't see it, but there may be a zero-width space or soft hyphen
+some­where in this text.
\ No newline at end of file
diff --git a/src/docs/is_digit_ascii_radix.txt b/src/docs/is_digit_ascii_radix.txt
new file mode 100644
index 00000000000..9f11cf43054
--- /dev/null
+++ b/src/docs/is_digit_ascii_radix.txt
@@ -0,0 +1,20 @@
+### What it does
+Finds usages of [`char::is_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit) that
+can be replaced with [`is_ascii_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_digit) or
+[`is_ascii_hexdigit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_hexdigit).
+
+### Why is this bad?
+`is_digit(..)` is slower and requires specifying the radix.
+
+### Example
+```
+let c: char = '6';
+c.is_digit(10);
+c.is_digit(16);
+```
+Use instead:
+```
+let c: char = '6';
+c.is_ascii_digit();
+c.is_ascii_hexdigit();
+```
\ No newline at end of file
diff --git a/src/docs/items_after_statements.txt b/src/docs/items_after_statements.txt
new file mode 100644
index 00000000000..6fdfff50d20
--- /dev/null
+++ b/src/docs/items_after_statements.txt
@@ -0,0 +1,37 @@
+### What it does
+Checks for items declared after some statement in a block.
+
+### Why is this bad?
+Items live for the entire scope they are declared
+in. But statements are processed in order. This might cause confusion as
+it's hard to figure out which item is meant in a statement.
+
+### Example
+```
+fn foo() {
+    println!("cake");
+}
+
+fn main() {
+    foo(); // prints "foo"
+    fn foo() {
+        println!("foo");
+    }
+    foo(); // prints "foo"
+}
+```
+
+Use instead:
+```
+fn foo() {
+    println!("cake");
+}
+
+fn main() {
+    fn foo() {
+        println!("foo");
+    }
+    foo(); // prints "foo"
+    foo(); // prints "foo"
+}
+```
\ No newline at end of file
diff --git a/src/docs/iter_cloned_collect.txt b/src/docs/iter_cloned_collect.txt
new file mode 100644
index 00000000000..90dc9ebb40f
--- /dev/null
+++ b/src/docs/iter_cloned_collect.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for the use of `.cloned().collect()` on slice to
+create a `Vec`.
+
+### Why is this bad?
+`.to_vec()` is clearer
+
+### Example
+```
+let s = [1, 2, 3, 4, 5];
+let s2: Vec<isize> = s[..].iter().cloned().collect();
+```
+The better use would be:
+```
+let s = [1, 2, 3, 4, 5];
+let s2: Vec<isize> = s.to_vec();
+```
\ No newline at end of file
diff --git a/src/docs/iter_count.txt b/src/docs/iter_count.txt
new file mode 100644
index 00000000000..f3db4a26c29
--- /dev/null
+++ b/src/docs/iter_count.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for the use of `.iter().count()`.
+
+### Why is this bad?
+`.len()` is more efficient and more
+readable.
+
+### Example
+```
+let some_vec = vec![0, 1, 2, 3];
+
+some_vec.iter().count();
+&some_vec[..].iter().count();
+```
+
+Use instead:
+```
+let some_vec = vec![0, 1, 2, 3];
+
+some_vec.len();
+&some_vec[..].len();
+```
\ No newline at end of file
diff --git a/src/docs/iter_next_loop.txt b/src/docs/iter_next_loop.txt
new file mode 100644
index 00000000000..b33eb39d6e1
--- /dev/null
+++ b/src/docs/iter_next_loop.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for loops on `x.next()`.
+
+### Why is this bad?
+`next()` returns either `Some(value)` if there was a
+value, or `None` otherwise. The insidious thing is that `Option<_>`
+implements `IntoIterator`, so that possibly one value will be iterated,
+leading to some hard to find bugs. No one will want to write such code
+[except to win an Underhanded Rust
+Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr).
+
+### Example
+```
+for x in y.next() {
+    ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/iter_next_slice.txt b/src/docs/iter_next_slice.txt
new file mode 100644
index 00000000000..1cea25eaf30
--- /dev/null
+++ b/src/docs/iter_next_slice.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `iter().next()` on a Slice or an Array
+
+### Why is this bad?
+These can be shortened into `.get()`
+
+### Example
+```
+a[2..].iter().next();
+b.iter().next();
+```
+should be written as:
+```
+a.get(2);
+b.get(0);
+```
\ No newline at end of file
diff --git a/src/docs/iter_not_returning_iterator.txt b/src/docs/iter_not_returning_iterator.txt
new file mode 100644
index 00000000000..0ca862910a6
--- /dev/null
+++ b/src/docs/iter_not_returning_iterator.txt
@@ -0,0 +1,26 @@
+### What it does
+Detects methods named `iter` or `iter_mut` that do not have a return type that implements `Iterator`.
+
+### Why is this bad?
+Methods named `iter` or `iter_mut` conventionally return an `Iterator`.
+
+### Example
+```
+// `String` does not implement `Iterator`
+struct Data {}
+impl Data {
+    fn iter(&self) -> String {
+        todo!()
+    }
+}
+```
+Use instead:
+```
+use std::str::Chars;
+struct Data {}
+impl Data {
+   fn iter(&self) -> Chars<'static> {
+       todo!()
+   }
+}
+```
\ No newline at end of file
diff --git a/src/docs/iter_nth.txt b/src/docs/iter_nth.txt
new file mode 100644
index 00000000000..3d67d583ffd
--- /dev/null
+++ b/src/docs/iter_nth.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for use of `.iter().nth()` (and the related
+`.iter_mut().nth()`) on standard library types with *O*(1) element access.
+
+### Why is this bad?
+`.get()` and `.get_mut()` are more efficient and more
+readable.
+
+### Example
+```
+let some_vec = vec![0, 1, 2, 3];
+let bad_vec = some_vec.iter().nth(3);
+let bad_slice = &some_vec[..].iter().nth(3);
+```
+The correct use would be:
+```
+let some_vec = vec![0, 1, 2, 3];
+let bad_vec = some_vec.get(3);
+let bad_slice = &some_vec[..].get(3);
+```
\ No newline at end of file
diff --git a/src/docs/iter_nth_zero.txt b/src/docs/iter_nth_zero.txt
new file mode 100644
index 00000000000..8efe47a16a1
--- /dev/null
+++ b/src/docs/iter_nth_zero.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for the use of `iter.nth(0)`.
+
+### Why is this bad?
+`iter.next()` is equivalent to
+`iter.nth(0)`, as they both consume the next element,
+ but is more readable.
+
+### Example
+```
+let x = s.iter().nth(0);
+```
+
+Use instead:
+```
+let x = s.iter().next();
+```
\ No newline at end of file
diff --git a/src/docs/iter_on_empty_collections.txt b/src/docs/iter_on_empty_collections.txt
new file mode 100644
index 00000000000..87c4ec12afa
--- /dev/null
+++ b/src/docs/iter_on_empty_collections.txt
@@ -0,0 +1,25 @@
+### What it does
+
+Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections
+
+### Why is this bad?
+
+It is simpler to use the empty function from the standard library:
+
+### Example
+
+```
+use std::{slice, option};
+let a: slice::Iter<i32> = [].iter();
+let f: option::IntoIter<i32> = None.into_iter();
+```
+Use instead:
+```
+use std::iter;
+let a: iter::Empty<i32> = iter::empty();
+let b: iter::Empty<i32> = iter::empty();
+```
+
+### Known problems
+
+The type of the resulting iterator might become incompatible with its usage
\ No newline at end of file
diff --git a/src/docs/iter_on_single_items.txt b/src/docs/iter_on_single_items.txt
new file mode 100644
index 00000000000..d0388f25d04
--- /dev/null
+++ b/src/docs/iter_on_single_items.txt
@@ -0,0 +1,24 @@
+### What it does
+
+Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item
+
+### Why is this bad?
+
+It is simpler to use the once function from the standard library:
+
+### Example
+
+```
+let a = [123].iter();
+let b = Some(123).into_iter();
+```
+Use instead:
+```
+use std::iter;
+let a = iter::once(&123);
+let b = iter::once(123);
+```
+
+### Known problems
+
+The type of the resulting iterator might become incompatible with its usage
\ No newline at end of file
diff --git a/src/docs/iter_overeager_cloned.txt b/src/docs/iter_overeager_cloned.txt
new file mode 100644
index 00000000000..2f902a0c2db
--- /dev/null
+++ b/src/docs/iter_overeager_cloned.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `_.cloned().<func>()` where call to `.cloned()` can be postponed.
+
+### Why is this bad?
+It's often inefficient to clone all elements of an iterator, when eventually, only some
+of them will be consumed.
+
+### Known Problems
+This `lint` removes the side of effect of cloning items in the iterator.
+A code that relies on that side-effect could fail.
+
+### Examples
+```
+vec.iter().cloned().take(10);
+vec.iter().cloned().last();
+```
+
+Use instead:
+```
+vec.iter().take(10).cloned();
+vec.iter().last().cloned();
+```
\ No newline at end of file
diff --git a/src/docs/iter_skip_next.txt b/src/docs/iter_skip_next.txt
new file mode 100644
index 00000000000..da226b041cf
--- /dev/null
+++ b/src/docs/iter_skip_next.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for use of `.skip(x).next()` on iterators.
+
+### Why is this bad?
+`.nth(x)` is cleaner
+
+### Example
+```
+let some_vec = vec![0, 1, 2, 3];
+let bad_vec = some_vec.iter().skip(3).next();
+let bad_slice = &some_vec[..].iter().skip(3).next();
+```
+The correct use would be:
+```
+let some_vec = vec![0, 1, 2, 3];
+let bad_vec = some_vec.iter().nth(3);
+let bad_slice = &some_vec[..].iter().nth(3);
+```
\ No newline at end of file
diff --git a/src/docs/iter_with_drain.txt b/src/docs/iter_with_drain.txt
new file mode 100644
index 00000000000..2c52b99f7a5
--- /dev/null
+++ b/src/docs/iter_with_drain.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for use of `.drain(..)` on `Vec` and `VecDeque` for iteration.
+
+### Why is this bad?
+`.into_iter()` is simpler with better performance.
+
+### Example
+```
+let mut foo = vec![0, 1, 2, 3];
+let bar: HashSet<usize> = foo.drain(..).collect();
+```
+Use instead:
+```
+let foo = vec![0, 1, 2, 3];
+let bar: HashSet<usize> = foo.into_iter().collect();
+```
\ No newline at end of file
diff --git a/src/docs/iterator_step_by_zero.txt b/src/docs/iterator_step_by_zero.txt
new file mode 100644
index 00000000000..73ecc99acfc
--- /dev/null
+++ b/src/docs/iterator_step_by_zero.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for calling `.step_by(0)` on iterators which panics.
+
+### Why is this bad?
+This very much looks like an oversight. Use `panic!()` instead if you
+actually intend to panic.
+
+### Example
+```
+for x in (0..100).step_by(0) {
+    //..
+}
+```
\ No newline at end of file
diff --git a/src/docs/just_underscores_and_digits.txt b/src/docs/just_underscores_and_digits.txt
new file mode 100644
index 00000000000..a8790bcf25b
--- /dev/null
+++ b/src/docs/just_underscores_and_digits.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks if you have variables whose name consists of just
+underscores and digits.
+
+### Why is this bad?
+It's hard to memorize what a variable means without a
+descriptive name.
+
+### Example
+```
+let _1 = 1;
+let ___1 = 1;
+let __1___2 = 11;
+```
\ No newline at end of file
diff --git a/src/docs/large_const_arrays.txt b/src/docs/large_const_arrays.txt
new file mode 100644
index 00000000000..71f67854f2a
--- /dev/null
+++ b/src/docs/large_const_arrays.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for large `const` arrays that should
+be defined as `static` instead.
+
+### Why is this bad?
+Performance: const variables are inlined upon use.
+Static items result in only one instance and has a fixed location in memory.
+
+### Example
+```
+pub const a = [0u32; 1_000_000];
+```
+
+Use instead:
+```
+pub static a = [0u32; 1_000_000];
+```
\ No newline at end of file
diff --git a/src/docs/large_digit_groups.txt b/src/docs/large_digit_groups.txt
new file mode 100644
index 00000000000..f60b19345af
--- /dev/null
+++ b/src/docs/large_digit_groups.txt
@@ -0,0 +1,12 @@
+### What it does
+Warns if the digits of an integral or floating-point
+constant are grouped into groups that
+are too large.
+
+### Why is this bad?
+Negatively impacts readability.
+
+### Example
+```
+let x: u64 = 6186491_8973511;
+```
\ No newline at end of file
diff --git a/src/docs/large_enum_variant.txt b/src/docs/large_enum_variant.txt
new file mode 100644
index 00000000000..787e8e027e1
--- /dev/null
+++ b/src/docs/large_enum_variant.txt
@@ -0,0 +1,40 @@
+### What it does
+Checks for large size differences between variants on
+`enum`s.
+
+### Why is this bad?
+Enum size is bounded by the largest variant. Having a
+large variant can penalize the memory layout of that enum.
+
+### Known problems
+This lint obviously cannot take the distribution of
+variants in your running program into account. It is possible that the
+smaller variants make up less than 1% of all instances, in which case
+the overhead is negligible and the boxing is counter-productive. Always
+measure the change this lint suggests.
+
+For types that implement `Copy`, the suggestion to `Box` a variant's
+data would require removing the trait impl. The types can of course
+still be `Clone`, but that is worse ergonomically. Depending on the
+use case it may be possible to store the large data in an auxiliary
+structure (e.g. Arena or ECS).
+
+The lint will ignore generic types if the layout depends on the
+generics, even if the size difference will be large anyway.
+
+### Example
+```
+enum Test {
+    A(i32),
+    B([i32; 8000]),
+}
+```
+
+Use instead:
+```
+// Possibly better
+enum Test2 {
+    A(i32),
+    B(Box<[i32; 8000]>),
+}
+```
\ No newline at end of file
diff --git a/src/docs/large_include_file.txt b/src/docs/large_include_file.txt
new file mode 100644
index 00000000000..b2a54bd2eb5
--- /dev/null
+++ b/src/docs/large_include_file.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for the inclusion of large files via `include_bytes!()`
+and `include_str!()`
+
+### Why is this bad?
+Including large files can increase the size of the binary
+
+### Example
+```
+let included_str = include_str!("very_large_file.txt");
+let included_bytes = include_bytes!("very_large_file.txt");
+```
+
+Use instead:
+```
+use std::fs;
+
+// You can load the file at runtime
+let string = fs::read_to_string("very_large_file.txt")?;
+let bytes = fs::read("very_large_file.txt")?;
+```
\ No newline at end of file
diff --git a/src/docs/large_stack_arrays.txt b/src/docs/large_stack_arrays.txt
new file mode 100644
index 00000000000..4a6f34785b0
--- /dev/null
+++ b/src/docs/large_stack_arrays.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for local arrays that may be too large.
+
+### Why is this bad?
+Large local arrays may cause stack overflow.
+
+### Example
+```
+let a = [0u32; 1_000_000];
+```
\ No newline at end of file
diff --git a/src/docs/large_types_passed_by_value.txt b/src/docs/large_types_passed_by_value.txt
new file mode 100644
index 00000000000..bca07f3ac61
--- /dev/null
+++ b/src/docs/large_types_passed_by_value.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for functions taking arguments by value, where
+the argument type is `Copy` and large enough to be worth considering
+passing by reference. Does not trigger if the function is being exported,
+because that might induce API breakage, if the parameter is declared as mutable,
+or if the argument is a `self`.
+
+### Why is this bad?
+Arguments passed by value might result in an unnecessary
+shallow copy, taking up more space in the stack and requiring a call to
+`memcpy`, which can be expensive.
+
+### Example
+```
+#[derive(Clone, Copy)]
+struct TooLarge([u8; 2048]);
+
+fn foo(v: TooLarge) {}
+```
+
+Use instead:
+```
+fn foo(v: &TooLarge) {}
+```
\ No newline at end of file
diff --git a/src/docs/len_without_is_empty.txt b/src/docs/len_without_is_empty.txt
new file mode 100644
index 00000000000..47a2e857522
--- /dev/null
+++ b/src/docs/len_without_is_empty.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for items that implement `.len()` but not
+`.is_empty()`.
+
+### Why is this bad?
+It is good custom to have both methods, because for
+some data structures, asking about the length will be a costly operation,
+whereas `.is_empty()` can usually answer in constant time. Also it used to
+lead to false positives on the [`len_zero`](#len_zero) lint – currently that
+lint will ignore such entities.
+
+### Example
+```
+impl X {
+    pub fn len(&self) -> usize {
+        ..
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/len_zero.txt b/src/docs/len_zero.txt
new file mode 100644
index 00000000000..664124bd391
--- /dev/null
+++ b/src/docs/len_zero.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for getting the length of something via `.len()`
+just to compare to zero, and suggests using `.is_empty()` where applicable.
+
+### Why is this bad?
+Some structures can answer `.is_empty()` much faster
+than calculating their length. So it is good to get into the habit of using
+`.is_empty()`, and having it is cheap.
+Besides, it makes the intent clearer than a manual comparison in some contexts.
+
+### Example
+```
+if x.len() == 0 {
+    ..
+}
+if y.len() != 0 {
+    ..
+}
+```
+instead use
+```
+if x.is_empty() {
+    ..
+}
+if !y.is_empty() {
+    ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/let_and_return.txt b/src/docs/let_and_return.txt
new file mode 100644
index 00000000000..eba5a90ddd6
--- /dev/null
+++ b/src/docs/let_and_return.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for `let`-bindings, which are subsequently
+returned.
+
+### Why is this bad?
+It is just extraneous code. Remove it to make your code
+more rusty.
+
+### Example
+```
+fn foo() -> String {
+    let x = String::new();
+    x
+}
+```
+instead, use
+```
+fn foo() -> String {
+    String::new()
+}
+```
\ No newline at end of file
diff --git a/src/docs/let_underscore_drop.txt b/src/docs/let_underscore_drop.txt
new file mode 100644
index 00000000000..29ce9bf50ce
--- /dev/null
+++ b/src/docs/let_underscore_drop.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for `let _ = <expr>`
+where expr has a type that implements `Drop`
+
+### Why is this bad?
+This statement immediately drops the initializer
+expression instead of extending its lifetime to the end of the scope, which
+is often not intended. To extend the expression's lifetime to the end of the
+scope, use an underscore-prefixed name instead (i.e. _var). If you want to
+explicitly drop the expression, `std::mem::drop` conveys your intention
+better and is less error-prone.
+
+### Example
+```
+{
+    let _ = DroppableItem;
+    //                   ^ dropped here
+    /* more code */
+}
+```
+
+Use instead:
+```
+{
+    let _droppable = DroppableItem;
+    /* more code */
+    // dropped at end of scope
+}
+```
\ No newline at end of file
diff --git a/src/docs/let_underscore_lock.txt b/src/docs/let_underscore_lock.txt
new file mode 100644
index 00000000000..bd8217fb58b
--- /dev/null
+++ b/src/docs/let_underscore_lock.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for `let _ = sync_lock`.
+This supports `mutex` and `rwlock` in `std::sync` and `parking_lot`.
+
+### Why is this bad?
+This statement immediately drops the lock instead of
+extending its lifetime to the end of the scope, which is often not intended.
+To extend lock lifetime to the end of the scope, use an underscore-prefixed
+name instead (i.e. _lock). If you want to explicitly drop the lock,
+`std::mem::drop` conveys your intention better and is less error-prone.
+
+### Example
+```
+let _ = mutex.lock();
+```
+
+Use instead:
+```
+let _lock = mutex.lock();
+```
\ No newline at end of file
diff --git a/src/docs/let_underscore_must_use.txt b/src/docs/let_underscore_must_use.txt
new file mode 100644
index 00000000000..270b81d9a4c
--- /dev/null
+++ b/src/docs/let_underscore_must_use.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for `let _ = <expr>` where expr is `#[must_use]`
+
+### Why is this bad?
+It's better to explicitly handle the value of a `#[must_use]`
+expr
+
+### Example
+```
+fn f() -> Result<u32, u32> {
+    Ok(0)
+}
+
+let _ = f();
+// is_ok() is marked #[must_use]
+let _ = f().is_ok();
+```
\ No newline at end of file
diff --git a/src/docs/let_unit_value.txt b/src/docs/let_unit_value.txt
new file mode 100644
index 00000000000..bc16d5b3d81
--- /dev/null
+++ b/src/docs/let_unit_value.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for binding a unit value.
+
+### Why is this bad?
+A unit value cannot usefully be used anywhere. So
+binding one is kind of pointless.
+
+### Example
+```
+let x = {
+    1;
+};
+```
\ No newline at end of file
diff --git a/src/docs/linkedlist.txt b/src/docs/linkedlist.txt
new file mode 100644
index 00000000000..986ff1369e3
--- /dev/null
+++ b/src/docs/linkedlist.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for usage of any `LinkedList`, suggesting to use a
+`Vec` or a `VecDeque` (formerly called `RingBuf`).
+
+### Why is this bad?
+Gankro says:
+
+> The TL;DR of `LinkedList` is that it's built on a massive amount of
+pointers and indirection.
+> It wastes memory, it has terrible cache locality, and is all-around slow.
+`RingBuf`, while
+> "only" amortized for push/pop, should be faster in the general case for
+almost every possible
+> workload, and isn't even amortized at all if you can predict the capacity
+you need.
+>
+> `LinkedList`s are only really good if you're doing a lot of merging or
+splitting of lists.
+> This is because they can just mangle some pointers instead of actually
+copying the data. Even
+> if you're doing a lot of insertion in the middle of the list, `RingBuf`
+can still be better
+> because of how expensive it is to seek to the middle of a `LinkedList`.
+
+### Known problems
+False positives – the instances where using a
+`LinkedList` makes sense are few and far between, but they can still happen.
+
+### Example
+```
+let x: LinkedList<usize> = LinkedList::new();
+```
\ No newline at end of file
diff --git a/src/docs/lossy_float_literal.txt b/src/docs/lossy_float_literal.txt
new file mode 100644
index 00000000000..bbcb9115ea6
--- /dev/null
+++ b/src/docs/lossy_float_literal.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for whole number float literals that
+cannot be represented as the underlying type without loss.
+
+### Why is this bad?
+Rust will silently lose precision during
+conversion to a float.
+
+### Example
+```
+let _: f32 = 16_777_217.0; // 16_777_216.0
+```
+
+Use instead:
+```
+let _: f32 = 16_777_216.0;
+let _: f64 = 16_777_217.0;
+```
\ No newline at end of file
diff --git a/src/docs/macro_use_imports.txt b/src/docs/macro_use_imports.txt
new file mode 100644
index 00000000000..6a8180a60bc
--- /dev/null
+++ b/src/docs/macro_use_imports.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for `#[macro_use] use...`.
+
+### Why is this bad?
+Since the Rust 2018 edition you can import
+macro's directly, this is considered idiomatic.
+
+### Example
+```
+#[macro_use]
+use some_macro;
+```
\ No newline at end of file
diff --git a/src/docs/main_recursion.txt b/src/docs/main_recursion.txt
new file mode 100644
index 00000000000..e49becd15bb
--- /dev/null
+++ b/src/docs/main_recursion.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for recursion using the entrypoint.
+
+### Why is this bad?
+Apart from special setups (which we could detect following attributes like #![no_std]),
+recursing into main() seems like an unintuitive anti-pattern we should be able to detect.
+
+### Example
+```
+fn main() {
+    main();
+}
+```
\ No newline at end of file
diff --git a/src/docs/manual_assert.txt b/src/docs/manual_assert.txt
new file mode 100644
index 00000000000..93653081a2c
--- /dev/null
+++ b/src/docs/manual_assert.txt
@@ -0,0 +1,18 @@
+### What it does
+Detects `if`-then-`panic!` that can be replaced with `assert!`.
+
+### Why is this bad?
+`assert!` is simpler than `if`-then-`panic!`.
+
+### Example
+```
+let sad_people: Vec<&str> = vec![];
+if !sad_people.is_empty() {
+    panic!("there are sad people: {:?}", sad_people);
+}
+```
+Use instead:
+```
+let sad_people: Vec<&str> = vec![];
+assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
+```
\ No newline at end of file
diff --git a/src/docs/manual_async_fn.txt b/src/docs/manual_async_fn.txt
new file mode 100644
index 00000000000..d01ac402e0d
--- /dev/null
+++ b/src/docs/manual_async_fn.txt
@@ -0,0 +1,16 @@
+### What it does
+It checks for manual implementations of `async` functions.
+
+### Why is this bad?
+It's more idiomatic to use the dedicated syntax.
+
+### Example
+```
+use std::future::Future;
+
+fn foo() -> impl Future<Output = i32> { async { 42 } }
+```
+Use instead:
+```
+async fn foo() -> i32 { 42 }
+```
\ No newline at end of file
diff --git a/src/docs/manual_bits.txt b/src/docs/manual_bits.txt
new file mode 100644
index 00000000000..b96c2eb151d
--- /dev/null
+++ b/src/docs/manual_bits.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for uses of `std::mem::size_of::<T>() * 8` when
+`T::BITS` is available.
+
+### Why is this bad?
+Can be written as the shorter `T::BITS`.
+
+### Example
+```
+std::mem::size_of::<usize>() * 8;
+```
+Use instead:
+```
+usize::BITS as usize;
+```
\ No newline at end of file
diff --git a/src/docs/manual_filter_map.txt b/src/docs/manual_filter_map.txt
new file mode 100644
index 00000000000..3b6860798ff
--- /dev/null
+++ b/src/docs/manual_filter_map.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `_.filter(_).map(_)` that can be written more simply
+as `filter_map(_)`.
+
+### Why is this bad?
+Redundant code in the `filter` and `map` operations is poor style and
+less performant.
+
+### Example
+```
+(0_i32..10)
+    .filter(|n| n.checked_add(1).is_some())
+    .map(|n| n.checked_add(1).unwrap());
+```
+
+Use instead:
+```
+(0_i32..10).filter_map(|n| n.checked_add(1));
+```
\ No newline at end of file
diff --git a/src/docs/manual_find.txt b/src/docs/manual_find.txt
new file mode 100644
index 00000000000..e3e07a2771f
--- /dev/null
+++ b/src/docs/manual_find.txt
@@ -0,0 +1,24 @@
+### What it does
+Check for manual implementations of Iterator::find
+
+### Why is this bad?
+It doesn't affect performance, but using `find` is shorter and easier to read.
+
+### Example
+
+```
+fn example(arr: Vec<i32>) -> Option<i32> {
+    for el in arr {
+        if el == 1 {
+            return Some(el);
+        }
+    }
+    None
+}
+```
+Use instead:
+```
+fn example(arr: Vec<i32>) -> Option<i32> {
+    arr.into_iter().find(|&el| el == 1)
+}
+```
\ No newline at end of file
diff --git a/src/docs/manual_find_map.txt b/src/docs/manual_find_map.txt
new file mode 100644
index 00000000000..83b22060c0e
--- /dev/null
+++ b/src/docs/manual_find_map.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `_.find(_).map(_)` that can be written more simply
+as `find_map(_)`.
+
+### Why is this bad?
+Redundant code in the `find` and `map` operations is poor style and
+less performant.
+
+### Example
+```
+(0_i32..10)
+    .find(|n| n.checked_add(1).is_some())
+    .map(|n| n.checked_add(1).unwrap());
+```
+
+Use instead:
+```
+(0_i32..10).find_map(|n| n.checked_add(1));
+```
\ No newline at end of file
diff --git a/src/docs/manual_flatten.txt b/src/docs/manual_flatten.txt
new file mode 100644
index 00000000000..62d5f3ec935
--- /dev/null
+++ b/src/docs/manual_flatten.txt
@@ -0,0 +1,25 @@
+### What it does
+Check for unnecessary `if let` usage in a for loop
+where only the `Some` or `Ok` variant of the iterator element is used.
+
+### Why is this bad?
+It is verbose and can be simplified
+by first calling the `flatten` method on the `Iterator`.
+
+### Example
+
+```
+let x = vec![Some(1), Some(2), Some(3)];
+for n in x {
+    if let Some(n) = n {
+        println!("{}", n);
+    }
+}
+```
+Use instead:
+```
+let x = vec![Some(1), Some(2), Some(3)];
+for n in x.into_iter().flatten() {
+    println!("{}", n);
+}
+```
\ No newline at end of file
diff --git a/src/docs/manual_instant_elapsed.txt b/src/docs/manual_instant_elapsed.txt
new file mode 100644
index 00000000000..dde3d493c70
--- /dev/null
+++ b/src/docs/manual_instant_elapsed.txt
@@ -0,0 +1,21 @@
+### What it does
+Lints subtraction between `Instant::now()` and another `Instant`.
+
+### Why is this bad?
+It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
+as `Instant` subtraction saturates.
+
+`prev_instant.elapsed()` also more clearly signals intention.
+
+### Example
+```
+use std::time::Instant;
+let prev_instant = Instant::now();
+let duration = Instant::now() - prev_instant;
+```
+Use instead:
+```
+use std::time::Instant;
+let prev_instant = Instant::now();
+let duration = prev_instant.elapsed();
+```
\ No newline at end of file
diff --git a/src/docs/manual_map.txt b/src/docs/manual_map.txt
new file mode 100644
index 00000000000..7f68ccd1037
--- /dev/null
+++ b/src/docs/manual_map.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for usages of `match` which could be implemented using `map`
+
+### Why is this bad?
+Using the `map` method is clearer and more concise.
+
+### Example
+```
+match Some(0) {
+    Some(x) => Some(x + 1),
+    None => None,
+};
+```
+Use instead:
+```
+Some(0).map(|x| x + 1);
+```
\ No newline at end of file
diff --git a/src/docs/manual_memcpy.txt b/src/docs/manual_memcpy.txt
new file mode 100644
index 00000000000..d7690bf2586
--- /dev/null
+++ b/src/docs/manual_memcpy.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for for-loops that manually copy items between
+slices that could be optimized by having a memcpy.
+
+### Why is this bad?
+It is not as fast as a memcpy.
+
+### Example
+```
+for i in 0..src.len() {
+    dst[i + 64] = src[i];
+}
+```
+
+Use instead:
+```
+dst[64..(src.len() + 64)].clone_from_slice(&src[..]);
+```
\ No newline at end of file
diff --git a/src/docs/manual_non_exhaustive.txt b/src/docs/manual_non_exhaustive.txt
new file mode 100644
index 00000000000..fb021393bd7
--- /dev/null
+++ b/src/docs/manual_non_exhaustive.txt
@@ -0,0 +1,41 @@
+### What it does
+Checks for manual implementations of the non-exhaustive pattern.
+
+### Why is this bad?
+Using the #[non_exhaustive] attribute expresses better the intent
+and allows possible optimizations when applied to enums.
+
+### Example
+```
+struct S {
+    pub a: i32,
+    pub b: i32,
+    _c: (),
+}
+
+enum E {
+    A,
+    B,
+    #[doc(hidden)]
+    _C,
+}
+
+struct T(pub i32, pub i32, ());
+```
+Use instead:
+```
+#[non_exhaustive]
+struct S {
+    pub a: i32,
+    pub b: i32,
+}
+
+#[non_exhaustive]
+enum E {
+    A,
+    B,
+}
+
+#[non_exhaustive]
+struct T(pub i32, pub i32);
+```
\ No newline at end of file
diff --git a/src/docs/manual_ok_or.txt b/src/docs/manual_ok_or.txt
new file mode 100644
index 00000000000..5accdf25965
--- /dev/null
+++ b/src/docs/manual_ok_or.txt
@@ -0,0 +1,19 @@
+### What it does
+
+Finds patterns that reimplement `Option::ok_or`.
+
+### Why is this bad?
+
+Concise code helps focusing on behavior instead of boilerplate.
+
+### Examples
+```
+let foo: Option<i32> = None;
+foo.map_or(Err("error"), |v| Ok(v));
+```
+
+Use instead:
+```
+let foo: Option<i32> = None;
+foo.ok_or("error");
+```
\ No newline at end of file
diff --git a/src/docs/manual_range_contains.txt b/src/docs/manual_range_contains.txt
new file mode 100644
index 00000000000..0ade26951d3
--- /dev/null
+++ b/src/docs/manual_range_contains.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for expressions like `x >= 3 && x < 8` that could
+be more readably expressed as `(3..8).contains(x)`.
+
+### Why is this bad?
+`contains` expresses the intent better and has less
+failure modes (such as fencepost errors or using `||` instead of `&&`).
+
+### Example
+```
+// given
+let x = 6;
+
+assert!(x >= 3 && x < 8);
+```
+Use instead:
+```
+assert!((3..8).contains(&x));
+```
\ No newline at end of file
diff --git a/src/docs/manual_rem_euclid.txt b/src/docs/manual_rem_euclid.txt
new file mode 100644
index 00000000000..d3bb8c61304
--- /dev/null
+++ b/src/docs/manual_rem_euclid.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for an expression like `((x % 4) + 4) % 4` which is a common manual reimplementation
+of `x.rem_euclid(4)`.
+
+### Why is this bad?
+It's simpler and more readable.
+
+### Example
+```
+let x: i32 = 24;
+let rem = ((x % 4) + 4) % 4;
+```
+Use instead:
+```
+let x: i32 = 24;
+let rem = x.rem_euclid(4);
+```
\ No newline at end of file
diff --git a/src/docs/manual_retain.txt b/src/docs/manual_retain.txt
new file mode 100644
index 00000000000..cd4f65a93fc
--- /dev/null
+++ b/src/docs/manual_retain.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for code to be replaced by `.retain()`.
+### Why is this bad?
+`.retain()` is simpler and avoids needless allocation.
+### Example
+```
+let mut vec = vec![0, 1, 2];
+vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect();
+vec = vec.into_iter().filter(|x| x % 2 == 0).collect();
+```
+Use instead:
+```
+let mut vec = vec![0, 1, 2];
+vec.retain(|x| x % 2 == 0);
+```
\ No newline at end of file
diff --git a/src/docs/manual_saturating_arithmetic.txt b/src/docs/manual_saturating_arithmetic.txt
new file mode 100644
index 00000000000..d9f5d3d1187
--- /dev/null
+++ b/src/docs/manual_saturating_arithmetic.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`.
+
+### Why is this bad?
+These can be written simply with `saturating_add/sub` methods.
+
+### Example
+```
+let add = x.checked_add(y).unwrap_or(u32::MAX);
+let sub = x.checked_sub(y).unwrap_or(u32::MIN);
+```
+
+can be written using dedicated methods for saturating addition/subtraction as:
+
+```
+let add = x.saturating_add(y);
+let sub = x.saturating_sub(y);
+```
\ No newline at end of file
diff --git a/src/docs/manual_split_once.txt b/src/docs/manual_split_once.txt
new file mode 100644
index 00000000000..291ae447de0
--- /dev/null
+++ b/src/docs/manual_split_once.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for usages of `str::splitn(2, _)`
+
+### Why is this bad?
+`split_once` is both clearer in intent and slightly more efficient.
+
+### Example
+```
+let s = "key=value=add";
+let (key, value) = s.splitn(2, '=').next_tuple()?;
+let value = s.splitn(2, '=').nth(1)?;
+
+let mut parts = s.splitn(2, '=');
+let key = parts.next()?;
+let value = parts.next()?;
+```
+
+Use instead:
+```
+let s = "key=value=add";
+let (key, value) = s.split_once('=')?;
+let value = s.split_once('=')?.1;
+
+let (key, value) = s.split_once('=')?;
+```
+
+### Limitations
+The multiple statement variant currently only detects `iter.next()?`/`iter.next().unwrap()`
+in two separate `let` statements that immediately follow the `splitn()`
\ No newline at end of file
diff --git a/src/docs/manual_str_repeat.txt b/src/docs/manual_str_repeat.txt
new file mode 100644
index 00000000000..1d4a7a48e20
--- /dev/null
+++ b/src/docs/manual_str_repeat.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for manual implementations of `str::repeat`
+
+### Why is this bad?
+These are both harder to read, as well as less performant.
+
+### Example
+```
+let x: String = std::iter::repeat('x').take(10).collect();
+```
+
+Use instead:
+```
+let x: String = "x".repeat(10);
+```
\ No newline at end of file
diff --git a/src/docs/manual_string_new.txt b/src/docs/manual_string_new.txt
new file mode 100644
index 00000000000..4cbc43f8f84
--- /dev/null
+++ b/src/docs/manual_string_new.txt
@@ -0,0 +1,20 @@
+### What it does
+
+Checks for usage of `""` to create a `String`, such as `"".to_string()`, `"".to_owned()`,
+`String::from("")` and others.
+
+### Why is this bad?
+
+Different ways of creating an empty string makes your code less standardized, which can
+be confusing.
+
+### Example
+```
+let a = "".to_string();
+let b: String = "".into();
+```
+Use instead:
+```
+let a = String::new();
+let b = String::new();
+```
\ No newline at end of file
diff --git a/src/docs/manual_strip.txt b/src/docs/manual_strip.txt
new file mode 100644
index 00000000000..f32d8e7a09b
--- /dev/null
+++ b/src/docs/manual_strip.txt
@@ -0,0 +1,24 @@
+### What it does
+Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using
+the pattern's length.
+
+### Why is this bad?
+Using `str:strip_{prefix,suffix}` is safer and may have better performance as there is no
+slicing which may panic and the compiler does not need to insert this panic code. It is
+also sometimes more readable as it removes the need for duplicating or storing the pattern
+used by `str::{starts,ends}_with` and in the slicing.
+
+### Example
+```
+let s = "hello, world!";
+if s.starts_with("hello, ") {
+    assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
+}
+```
+Use instead:
+```
+let s = "hello, world!";
+if let Some(end) = s.strip_prefix("hello, ") {
+    assert_eq!(end.to_uppercase(), "WORLD!");
+}
+```
\ No newline at end of file
diff --git a/src/docs/manual_swap.txt b/src/docs/manual_swap.txt
new file mode 100644
index 00000000000..bd9526288e3
--- /dev/null
+++ b/src/docs/manual_swap.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for manual swapping.
+
+### Why is this bad?
+The `std::mem::swap` function exposes the intent better
+without deinitializing or copying either variable.
+
+### Example
+```
+let mut a = 42;
+let mut b = 1337;
+
+let t = b;
+b = a;
+a = t;
+```
+Use std::mem::swap():
+```
+let mut a = 1;
+let mut b = 2;
+std::mem::swap(&mut a, &mut b);
+```
\ No newline at end of file
diff --git a/src/docs/manual_unwrap_or.txt b/src/docs/manual_unwrap_or.txt
new file mode 100644
index 00000000000..1fd7d831bfc
--- /dev/null
+++ b/src/docs/manual_unwrap_or.txt
@@ -0,0 +1,20 @@
+### What it does
+Finds patterns that reimplement `Option::unwrap_or` or `Result::unwrap_or`.
+
+### Why is this bad?
+Concise code helps focusing on behavior instead of boilerplate.
+
+### Example
+```
+let foo: Option<i32> = None;
+match foo {
+    Some(v) => v,
+    None => 1,
+};
+```
+
+Use instead:
+```
+let foo: Option<i32> = None;
+foo.unwrap_or(1);
+```
\ No newline at end of file
diff --git a/src/docs/many_single_char_names.txt b/src/docs/many_single_char_names.txt
new file mode 100644
index 00000000000..55ee5da5557
--- /dev/null
+++ b/src/docs/many_single_char_names.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for too many variables whose name consists of a
+single character.
+
+### Why is this bad?
+It's hard to memorize what a variable means without a
+descriptive name.
+
+### Example
+```
+let (a, b, c, d, e, f, g) = (...);
+```
\ No newline at end of file
diff --git a/src/docs/map_clone.txt b/src/docs/map_clone.txt
new file mode 100644
index 00000000000..3ee27f072ef
--- /dev/null
+++ b/src/docs/map_clone.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `map(|x| x.clone())` or
+dereferencing closures for `Copy` types, on `Iterator` or `Option`,
+and suggests `cloned()` or `copied()` instead
+
+### Why is this bad?
+Readability, this can be written more concisely
+
+### Example
+```
+let x = vec![42, 43];
+let y = x.iter();
+let z = y.map(|i| *i);
+```
+
+The correct use would be:
+
+```
+let x = vec![42, 43];
+let y = x.iter();
+let z = y.cloned();
+```
\ No newline at end of file
diff --git a/src/docs/map_collect_result_unit.txt b/src/docs/map_collect_result_unit.txt
new file mode 100644
index 00000000000..9b720612495
--- /dev/null
+++ b/src/docs/map_collect_result_unit.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for usage of `_.map(_).collect::<Result<(), _>()`.
+
+### Why is this bad?
+Using `try_for_each` instead is more readable and idiomatic.
+
+### Example
+```
+(0..3).map(|t| Err(t)).collect::<Result<(), _>>();
+```
+Use instead:
+```
+(0..3).try_for_each(|t| Err(t));
+```
\ No newline at end of file
diff --git a/src/docs/map_entry.txt b/src/docs/map_entry.txt
new file mode 100644
index 00000000000..20dba1798d0
--- /dev/null
+++ b/src/docs/map_entry.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for uses of `contains_key` + `insert` on `HashMap`
+or `BTreeMap`.
+
+### Why is this bad?
+Using `entry` is more efficient.
+
+### Known problems
+The suggestion may have type inference errors in some cases. e.g.
+```
+let mut map = std::collections::HashMap::new();
+let _ = if !map.contains_key(&0) {
+    map.insert(0, 0)
+} else {
+    None
+};
+```
+
+### Example
+```
+if !map.contains_key(&k) {
+    map.insert(k, v);
+}
+```
+Use instead:
+```
+map.entry(k).or_insert(v);
+```
\ No newline at end of file
diff --git a/src/docs/map_err_ignore.txt b/src/docs/map_err_ignore.txt
new file mode 100644
index 00000000000..2606c13a7af
--- /dev/null
+++ b/src/docs/map_err_ignore.txt
@@ -0,0 +1,93 @@
+### What it does
+Checks for instances of `map_err(|_| Some::Enum)`
+
+### Why is this bad?
+This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error
+
+### Example
+Before:
+```
+use std::fmt;
+
+#[derive(Debug)]
+enum Error {
+    Indivisible,
+    Remainder(u8),
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Error::Indivisible => write!(f, "could not divide input by three"),
+            Error::Remainder(remainder) => write!(
+                f,
+                "input is not divisible by three, remainder = {}",
+                remainder
+            ),
+        }
+    }
+}
+
+impl std::error::Error for Error {}
+
+fn divisible_by_3(input: &str) -> Result<(), Error> {
+    input
+        .parse::<i32>()
+        .map_err(|_| Error::Indivisible)
+        .map(|v| v % 3)
+        .and_then(|remainder| {
+            if remainder == 0 {
+                Ok(())
+            } else {
+                Err(Error::Remainder(remainder as u8))
+            }
+        })
+}
+ ```
+
+ After:
+ ```rust
+use std::{fmt, num::ParseIntError};
+
+#[derive(Debug)]
+enum Error {
+    Indivisible(ParseIntError),
+    Remainder(u8),
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Error::Indivisible(_) => write!(f, "could not divide input by three"),
+            Error::Remainder(remainder) => write!(
+                f,
+                "input is not divisible by three, remainder = {}",
+                remainder
+            ),
+        }
+    }
+}
+
+impl std::error::Error for Error {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        match self {
+            Error::Indivisible(source) => Some(source),
+            _ => None,
+        }
+    }
+}
+
+fn divisible_by_3(input: &str) -> Result<(), Error> {
+    input
+        .parse::<i32>()
+        .map_err(Error::Indivisible)
+        .map(|v| v % 3)
+        .and_then(|remainder| {
+            if remainder == 0 {
+                Ok(())
+            } else {
+                Err(Error::Remainder(remainder as u8))
+            }
+        })
+}
+```
\ No newline at end of file
diff --git a/src/docs/map_flatten.txt b/src/docs/map_flatten.txt
new file mode 100644
index 00000000000..73c0e51407f
--- /dev/null
+++ b/src/docs/map_flatten.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option`
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option`
+
+### Example
+```
+let vec = vec![vec![1]];
+let opt = Some(5);
+
+vec.iter().map(|x| x.iter()).flatten();
+opt.map(|x| Some(x * 2)).flatten();
+```
+
+Use instead:
+```
+vec.iter().flat_map(|x| x.iter());
+opt.and_then(|x| Some(x * 2));
+```
\ No newline at end of file
diff --git a/src/docs/map_identity.txt b/src/docs/map_identity.txt
new file mode 100644
index 00000000000..e2e7af0bed9
--- /dev/null
+++ b/src/docs/map_identity.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for instances of `map(f)` where `f` is the identity function.
+
+### Why is this bad?
+It can be written more concisely without the call to `map`.
+
+### Example
+```
+let x = [1, 2, 3];
+let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
+```
+Use instead:
+```
+let x = [1, 2, 3];
+let y: Vec<_> = x.iter().map(|x| 2*x).collect();
+```
\ No newline at end of file
diff --git a/src/docs/map_unwrap_or.txt b/src/docs/map_unwrap_or.txt
new file mode 100644
index 00000000000..485b29f01b1
--- /dev/null
+++ b/src/docs/map_unwrap_or.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or
+`result.map(_).unwrap_or_else(_)`.
+
+### Why is this bad?
+Readability, these can be written more concisely (resp.) as
+`option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`.
+
+### Known problems
+The order of the arguments is not in execution order
+
+### Examples
+```
+option.map(|a| a + 1).unwrap_or(0);
+result.map(|a| a + 1).unwrap_or_else(some_function);
+```
+
+Use instead:
+```
+option.map_or(0, |a| a + 1);
+result.map_or_else(some_function, |a| a + 1);
+```
\ No newline at end of file
diff --git a/src/docs/match_as_ref.txt b/src/docs/match_as_ref.txt
new file mode 100644
index 00000000000..5e5f3d645a4
--- /dev/null
+++ b/src/docs/match_as_ref.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for match which is used to add a reference to an
+`Option` value.
+
+### Why is this bad?
+Using `as_ref()` or `as_mut()` instead is shorter.
+
+### Example
+```
+let x: Option<()> = None;
+
+let r: Option<&()> = match x {
+    None => None,
+    Some(ref v) => Some(v),
+};
+```
+
+Use instead:
+```
+let x: Option<()> = None;
+
+let r: Option<&()> = x.as_ref();
+```
\ No newline at end of file
diff --git a/src/docs/match_bool.txt b/src/docs/match_bool.txt
new file mode 100644
index 00000000000..96f9e1f8b7d
--- /dev/null
+++ b/src/docs/match_bool.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for matches where match expression is a `bool`. It
+suggests to replace the expression with an `if...else` block.
+
+### Why is this bad?
+It makes the code less readable.
+
+### Example
+```
+let condition: bool = true;
+match condition {
+    true => foo(),
+    false => bar(),
+}
+```
+Use if/else instead:
+```
+let condition: bool = true;
+if condition {
+    foo();
+} else {
+    bar();
+}
+```
\ No newline at end of file
diff --git a/src/docs/match_like_matches_macro.txt b/src/docs/match_like_matches_macro.txt
new file mode 100644
index 00000000000..643e2ddc97b
--- /dev/null
+++ b/src/docs/match_like_matches_macro.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for `match`  or `if let` expressions producing a
+`bool` that could be written using `matches!`
+
+### Why is this bad?
+Readability and needless complexity.
+
+### Known problems
+This lint falsely triggers, if there are arms with
+`cfg` attributes that remove an arm evaluating to `false`.
+
+### Example
+```
+let x = Some(5);
+
+let a = match x {
+    Some(0) => true,
+    _ => false,
+};
+
+let a = if let Some(0) = x {
+    true
+} else {
+    false
+};
+```
+
+Use instead:
+```
+let x = Some(5);
+let a = matches!(x, Some(0));
+```
\ No newline at end of file
diff --git a/src/docs/match_on_vec_items.txt b/src/docs/match_on_vec_items.txt
new file mode 100644
index 00000000000..981d18d0f9e
--- /dev/null
+++ b/src/docs/match_on_vec_items.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for `match vec[idx]` or `match vec[n..m]`.
+
+### Why is this bad?
+This can panic at runtime.
+
+### Example
+```
+let arr = vec![0, 1, 2, 3];
+let idx = 1;
+
+match arr[idx] {
+    0 => println!("{}", 0),
+    1 => println!("{}", 3),
+    _ => {},
+}
+```
+
+Use instead:
+```
+let arr = vec![0, 1, 2, 3];
+let idx = 1;
+
+match arr.get(idx) {
+    Some(0) => println!("{}", 0),
+    Some(1) => println!("{}", 3),
+    _ => {},
+}
+```
\ No newline at end of file
diff --git a/src/docs/match_overlapping_arm.txt b/src/docs/match_overlapping_arm.txt
new file mode 100644
index 00000000000..841c091bd5c
--- /dev/null
+++ b/src/docs/match_overlapping_arm.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for overlapping match arms.
+
+### Why is this bad?
+It is likely to be an error and if not, makes the code
+less obvious.
+
+### Example
+```
+let x = 5;
+match x {
+    1..=10 => println!("1 ... 10"),
+    5..=15 => println!("5 ... 15"),
+    _ => (),
+}
+```
\ No newline at end of file
diff --git a/src/docs/match_ref_pats.txt b/src/docs/match_ref_pats.txt
new file mode 100644
index 00000000000..b1d90299509
--- /dev/null
+++ b/src/docs/match_ref_pats.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for matches where all arms match a reference,
+suggesting to remove the reference and deref the matched expression
+instead. It also checks for `if let &foo = bar` blocks.
+
+### Why is this bad?
+It just makes the code less readable. That reference
+destructuring adds nothing to the code.
+
+### Example
+```
+match x {
+    &A(ref y) => foo(y),
+    &B => bar(),
+    _ => frob(&x),
+}
+```
+
+Use instead:
+```
+match *x {
+    A(ref y) => foo(y),
+    B => bar(),
+    _ => frob(x),
+}
+```
\ No newline at end of file
diff --git a/src/docs/match_result_ok.txt b/src/docs/match_result_ok.txt
new file mode 100644
index 00000000000..eea7c8e00f1
--- /dev/null
+++ b/src/docs/match_result_ok.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for unnecessary `ok()` in `while let`.
+
+### Why is this bad?
+Calling `ok()` in `while let` is unnecessary, instead match
+on `Ok(pat)`
+
+### Example
+```
+while let Some(value) = iter.next().ok() {
+    vec.push(value)
+}
+
+if let Some(value) = iter.next().ok() {
+    vec.push(value)
+}
+```
+Use instead:
+```
+while let Ok(value) = iter.next() {
+    vec.push(value)
+}
+
+if let Ok(value) = iter.next() {
+       vec.push(value)
+}
+```
\ No newline at end of file
diff --git a/src/docs/match_same_arms.txt b/src/docs/match_same_arms.txt
new file mode 100644
index 00000000000..14edf12032e
--- /dev/null
+++ b/src/docs/match_same_arms.txt
@@ -0,0 +1,38 @@
+### What it does
+Checks for `match` with identical arm bodies.
+
+### Why is this bad?
+This is probably a copy & paste error. If arm bodies
+are the same on purpose, you can factor them
+[using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
+
+### Known problems
+False positive possible with order dependent `match`
+(see issue
+[#860](https://github.com/rust-lang/rust-clippy/issues/860)).
+
+### Example
+```
+match foo {
+    Bar => bar(),
+    Quz => quz(),
+    Baz => bar(), // <= oops
+}
+```
+
+This should probably be
+```
+match foo {
+    Bar => bar(),
+    Quz => quz(),
+    Baz => baz(), // <= fixed
+}
+```
+
+or if the original code was not a typo:
+```
+match foo {
+    Bar | Baz => bar(), // <= shows the intent better
+    Quz => quz(),
+}
+```
\ No newline at end of file
diff --git a/src/docs/match_single_binding.txt b/src/docs/match_single_binding.txt
new file mode 100644
index 00000000000..67ded0bbd55
--- /dev/null
+++ b/src/docs/match_single_binding.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for useless match that binds to only one value.
+
+### Why is this bad?
+Readability and needless complexity.
+
+### Known problems
+ Suggested replacements may be incorrect when `match`
+is actually binding temporary value, bringing a 'dropped while borrowed' error.
+
+### Example
+```
+match (a, b) {
+    (c, d) => {
+        // useless match
+    }
+}
+```
+
+Use instead:
+```
+let (c, d) = (a, b);
+```
\ No newline at end of file
diff --git a/src/docs/match_str_case_mismatch.txt b/src/docs/match_str_case_mismatch.txt
new file mode 100644
index 00000000000..19e74c2084e
--- /dev/null
+++ b/src/docs/match_str_case_mismatch.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for `match` expressions modifying the case of a string with non-compliant arms
+
+### Why is this bad?
+The arm is unreachable, which is likely a mistake
+
+### Example
+```
+match &*text.to_ascii_lowercase() {
+    "foo" => {},
+    "Bar" => {},
+    _ => {},
+}
+```
+Use instead:
+```
+match &*text.to_ascii_lowercase() {
+    "foo" => {},
+    "bar" => {},
+    _ => {},
+}
+```
\ No newline at end of file
diff --git a/src/docs/match_wild_err_arm.txt b/src/docs/match_wild_err_arm.txt
new file mode 100644
index 00000000000..f89b3a23a1c
--- /dev/null
+++ b/src/docs/match_wild_err_arm.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for arm which matches all errors with `Err(_)`
+and take drastic actions like `panic!`.
+
+### Why is this bad?
+It is generally a bad practice, similar to
+catching all exceptions in java with `catch(Exception)`
+
+### Example
+```
+let x: Result<i32, &str> = Ok(3);
+match x {
+    Ok(_) => println!("ok"),
+    Err(_) => panic!("err"),
+}
+```
\ No newline at end of file
diff --git a/src/docs/match_wildcard_for_single_variants.txt b/src/docs/match_wildcard_for_single_variants.txt
new file mode 100644
index 00000000000..25559b9ecdc
--- /dev/null
+++ b/src/docs/match_wildcard_for_single_variants.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for wildcard enum matches for a single variant.
+
+### Why is this bad?
+New enum variants added by library updates can be missed.
+
+### Known problems
+Suggested replacements may not use correct path to enum
+if it's not present in the current scope.
+
+### Example
+```
+match x {
+    Foo::A => {},
+    Foo::B => {},
+    _ => {},
+}
+```
+
+Use instead:
+```
+match x {
+    Foo::A => {},
+    Foo::B => {},
+    Foo::C => {},
+}
+```
\ No newline at end of file
diff --git a/src/docs/maybe_infinite_iter.txt b/src/docs/maybe_infinite_iter.txt
new file mode 100644
index 00000000000..1204a49b466
--- /dev/null
+++ b/src/docs/maybe_infinite_iter.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for iteration that may be infinite.
+
+### Why is this bad?
+While there may be places where this is acceptable
+(e.g., in event streams), in most cases this is simply an error.
+
+### Known problems
+The code may have a condition to stop iteration, but
+this lint is not clever enough to analyze it.
+
+### Example
+```
+let infinite_iter = 0..;
+[0..].iter().zip(infinite_iter.take_while(|x| *x > 5));
+```
\ No newline at end of file
diff --git a/src/docs/mem_forget.txt b/src/docs/mem_forget.txt
new file mode 100644
index 00000000000..a6888c48fc3
--- /dev/null
+++ b/src/docs/mem_forget.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for usage of `std::mem::forget(t)` where `t` is
+`Drop`.
+
+### Why is this bad?
+`std::mem::forget(t)` prevents `t` from running its
+destructor, possibly causing leaks.
+
+### Example
+```
+mem::forget(Rc::new(55))
+```
\ No newline at end of file
diff --git a/src/docs/mem_replace_option_with_none.txt b/src/docs/mem_replace_option_with_none.txt
new file mode 100644
index 00000000000..7f243d1c165
--- /dev/null
+++ b/src/docs/mem_replace_option_with_none.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for `mem::replace()` on an `Option` with
+`None`.
+
+### Why is this bad?
+`Option` already has the method `take()` for
+taking its current value (Some(..) or None) and replacing it with
+`None`.
+
+### Example
+```
+use std::mem;
+
+let mut an_option = Some(0);
+let replaced = mem::replace(&mut an_option, None);
+```
+Is better expressed with:
+```
+let mut an_option = Some(0);
+let taken = an_option.take();
+```
\ No newline at end of file
diff --git a/src/docs/mem_replace_with_default.txt b/src/docs/mem_replace_with_default.txt
new file mode 100644
index 00000000000..24e0913a30c
--- /dev/null
+++ b/src/docs/mem_replace_with_default.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for `std::mem::replace` on a value of type
+`T` with `T::default()`.
+
+### Why is this bad?
+`std::mem` module already has the method `take` to
+take the current value and replace it with the default value of that type.
+
+### Example
+```
+let mut text = String::from("foo");
+let replaced = std::mem::replace(&mut text, String::default());
+```
+Is better expressed with:
+```
+let mut text = String::from("foo");
+let taken = std::mem::take(&mut text);
+```
\ No newline at end of file
diff --git a/src/docs/mem_replace_with_uninit.txt b/src/docs/mem_replace_with_uninit.txt
new file mode 100644
index 00000000000..0bb483668ab
--- /dev/null
+++ b/src/docs/mem_replace_with_uninit.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for `mem::replace(&mut _, mem::uninitialized())`
+and `mem::replace(&mut _, mem::zeroed())`.
+
+### Why is this bad?
+This will lead to undefined behavior even if the
+value is overwritten later, because the uninitialized value may be
+observed in the case of a panic.
+
+### Example
+```
+use std::mem;
+
+#[allow(deprecated, invalid_value)]
+fn myfunc (v: &mut Vec<i32>) {
+    let taken_v = unsafe { mem::replace(v, mem::uninitialized()) };
+    let new_v = may_panic(taken_v); // undefined behavior on panic
+    mem::forget(mem::replace(v, new_v));
+}
+```
+
+The [take_mut](https://docs.rs/take_mut) crate offers a sound solution,
+at the cost of either lazily creating a replacement value or aborting
+on panic, to ensure that the uninitialized value cannot be observed.
\ No newline at end of file
diff --git a/src/docs/min_max.txt b/src/docs/min_max.txt
new file mode 100644
index 00000000000..6acf0f932e9
--- /dev/null
+++ b/src/docs/min_max.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for expressions where `std::cmp::min` and `max` are
+used to clamp values, but switched so that the result is constant.
+
+### Why is this bad?
+This is in all probability not the intended outcome. At
+the least it hurts readability of the code.
+
+### Example
+```
+min(0, max(100, x))
+
+// or
+
+x.max(100).min(0)
+```
+It will always be equal to `0`. Probably the author meant to clamp the value
+between 0 and 100, but has erroneously swapped `min` and `max`.
\ No newline at end of file
diff --git a/src/docs/mismatched_target_os.txt b/src/docs/mismatched_target_os.txt
new file mode 100644
index 00000000000..51e5ec6e7c5
--- /dev/null
+++ b/src/docs/mismatched_target_os.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for cfg attributes having operating systems used in target family position.
+
+### Why is this bad?
+The configuration option will not be recognised and the related item will not be included
+by the conditional compilation engine.
+
+### Example
+```
+#[cfg(linux)]
+fn conditional() { }
+```
+
+Use instead:
+```
+#[cfg(target_os = "linux")]
+fn conditional() { }
+
+// or
+
+#[cfg(unix)]
+fn conditional() { }
+```
+Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details.
\ No newline at end of file
diff --git a/src/docs/mismatching_type_param_order.txt b/src/docs/mismatching_type_param_order.txt
new file mode 100644
index 00000000000..ffc7f32d0aa
--- /dev/null
+++ b/src/docs/mismatching_type_param_order.txt
@@ -0,0 +1,33 @@
+### What it does
+Checks for type parameters which are positioned inconsistently between
+a type definition and impl block. Specifically, a parameter in an impl
+block which has the same name as a parameter in the type def, but is in
+a different place.
+
+### Why is this bad?
+Type parameters are determined by their position rather than name.
+Naming type parameters inconsistently may cause you to refer to the
+wrong type parameter.
+
+### Limitations
+This lint only applies to impl blocks with simple generic params, e.g.
+`A`. If there is anything more complicated, such as a tuple, it will be
+ignored.
+
+### Example
+```
+struct Foo<A, B> {
+    x: A,
+    y: B,
+}
+// inside the impl, B refers to Foo::A
+impl<B, A> Foo<B, A> {}
+```
+Use instead:
+```
+struct Foo<A, B> {
+    x: A,
+    y: B,
+}
+impl<A, B> Foo<A, B> {}
+```
\ No newline at end of file
diff --git a/src/docs/misrefactored_assign_op.txt b/src/docs/misrefactored_assign_op.txt
new file mode 100644
index 00000000000..3d691fe4178
--- /dev/null
+++ b/src/docs/misrefactored_assign_op.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for `a op= a op b` or `a op= b op a` patterns.
+
+### Why is this bad?
+Most likely these are bugs where one meant to write `a
+op= b`.
+
+### Known problems
+Clippy cannot know for sure if `a op= a op b` should have
+been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both.
+If `a op= a op b` is really the correct behavior it should be
+written as `a = a op a op b` as it's less confusing.
+
+### Example
+```
+let mut a = 5;
+let b = 2;
+// ...
+a += a + b;
+```
\ No newline at end of file
diff --git a/src/docs/missing_const_for_fn.txt b/src/docs/missing_const_for_fn.txt
new file mode 100644
index 00000000000..067614d4c46
--- /dev/null
+++ b/src/docs/missing_const_for_fn.txt
@@ -0,0 +1,40 @@
+### What it does
+Suggests the use of `const` in functions and methods where possible.
+
+### Why is this bad?
+Not having the function const prevents callers of the function from being const as well.
+
+### Known problems
+Const functions are currently still being worked on, with some features only being available
+on nightly. This lint does not consider all edge cases currently and the suggestions may be
+incorrect if you are using this lint on stable.
+
+Also, the lint only runs one pass over the code. Consider these two non-const functions:
+
+```
+fn a() -> i32 {
+    0
+}
+fn b() -> i32 {
+    a()
+}
+```
+
+When running Clippy, the lint will only suggest to make `a` const, because `b` at this time
+can't be const as it calls a non-const function. Making `a` const and running Clippy again,
+will suggest to make `b` const, too.
+
+### Example
+```
+fn new() -> Self {
+    Self { random_number: 42 }
+}
+```
+
+Could be a const fn:
+
+```
+const fn new() -> Self {
+    Self { random_number: 42 }
+}
+```
\ No newline at end of file
diff --git a/src/docs/missing_docs_in_private_items.txt b/src/docs/missing_docs_in_private_items.txt
new file mode 100644
index 00000000000..5d37505bb17
--- /dev/null
+++ b/src/docs/missing_docs_in_private_items.txt
@@ -0,0 +1,9 @@
+### What it does
+Warns if there is missing doc for any documentable item
+(public or private).
+
+### Why is this bad?
+Doc is good. *rustc* has a `MISSING_DOCS`
+allowed-by-default lint for
+public members, but has no way to enforce documentation of private items.
+This lint fixes that.
\ No newline at end of file
diff --git a/src/docs/missing_enforced_import_renames.txt b/src/docs/missing_enforced_import_renames.txt
new file mode 100644
index 00000000000..8f4649bd592
--- /dev/null
+++ b/src/docs/missing_enforced_import_renames.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for imports that do not rename the item as specified
+in the `enforce-import-renames` config option.
+
+### Why is this bad?
+Consistency is important, if a project has defined import
+renames they should be followed. More practically, some item names are too
+vague outside of their defining scope this can enforce a more meaningful naming.
+
+### Example
+An example clippy.toml configuration:
+```
+enforced-import-renames = [ { path = "serde_json::Value", rename = "JsonValue" }]
+```
+
+```
+use serde_json::Value;
+```
+Use instead:
+```
+use serde_json::Value as JsonValue;
+```
\ No newline at end of file
diff --git a/src/docs/missing_errors_doc.txt b/src/docs/missing_errors_doc.txt
new file mode 100644
index 00000000000..028778d85ae
--- /dev/null
+++ b/src/docs/missing_errors_doc.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks the doc comments of publicly visible functions that
+return a `Result` type and warns if there is no `# Errors` section.
+
+### Why is this bad?
+Documenting the type of errors that can be returned from a
+function can help callers write code to handle the errors appropriately.
+
+### Examples
+Since the following function returns a `Result` it has an `# Errors` section in
+its doc comment:
+
+```
+/// # Errors
+///
+/// Will return `Err` if `filename` does not exist or the user does not have
+/// permission to read it.
+pub fn read(filename: String) -> io::Result<String> {
+    unimplemented!();
+}
+```
\ No newline at end of file
diff --git a/src/docs/missing_inline_in_public_items.txt b/src/docs/missing_inline_in_public_items.txt
new file mode 100644
index 00000000000..d90c50fe7f9
--- /dev/null
+++ b/src/docs/missing_inline_in_public_items.txt
@@ -0,0 +1,45 @@
+### What it does
+It lints if an exported function, method, trait method with default impl,
+or trait method impl is not `#[inline]`.
+
+### Why is this bad?
+In general, it is not. Functions can be inlined across
+crates when that's profitable as long as any form of LTO is used. When LTO is disabled,
+functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates
+might intend for most of the methods in their public API to be able to be inlined across
+crates even when LTO is disabled. For these types of crates, enabling this lint might make
+sense. It allows the crate to require all exported methods to be `#[inline]` by default, and
+then opt out for specific methods where this might not make sense.
+
+### Example
+```
+pub fn foo() {} // missing #[inline]
+fn ok() {} // ok
+#[inline] pub fn bar() {} // ok
+#[inline(always)] pub fn baz() {} // ok
+
+pub trait Bar {
+  fn bar(); // ok
+  fn def_bar() {} // missing #[inline]
+}
+
+struct Baz;
+impl Baz {
+   fn private() {} // ok
+}
+
+impl Bar for Baz {
+  fn bar() {} // ok - Baz is not exported
+}
+
+pub struct PubBaz;
+impl PubBaz {
+   fn private() {} // ok
+   pub fn not_private() {} // missing #[inline]
+}
+
+impl Bar for PubBaz {
+   fn bar() {} // missing #[inline]
+   fn def_bar() {} // missing #[inline]
+}
+```
\ No newline at end of file
diff --git a/src/docs/missing_panics_doc.txt b/src/docs/missing_panics_doc.txt
new file mode 100644
index 00000000000..e5e39a82451
--- /dev/null
+++ b/src/docs/missing_panics_doc.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks the doc comments of publicly visible functions that
+may panic and warns if there is no `# Panics` section.
+
+### Why is this bad?
+Documenting the scenarios in which panicking occurs
+can help callers who do not want to panic to avoid those situations.
+
+### Examples
+Since the following function may panic it has a `# Panics` section in
+its doc comment:
+
+```
+/// # Panics
+///
+/// Will panic if y is 0
+pub fn divide_by(x: i32, y: i32) -> i32 {
+    if y == 0 {
+        panic!("Cannot divide by 0")
+    } else {
+        x / y
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/missing_safety_doc.txt b/src/docs/missing_safety_doc.txt
new file mode 100644
index 00000000000..6492eb84f63
--- /dev/null
+++ b/src/docs/missing_safety_doc.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for the doc comments of publicly visible
+unsafe functions and warns if there is no `# Safety` section.
+
+### Why is this bad?
+Unsafe functions should document their safety
+preconditions, so that users can be sure they are using them safely.
+
+### Examples
+```
+/// This function should really be documented
+pub unsafe fn start_apocalypse(u: &mut Universe) {
+    unimplemented!();
+}
+```
+
+At least write a line about safety:
+
+```
+/// # Safety
+///
+/// This function should not be called before the horsemen are ready.
+pub unsafe fn start_apocalypse(u: &mut Universe) {
+    unimplemented!();
+}
+```
\ No newline at end of file
diff --git a/src/docs/missing_spin_loop.txt b/src/docs/missing_spin_loop.txt
new file mode 100644
index 00000000000..3a06a91d718
--- /dev/null
+++ b/src/docs/missing_spin_loop.txt
@@ -0,0 +1,27 @@
+### What it does
+Check for empty spin loops
+
+### Why is this bad?
+The loop body should have something like `thread::park()` or at least
+`std::hint::spin_loop()` to avoid needlessly burning cycles and conserve
+energy. Perhaps even better use an actual lock, if possible.
+
+### Known problems
+This lint doesn't currently trigger on `while let` or
+`loop { match .. { .. } }` loops, which would be considered idiomatic in
+combination with e.g. `AtomicBool::compare_exchange_weak`.
+
+### Example
+
+```
+use core::sync::atomic::{AtomicBool, Ordering};
+let b = AtomicBool::new(true);
+// give a ref to `b` to another thread,wait for it to become false
+while b.load(Ordering::Acquire) {};
+```
+Use instead:
+```
+while b.load(Ordering::Acquire) {
+    std::hint::spin_loop()
+}
+```
\ No newline at end of file
diff --git a/src/docs/mistyped_literal_suffixes.txt b/src/docs/mistyped_literal_suffixes.txt
new file mode 100644
index 00000000000..1760fcbfeac
--- /dev/null
+++ b/src/docs/mistyped_literal_suffixes.txt
@@ -0,0 +1,15 @@
+### What it does
+Warns for mistyped suffix in literals
+
+### Why is this bad?
+This is most probably a typo
+
+### Known problems
+- Does not match on integers too large to fit in the corresponding unsigned type
+- Does not match on `_127` since that is a valid grouping for decimal and octal numbers
+
+### Example
+```
+`2_32` => `2_i32`
+`250_8 => `250_u8`
+```
\ No newline at end of file
diff --git a/src/docs/mixed_case_hex_literals.txt b/src/docs/mixed_case_hex_literals.txt
new file mode 100644
index 00000000000..d2d01e0c98e
--- /dev/null
+++ b/src/docs/mixed_case_hex_literals.txt
@@ -0,0 +1,16 @@
+### What it does
+Warns on hexadecimal literals with mixed-case letter
+digits.
+
+### Why is this bad?
+It looks confusing.
+
+### Example
+```
+0x1a9BAcD
+```
+
+Use instead:
+```
+0x1A9BACD
+```
\ No newline at end of file
diff --git a/src/docs/mixed_read_write_in_expression.txt b/src/docs/mixed_read_write_in_expression.txt
new file mode 100644
index 00000000000..02d1c5d0525
--- /dev/null
+++ b/src/docs/mixed_read_write_in_expression.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for a read and a write to the same variable where
+whether the read occurs before or after the write depends on the evaluation
+order of sub-expressions.
+
+### Why is this bad?
+It is often confusing to read. As described [here](https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands),
+the operands of these expressions are evaluated before applying the effects of the expression.
+
+### Known problems
+Code which intentionally depends on the evaluation
+order, or which is correct for any evaluation order.
+
+### Example
+```
+let mut x = 0;
+
+let a = {
+    x = 1;
+    1
+} + x;
+// Unclear whether a is 1 or 2.
+```
+
+Use instead:
+```
+let tmp = {
+    x = 1;
+    1
+};
+let a = tmp + x;
+```
\ No newline at end of file
diff --git a/src/docs/mod_module_files.txt b/src/docs/mod_module_files.txt
new file mode 100644
index 00000000000..95bca583afd
--- /dev/null
+++ b/src/docs/mod_module_files.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks that module layout uses only self named module files, bans `mod.rs` files.
+
+### Why is this bad?
+Having multiple module layout styles in a project can be confusing.
+
+### Example
+```
+src/
+  stuff/
+    stuff_files.rs
+    mod.rs
+  lib.rs
+```
+Use instead:
+```
+src/
+  stuff/
+    stuff_files.rs
+  stuff.rs
+  lib.rs
+```
\ No newline at end of file
diff --git a/src/docs/module_inception.txt b/src/docs/module_inception.txt
new file mode 100644
index 00000000000..d80a1b8d8fe
--- /dev/null
+++ b/src/docs/module_inception.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for modules that have the same name as their
+parent module
+
+### Why is this bad?
+A typical beginner mistake is to have `mod foo;` and
+again `mod foo { ..
+}` in `foo.rs`.
+The expectation is that items inside the inner `mod foo { .. }` are then
+available
+through `foo::x`, but they are only available through
+`foo::foo::x`.
+If this is done on purpose, it would be better to choose a more
+representative module name.
+
+### Example
+```
+// lib.rs
+mod foo;
+// foo.rs
+mod foo {
+    ...
+}
+```
\ No newline at end of file
diff --git a/src/docs/module_name_repetitions.txt b/src/docs/module_name_repetitions.txt
new file mode 100644
index 00000000000..3bc05d02780
--- /dev/null
+++ b/src/docs/module_name_repetitions.txt
@@ -0,0 +1,20 @@
+### What it does
+Detects type names that are prefixed or suffixed by the
+containing module's name.
+
+### Why is this bad?
+It requires the user to type the module name twice.
+
+### Example
+```
+mod cake {
+    struct BlackForestCake;
+}
+```
+
+Use instead:
+```
+mod cake {
+    struct BlackForest;
+}
+```
\ No newline at end of file
diff --git a/src/docs/modulo_arithmetic.txt b/src/docs/modulo_arithmetic.txt
new file mode 100644
index 00000000000..ff7296f3c5b
--- /dev/null
+++ b/src/docs/modulo_arithmetic.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for modulo arithmetic.
+
+### Why is this bad?
+The results of modulo (%) operation might differ
+depending on the language, when negative numbers are involved.
+If you interop with different languages it might be beneficial
+to double check all places that use modulo arithmetic.
+
+For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`.
+
+### Example
+```
+let x = -17 % 3;
+```
\ No newline at end of file
diff --git a/src/docs/modulo_one.txt b/src/docs/modulo_one.txt
new file mode 100644
index 00000000000..bc8f95b0be6
--- /dev/null
+++ b/src/docs/modulo_one.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for getting the remainder of a division by one or minus
+one.
+
+### Why is this bad?
+The result for a divisor of one can only ever be zero; for
+minus one it can cause panic/overflow (if the left operand is the minimal value of
+the respective integer type) or results in zero. No one will write such code
+deliberately, unless trying to win an Underhanded Rust Contest. Even for that
+contest, it's probably a bad idea. Use something more underhanded.
+
+### Example
+```
+let a = x % 1;
+let a = x % -1;
+```
\ No newline at end of file
diff --git a/src/docs/multi_assignments.txt b/src/docs/multi_assignments.txt
new file mode 100644
index 00000000000..ed1f1b420cb
--- /dev/null
+++ b/src/docs/multi_assignments.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for nested assignments.
+
+### Why is this bad?
+While this is in most cases already a type mismatch,
+the result of an assignment being `()` can throw off people coming from languages like python or C,
+where such assignments return a copy of the assigned value.
+
+### Example
+```
+a = b = 42;
+```
+Use instead:
+```
+b = 42;
+a = b;
+```
\ No newline at end of file
diff --git a/src/docs/multiple_crate_versions.txt b/src/docs/multiple_crate_versions.txt
new file mode 100644
index 00000000000..cf2d2c6abee
--- /dev/null
+++ b/src/docs/multiple_crate_versions.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks to see if multiple versions of a crate are being
+used.
+
+### Why is this bad?
+This bloats the size of targets, and can lead to
+confusing error messages when structs or traits are used interchangeably
+between different versions of a crate.
+
+### Known problems
+Because this can be caused purely by the dependencies
+themselves, it's not always possible to fix this issue.
+
+### Example
+```
+[dependencies]
+ctrlc = "=3.1.0"
+ansi_term = "=0.11.0"
+```
\ No newline at end of file
diff --git a/src/docs/multiple_inherent_impl.txt b/src/docs/multiple_inherent_impl.txt
new file mode 100644
index 00000000000..9d42286560c
--- /dev/null
+++ b/src/docs/multiple_inherent_impl.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for multiple inherent implementations of a struct
+
+### Why is this bad?
+Splitting the implementation of a type makes the code harder to navigate.
+
+### Example
+```
+struct X;
+impl X {
+    fn one() {}
+}
+impl X {
+    fn other() {}
+}
+```
+
+Could be written:
+
+```
+struct X;
+impl X {
+    fn one() {}
+    fn other() {}
+}
+```
\ No newline at end of file
diff --git a/src/docs/must_use_candidate.txt b/src/docs/must_use_candidate.txt
new file mode 100644
index 00000000000..70890346fe6
--- /dev/null
+++ b/src/docs/must_use_candidate.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for public functions that have no
+`#[must_use]` attribute, but return something not already marked
+must-use, have no mutable arg and mutate no statics.
+
+### Why is this bad?
+Not bad at all, this lint just shows places where
+you could add the attribute.
+
+### Known problems
+The lint only checks the arguments for mutable
+types without looking if they are actually changed. On the other hand,
+it also ignores a broad range of potentially interesting side effects,
+because we cannot decide whether the programmer intends the function to
+be called for the side effect or the result. Expect many false
+positives. At least we don't lint if the result type is unit or already
+`#[must_use]`.
+
+### Examples
+```
+// this could be annotated with `#[must_use]`.
+fn id<T>(t: T) -> T { t }
+```
\ No newline at end of file
diff --git a/src/docs/must_use_unit.txt b/src/docs/must_use_unit.txt
new file mode 100644
index 00000000000..cabbb23f865
--- /dev/null
+++ b/src/docs/must_use_unit.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for a `#[must_use]` attribute on
+unit-returning functions and methods.
+
+### Why is this bad?
+Unit values are useless. The attribute is likely
+a remnant of a refactoring that removed the return type.
+
+### Examples
+```
+#[must_use]
+fn useless() { }
+```
\ No newline at end of file
diff --git a/src/docs/mut_from_ref.txt b/src/docs/mut_from_ref.txt
new file mode 100644
index 00000000000..cc1da12549a
--- /dev/null
+++ b/src/docs/mut_from_ref.txt
@@ -0,0 +1,26 @@
+### What it does
+This lint checks for functions that take immutable references and return
+mutable ones. This will not trigger if no unsafe code exists as there
+are multiple safe functions which will do this transformation
+
+To be on the conservative side, if there's at least one mutable
+reference with the output lifetime, this lint will not trigger.
+
+### Why is this bad?
+Creating a mutable reference which can be repeatably derived from an
+immutable reference is unsound as it allows creating multiple live
+mutable references to the same object.
+
+This [error](https://github.com/rust-lang/rust/issues/39465) actually
+lead to an interim Rust release 1.15.1.
+
+### Known problems
+This pattern is used by memory allocators to allow allocating multiple
+objects while returning mutable references to each one. So long as
+different mutable references are returned each time such a function may
+be safe.
+
+### Example
+```
+fn foo(&Foo) -> &mut Bar { .. }
+```
\ No newline at end of file
diff --git a/src/docs/mut_mut.txt b/src/docs/mut_mut.txt
new file mode 100644
index 00000000000..0bd34dd24b2
--- /dev/null
+++ b/src/docs/mut_mut.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for instances of `mut mut` references.
+
+### Why is this bad?
+Multiple `mut`s don't add anything meaningful to the
+source. This is either a copy'n'paste error, or it shows a fundamental
+misunderstanding of references.
+
+### Example
+```
+let x = &mut &mut y;
+```
\ No newline at end of file
diff --git a/src/docs/mut_mutex_lock.txt b/src/docs/mut_mutex_lock.txt
new file mode 100644
index 00000000000..5e9ad8a3f17
--- /dev/null
+++ b/src/docs/mut_mutex_lock.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for `&mut Mutex::lock` calls
+
+### Why is this bad?
+`Mutex::lock` is less efficient than
+calling `Mutex::get_mut`. In addition you also have a statically
+guarantee that the mutex isn't locked, instead of just a runtime
+guarantee.
+
+### Example
+```
+use std::sync::{Arc, Mutex};
+
+let mut value_rc = Arc::new(Mutex::new(42_u8));
+let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
+
+let mut value = value_mutex.lock().unwrap();
+*value += 1;
+```
+Use instead:
+```
+use std::sync::{Arc, Mutex};
+
+let mut value_rc = Arc::new(Mutex::new(42_u8));
+let value_mutex = Arc::get_mut(&mut value_rc).unwrap();
+
+let value = value_mutex.get_mut().unwrap();
+*value += 1;
+```
\ No newline at end of file
diff --git a/src/docs/mut_range_bound.txt b/src/docs/mut_range_bound.txt
new file mode 100644
index 00000000000..e9c38a543b1
--- /dev/null
+++ b/src/docs/mut_range_bound.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for loops which have a range bound that is a mutable variable
+
+### Why is this bad?
+One might think that modifying the mutable variable changes the loop bounds
+
+### Known problems
+False positive when mutation is followed by a `break`, but the `break` is not immediately
+after the mutation:
+
+```
+let mut x = 5;
+for _ in 0..x {
+    x += 1; // x is a range bound that is mutated
+    ..; // some other expression
+    break; // leaves the loop, so mutation is not an issue
+}
+```
+
+False positive on nested loops ([#6072](https://github.com/rust-lang/rust-clippy/issues/6072))
+
+### Example
+```
+let mut foo = 42;
+for i in 0..foo {
+    foo -= 1;
+    println!("{}", i); // prints numbers from 0 to 42, not 0 to 21
+}
+```
\ No newline at end of file
diff --git a/src/docs/mutable_key_type.txt b/src/docs/mutable_key_type.txt
new file mode 100644
index 00000000000..15fe34f2bb5
--- /dev/null
+++ b/src/docs/mutable_key_type.txt
@@ -0,0 +1,61 @@
+### What it does
+Checks for sets/maps with mutable key types.
+
+### Why is this bad?
+All of `HashMap`, `HashSet`, `BTreeMap` and
+`BtreeSet` rely on either the hash or the order of keys be unchanging,
+so having types with interior mutability is a bad idea.
+
+### Known problems
+
+#### False Positives
+It's correct to use a struct that contains interior mutability as a key, when its
+implementation of `Hash` or `Ord` doesn't access any of the interior mutable types.
+However, this lint is unable to recognize this, so it will often cause false positives in
+theses cases.  The `bytes` crate is a great example of this.
+
+#### False Negatives
+For custom `struct`s/`enum`s, this lint is unable to check for interior mutability behind
+indirection.  For example, `struct BadKey<'a>(&'a Cell<usize>)` will be seen as immutable
+and cause a false negative if its implementation of `Hash`/`Ord` accesses the `Cell`.
+
+This lint does check a few cases for indirection.  Firstly, using some standard library
+types (`Option`, `Result`, `Box`, `Rc`, `Arc`, `Vec`, `VecDeque`, `BTreeMap` and
+`BTreeSet`) directly as keys (e.g. in `HashMap<Box<Cell<usize>>, ()>`) **will** trigger the
+lint, because the impls of `Hash`/`Ord` for these types directly call `Hash`/`Ord` on their
+contained type.
+
+Secondly, the implementations of `Hash` and `Ord` for raw pointers (`*const T` or `*mut T`)
+apply only to the **address** of the contained value.  Therefore, interior mutability
+behind raw pointers (e.g. in `HashSet<*mut Cell<usize>>`) can't impact the value of `Hash`
+or `Ord`, and therefore will not trigger this link.  For more info, see issue
+[#6745](https://github.com/rust-lang/rust-clippy/issues/6745).
+
+### Example
+```
+use std::cmp::{PartialEq, Eq};
+use std::collections::HashSet;
+use std::hash::{Hash, Hasher};
+use std::sync::atomic::AtomicUsize;
+
+struct Bad(AtomicUsize);
+impl PartialEq for Bad {
+    fn eq(&self, rhs: &Self) -> bool {
+         ..
+; unimplemented!();
+    }
+}
+
+impl Eq for Bad {}
+
+impl Hash for Bad {
+    fn hash<H: Hasher>(&self, h: &mut H) {
+        ..
+; unimplemented!();
+    }
+}
+
+fn main() {
+    let _: HashSet<Bad> = HashSet::new();
+}
+```
\ No newline at end of file
diff --git a/src/docs/mutex_atomic.txt b/src/docs/mutex_atomic.txt
new file mode 100644
index 00000000000..062ac8b323b
--- /dev/null
+++ b/src/docs/mutex_atomic.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usages of `Mutex<X>` where an atomic will do.
+
+### Why is this bad?
+Using a mutex just to make access to a plain bool or
+reference sequential is shooting flies with cannons.
+`std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and
+faster.
+
+### Known problems
+This lint cannot detect if the mutex is actually used
+for waiting before a critical section.
+
+### Example
+```
+let x = Mutex::new(&y);
+```
+
+Use instead:
+```
+let x = AtomicBool::new(y);
+```
\ No newline at end of file
diff --git a/src/docs/mutex_integer.txt b/src/docs/mutex_integer.txt
new file mode 100644
index 00000000000..f9dbdfb904c
--- /dev/null
+++ b/src/docs/mutex_integer.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usages of `Mutex<X>` where `X` is an integral
+type.
+
+### Why is this bad?
+Using a mutex just to make access to a plain integer
+sequential is
+shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster.
+
+### Known problems
+This lint cannot detect if the mutex is actually used
+for waiting before a critical section.
+
+### Example
+```
+let x = Mutex::new(0usize);
+```
+
+Use instead:
+```
+let x = AtomicUsize::new(0usize);
+```
\ No newline at end of file
diff --git a/src/docs/naive_bytecount.txt b/src/docs/naive_bytecount.txt
new file mode 100644
index 00000000000..24659dc79ae
--- /dev/null
+++ b/src/docs/naive_bytecount.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for naive byte counts
+
+### Why is this bad?
+The [`bytecount`](https://crates.io/crates/bytecount)
+crate has methods to count your bytes faster, especially for large slices.
+
+### Known problems
+If you have predominantly small slices, the
+`bytecount::count(..)` method may actually be slower. However, if you can
+ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be
+faster in those cases.
+
+### Example
+```
+let count = vec.iter().filter(|x| **x == 0u8).count();
+```
+
+Use instead:
+```
+let count = bytecount::count(&vec, 0u8);
+```
\ No newline at end of file
diff --git a/src/docs/needless_arbitrary_self_type.txt b/src/docs/needless_arbitrary_self_type.txt
new file mode 100644
index 00000000000..8216a3a3fb6
--- /dev/null
+++ b/src/docs/needless_arbitrary_self_type.txt
@@ -0,0 +1,44 @@
+### What it does
+The lint checks for `self` in fn parameters that
+specify the `Self`-type explicitly
+### Why is this bad?
+Increases the amount and decreases the readability of code
+
+### Example
+```
+enum ValType {
+    I32,
+    I64,
+    F32,
+    F64,
+}
+
+impl ValType {
+    pub fn bytes(self: Self) -> usize {
+        match self {
+            Self::I32 | Self::F32 => 4,
+            Self::I64 | Self::F64 => 8,
+        }
+    }
+}
+```
+
+Could be rewritten as
+
+```
+enum ValType {
+    I32,
+    I64,
+    F32,
+    F64,
+}
+
+impl ValType {
+    pub fn bytes(self) -> usize {
+        match self {
+            Self::I32 | Self::F32 => 4,
+            Self::I64 | Self::F64 => 8,
+        }
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/needless_bitwise_bool.txt b/src/docs/needless_bitwise_bool.txt
new file mode 100644
index 00000000000..fcd7b730aaa
--- /dev/null
+++ b/src/docs/needless_bitwise_bool.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using
+a lazy and.
+
+### Why is this bad?
+The bitwise operators do not support short-circuiting, so it may hinder code performance.
+Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold`
+
+### Known problems
+This lint evaluates only when the right side is determined to have no side effects. At this time, that
+determination is quite conservative.
+
+### Example
+```
+let (x,y) = (true, false);
+if x & !y {} // where both x and y are booleans
+```
+Use instead:
+```
+let (x,y) = (true, false);
+if x && !y {}
+```
\ No newline at end of file
diff --git a/src/docs/needless_bool.txt b/src/docs/needless_bool.txt
new file mode 100644
index 00000000000..b5c78871f14
--- /dev/null
+++ b/src/docs/needless_bool.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for expressions of the form `if c { true } else {
+false }` (or vice versa) and suggests using the condition directly.
+
+### Why is this bad?
+Redundant code.
+
+### Known problems
+Maybe false positives: Sometimes, the two branches are
+painstakingly documented (which we, of course, do not detect), so they *may*
+have some value. Even then, the documentation can be rewritten to match the
+shorter code.
+
+### Example
+```
+if x {
+    false
+} else {
+    true
+}
+```
+
+Use instead:
+```
+!x
+```
\ No newline at end of file
diff --git a/src/docs/needless_borrow.txt b/src/docs/needless_borrow.txt
new file mode 100644
index 00000000000..4debcf47372
--- /dev/null
+++ b/src/docs/needless_borrow.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for address of operations (`&`) that are going to
+be dereferenced immediately by the compiler.
+
+### Why is this bad?
+Suggests that the receiver of the expression borrows
+the expression.
+
+### Example
+```
+fn fun(_a: &i32) {}
+
+let x: &i32 = &&&&&&5;
+fun(&x);
+```
+
+Use instead:
+```
+let x: &i32 = &5;
+fun(x);
+```
\ No newline at end of file
diff --git a/src/docs/needless_borrowed_reference.txt b/src/docs/needless_borrowed_reference.txt
new file mode 100644
index 00000000000..55faa0cf571
--- /dev/null
+++ b/src/docs/needless_borrowed_reference.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for bindings that destructure a reference and borrow the inner
+value with `&ref`.
+
+### Why is this bad?
+This pattern has no effect in almost all cases.
+
+### Known problems
+In some cases, `&ref` is needed to avoid a lifetime mismatch error.
+Example:
+```
+fn foo(a: &Option<String>, b: &Option<String>) {
+    match (a, b) {
+        (None, &ref c) | (&ref c, None) => (),
+        (&Some(ref c), _) => (),
+    };
+}
+```
+
+### Example
+```
+let mut v = Vec::<String>::new();
+v.iter_mut().filter(|&ref a| a.is_empty());
+```
+
+Use instead:
+```
+let mut v = Vec::<String>::new();
+v.iter_mut().filter(|a| a.is_empty());
+```
\ No newline at end of file
diff --git a/src/docs/needless_collect.txt b/src/docs/needless_collect.txt
new file mode 100644
index 00000000000..275c39afc9d
--- /dev/null
+++ b/src/docs/needless_collect.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for functions collecting an iterator when collect
+is not needed.
+
+### Why is this bad?
+`collect` causes the allocation of a new data structure,
+when this allocation may not be needed.
+
+### Example
+```
+let len = iterator.clone().collect::<Vec<_>>().len();
+// should be
+let len = iterator.count();
+```
\ No newline at end of file
diff --git a/src/docs/needless_continue.txt b/src/docs/needless_continue.txt
new file mode 100644
index 00000000000..2cee621c1af
--- /dev/null
+++ b/src/docs/needless_continue.txt
@@ -0,0 +1,61 @@
+### What it does
+The lint checks for `if`-statements appearing in loops
+that contain a `continue` statement in either their main blocks or their
+`else`-blocks, when omitting the `else`-block possibly with some
+rearrangement of code can make the code easier to understand.
+
+### Why is this bad?
+Having explicit `else` blocks for `if` statements
+containing `continue` in their THEN branch adds unnecessary branching and
+nesting to the code. Having an else block containing just `continue` can
+also be better written by grouping the statements following the whole `if`
+statement within the THEN block and omitting the else block completely.
+
+### Example
+```
+while condition() {
+    update_condition();
+    if x {
+        // ...
+    } else {
+        continue;
+    }
+    println!("Hello, world");
+}
+```
+
+Could be rewritten as
+
+```
+while condition() {
+    update_condition();
+    if x {
+        // ...
+        println!("Hello, world");
+    }
+}
+```
+
+As another example, the following code
+
+```
+loop {
+    if waiting() {
+        continue;
+    } else {
+        // Do something useful
+    }
+    # break;
+}
+```
+Could be rewritten as
+
+```
+loop {
+    if waiting() {
+        continue;
+    }
+    // Do something useful
+    # break;
+}
+```
\ No newline at end of file
diff --git a/src/docs/needless_doctest_main.txt b/src/docs/needless_doctest_main.txt
new file mode 100644
index 00000000000..8f91a7baa71
--- /dev/null
+++ b/src/docs/needless_doctest_main.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for `fn main() { .. }` in doctests
+
+### Why is this bad?
+The test can be shorter (and likely more readable)
+if the `fn main()` is left implicit.
+
+### Examples
+```
+/// An example of a doctest with a `main()` function
+///
+/// # Examples
+///
+/// ```
+/// fn main() {
+///     // this needs not be in an `fn`
+/// }
+/// ```
+fn needless_main() {
+    unimplemented!();
+}
+```
\ No newline at end of file
diff --git a/src/docs/needless_for_each.txt b/src/docs/needless_for_each.txt
new file mode 100644
index 00000000000..9ae6dd360c8
--- /dev/null
+++ b/src/docs/needless_for_each.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for usage of `for_each` that would be more simply written as a
+`for` loop.
+
+### Why is this bad?
+`for_each` may be used after applying iterator transformers like
+`filter` for better readability and performance. It may also be used to fit a simple
+operation on one line.
+But when none of these apply, a simple `for` loop is more idiomatic.
+
+### Example
+```
+let v = vec![0, 1, 2];
+v.iter().for_each(|elem| {
+    println!("{}", elem);
+})
+```
+Use instead:
+```
+let v = vec![0, 1, 2];
+for elem in v.iter() {
+    println!("{}", elem);
+}
+```
\ No newline at end of file
diff --git a/src/docs/needless_late_init.txt b/src/docs/needless_late_init.txt
new file mode 100644
index 00000000000..9e7bbcea998
--- /dev/null
+++ b/src/docs/needless_late_init.txt
@@ -0,0 +1,42 @@
+### What it does
+Checks for late initializations that can be replaced by a `let` statement
+with an initializer.
+
+### Why is this bad?
+Assigning in the `let` statement is less repetitive.
+
+### Example
+```
+let a;
+a = 1;
+
+let b;
+match 3 {
+    0 => b = "zero",
+    1 => b = "one",
+    _ => b = "many",
+}
+
+let c;
+if true {
+    c = 1;
+} else {
+    c = -1;
+}
+```
+Use instead:
+```
+let a = 1;
+
+let b = match 3 {
+    0 => "zero",
+    1 => "one",
+    _ => "many",
+};
+
+let c = if true {
+    1
+} else {
+    -1
+};
+```
\ No newline at end of file
diff --git a/src/docs/needless_lifetimes.txt b/src/docs/needless_lifetimes.txt
new file mode 100644
index 00000000000..b280caa66b5
--- /dev/null
+++ b/src/docs/needless_lifetimes.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for lifetime annotations which can be removed by
+relying on lifetime elision.
+
+### Why is this bad?
+The additional lifetimes make the code look more
+complicated, while there is nothing out of the ordinary going on. Removing
+them leads to more readable code.
+
+### Known problems
+- We bail out if the function has a `where` clause where lifetimes
+are mentioned due to potential false positives.
+- Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the
+placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`.
+
+### Example
+```
+// Unnecessary lifetime annotations
+fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 {
+    x
+}
+```
+
+Use instead:
+```
+fn elided(x: &u8, y: u8) -> &u8 {
+    x
+}
+```
\ No newline at end of file
diff --git a/src/docs/needless_match.txt b/src/docs/needless_match.txt
new file mode 100644
index 00000000000..92b40a5df64
--- /dev/null
+++ b/src/docs/needless_match.txt
@@ -0,0 +1,36 @@
+### What it does
+Checks for unnecessary `match` or match-like `if let` returns for `Option` and `Result`
+when function signatures are the same.
+
+### Why is this bad?
+This `match` block does nothing and might not be what the coder intended.
+
+### Example
+```
+fn foo() -> Result<(), i32> {
+    match result {
+        Ok(val) => Ok(val),
+        Err(err) => Err(err),
+    }
+}
+
+fn bar() -> Option<i32> {
+    if let Some(val) = option {
+        Some(val)
+    } else {
+        None
+    }
+}
+```
+
+Could be replaced as
+
+```
+fn foo() -> Result<(), i32> {
+    result
+}
+
+fn bar() -> Option<i32> {
+    option
+}
+```
\ No newline at end of file
diff --git a/src/docs/needless_option_as_deref.txt b/src/docs/needless_option_as_deref.txt
new file mode 100644
index 00000000000..226396c97ac
--- /dev/null
+++ b/src/docs/needless_option_as_deref.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for no-op uses of `Option::{as_deref, as_deref_mut}`,
+for example, `Option<&T>::as_deref()` returns the same type.
+
+### Why is this bad?
+Redundant code and improving readability.
+
+### Example
+```
+let a = Some(&1);
+let b = a.as_deref(); // goes from Option<&i32> to Option<&i32>
+```
+
+Use instead:
+```
+let a = Some(&1);
+let b = a;
+```
\ No newline at end of file
diff --git a/src/docs/needless_option_take.txt b/src/docs/needless_option_take.txt
new file mode 100644
index 00000000000..6bac65a13b5
--- /dev/null
+++ b/src/docs/needless_option_take.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for calling `take` function after `as_ref`.
+
+### Why is this bad?
+Redundant code. `take` writes `None` to its argument.
+In this case the modification is useless as it's a temporary that cannot be read from afterwards.
+
+### Example
+```
+let x = Some(3);
+x.as_ref().take();
+```
+Use instead:
+```
+let x = Some(3);
+x.as_ref();
+```
\ No newline at end of file
diff --git a/src/docs/needless_parens_on_range_literals.txt b/src/docs/needless_parens_on_range_literals.txt
new file mode 100644
index 00000000000..85fab10cb5f
--- /dev/null
+++ b/src/docs/needless_parens_on_range_literals.txt
@@ -0,0 +1,23 @@
+### What it does
+The lint checks for parenthesis on literals in range statements that are
+superfluous.
+
+### Why is this bad?
+Having superfluous parenthesis makes the code less readable
+overhead when reading.
+
+### Example
+
+```
+for i in (0)..10 {
+  println!("{i}");
+}
+```
+
+Use instead:
+
+```
+for i in 0..10 {
+  println!("{i}");
+}
+```
\ No newline at end of file
diff --git a/src/docs/needless_pass_by_value.txt b/src/docs/needless_pass_by_value.txt
new file mode 100644
index 00000000000..58c420b19f6
--- /dev/null
+++ b/src/docs/needless_pass_by_value.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for functions taking arguments by value, but not
+consuming them in its
+body.
+
+### Why is this bad?
+Taking arguments by reference is more flexible and can
+sometimes avoid
+unnecessary allocations.
+
+### Known problems
+* This lint suggests taking an argument by reference,
+however sometimes it is better to let users decide the argument type
+(by using `Borrow` trait, for example), depending on how the function is used.
+
+### Example
+```
+fn foo(v: Vec<i32>) {
+    assert_eq!(v.len(), 42);
+}
+```
+should be
+```
+fn foo(v: &[i32]) {
+    assert_eq!(v.len(), 42);
+}
+```
\ No newline at end of file
diff --git a/src/docs/needless_question_mark.txt b/src/docs/needless_question_mark.txt
new file mode 100644
index 00000000000..540739fd45f
--- /dev/null
+++ b/src/docs/needless_question_mark.txt
@@ -0,0 +1,43 @@
+### What it does
+Suggests alternatives for useless applications of `?` in terminating expressions
+
+### Why is this bad?
+There's no reason to use `?` to short-circuit when execution of the body will end there anyway.
+
+### Example
+```
+struct TO {
+    magic: Option<usize>,
+}
+
+fn f(to: TO) -> Option<usize> {
+    Some(to.magic?)
+}
+
+struct TR {
+    magic: Result<usize, bool>,
+}
+
+fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
+    tr.and_then(|t| Ok(t.magic?))
+}
+
+```
+Use instead:
+```
+struct TO {
+    magic: Option<usize>,
+}
+
+fn f(to: TO) -> Option<usize> {
+   to.magic
+}
+
+struct TR {
+    magic: Result<usize, bool>,
+}
+
+fn g(tr: Result<TR, bool>) -> Result<usize, bool> {
+    tr.and_then(|t| t.magic)
+}
+```
\ No newline at end of file
diff --git a/src/docs/needless_range_loop.txt b/src/docs/needless_range_loop.txt
new file mode 100644
index 00000000000..583c09b2849
--- /dev/null
+++ b/src/docs/needless_range_loop.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for looping over the range of `0..len` of some
+collection just to get the values by index.
+
+### Why is this bad?
+Just iterating the collection itself makes the intent
+more clear and is probably faster.
+
+### Example
+```
+let vec = vec!['a', 'b', 'c'];
+for i in 0..vec.len() {
+    println!("{}", vec[i]);
+}
+```
+
+Use instead:
+```
+let vec = vec!['a', 'b', 'c'];
+for i in vec {
+    println!("{}", i);
+}
+```
\ No newline at end of file
diff --git a/src/docs/needless_return.txt b/src/docs/needless_return.txt
new file mode 100644
index 00000000000..48782cb0ca8
--- /dev/null
+++ b/src/docs/needless_return.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for return statements at the end of a block.
+
+### Why is this bad?
+Removing the `return` and semicolon will make the code
+more rusty.
+
+### Example
+```
+fn foo(x: usize) -> usize {
+    return x;
+}
+```
+simplify to
+```
+fn foo(x: usize) -> usize {
+    x
+}
+```
\ No newline at end of file
diff --git a/src/docs/needless_splitn.txt b/src/docs/needless_splitn.txt
new file mode 100644
index 00000000000..b10a84fbc42
--- /dev/null
+++ b/src/docs/needless_splitn.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same.
+### Why is this bad?
+The function `split` is simpler and there is no performance difference in these cases, considering
+that both functions return a lazy iterator.
+### Example
+```
+let str = "key=value=add";
+let _ = str.splitn(3, '=').next().unwrap();
+```
+
+Use instead:
+```
+let str = "key=value=add";
+let _ = str.split('=').next().unwrap();
+```
\ No newline at end of file
diff --git a/src/docs/needless_update.txt b/src/docs/needless_update.txt
new file mode 100644
index 00000000000..82adabf6482
--- /dev/null
+++ b/src/docs/needless_update.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for needlessly including a base struct on update
+when all fields are changed anyway.
+
+This lint is not applied to structs marked with
+[non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html).
+
+### Why is this bad?
+This will cost resources (because the base has to be
+somewhere), and make the code less readable.
+
+### Example
+```
+Point {
+    x: 1,
+    y: 1,
+    z: 1,
+    ..zero_point
+};
+```
+
+Use instead:
+```
+// Missing field `z`
+Point {
+    x: 1,
+    y: 1,
+    ..zero_point
+};
+```
\ No newline at end of file
diff --git a/src/docs/neg_cmp_op_on_partial_ord.txt b/src/docs/neg_cmp_op_on_partial_ord.txt
new file mode 100644
index 00000000000..fa55c6cfd74
--- /dev/null
+++ b/src/docs/neg_cmp_op_on_partial_ord.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for the usage of negated comparison operators on types which only implement
+`PartialOrd` (e.g., `f64`).
+
+### Why is this bad?
+These operators make it easy to forget that the underlying types actually allow not only three
+potential Orderings (Less, Equal, Greater) but also a fourth one (Uncomparable). This is
+especially easy to miss if the operator based comparison result is negated.
+
+### Example
+```
+let a = 1.0;
+let b = f64::NAN;
+
+let not_less_or_equal = !(a <= b);
+```
+
+Use instead:
+```
+use std::cmp::Ordering;
+
+let _not_less_or_equal = match a.partial_cmp(&b) {
+    None | Some(Ordering::Greater) => true,
+    _ => false,
+};
+```
\ No newline at end of file
diff --git a/src/docs/neg_multiply.txt b/src/docs/neg_multiply.txt
new file mode 100644
index 00000000000..4e8b096eb9c
--- /dev/null
+++ b/src/docs/neg_multiply.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for multiplication by -1 as a form of negation.
+
+### Why is this bad?
+It's more readable to just negate.
+
+### Known problems
+This only catches integers (for now).
+
+### Example
+```
+let a = x * -1;
+```
+
+Use instead:
+```
+let a = -x;
+```
\ No newline at end of file
diff --git a/src/docs/negative_feature_names.txt b/src/docs/negative_feature_names.txt
new file mode 100644
index 00000000000..01ee9efb318
--- /dev/null
+++ b/src/docs/negative_feature_names.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for negative feature names with prefix `no-` or `not-`
+
+### Why is this bad?
+Features are supposed to be additive, and negatively-named features violate it.
+
+### Example
+```
+[features]
+default = []
+no-abc = []
+not-def = []
+
+```
+Use instead:
+```
+[features]
+default = ["abc", "def"]
+abc = []
+def = []
+
+```
\ No newline at end of file
diff --git a/src/docs/never_loop.txt b/src/docs/never_loop.txt
new file mode 100644
index 00000000000..737ccf415cb
--- /dev/null
+++ b/src/docs/never_loop.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for loops that will always `break`, `return` or
+`continue` an outer loop.
+
+### Why is this bad?
+This loop never loops, all it does is obfuscating the
+code.
+
+### Example
+```
+loop {
+    ..;
+    break;
+}
+```
\ No newline at end of file
diff --git a/src/docs/new_ret_no_self.txt b/src/docs/new_ret_no_self.txt
new file mode 100644
index 00000000000..291bad24a64
--- /dev/null
+++ b/src/docs/new_ret_no_self.txt
@@ -0,0 +1,47 @@
+### What it does
+Checks for `new` not returning a type that contains `Self`.
+
+### Why is this bad?
+As a convention, `new` methods are used to make a new
+instance of a type.
+
+### Example
+In an impl block:
+```
+impl Foo {
+    fn new() -> NotAFoo {
+    }
+}
+```
+
+```
+struct Bar(Foo);
+impl Foo {
+    // Bad. The type name must contain `Self`
+    fn new() -> Bar {
+    }
+}
+```
+
+```
+impl Foo {
+    // Good. Return type contains `Self`
+    fn new() -> Result<Foo, FooError> {
+    }
+}
+```
+
+Or in a trait definition:
+```
+pub trait Trait {
+    // Bad. The type name must contain `Self`
+    fn new();
+}
+```
+
+```
+pub trait Trait {
+    // Good. Return type contains `Self`
+    fn new() -> Self;
+}
+```
\ No newline at end of file
diff --git a/src/docs/new_without_default.txt b/src/docs/new_without_default.txt
new file mode 100644
index 00000000000..662d39c8efd
--- /dev/null
+++ b/src/docs/new_without_default.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for public types with a `pub fn new() -> Self` method and no
+implementation of
+[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html).
+
+### Why is this bad?
+The user might expect to be able to use
+[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
+type can be constructed without arguments.
+
+### Example
+```
+pub struct Foo(Bar);
+
+impl Foo {
+    pub fn new() -> Self {
+        Foo(Bar::new())
+    }
+}
+```
+
+To fix the lint, add a `Default` implementation that delegates to `new`:
+
+```
+pub struct Foo(Bar);
+
+impl Default for Foo {
+    fn default() -> Self {
+        Foo::new()
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/no_effect.txt b/src/docs/no_effect.txt
new file mode 100644
index 00000000000..d4cc08fa8a7
--- /dev/null
+++ b/src/docs/no_effect.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for statements which have no effect.
+
+### Why is this bad?
+Unlike dead code, these statements are actually
+executed. However, as they have no effect, all they do is make the code less
+readable.
+
+### Example
+```
+0;
+```
\ No newline at end of file
diff --git a/src/docs/no_effect_replace.txt b/src/docs/no_effect_replace.txt
new file mode 100644
index 00000000000..646d45287ef
--- /dev/null
+++ b/src/docs/no_effect_replace.txt
@@ -0,0 +1,11 @@
+### What it does
+Checks for `replace` statements which have no effect.
+
+### Why is this bad?
+It's either a mistake or confusing.
+
+### Example
+```
+"1234".replace("12", "12");
+"1234".replacen("12", "12", 1);
+```
\ No newline at end of file
diff --git a/src/docs/no_effect_underscore_binding.txt b/src/docs/no_effect_underscore_binding.txt
new file mode 100644
index 00000000000..972f60dd01e
--- /dev/null
+++ b/src/docs/no_effect_underscore_binding.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for binding to underscore prefixed variable without side-effects.
+
+### Why is this bad?
+Unlike dead code, these bindings are actually
+executed. However, as they have no effect and shouldn't be used further on, all they
+do is make the code less readable.
+
+### Known problems
+Further usage of this variable is not checked, which can lead to false positives if it is
+used later in the code.
+
+### Example
+```
+let _i_serve_no_purpose = 1;
+```
\ No newline at end of file
diff --git a/src/docs/non_ascii_literal.txt b/src/docs/non_ascii_literal.txt
new file mode 100644
index 00000000000..164902b4726
--- /dev/null
+++ b/src/docs/non_ascii_literal.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for non-ASCII characters in string and char literals.
+
+### Why is this bad?
+Yeah, we know, the 90's called and wanted their charset
+back. Even so, there still are editors and other programs out there that
+don't work well with Unicode. So if the code is meant to be used
+internationally, on multiple operating systems, or has other portability
+requirements, activating this lint could be useful.
+
+### Example
+```
+let x = String::from("€");
+```
+
+Use instead:
+```
+let x = String::from("\u{20ac}");
+```
\ No newline at end of file
diff --git a/src/docs/non_octal_unix_permissions.txt b/src/docs/non_octal_unix_permissions.txt
new file mode 100644
index 00000000000..4a468e94db1
--- /dev/null
+++ b/src/docs/non_octal_unix_permissions.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for non-octal values used to set Unix file permissions.
+
+### Why is this bad?
+They will be converted into octal, creating potentially
+unintended file permissions.
+
+### Example
+```
+use std::fs::OpenOptions;
+use std::os::unix::fs::OpenOptionsExt;
+
+let mut options = OpenOptions::new();
+options.mode(644);
+```
+Use instead:
+```
+use std::fs::OpenOptions;
+use std::os::unix::fs::OpenOptionsExt;
+
+let mut options = OpenOptions::new();
+options.mode(0o644);
+```
\ No newline at end of file
diff --git a/src/docs/non_send_fields_in_send_ty.txt b/src/docs/non_send_fields_in_send_ty.txt
new file mode 100644
index 00000000000..11e6f6e162c
--- /dev/null
+++ b/src/docs/non_send_fields_in_send_ty.txt
@@ -0,0 +1,36 @@
+### What it does
+This lint warns about a `Send` implementation for a type that
+contains fields that are not safe to be sent across threads.
+It tries to detect fields that can cause a soundness issue
+when sent to another thread (e.g., `Rc`) while allowing `!Send` fields
+that are expected to exist in a `Send` type, such as raw pointers.
+
+### Why is this bad?
+Sending the struct to another thread effectively sends all of its fields,
+and the fields that do not implement `Send` can lead to soundness bugs
+such as data races when accessed in a thread
+that is different from the thread that created it.
+
+See:
+* [*The Rustonomicon* about *Send and Sync*](https://doc.rust-lang.org/nomicon/send-and-sync.html)
+* [The documentation of `Send`](https://doc.rust-lang.org/std/marker/trait.Send.html)
+
+### Known Problems
+This lint relies on heuristics to distinguish types that are actually
+unsafe to be sent across threads and `!Send` types that are expected to
+exist in  `Send` type. Its rule can filter out basic cases such as
+`Vec<*const T>`, but it's not perfect. Feel free to create an issue if
+you have a suggestion on how this heuristic can be improved.
+
+### Example
+```
+struct ExampleStruct<T> {
+    rc_is_not_send: Rc<String>,
+    unbounded_generic_field: T,
+}
+
+// This impl is unsound because it allows sending `!Send` types through `ExampleStruct`
+unsafe impl<T> Send for ExampleStruct<T> {}
+```
+Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html)
+or specify correct bounds on generic type parameters (`T: Send`).
\ No newline at end of file
diff --git a/src/docs/nonminimal_bool.txt b/src/docs/nonminimal_bool.txt
new file mode 100644
index 00000000000..488980ddf02
--- /dev/null
+++ b/src/docs/nonminimal_bool.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for boolean expressions that can be written more
+concisely.
+
+### Why is this bad?
+Readability of boolean expressions suffers from
+unnecessary duplication.
+
+### Known problems
+Ignores short circuiting behavior of `||` and
+`&&`. Ignores `|`, `&` and `^`.
+
+### Example
+```
+if a && true {}
+if !(a == b) {}
+```
+
+Use instead:
+```
+if a {}
+if a != b {}
+```
\ No newline at end of file
diff --git a/src/docs/nonsensical_open_options.txt b/src/docs/nonsensical_open_options.txt
new file mode 100644
index 00000000000..7a95443b51a
--- /dev/null
+++ b/src/docs/nonsensical_open_options.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for duplicate open options as well as combinations
+that make no sense.
+
+### Why is this bad?
+In the best case, the code will be harder to read than
+necessary. I don't know the worst case.
+
+### Example
+```
+use std::fs::OpenOptions;
+
+OpenOptions::new().read(true).truncate(true);
+```
\ No newline at end of file
diff --git a/src/docs/nonstandard_macro_braces.txt b/src/docs/nonstandard_macro_braces.txt
new file mode 100644
index 00000000000..7e8d0d2d33b
--- /dev/null
+++ b/src/docs/nonstandard_macro_braces.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks that common macros are used with consistent bracing.
+
+### Why is this bad?
+This is mostly a consistency lint although using () or []
+doesn't give you a semicolon in item position, which can be unexpected.
+
+### Example
+```
+vec!{1, 2, 3};
+```
+Use instead:
+```
+vec![1, 2, 3];
+```
\ No newline at end of file
diff --git a/src/docs/not_unsafe_ptr_arg_deref.txt b/src/docs/not_unsafe_ptr_arg_deref.txt
new file mode 100644
index 00000000000..31355fbb7b6
--- /dev/null
+++ b/src/docs/not_unsafe_ptr_arg_deref.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for public functions that dereference raw pointer
+arguments but are not marked `unsafe`.
+
+### Why is this bad?
+The function should probably be marked `unsafe`, since
+for an arbitrary raw pointer, there is no way of telling for sure if it is
+valid.
+
+### Known problems
+* It does not check functions recursively so if the pointer is passed to a
+private non-`unsafe` function which does the dereferencing, the lint won't
+trigger.
+* It only checks for arguments whose type are raw pointers, not raw pointers
+got from an argument in some other way (`fn foo(bar: &[*const u8])` or
+`some_argument.get_raw_ptr()`).
+
+### Example
+```
+pub fn foo(x: *const u8) {
+    println!("{}", unsafe { *x });
+}
+```
+
+Use instead:
+```
+pub unsafe fn foo(x: *const u8) {
+    println!("{}", unsafe { *x });
+}
+```
\ No newline at end of file
diff --git a/src/docs/obfuscated_if_else.txt b/src/docs/obfuscated_if_else.txt
new file mode 100644
index 00000000000..638f63b0db5
--- /dev/null
+++ b/src/docs/obfuscated_if_else.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for usages of `.then_some(..).unwrap_or(..)`
+
+### Why is this bad?
+This can be written more clearly with `if .. else ..`
+
+### Limitations
+This lint currently only looks for usages of
+`.then_some(..).unwrap_or(..)`, but will be expanded
+to account for similar patterns.
+
+### Example
+```
+let x = true;
+x.then_some("a").unwrap_or("b");
+```
+Use instead:
+```
+let x = true;
+if x { "a" } else { "b" };
+```
\ No newline at end of file
diff --git a/src/docs/octal_escapes.txt b/src/docs/octal_escapes.txt
new file mode 100644
index 00000000000..eee82058715
--- /dev/null
+++ b/src/docs/octal_escapes.txt
@@ -0,0 +1,33 @@
+### What it does
+Checks for `\0` escapes in string and byte literals that look like octal
+character escapes in C.
+
+### Why is this bad?
+
+C and other languages support octal character escapes in strings, where
+a backslash is followed by up to three octal digits. For example, `\033`
+stands for the ASCII character 27 (ESC). Rust does not support this
+notation, but has the escape code `\0` which stands for a null
+byte/character, and any following digits do not form part of the escape
+sequence. Therefore, `\033` is not a compiler error but the result may
+be surprising.
+
+### Known problems
+The actual meaning can be the intended one. `\x00` can be used in these
+cases to be unambiguous.
+
+The lint does not trigger for format strings in `print!()`, `write!()`
+and friends since the string is already preprocessed when Clippy lints
+can see it.
+
+### Example
+```
+let one = "\033[1m Bold? \033[0m";  // \033 intended as escape
+let two = "\033\0";                 // \033 intended as null-3-3
+```
+
+Use instead:
+```
+let one = "\x1b[1mWill this be bold?\x1b[0m";
+let two = "\x0033\x00";
+```
\ No newline at end of file
diff --git a/src/docs/ok_expect.txt b/src/docs/ok_expect.txt
new file mode 100644
index 00000000000..fd5205d49dc
--- /dev/null
+++ b/src/docs/ok_expect.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `ok().expect(..)`.
+
+### Why is this bad?
+Because you usually call `expect()` on the `Result`
+directly to get a better error message.
+
+### Known problems
+The error type needs to implement `Debug`
+
+### Example
+```
+x.ok().expect("why did I do this again?");
+```
+
+Use instead:
+```
+x.expect("why did I do this again?");
+```
\ No newline at end of file
diff --git a/src/docs/only_used_in_recursion.txt b/src/docs/only_used_in_recursion.txt
new file mode 100644
index 00000000000..f19f47ff9eb
--- /dev/null
+++ b/src/docs/only_used_in_recursion.txt
@@ -0,0 +1,58 @@
+### What it does
+Checks for arguments that are only used in recursion with no side-effects.
+
+### Why is this bad?
+It could contain a useless calculation and can make function simpler.
+
+The arguments can be involved in calculations and assignments but as long as
+the calculations have no side-effects (function calls or mutating dereference)
+and the assigned variables are also only in recursion, it is useless.
+
+### Known problems
+Too many code paths in the linting code are currently untested and prone to produce false
+positives or are prone to have performance implications.
+
+In some cases, this would not catch all useless arguments.
+
+```
+fn foo(a: usize, b: usize) -> usize {
+    let f = |x| x + 1;
+
+    if a == 0 {
+        1
+    } else {
+        foo(a - 1, f(b))
+    }
+}
+```
+
+For example, the argument `b` is only used in recursion, but the lint would not catch it.
+
+List of some examples that can not be caught:
+- binary operation of non-primitive types
+- closure usage
+- some `break` relative operations
+- struct pattern binding
+
+Also, when you recurse the function name with path segments, it is not possible to detect.
+
+### Example
+```
+fn f(a: usize, b: usize) -> usize {
+    if a == 0 {
+        1
+    } else {
+        f(a - 1, b + 1)
+    }
+}
+```
+Use instead:
+```
+fn f(a: usize) -> usize {
+    if a == 0 {
+        1
+    } else {
+        f(a - 1)
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/op_ref.txt b/src/docs/op_ref.txt
new file mode 100644
index 00000000000..7a7ed1bc9ba
--- /dev/null
+++ b/src/docs/op_ref.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for arguments to `==` which have their address
+taken to satisfy a bound
+and suggests to dereference the other argument instead
+
+### Why is this bad?
+It is more idiomatic to dereference the other argument.
+
+### Example
+```
+&x == y
+```
+
+Use instead:
+```
+x == *y
+```
\ No newline at end of file
diff --git a/src/docs/option_as_ref_deref.txt b/src/docs/option_as_ref_deref.txt
new file mode 100644
index 00000000000..ad7411d3d4b
--- /dev/null
+++ b/src/docs/option_as_ref_deref.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.as_deref()`.
+
+### Example
+```
+opt.as_ref().map(String::as_str)
+```
+Can be written as
+```
+opt.as_deref()
+```
\ No newline at end of file
diff --git a/src/docs/option_env_unwrap.txt b/src/docs/option_env_unwrap.txt
new file mode 100644
index 00000000000..c952cba8e26
--- /dev/null
+++ b/src/docs/option_env_unwrap.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `option_env!(...).unwrap()` and
+suggests usage of the `env!` macro.
+
+### Why is this bad?
+Unwrapping the result of `option_env!` will panic
+at run-time if the environment variable doesn't exist, whereas `env!`
+catches it at compile-time.
+
+### Example
+```
+let _ = option_env!("HOME").unwrap();
+```
+
+Is better expressed as:
+
+```
+let _ = env!("HOME");
+```
\ No newline at end of file
diff --git a/src/docs/option_filter_map.txt b/src/docs/option_filter_map.txt
new file mode 100644
index 00000000000..25f7bde7b4d
--- /dev/null
+++ b/src/docs/option_filter_map.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for indirect collection of populated `Option`
+
+### Why is this bad?
+`Option` is like a collection of 0-1 things, so `flatten`
+automatically does this without suspicious-looking `unwrap` calls.
+
+### Example
+```
+let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap);
+```
+Use instead:
+```
+let _ = std::iter::empty::<Option<i32>>().flatten();
+```
\ No newline at end of file
diff --git a/src/docs/option_if_let_else.txt b/src/docs/option_if_let_else.txt
new file mode 100644
index 00000000000..43652db513b
--- /dev/null
+++ b/src/docs/option_if_let_else.txt
@@ -0,0 +1,46 @@
+### What it does
+Lints usage of `if let Some(v) = ... { y } else { x }` and
+`match .. { Some(v) => y, None/_ => x }` which are more
+idiomatically done with `Option::map_or` (if the else bit is a pure
+expression) or `Option::map_or_else` (if the else bit is an impure
+expression).
+
+### Why is this bad?
+Using the dedicated functions of the `Option` type is clearer and
+more concise than an `if let` expression.
+
+### Known problems
+This lint uses a deliberately conservative metric for checking
+if the inside of either body contains breaks or continues which will
+cause it to not suggest a fix if either block contains a loop with
+continues or breaks contained within the loop.
+
+### Example
+```
+let _ = if let Some(foo) = optional {
+    foo
+} else {
+    5
+};
+let _ = match optional {
+    Some(val) => val + 1,
+    None => 5
+};
+let _ = if let Some(foo) = optional {
+    foo
+} else {
+    let y = do_complicated_function();
+    y*y
+};
+```
+
+should be
+
+```
+let _ = optional.map_or(5, |foo| foo);
+let _ = optional.map_or(5, |val| val + 1);
+let _ = optional.map_or_else(||{
+    let y = do_complicated_function();
+    y*y
+}, |foo| foo);
+```
\ No newline at end of file
diff --git a/src/docs/option_map_or_none.txt b/src/docs/option_map_or_none.txt
new file mode 100644
index 00000000000..c86c65215f0
--- /dev/null
+++ b/src/docs/option_map_or_none.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `_.map_or(None, _)`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.and_then(_)`.
+
+### Known problems
+The order of the arguments is not in execution order.
+
+### Example
+```
+opt.map_or(None, |a| Some(a + 1));
+```
+
+Use instead:
+```
+opt.and_then(|a| Some(a + 1));
+```
\ No newline at end of file
diff --git a/src/docs/option_map_unit_fn.txt b/src/docs/option_map_unit_fn.txt
new file mode 100644
index 00000000000..fc4b528f092
--- /dev/null
+++ b/src/docs/option_map_unit_fn.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for usage of `option.map(f)` where f is a function
+or closure that returns the unit type `()`.
+
+### Why is this bad?
+Readability, this can be written more clearly with
+an if let statement
+
+### Example
+```
+let x: Option<String> = do_stuff();
+x.map(log_err_msg);
+x.map(|msg| log_err_msg(format_msg(msg)));
+```
+
+The correct use would be:
+
+```
+let x: Option<String> = do_stuff();
+if let Some(msg) = x {
+    log_err_msg(msg);
+}
+
+if let Some(msg) = x {
+    log_err_msg(format_msg(msg));
+}
+```
\ No newline at end of file
diff --git a/src/docs/option_option.txt b/src/docs/option_option.txt
new file mode 100644
index 00000000000..b4324bd8399
--- /dev/null
+++ b/src/docs/option_option.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for use of `Option<Option<_>>` in function signatures and type
+definitions
+
+### 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.
+
+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.
+
+### Example
+```
+fn get_data() -> Option<Option<u32>> {
+    None
+}
+```
+
+Better:
+
+```
+pub enum Contents {
+    Data(Vec<u8>), // Was Some(Some(Vec<u8>))
+    NotYetFetched, // Was Some(None)
+    None,          // Was None
+}
+
+fn get_data() -> Contents {
+    Contents::None
+}
+```
\ No newline at end of file
diff --git a/src/docs/or_fun_call.txt b/src/docs/or_fun_call.txt
new file mode 100644
index 00000000000..5605e96c98e
--- /dev/null
+++ b/src/docs/or_fun_call.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
+etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
+`unwrap_or_default` instead.
+
+### Why is this bad?
+The function will always be called and potentially
+allocate an object acting as the default.
+
+### Known problems
+If the function has side-effects, not calling it will
+change the semantic of the program, but you shouldn't rely on that anyway.
+
+### Example
+```
+foo.unwrap_or(String::new());
+```
+
+Use instead:
+```
+foo.unwrap_or_else(String::new);
+
+// or
+
+foo.unwrap_or_default();
+```
\ No newline at end of file
diff --git a/src/docs/or_then_unwrap.txt b/src/docs/or_then_unwrap.txt
new file mode 100644
index 00000000000..64ac53749e8
--- /dev/null
+++ b/src/docs/or_then_unwrap.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for `.or(…).unwrap()` calls to Options and Results.
+
+### Why is this bad?
+You should use `.unwrap_or(…)` instead for clarity.
+
+### Example
+```
+// Result
+let value = result.or::<Error>(Ok(fallback)).unwrap();
+
+// Option
+let value = option.or(Some(fallback)).unwrap();
+```
+Use instead:
+```
+// Result
+let value = result.unwrap_or(fallback);
+
+// Option
+let value = option.unwrap_or(fallback);
+```
\ No newline at end of file
diff --git a/src/docs/out_of_bounds_indexing.txt b/src/docs/out_of_bounds_indexing.txt
new file mode 100644
index 00000000000..5802eea2996
--- /dev/null
+++ b/src/docs/out_of_bounds_indexing.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for out of bounds array indexing with a constant
+index.
+
+### Why is this bad?
+This will always panic at runtime.
+
+### Example
+```
+let x = [1, 2, 3, 4];
+
+x[9];
+&x[2..9];
+```
+
+Use instead:
+```
+// Index within bounds
+
+x[0];
+x[3];
+```
\ No newline at end of file
diff --git a/src/docs/overflow_check_conditional.txt b/src/docs/overflow_check_conditional.txt
new file mode 100644
index 00000000000..a09cc18a0bc
--- /dev/null
+++ b/src/docs/overflow_check_conditional.txt
@@ -0,0 +1,11 @@
+### What it does
+Detects classic underflow/overflow checks.
+
+### Why is this bad?
+Most classic C underflow/overflow checks will fail in
+Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
+
+### Example
+```
+a + b < a;
+```
\ No newline at end of file
diff --git a/src/docs/overly_complex_bool_expr.txt b/src/docs/overly_complex_bool_expr.txt
new file mode 100644
index 00000000000..65ca18392e7
--- /dev/null
+++ b/src/docs/overly_complex_bool_expr.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for boolean expressions that contain terminals that
+can be eliminated.
+
+### Why is this bad?
+This is most likely a logic bug.
+
+### Known problems
+Ignores short circuiting behavior.
+
+### Example
+```
+// The `b` is unnecessary, the expression is equivalent to `if a`.
+if a && b || a { ... }
+```
+
+Use instead:
+```
+if a {}
+```
\ No newline at end of file
diff --git a/src/docs/panic.txt b/src/docs/panic.txt
new file mode 100644
index 00000000000..f9bdc6e87cc
--- /dev/null
+++ b/src/docs/panic.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for usage of `panic!`.
+
+### Why is this bad?
+`panic!` will stop the execution of the executable
+
+### Example
+```
+panic!("even with a good reason");
+```
\ No newline at end of file
diff --git a/src/docs/panic_in_result_fn.txt b/src/docs/panic_in_result_fn.txt
new file mode 100644
index 00000000000..51c2f8ae5a3
--- /dev/null
+++ b/src/docs/panic_in_result_fn.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result.
+
+### Why is this bad?
+For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided.
+
+### Known problems
+Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked.
+
+### Example
+```
+fn result_with_panic() -> Result<bool, String>
+{
+    panic!("error");
+}
+```
+Use instead:
+```
+fn result_without_panic() -> Result<bool, String> {
+    Err(String::from("error"))
+}
+```
\ No newline at end of file
diff --git a/src/docs/panicking_unwrap.txt b/src/docs/panicking_unwrap.txt
new file mode 100644
index 00000000000..1fbc245c8ec
--- /dev/null
+++ b/src/docs/panicking_unwrap.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for calls of `unwrap[_err]()` that will always fail.
+
+### Why is this bad?
+If panicking is desired, an explicit `panic!()` should be used.
+
+### Known problems
+This lint only checks `if` conditions not assignments.
+So something like `let x: Option<()> = None; x.unwrap();` will not be recognized.
+
+### Example
+```
+if option.is_none() {
+    do_something_with(option.unwrap())
+}
+```
+
+This code will always panic. The if condition should probably be inverted.
\ No newline at end of file
diff --git a/src/docs/partialeq_ne_impl.txt b/src/docs/partialeq_ne_impl.txt
new file mode 100644
index 00000000000..78f55188bab
--- /dev/null
+++ b/src/docs/partialeq_ne_impl.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for manual re-implementations of `PartialEq::ne`.
+
+### Why is this bad?
+`PartialEq::ne` is required to always return the
+negated result of `PartialEq::eq`, which is exactly what the default
+implementation does. Therefore, there should never be any need to
+re-implement it.
+
+### Example
+```
+struct Foo;
+
+impl PartialEq for Foo {
+   fn eq(&self, other: &Foo) -> bool { true }
+   fn ne(&self, other: &Foo) -> bool { !(self == other) }
+}
+```
\ No newline at end of file
diff --git a/src/docs/partialeq_to_none.txt b/src/docs/partialeq_to_none.txt
new file mode 100644
index 00000000000..5cc07bf8843
--- /dev/null
+++ b/src/docs/partialeq_to_none.txt
@@ -0,0 +1,24 @@
+### What it does
+
+Checks for binary comparisons to a literal `Option::None`.
+
+### Why is this bad?
+
+A programmer checking if some `foo` is `None` via a comparison `foo == None`
+is usually inspired from other programming languages (e.g. `foo is None`
+in Python).
+Checking if a value of type `Option<T>` is (not) equal to `None` in that
+way relies on `T: PartialEq` to do the comparison, which is unneeded.
+
+### Example
+```
+fn foo(f: Option<u32>) -> &'static str {
+    if f != None { "yay" } else { "nay" }
+}
+```
+Use instead:
+```
+fn foo(f: Option<u32>) -> &'static str {
+    if f.is_some() { "yay" } else { "nay" }
+}
+```
\ No newline at end of file
diff --git a/src/docs/path_buf_push_overwrite.txt b/src/docs/path_buf_push_overwrite.txt
new file mode 100644
index 00000000000..34f8901da23
--- /dev/null
+++ b/src/docs/path_buf_push_overwrite.txt
@@ -0,0 +1,25 @@
+### What it does
+* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push)
+calls on `PathBuf` that can cause overwrites.
+
+### Why is this bad?
+Calling `push` with a root path at the start can overwrite the
+previous defined path.
+
+### Example
+```
+use std::path::PathBuf;
+
+let mut x = PathBuf::from("/foo");
+x.push("/bar");
+assert_eq!(x, PathBuf::from("/bar"));
+```
+Could be written:
+
+```
+use std::path::PathBuf;
+
+let mut x = PathBuf::from("/foo");
+x.push("bar");
+assert_eq!(x, PathBuf::from("/foo/bar"));
+```
\ No newline at end of file
diff --git a/src/docs/pattern_type_mismatch.txt b/src/docs/pattern_type_mismatch.txt
new file mode 100644
index 00000000000..64da881d592
--- /dev/null
+++ b/src/docs/pattern_type_mismatch.txt
@@ -0,0 +1,64 @@
+### What it does
+Checks for patterns that aren't exact representations of the types
+they are applied to.
+
+To satisfy this lint, you will have to adjust either the expression that is matched
+against or the pattern itself, as well as the bindings that are introduced by the
+adjusted patterns. For matching you will have to either dereference the expression
+with the `*` operator, or amend the patterns to explicitly match against `&<pattern>`
+or `&mut <pattern>` depending on the reference mutability. For the bindings you need
+to use the inverse. You can leave them as plain bindings if you wish for the value
+to be copied, but you must use `ref mut <variable>` or `ref <variable>` to construct
+a reference into the matched structure.
+
+If you are looking for a way to learn about ownership semantics in more detail, it
+is recommended to look at IDE options available to you to highlight types, lifetimes
+and reference semantics in your code. The available tooling would expose these things
+in a general way even outside of the various pattern matching mechanics. Of course
+this lint can still be used to highlight areas of interest and ensure a good understanding
+of ownership semantics.
+
+### Why is this bad?
+It isn't bad in general. But in some contexts it can be desirable
+because it increases ownership hints in the code, and will guard against some changes
+in ownership.
+
+### Example
+This example shows the basic adjustments necessary to satisfy the lint. Note how
+the matched expression is explicitly dereferenced with `*` and the `inner` variable
+is bound to a shared borrow via `ref inner`.
+
+```
+// Bad
+let value = &Some(Box::new(23));
+match value {
+    Some(inner) => println!("{}", inner),
+    None => println!("none"),
+}
+
+// Good
+let value = &Some(Box::new(23));
+match *value {
+    Some(ref inner) => println!("{}", inner),
+    None => println!("none"),
+}
+```
+
+The following example demonstrates one of the advantages of the more verbose style.
+Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable
+borrow, while `b` is simply taken by value. This ensures that the loop body cannot
+accidentally modify the wrong part of the structure.
+
+```
+// Bad
+let mut values = vec![(2, 3), (3, 4)];
+for (a, b) in &mut values {
+    *a += *b;
+}
+
+// Good
+let mut values = vec![(2, 3), (3, 4)];
+for &mut (ref mut a, b) in &mut values {
+    *a += b;
+}
+```
\ No newline at end of file
diff --git a/src/docs/positional_named_format_parameters.txt b/src/docs/positional_named_format_parameters.txt
new file mode 100644
index 00000000000..e391d240667
--- /dev/null
+++ b/src/docs/positional_named_format_parameters.txt
@@ -0,0 +1,15 @@
+### What it does
+This lint warns when a named parameter in a format string is used as a positional one.
+
+### Why is this bad?
+It may be confused for an assignment and obfuscates which parameter is being used.
+
+### Example
+```
+println!("{}", x = 10);
+```
+
+Use instead:
+```
+println!("{x}", x = 10);
+```
\ No newline at end of file
diff --git a/src/docs/possible_missing_comma.txt b/src/docs/possible_missing_comma.txt
new file mode 100644
index 00000000000..5d92f4cae91
--- /dev/null
+++ b/src/docs/possible_missing_comma.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for possible missing comma in an array. It lints if
+an array element is a binary operator expression and it lies on two lines.
+
+### Why is this bad?
+This could lead to unexpected results.
+
+### Example
+```
+let a = &[
+    -1, -2, -3 // <= no comma here
+    -4, -5, -6
+];
+```
\ No newline at end of file
diff --git a/src/docs/precedence.txt b/src/docs/precedence.txt
new file mode 100644
index 00000000000..fda0b831f33
--- /dev/null
+++ b/src/docs/precedence.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for operations where precedence may be unclear
+and suggests to add parentheses. Currently it catches the following:
+* mixed usage of arithmetic and bit shifting/combining operators without
+parentheses
+* a "negative" numeric literal (which is really a unary `-` followed by a
+numeric literal)
+  followed by a method call
+
+### Why is this bad?
+Not everyone knows the precedence of those operators by
+heart, so expressions like these may trip others trying to reason about the
+code.
+
+### Example
+* `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7
+* `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1
\ No newline at end of file
diff --git a/src/docs/print_in_format_impl.txt b/src/docs/print_in_format_impl.txt
new file mode 100644
index 00000000000..140d23d6faa
--- /dev/null
+++ b/src/docs/print_in_format_impl.txt
@@ -0,0 +1,34 @@
+### What it does
+Checks for use of `println`, `print`, `eprintln` or `eprint` in an
+implementation of a formatting trait.
+
+### Why is this bad?
+Using a print macro is likely unintentional since formatting traits
+should write to the `Formatter`, not stdout/stderr.
+
+### Example
+```
+use std::fmt::{Display, Error, Formatter};
+
+struct S;
+impl Display for S {
+    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+        println!("S");
+
+        Ok(())
+    }
+}
+```
+Use instead:
+```
+use std::fmt::{Display, Error, Formatter};
+
+struct S;
+impl Display for S {
+    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
+        writeln!(f, "S");
+
+        Ok(())
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/print_literal.txt b/src/docs/print_literal.txt
new file mode 100644
index 00000000000..160073414f9
--- /dev/null
+++ b/src/docs/print_literal.txt
@@ -0,0 +1,20 @@
+### What it does
+This lint warns about the use of literals as `print!`/`println!` args.
+
+### Why is this bad?
+Using literals as `println!` args is inefficient
+(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
+(i.e., just put the literal in the format string)
+
+### Known problems
+Will also warn with macro calls as arguments that expand to literals
+-- e.g., `println!("{}", env!("FOO"))`.
+
+### Example
+```
+println!("{}", "foo");
+```
+use the literal without formatting:
+```
+println!("foo");
+```
\ No newline at end of file
diff --git a/src/docs/print_stderr.txt b/src/docs/print_stderr.txt
new file mode 100644
index 00000000000..fc14511cd6a
--- /dev/null
+++ b/src/docs/print_stderr.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for printing on *stderr*. The purpose of this lint
+is to catch debugging remnants.
+
+### Why is this bad?
+People often print on *stderr* while debugging an
+application and might forget to remove those prints afterward.
+
+### Known problems
+* Only catches `eprint!` and `eprintln!` calls.
+* The lint level is unaffected by crate attributes. The level can still
+  be set for functions, modules and other items. To change the level for
+  the entire crate, please use command line flags. More information and a
+  configuration example can be found in [clippy#6610].
+
+[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
+
+### Example
+```
+eprintln!("Hello world!");
+```
\ No newline at end of file
diff --git a/src/docs/print_stdout.txt b/src/docs/print_stdout.txt
new file mode 100644
index 00000000000..6c9a4b98e1e
--- /dev/null
+++ b/src/docs/print_stdout.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for printing on *stdout*. The purpose of this lint
+is to catch debugging remnants.
+
+### Why is this bad?
+People often print on *stdout* while debugging an
+application and might forget to remove those prints afterward.
+
+### Known problems
+* Only catches `print!` and `println!` calls.
+* The lint level is unaffected by crate attributes. The level can still
+  be set for functions, modules and other items. To change the level for
+  the entire crate, please use command line flags. More information and a
+  configuration example can be found in [clippy#6610].
+
+[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558
+
+### Example
+```
+println!("Hello world!");
+```
\ No newline at end of file
diff --git a/src/docs/print_with_newline.txt b/src/docs/print_with_newline.txt
new file mode 100644
index 00000000000..640323e822d
--- /dev/null
+++ b/src/docs/print_with_newline.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint warns when you use `print!()` with a format
+string that ends in a newline.
+
+### Why is this bad?
+You should use `println!()` instead, which appends the
+newline.
+
+### Example
+```
+print!("Hello {}!\n", name);
+```
+use println!() instead
+```
+println!("Hello {}!", name);
+```
\ No newline at end of file
diff --git a/src/docs/println_empty_string.txt b/src/docs/println_empty_string.txt
new file mode 100644
index 00000000000..b980413022c
--- /dev/null
+++ b/src/docs/println_empty_string.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint warns when you use `println!("")` to
+print a newline.
+
+### Why is this bad?
+You should use `println!()`, which is simpler.
+
+### Example
+```
+println!("");
+```
+
+Use instead:
+```
+println!();
+```
\ No newline at end of file
diff --git a/src/docs/ptr_arg.txt b/src/docs/ptr_arg.txt
new file mode 100644
index 00000000000..796b0a65b71
--- /dev/null
+++ b/src/docs/ptr_arg.txt
@@ -0,0 +1,29 @@
+### What it does
+This lint checks for function arguments of type `&String`, `&Vec`,
+`&PathBuf`, and `Cow<_>`. It will also suggest you replace `.clone()` calls
+with the appropriate `.to_owned()`/`to_string()` calls.
+
+### Why is this bad?
+Requiring the argument to be of the specific size
+makes the function less useful for no benefit; slices in the form of `&[T]`
+or `&str` usually suffice and can be obtained from other types, too.
+
+### Known problems
+There may be `fn(&Vec)`-typed references pointing to your function.
+If you have them, you will get a compiler error after applying this lint's
+suggestions. You then have the choice to undo your changes or change the
+type of the reference.
+
+Note that if the function is part of your public interface, there may be
+other crates referencing it, of which you may not be aware. Carefully
+deprecate the function before applying the lint suggestions in this case.
+
+### Example
+```
+fn foo(&Vec<u32>) { .. }
+```
+
+Use instead:
+```
+fn foo(&[u32]) { .. }
+```
\ No newline at end of file
diff --git a/src/docs/ptr_as_ptr.txt b/src/docs/ptr_as_ptr.txt
new file mode 100644
index 00000000000..8fb35c4aae8
--- /dev/null
+++ b/src/docs/ptr_as_ptr.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for `as` casts between raw pointers without changing its mutability,
+namely `*const T` to `*const U` and `*mut T` to `*mut U`.
+
+### Why is this bad?
+Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because
+it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
+
+### Example
+```
+let ptr: *const u32 = &42_u32;
+let mut_ptr: *mut u32 = &mut 42_u32;
+let _ = ptr as *const i32;
+let _ = mut_ptr as *mut i32;
+```
+Use instead:
+```
+let ptr: *const u32 = &42_u32;
+let mut_ptr: *mut u32 = &mut 42_u32;
+let _ = ptr.cast::<i32>();
+let _ = mut_ptr.cast::<i32>();
+```
\ No newline at end of file
diff --git a/src/docs/ptr_eq.txt b/src/docs/ptr_eq.txt
new file mode 100644
index 00000000000..06b36ca55e6
--- /dev/null
+++ b/src/docs/ptr_eq.txt
@@ -0,0 +1,22 @@
+### What it does
+Use `std::ptr::eq` when applicable
+
+### Why is this bad?
+`ptr::eq` can be used to compare `&T` references
+(which coerce to `*const T` implicitly) by their address rather than
+comparing the values they point to.
+
+### Example
+```
+let a = &[1, 2, 3];
+let b = &[1, 2, 3];
+
+assert!(a as *const _ as usize == b as *const _ as usize);
+```
+Use instead:
+```
+let a = &[1, 2, 3];
+let b = &[1, 2, 3];
+
+assert!(std::ptr::eq(a, b));
+```
\ No newline at end of file
diff --git a/src/docs/ptr_offset_with_cast.txt b/src/docs/ptr_offset_with_cast.txt
new file mode 100644
index 00000000000..f204e769bf4
--- /dev/null
+++ b/src/docs/ptr_offset_with_cast.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for usage of the `offset` pointer method with a `usize` casted to an
+`isize`.
+
+### Why is this bad?
+If we’re always increasing the pointer address, we can avoid the numeric
+cast by using the `add` method instead.
+
+### Example
+```
+let vec = vec![b'a', b'b', b'c'];
+let ptr = vec.as_ptr();
+let offset = 1_usize;
+
+unsafe {
+    ptr.offset(offset as isize);
+}
+```
+
+Could be written:
+
+```
+let vec = vec![b'a', b'b', b'c'];
+let ptr = vec.as_ptr();
+let offset = 1_usize;
+
+unsafe {
+    ptr.add(offset);
+}
+```
\ No newline at end of file
diff --git a/src/docs/pub_use.txt b/src/docs/pub_use.txt
new file mode 100644
index 00000000000..407cafa0190
--- /dev/null
+++ b/src/docs/pub_use.txt
@@ -0,0 +1,28 @@
+### What it does
+
+Restricts the usage of `pub use ...`
+
+### Why is this bad?
+
+`pub use` is usually fine, but a project may wish to limit `pub use` instances to prevent
+unintentional exports or to encourage placing exported items directly in public modules
+
+### Example
+```
+pub mod outer {
+    mod inner {
+        pub struct Test {}
+    }
+    pub use inner::Test;
+}
+
+use outer::Test;
+```
+Use instead:
+```
+pub mod outer {
+    pub struct Test {}
+}
+
+use outer::Test;
+```
\ No newline at end of file
diff --git a/src/docs/question_mark.txt b/src/docs/question_mark.txt
new file mode 100644
index 00000000000..4dc987be881
--- /dev/null
+++ b/src/docs/question_mark.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for expressions that could be replaced by the question mark operator.
+
+### Why is this bad?
+Question mark usage is more idiomatic.
+
+### Example
+```
+if option.is_none() {
+    return None;
+}
+```
+
+Could be written:
+
+```
+option?;
+```
\ No newline at end of file
diff --git a/src/docs/range_minus_one.txt b/src/docs/range_minus_one.txt
new file mode 100644
index 00000000000..fcb96dcc34e
--- /dev/null
+++ b/src/docs/range_minus_one.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for inclusive ranges where 1 is subtracted from
+the upper bound, e.g., `x..=(y-1)`.
+
+### Why is this bad?
+The code is more readable with an exclusive range
+like `x..y`.
+
+### Known problems
+This will cause a warning that cannot be fixed if
+the consumer of the range only accepts a specific range type, instead of
+the generic `RangeBounds` trait
+([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
+
+### Example
+```
+for i in x..=(y-1) {
+    // ..
+}
+```
+
+Use instead:
+```
+for i in x..y {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/range_plus_one.txt b/src/docs/range_plus_one.txt
new file mode 100644
index 00000000000..193c85f9cbc
--- /dev/null
+++ b/src/docs/range_plus_one.txt
@@ -0,0 +1,36 @@
+### What it does
+Checks for exclusive ranges where 1 is added to the
+upper bound, e.g., `x..(y+1)`.
+
+### Why is this bad?
+The code is more readable with an inclusive range
+like `x..=y`.
+
+### Known problems
+Will add unnecessary pair of parentheses when the
+expression is not wrapped in a pair but starts with an opening parenthesis
+and ends with a closing one.
+I.e., `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..=f())`.
+
+Also in many cases, inclusive ranges are still slower to run than
+exclusive ranges, because they essentially add an extra branch that
+LLVM may fail to hoist out of the loop.
+
+This will cause a warning that cannot be fixed if the consumer of the
+range only accepts a specific range type, instead of the generic
+`RangeBounds` trait
+([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
+
+### Example
+```
+for i in x..(y+1) {
+    // ..
+}
+```
+
+Use instead:
+```
+for i in x..=y {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/range_zip_with_len.txt b/src/docs/range_zip_with_len.txt
new file mode 100644
index 00000000000..24c1efec789
--- /dev/null
+++ b/src/docs/range_zip_with_len.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for zipping a collection with the range of
+`0.._.len()`.
+
+### Why is this bad?
+The code is better expressed with `.enumerate()`.
+
+### Example
+```
+let _ = x.iter().zip(0..x.len());
+```
+
+Use instead:
+```
+let _ = x.iter().enumerate();
+```
\ No newline at end of file
diff --git a/src/docs/rc_buffer.txt b/src/docs/rc_buffer.txt
new file mode 100644
index 00000000000..82ac58eeb30
--- /dev/null
+++ b/src/docs/rc_buffer.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for `Rc<T>` and `Arc<T>` when `T` is a mutable buffer type such as `String` or `Vec`.
+
+### Why is this bad?
+Expressions such as `Rc<String>` usually have no advantage over `Rc<str>`, since
+it is larger and involves an extra level of indirection, and doesn't implement `Borrow<str>`.
+
+While mutating a buffer type would still be possible with `Rc::get_mut()`, it only
+works if there are no additional references yet, which usually defeats the purpose of
+enclosing it in a shared ownership type. Instead, additionally wrapping the inner
+type with an interior mutable container (such as `RefCell` or `Mutex`) would normally
+be used.
+
+### Known problems
+This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for
+cases where mutation only happens before there are any additional references.
+
+### Example
+```
+fn foo(interned: Rc<String>) { ... }
+```
+
+Better:
+
+```
+fn foo(interned: Rc<str>) { ... }
+```
\ No newline at end of file
diff --git a/src/docs/rc_clone_in_vec_init.txt b/src/docs/rc_clone_in_vec_init.txt
new file mode 100644
index 00000000000..6fc08aaf9ab
--- /dev/null
+++ b/src/docs/rc_clone_in_vec_init.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for reference-counted pointers (`Arc`, `Rc`, `rc::Weak`, and `sync::Weak`)
+in `vec![elem; len]`
+
+### Why is this bad?
+This will create `elem` once and clone it `len` times - doing so with `Arc`/`Rc`/`Weak`
+is a bit misleading, as it will create references to the same pointer, rather
+than different instances.
+
+### Example
+```
+let v = vec![std::sync::Arc::new("some data".to_string()); 100];
+// or
+let v = vec![std::rc::Rc::new("some data".to_string()); 100];
+```
+Use instead:
+```
+// Initialize each value separately:
+let mut data = Vec::with_capacity(100);
+for _ in 0..100 {
+    data.push(std::rc::Rc::new("some data".to_string()));
+}
+
+// Or if you want clones of the same reference,
+// Create the reference beforehand to clarify that
+// it should be cloned for each value
+let data = std::rc::Rc::new("some data".to_string());
+let v = vec![data; 100];
+```
\ No newline at end of file
diff --git a/src/docs/rc_mutex.txt b/src/docs/rc_mutex.txt
new file mode 100644
index 00000000000..ed7a1e344d0
--- /dev/null
+++ b/src/docs/rc_mutex.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for `Rc<Mutex<T>>`.
+
+### Why is this bad?
+`Rc` is used in single thread and `Mutex` is used in multi thread.
+Consider using `Rc<RefCell<T>>` in single thread or `Arc<Mutex<T>>` in multi thread.
+
+### Known problems
+Sometimes combining generic types can lead to the requirement that a
+type use Rc in conjunction with Mutex. We must consider those cases false positives, but
+alas they are quite hard to rule out. Luckily they are also rare.
+
+### Example
+```
+use std::rc::Rc;
+use std::sync::Mutex;
+fn foo(interned: Rc<Mutex<i32>>) { ... }
+```
+
+Better:
+
+```
+use std::rc::Rc;
+use std::cell::RefCell
+fn foo(interned: Rc<RefCell<i32>>) { ... }
+```
\ No newline at end of file
diff --git a/src/docs/read_zero_byte_vec.txt b/src/docs/read_zero_byte_vec.txt
new file mode 100644
index 00000000000..cef5604e01c
--- /dev/null
+++ b/src/docs/read_zero_byte_vec.txt
@@ -0,0 +1,30 @@
+### What it does
+This lint catches reads into a zero-length `Vec`.
+Especially in the case of a call to `with_capacity`, this lint warns that read
+gets the number of bytes from the `Vec`'s length, not its capacity.
+
+### Why is this bad?
+Reading zero bytes is almost certainly not the intended behavior.
+
+### Known problems
+In theory, a very unusual read implementation could assign some semantic meaning
+to zero-byte reads. But it seems exceptionally unlikely that code intending to do
+a zero-byte read would allocate a `Vec` for it.
+
+### Example
+```
+use std::io;
+fn foo<F: io::Read>(mut f: F) {
+    let mut data = Vec::with_capacity(100);
+    f.read(&mut data).unwrap();
+}
+```
+Use instead:
+```
+use std::io;
+fn foo<F: io::Read>(mut f: F) {
+    let mut data = Vec::with_capacity(100);
+    data.resize(100, 0);
+    f.read(&mut data).unwrap();
+}
+```
\ No newline at end of file
diff --git a/src/docs/recursive_format_impl.txt b/src/docs/recursive_format_impl.txt
new file mode 100644
index 00000000000..32fffd84cf4
--- /dev/null
+++ b/src/docs/recursive_format_impl.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for format trait implementations (e.g. `Display`) with a recursive call to itself
+which uses `self` as a parameter.
+This is typically done indirectly with the `write!` macro or with `to_string()`.
+
+### Why is this bad?
+This will lead to infinite recursion and a stack overflow.
+
+### Example
+
+```
+use std::fmt;
+
+struct Structure(i32);
+impl fmt::Display for Structure {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.to_string())
+    }
+}
+
+```
+Use instead:
+```
+use std::fmt;
+
+struct Structure(i32);
+impl fmt::Display for Structure {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.0)
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/redundant_allocation.txt b/src/docs/redundant_allocation.txt
new file mode 100644
index 00000000000..86bf51e8dfe
--- /dev/null
+++ b/src/docs/redundant_allocation.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for use of redundant allocations anywhere in the code.
+
+### Why is this bad?
+Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Arc<T>>`, `Rc<Box<T>>`, `Arc<&T>`, `Arc<Rc<T>>`,
+`Arc<Arc<T>>`, `Arc<Box<T>>`, `Box<&T>`, `Box<Rc<T>>`, `Box<Arc<T>>`, `Box<Box<T>>`, add an unnecessary level of indirection.
+
+### Example
+```
+fn foo(bar: Rc<&usize>) {}
+```
+
+Better:
+
+```
+fn foo(bar: &usize) {}
+```
\ No newline at end of file
diff --git a/src/docs/redundant_clone.txt b/src/docs/redundant_clone.txt
new file mode 100644
index 00000000000..b29aed0b5e7
--- /dev/null
+++ b/src/docs/redundant_clone.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for a redundant `clone()` (and its relatives) which clones an owned
+value that is going to be dropped without further use.
+
+### Why is this bad?
+It is not always possible for the compiler to eliminate useless
+allocations and deallocations generated by redundant `clone()`s.
+
+### Known problems
+False-negatives: analysis performed by this lint is conservative and limited.
+
+### Example
+```
+{
+    let x = Foo::new();
+    call(x.clone());
+    call(x.clone()); // this can just pass `x`
+}
+
+["lorem", "ipsum"].join(" ").to_string();
+
+Path::new("/a/b").join("c").to_path_buf();
+```
\ No newline at end of file
diff --git a/src/docs/redundant_closure.txt b/src/docs/redundant_closure.txt
new file mode 100644
index 00000000000..0faa9513f97
--- /dev/null
+++ b/src/docs/redundant_closure.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for closures which just call another function where
+the function can be called directly. `unsafe` functions or calls where types
+get adjusted are ignored.
+
+### Why is this bad?
+Needlessly creating a closure adds code for no benefit
+and gives the optimizer more work.
+
+### Known problems
+If creating the closure inside the closure has a side-
+effect then moving the closure creation out will change when that side-
+effect runs.
+See [#1439](https://github.com/rust-lang/rust-clippy/issues/1439) for more details.
+
+### Example
+```
+xs.map(|x| foo(x))
+```
+
+Use instead:
+```
+// where `foo(_)` is a plain function that takes the exact argument type of `x`.
+xs.map(foo)
+```
\ No newline at end of file
diff --git a/src/docs/redundant_closure_call.txt b/src/docs/redundant_closure_call.txt
new file mode 100644
index 00000000000..913d1a705e2
--- /dev/null
+++ b/src/docs/redundant_closure_call.txt
@@ -0,0 +1,17 @@
+### What it does
+Detects closures called in the same expression where they
+are defined.
+
+### Why is this bad?
+It is unnecessarily adding to the expression's
+complexity.
+
+### Example
+```
+let a = (|| 42)();
+```
+
+Use instead:
+```
+let a = 42;
+```
\ No newline at end of file
diff --git a/src/docs/redundant_closure_for_method_calls.txt b/src/docs/redundant_closure_for_method_calls.txt
new file mode 100644
index 00000000000..865510e1475
--- /dev/null
+++ b/src/docs/redundant_closure_for_method_calls.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for closures which only invoke a method on the closure
+argument and can be replaced by referencing the method directly.
+
+### Why is this bad?
+It's unnecessary to create the closure.
+
+### Example
+```
+Some('a').map(|s| s.to_uppercase());
+```
+may be rewritten as
+```
+Some('a').map(char::to_uppercase);
+```
\ No newline at end of file
diff --git a/src/docs/redundant_else.txt b/src/docs/redundant_else.txt
new file mode 100644
index 00000000000..3f4e8691760
--- /dev/null
+++ b/src/docs/redundant_else.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for `else` blocks that can be removed without changing semantics.
+
+### Why is this bad?
+The `else` block adds unnecessary indentation and verbosity.
+
+### Known problems
+Some may prefer to keep the `else` block for clarity.
+
+### Example
+```
+fn my_func(count: u32) {
+    if count == 0 {
+        print!("Nothing to do");
+        return;
+    } else {
+        print!("Moving on...");
+    }
+}
+```
+Use instead:
+```
+fn my_func(count: u32) {
+    if count == 0 {
+        print!("Nothing to do");
+        return;
+    }
+    print!("Moving on...");
+}
+```
\ No newline at end of file
diff --git a/src/docs/redundant_feature_names.txt b/src/docs/redundant_feature_names.txt
new file mode 100644
index 00000000000..5bd6925ed47
--- /dev/null
+++ b/src/docs/redundant_feature_names.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for feature names with prefix `use-`, `with-` or suffix `-support`
+
+### Why is this bad?
+These prefixes and suffixes have no significant meaning.
+
+### Example
+```
+[features]
+default = ["use-abc", "with-def", "ghi-support"]
+use-abc = []  // redundant
+with-def = []   // redundant
+ghi-support = []   // redundant
+```
+
+Use instead:
+```
+[features]
+default = ["abc", "def", "ghi"]
+abc = []
+def = []
+ghi = []
+```
diff --git a/src/docs/redundant_field_names.txt b/src/docs/redundant_field_names.txt
new file mode 100644
index 00000000000..35f20a466b3
--- /dev/null
+++ b/src/docs/redundant_field_names.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for fields in struct literals where shorthands
+could be used.
+
+### Why is this bad?
+If the field and variable names are the same,
+the field name is redundant.
+
+### Example
+```
+let bar: u8 = 123;
+
+struct Foo {
+    bar: u8,
+}
+
+let foo = Foo { bar: bar };
+```
+the last line can be simplified to
+```
+let foo = Foo { bar };
+```
\ No newline at end of file
diff --git a/src/docs/redundant_pattern.txt b/src/docs/redundant_pattern.txt
new file mode 100644
index 00000000000..45f6cfc8670
--- /dev/null
+++ b/src/docs/redundant_pattern.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for patterns in the form `name @ _`.
+
+### Why is this bad?
+It's almost always more readable to just use direct
+bindings.
+
+### Example
+```
+match v {
+    Some(x) => (),
+    y @ _ => (),
+}
+```
+
+Use instead:
+```
+match v {
+    Some(x) => (),
+    y => (),
+}
+```
\ No newline at end of file
diff --git a/src/docs/redundant_pattern_matching.txt b/src/docs/redundant_pattern_matching.txt
new file mode 100644
index 00000000000..77b1021e0db
--- /dev/null
+++ b/src/docs/redundant_pattern_matching.txt
@@ -0,0 +1,45 @@
+### What it does
+Lint for redundant pattern matching over `Result`, `Option`,
+`std::task::Poll` or `std::net::IpAddr`
+
+### Why is this bad?
+It's more concise and clear to just use the proper
+utility function
+
+### Known problems
+This will change the drop order for the matched type. Both `if let` and
+`while let` will drop the value at the end of the block, both `if` and `while` will drop the
+value before entering the block. For most types this change will not matter, but for a few
+types this will not be an acceptable change (e.g. locks). See the
+[reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
+drop order.
+
+### Example
+```
+if let Ok(_) = Ok::<i32, i32>(42) {}
+if let Err(_) = Err::<i32, i32>(42) {}
+if let None = None::<()> {}
+if let Some(_) = Some(42) {}
+if let Poll::Pending = Poll::Pending::<()> {}
+if let Poll::Ready(_) = Poll::Ready(42) {}
+if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {}
+if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {}
+match Ok::<i32, i32>(42) {
+    Ok(_) => true,
+    Err(_) => false,
+};
+```
+
+The more idiomatic use would be:
+
+```
+if Ok::<i32, i32>(42).is_ok() {}
+if Err::<i32, i32>(42).is_err() {}
+if None::<()>.is_none() {}
+if Some(42).is_some() {}
+if Poll::Pending::<()>.is_pending() {}
+if Poll::Ready(42).is_ready() {}
+if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
+if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
+Ok::<i32, i32>(42).is_ok();
+```
\ No newline at end of file
diff --git a/src/docs/redundant_pub_crate.txt b/src/docs/redundant_pub_crate.txt
new file mode 100644
index 00000000000..a527bb5acda
--- /dev/null
+++ b/src/docs/redundant_pub_crate.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for items declared `pub(crate)` that are not crate visible because they
+are inside a private module.
+
+### Why is this bad?
+Writing `pub(crate)` is misleading when it's redundant due to the parent
+module's visibility.
+
+### Example
+```
+mod internal {
+    pub(crate) fn internal_fn() { }
+}
+```
+This function is not visible outside the module and it can be declared with `pub` or
+private visibility
+```
+mod internal {
+    pub fn internal_fn() { }
+}
+```
\ No newline at end of file
diff --git a/src/docs/redundant_slicing.txt b/src/docs/redundant_slicing.txt
new file mode 100644
index 00000000000..6798911ed76
--- /dev/null
+++ b/src/docs/redundant_slicing.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for redundant slicing expressions which use the full range, and
+do not change the type.
+
+### Why is this bad?
+It unnecessarily adds complexity to the expression.
+
+### Known problems
+If the type being sliced has an implementation of `Index<RangeFull>`
+that actually changes anything then it can't be removed. However, this would be surprising
+to people reading the code and should have a note with it.
+
+### Example
+```
+fn get_slice(x: &[u32]) -> &[u32] {
+    &x[..]
+}
+```
+Use instead:
+```
+fn get_slice(x: &[u32]) -> &[u32] {
+    x
+}
+```
\ No newline at end of file
diff --git a/src/docs/redundant_static_lifetimes.txt b/src/docs/redundant_static_lifetimes.txt
new file mode 100644
index 00000000000..edb8e7b5c62
--- /dev/null
+++ b/src/docs/redundant_static_lifetimes.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for constants and statics with an explicit `'static` lifetime.
+
+### Why is this bad?
+Adding `'static` to every reference can create very
+complicated types.
+
+### Example
+```
+const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
+&[...]
+static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] =
+&[...]
+```
+This code can be rewritten as
+```
+ const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
+ static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...]
+```
\ No newline at end of file
diff --git a/src/docs/ref_binding_to_reference.txt b/src/docs/ref_binding_to_reference.txt
new file mode 100644
index 00000000000..dc391cd988e
--- /dev/null
+++ b/src/docs/ref_binding_to_reference.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for `ref` bindings which create a reference to a reference.
+
+### Why is this bad?
+The address-of operator at the use site is clearer about the need for a reference.
+
+### Example
+```
+let x = Some("");
+if let Some(ref x) = x {
+    // use `x` here
+}
+```
+
+Use instead:
+```
+let x = Some("");
+if let Some(x) = x {
+    // use `&x` here
+}
+```
\ No newline at end of file
diff --git a/src/docs/ref_option_ref.txt b/src/docs/ref_option_ref.txt
new file mode 100644
index 00000000000..951c7bd7f7e
--- /dev/null
+++ b/src/docs/ref_option_ref.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for usage of `&Option<&T>`.
+
+### Why is this bad?
+Since `&` is Copy, it's useless to have a
+reference on `Option<&T>`.
+
+### Known problems
+It may be irrelevant to use this lint on
+public API code as it will make a breaking change to apply it.
+
+### Example
+```
+let x: &Option<&u32> = &Some(&0u32);
+```
+Use instead:
+```
+let x: Option<&u32> = Some(&0u32);
+```
\ No newline at end of file
diff --git a/src/docs/repeat_once.txt b/src/docs/repeat_once.txt
new file mode 100644
index 00000000000..3ba189c1945
--- /dev/null
+++ b/src/docs/repeat_once.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for usage of `.repeat(1)` and suggest the following method for each types.
+- `.to_string()` for `str`
+- `.clone()` for `String`
+- `.to_vec()` for `slice`
+
+The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if
+they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306))
+
+### Why is this bad?
+For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning
+the string is the intention behind this, `clone()` should be used.
+
+### Example
+```
+fn main() {
+    let x = String::from("hello world").repeat(1);
+}
+```
+Use instead:
+```
+fn main() {
+    let x = String::from("hello world").clone();
+}
+```
\ No newline at end of file
diff --git a/src/docs/rest_pat_in_fully_bound_structs.txt b/src/docs/rest_pat_in_fully_bound_structs.txt
new file mode 100644
index 00000000000..40ebbe754a3
--- /dev/null
+++ b/src/docs/rest_pat_in_fully_bound_structs.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched.
+
+### Why is this bad?
+Correctness and readability. It's like having a wildcard pattern after
+matching all enum variants explicitly.
+
+### Example
+```
+let a = A { a: 5 };
+
+match a {
+    A { a: 5, .. } => {},
+    _ => {},
+}
+```
+
+Use instead:
+```
+match a {
+    A { a: 5 } => {},
+    _ => {},
+}
+```
\ No newline at end of file
diff --git a/src/docs/result_large_err.txt b/src/docs/result_large_err.txt
new file mode 100644
index 00000000000..e5fab3c5cfc
--- /dev/null
+++ b/src/docs/result_large_err.txt
@@ -0,0 +1,36 @@
+### What it does
+Checks for functions that return `Result` with an unusually large
+`Err`-variant.
+
+### Why is this bad?
+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.
+
+### Known problems
+The size determined by Clippy is platform-dependent.
+
+### Examples
+```
+pub enum ParseError {
+    UnparsedBytes([u8; 512]),
+    UnexpectedEof,
+}
+
+// The `Result` has at least 512 bytes, even in the `Ok`-case
+pub fn parse() -> Result<(), ParseError> {
+    Ok(())
+}
+```
+should be
+```
+pub enum ParseError {
+    UnparsedBytes(Box<[u8; 512]>),
+    UnexpectedEof,
+}
+
+// The `Result` is slightly larger than a pointer
+pub fn parse() -> Result<(), ParseError> {
+    Ok(())
+}
+```
\ No newline at end of file
diff --git a/src/docs/result_map_or_into_option.txt b/src/docs/result_map_or_into_option.txt
new file mode 100644
index 00000000000..899d98c307c
--- /dev/null
+++ b/src/docs/result_map_or_into_option.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `_.map_or(None, Some)`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.ok()`.
+
+### Example
+```
+assert_eq!(Some(1), r.map_or(None, Some));
+```
+
+Use instead:
+```
+assert_eq!(Some(1), r.ok());
+```
\ No newline at end of file
diff --git a/src/docs/result_map_unit_fn.txt b/src/docs/result_map_unit_fn.txt
new file mode 100644
index 00000000000..3455c5c1f9b
--- /dev/null
+++ b/src/docs/result_map_unit_fn.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for usage of `result.map(f)` where f is a function
+or closure that returns the unit type `()`.
+
+### Why is this bad?
+Readability, this can be written more clearly with
+an if let statement
+
+### Example
+```
+let x: Result<String, String> = do_stuff();
+x.map(log_err_msg);
+x.map(|msg| log_err_msg(format_msg(msg)));
+```
+
+The correct use would be:
+
+```
+let x: Result<String, String> = do_stuff();
+if let Ok(msg) = x {
+    log_err_msg(msg);
+};
+if let Ok(msg) = x {
+    log_err_msg(format_msg(msg));
+};
+```
\ No newline at end of file
diff --git a/src/docs/result_unit_err.txt b/src/docs/result_unit_err.txt
new file mode 100644
index 00000000000..7c8ec2ffcf9
--- /dev/null
+++ b/src/docs/result_unit_err.txt
@@ -0,0 +1,40 @@
+### What it does
+Checks for public functions that return a `Result`
+with an `Err` type of `()`. It suggests using a custom type that
+implements `std::error::Error`.
+
+### Why is this bad?
+Unit does not implement `Error` and carries no
+further information about what went wrong.
+
+### Known problems
+Of course, this lint assumes that `Result` is used
+for a fallible operation (which is after all the intended use). However
+code may opt to (mis)use it as a basic two-variant-enum. In that case,
+the suggestion is misguided, and the code should use a custom enum
+instead.
+
+### Examples
+```
+pub fn read_u8() -> Result<u8, ()> { Err(()) }
+```
+should become
+```
+use std::fmt;
+
+#[derive(Debug)]
+pub struct EndOfStream;
+
+impl fmt::Display for EndOfStream {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "End of Stream")
+    }
+}
+
+impl std::error::Error for EndOfStream { }
+
+pub fn read_u8() -> Result<u8, EndOfStream> { Err(EndOfStream) }
+```
+
+Note that there are crates that simplify creating the error type, e.g.
+[`thiserror`](https://docs.rs/thiserror).
\ No newline at end of file
diff --git a/src/docs/return_self_not_must_use.txt b/src/docs/return_self_not_must_use.txt
new file mode 100644
index 00000000000..4a4fd2c6e51
--- /dev/null
+++ b/src/docs/return_self_not_must_use.txt
@@ -0,0 +1,46 @@
+### What it does
+This lint warns when a method returning `Self` doesn't have the `#[must_use]` attribute.
+
+### Why is this bad?
+Methods returning `Self` often create new values, having the `#[must_use]` attribute
+prevents users from "forgetting" to use the newly created value.
+
+The `#[must_use]` attribute can be added to the type itself to ensure that instances
+are never forgotten. Functions returning a type marked with `#[must_use]` will not be
+linted, as the usage is already enforced by the type attribute.
+
+### Limitations
+This lint is only applied on methods taking a `self` argument. It would be mostly noise
+if it was added on constructors for example.
+
+### Example
+```
+pub struct Bar;
+impl Bar {
+    // Missing attribute
+    pub fn bar(&self) -> Self {
+        Self
+    }
+}
+```
+
+Use instead:
+```
+// It's better to have the `#[must_use]` attribute on the method like this:
+pub struct Bar;
+impl Bar {
+    #[must_use]
+    pub fn bar(&self) -> Self {
+        Self
+    }
+}
+
+// Or on the type definition like this:
+#[must_use]
+pub struct Bar;
+impl Bar {
+    pub fn bar(&self) -> Self {
+        Self
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/reversed_empty_ranges.txt b/src/docs/reversed_empty_ranges.txt
new file mode 100644
index 00000000000..39f48119386
--- /dev/null
+++ b/src/docs/reversed_empty_ranges.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for range expressions `x..y` where both `x` and `y`
+are constant and `x` is greater or equal to `y`.
+
+### Why is this bad?
+Empty ranges yield no values so iterating them is a no-op.
+Moreover, trying to use a reversed range to index a slice will panic at run-time.
+
+### Example
+```
+fn main() {
+    (10..=0).for_each(|x| println!("{}", x));
+
+    let arr = [1, 2, 3, 4, 5];
+    let sub = &arr[3..1];
+}
+```
+Use instead:
+```
+fn main() {
+    (0..=10).rev().for_each(|x| println!("{}", x));
+
+    let arr = [1, 2, 3, 4, 5];
+    let sub = &arr[1..3];
+}
+```
\ No newline at end of file
diff --git a/src/docs/same_functions_in_if_condition.txt b/src/docs/same_functions_in_if_condition.txt
new file mode 100644
index 00000000000..a0a90eec681
--- /dev/null
+++ b/src/docs/same_functions_in_if_condition.txt
@@ -0,0 +1,41 @@
+### What it does
+Checks for consecutive `if`s with the same function call.
+
+### Why is this bad?
+This is probably a copy & paste error.
+Despite the fact that function can have side effects and `if` works as
+intended, such an approach is implicit and can be considered a "code smell".
+
+### Example
+```
+if foo() == bar {
+    …
+} else if foo() == bar {
+    …
+}
+```
+
+This probably should be:
+```
+if foo() == bar {
+    …
+} else if foo() == baz {
+    …
+}
+```
+
+or if the original code was not a typo and called function mutates a state,
+consider move the mutation out of the `if` condition to avoid similarity to
+a copy & paste error:
+
+```
+let first = foo();
+if first == bar {
+    …
+} else {
+    let second = foo();
+    if second == bar {
+    …
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/same_item_push.txt b/src/docs/same_item_push.txt
new file mode 100644
index 00000000000..7e724073f8a
--- /dev/null
+++ b/src/docs/same_item_push.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks whether a for loop is being used to push a constant
+value into a Vec.
+
+### Why is this bad?
+This kind of operation can be expressed more succinctly with
+`vec![item; SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also
+have better performance.
+
+### Example
+```
+let item1 = 2;
+let item2 = 3;
+let mut vec: Vec<u8> = Vec::new();
+for _ in 0..20 {
+   vec.push(item1);
+}
+for _ in 0..30 {
+    vec.push(item2);
+}
+```
+
+Use instead:
+```
+let item1 = 2;
+let item2 = 3;
+let mut vec: Vec<u8> = vec![item1; 20];
+vec.resize(20 + 30, item2);
+```
\ No newline at end of file
diff --git a/src/docs/same_name_method.txt b/src/docs/same_name_method.txt
new file mode 100644
index 00000000000..792dd717fc6
--- /dev/null
+++ b/src/docs/same_name_method.txt
@@ -0,0 +1,23 @@
+### What it does
+It lints if a struct has two methods with the same name:
+one from a trait, another not from trait.
+
+### Why is this bad?
+Confusing.
+
+### Example
+```
+trait T {
+    fn foo(&self) {}
+}
+
+struct S;
+
+impl T for S {
+    fn foo(&self) {}
+}
+
+impl S {
+    fn foo(&self) {}
+}
+```
\ No newline at end of file
diff --git a/src/docs/search_is_some.txt b/src/docs/search_is_some.txt
new file mode 100644
index 00000000000..67292d54585
--- /dev/null
+++ b/src/docs/search_is_some.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for an iterator or string search (such as `find()`,
+`position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`.
+
+### Why is this bad?
+Readability, this can be written more concisely as:
+* `_.any(_)`, or `_.contains(_)` for `is_some()`,
+* `!_.any(_)`, or `!_.contains(_)` for `is_none()`.
+
+### Example
+```
+let vec = vec![1];
+vec.iter().find(|x| **x == 0).is_some();
+
+"hello world".find("world").is_none();
+```
+
+Use instead:
+```
+let vec = vec![1];
+vec.iter().any(|x| *x == 0);
+
+!"hello world".contains("world");
+```
\ No newline at end of file
diff --git a/src/docs/self_assignment.txt b/src/docs/self_assignment.txt
new file mode 100644
index 00000000000..ea60ea077ab
--- /dev/null
+++ b/src/docs/self_assignment.txt
@@ -0,0 +1,32 @@
+### What it does
+Checks for explicit self-assignments.
+
+### Why is this bad?
+Self-assignments are redundant and unlikely to be
+intentional.
+
+### Known problems
+If expression contains any deref coercions or
+indexing operations they are assumed not to have any side effects.
+
+### Example
+```
+struct Event {
+    x: i32,
+}
+
+fn copy_position(a: &mut Event, b: &Event) {
+    a.x = a.x;
+}
+```
+
+Should be:
+```
+struct Event {
+    x: i32,
+}
+
+fn copy_position(a: &mut Event, b: &Event) {
+    a.x = b.x;
+}
+```
\ No newline at end of file
diff --git a/src/docs/self_named_constructors.txt b/src/docs/self_named_constructors.txt
new file mode 100644
index 00000000000..a01669a8454
--- /dev/null
+++ b/src/docs/self_named_constructors.txt
@@ -0,0 +1,26 @@
+### What it does
+Warns when constructors have the same name as their types.
+
+### Why is this bad?
+Repeating the name of the type is redundant.
+
+### Example
+```
+struct Foo {}
+
+impl Foo {
+    pub fn foo() -> Foo {
+        Foo {}
+    }
+}
+```
+Use instead:
+```
+struct Foo {}
+
+impl Foo {
+    pub fn new() -> Foo {
+        Foo {}
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/self_named_module_files.txt b/src/docs/self_named_module_files.txt
new file mode 100644
index 00000000000..73e80513628
--- /dev/null
+++ b/src/docs/self_named_module_files.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks that module layout uses only `mod.rs` files.
+
+### Why is this bad?
+Having multiple module layout styles in a project can be confusing.
+
+### Example
+```
+src/
+  stuff/
+    stuff_files.rs
+  stuff.rs
+  lib.rs
+```
+Use instead:
+```
+src/
+  stuff/
+    stuff_files.rs
+    mod.rs
+  lib.rs
+```
\ No newline at end of file
diff --git a/src/docs/semicolon_if_nothing_returned.txt b/src/docs/semicolon_if_nothing_returned.txt
new file mode 100644
index 00000000000..30c963ca211
--- /dev/null
+++ b/src/docs/semicolon_if_nothing_returned.txt
@@ -0,0 +1,20 @@
+### What it does
+Looks for blocks of expressions and fires if the last expression returns
+`()` but is not followed by a semicolon.
+
+### Why is this bad?
+The semicolon might be optional but when extending the block with new
+code, it doesn't require a change in previous last line.
+
+### Example
+```
+fn main() {
+    println!("Hello world")
+}
+```
+Use instead:
+```
+fn main() {
+    println!("Hello world");
+}
+```
\ No newline at end of file
diff --git a/src/docs/separated_literal_suffix.txt b/src/docs/separated_literal_suffix.txt
new file mode 100644
index 00000000000..226a6b8a987
--- /dev/null
+++ b/src/docs/separated_literal_suffix.txt
@@ -0,0 +1,17 @@
+### What it does
+Warns if literal suffixes are separated by an underscore.
+To enforce separated literal suffix style,
+see the `unseparated_literal_suffix` lint.
+
+### Why is this bad?
+Suffix style should be consistent.
+
+### Example
+```
+123832_i32
+```
+
+Use instead:
+```
+123832i32
+```
\ No newline at end of file
diff --git a/src/docs/serde_api_misuse.txt b/src/docs/serde_api_misuse.txt
new file mode 100644
index 00000000000..8a3c89ac11a
--- /dev/null
+++ b/src/docs/serde_api_misuse.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for mis-uses of the serde API.
+
+### Why is this bad?
+Serde is very finnicky about how its API should be
+used, but the type system can't be used to enforce it (yet?).
+
+### Example
+Implementing `Visitor::visit_string` but not
+`Visitor::visit_str`.
\ No newline at end of file
diff --git a/src/docs/shadow_reuse.txt b/src/docs/shadow_reuse.txt
new file mode 100644
index 00000000000..9eb8e7ad164
--- /dev/null
+++ b/src/docs/shadow_reuse.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for bindings that shadow other bindings already in
+scope, while reusing the original value.
+
+### Why is this bad?
+Not too much, in fact it's a common pattern in Rust
+code. Still, some argue that name shadowing like this hurts readability,
+because a value may be bound to different things depending on position in
+the code.
+
+### Example
+```
+let x = 2;
+let x = x + 1;
+```
+use different variable name:
+```
+let x = 2;
+let y = x + 1;
+```
\ No newline at end of file
diff --git a/src/docs/shadow_same.txt b/src/docs/shadow_same.txt
new file mode 100644
index 00000000000..3cd96f560a5
--- /dev/null
+++ b/src/docs/shadow_same.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for bindings that shadow other bindings already in
+scope, while just changing reference level or mutability.
+
+### Why is this bad?
+Not much, in fact it's a very common pattern in Rust
+code. Still, some may opt to avoid it in their code base, they can set this
+lint to `Warn`.
+
+### Example
+```
+let x = &x;
+```
+
+Use instead:
+```
+let y = &x; // use different variable name
+```
\ No newline at end of file
diff --git a/src/docs/shadow_unrelated.txt b/src/docs/shadow_unrelated.txt
new file mode 100644
index 00000000000..436251c520a
--- /dev/null
+++ b/src/docs/shadow_unrelated.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for bindings that shadow other bindings already in
+scope, either without an initialization or with one that does not even use
+the original value.
+
+### Why is this bad?
+Name shadowing can hurt readability, especially in
+large code bases, because it is easy to lose track of the active binding at
+any place in the code. This can be alleviated by either giving more specific
+names to bindings or introducing more scopes to contain the bindings.
+
+### Example
+```
+let x = y;
+let x = z; // shadows the earlier binding
+```
+
+Use instead:
+```
+let x = y;
+let w = z; // use different variable name
+```
\ No newline at end of file
diff --git a/src/docs/short_circuit_statement.txt b/src/docs/short_circuit_statement.txt
new file mode 100644
index 00000000000..31492bed03d
--- /dev/null
+++ b/src/docs/short_circuit_statement.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for the use of short circuit boolean conditions as
+a
+statement.
+
+### Why is this bad?
+Using a short circuit boolean condition as a statement
+may hide the fact that the second part is executed or not depending on the
+outcome of the first part.
+
+### Example
+```
+f() && g(); // We should write `if f() { g(); }`.
+```
\ No newline at end of file
diff --git a/src/docs/should_implement_trait.txt b/src/docs/should_implement_trait.txt
new file mode 100644
index 00000000000..02e74751ae0
--- /dev/null
+++ b/src/docs/should_implement_trait.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for methods that should live in a trait
+implementation of a `std` trait (see [llogiq's blog
+post](http://llogiq.github.io/2015/07/30/traits.html) for further
+information) instead of an inherent implementation.
+
+### Why is this bad?
+Implementing the traits improve ergonomics for users of
+the code, often with very little cost. Also people seeing a `mul(...)`
+method
+may expect `*` to work equally, so you should have good reason to disappoint
+them.
+
+### Example
+```
+struct X;
+impl X {
+    fn add(&self, other: &X) -> X {
+        // ..
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/significant_drop_in_scrutinee.txt b/src/docs/significant_drop_in_scrutinee.txt
new file mode 100644
index 00000000000..f869def0ddb
--- /dev/null
+++ b/src/docs/significant_drop_in_scrutinee.txt
@@ -0,0 +1,43 @@
+### What it does
+Check for temporaries returned from function calls in a match scrutinee that have the
+`clippy::has_significant_drop` attribute.
+
+### Why is this bad?
+The `clippy::has_significant_drop` attribute can be added to types whose Drop impls have
+an important side-effect, such as unlocking a mutex, making it important for users to be
+able to accurately understand their lifetimes. When a temporary is returned in a function
+call in a match scrutinee, its lifetime lasts until the end of the match block, which may
+be surprising.
+
+For `Mutex`es this can lead to a deadlock. This happens when the match scrutinee uses a
+function call that returns a `MutexGuard` and then tries to lock again in one of the match
+arms. In that case the `MutexGuard` in the scrutinee will not be dropped until the end of
+the match block and thus will not unlock.
+
+### Example
+```
+let mutex = Mutex::new(State {});
+
+match mutex.lock().unwrap().foo() {
+    true => {
+        mutex.lock().unwrap().bar(); // Deadlock!
+    }
+    false => {}
+};
+
+println!("All done!");
+```
+Use instead:
+```
+let mutex = Mutex::new(State {});
+
+let is_foo = mutex.lock().unwrap().foo();
+match is_foo {
+    true => {
+        mutex.lock().unwrap().bar();
+    }
+    false => {}
+};
+
+println!("All done!");
+```
\ No newline at end of file
diff --git a/src/docs/similar_names.txt b/src/docs/similar_names.txt
new file mode 100644
index 00000000000..13aca9c0bb7
--- /dev/null
+++ b/src/docs/similar_names.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for names that are very similar and thus confusing.
+
+### Why is this bad?
+It's hard to distinguish between names that differ only
+by a single character.
+
+### Example
+```
+let checked_exp = something;
+let checked_expr = something_else;
+```
\ No newline at end of file
diff --git a/src/docs/single_char_add_str.txt b/src/docs/single_char_add_str.txt
new file mode 100644
index 00000000000..cf23dc0c89b
--- /dev/null
+++ b/src/docs/single_char_add_str.txt
@@ -0,0 +1,18 @@
+### What it does
+Warns when using `push_str`/`insert_str` with a single-character string literal
+where `push`/`insert` with a `char` would work fine.
+
+### Why is this bad?
+It's less clear that we are pushing a single character.
+
+### Example
+```
+string.insert_str(0, "R");
+string.push_str("R");
+```
+
+Use instead:
+```
+string.insert(0, 'R');
+string.push('R');
+```
\ No newline at end of file
diff --git a/src/docs/single_char_lifetime_names.txt b/src/docs/single_char_lifetime_names.txt
new file mode 100644
index 00000000000..92dd24bf247
--- /dev/null
+++ b/src/docs/single_char_lifetime_names.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for lifetimes with names which are one character
+long.
+
+### Why is this bad?
+A single character is likely not enough to express the
+purpose of a lifetime. Using a longer name can make code
+easier to understand, especially for those who are new to
+Rust.
+
+### Known problems
+Rust programmers and learning resources tend to use single
+character lifetimes, so this lint is at odds with the
+ecosystem at large. In addition, the lifetime's purpose may
+be obvious or, rarely, expressible in one character.
+
+### Example
+```
+struct DiagnosticCtx<'a> {
+    source: &'a str,
+}
+```
+Use instead:
+```
+struct DiagnosticCtx<'src> {
+    source: &'src str,
+}
+```
\ No newline at end of file
diff --git a/src/docs/single_char_pattern.txt b/src/docs/single_char_pattern.txt
new file mode 100644
index 00000000000..9e5ad1e7d63
--- /dev/null
+++ b/src/docs/single_char_pattern.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for string methods that receive a single-character
+`str` as an argument, e.g., `_.split("x")`.
+
+### Why is this bad?
+Performing these methods using a `char` is faster than
+using a `str`.
+
+### Known problems
+Does not catch multi-byte unicode characters.
+
+### Example
+```
+_.split("x");
+```
+
+Use instead:
+```
+_.split('x');
+```
\ No newline at end of file
diff --git a/src/docs/single_component_path_imports.txt b/src/docs/single_component_path_imports.txt
new file mode 100644
index 00000000000..3a026388183
--- /dev/null
+++ b/src/docs/single_component_path_imports.txt
@@ -0,0 +1,21 @@
+### What it does
+Checking for imports with single component use path.
+
+### Why is this bad?
+Import with single component use path such as `use cratename;`
+is not necessary, and thus should be removed.
+
+### Example
+```
+use regex;
+
+fn main() {
+    regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
+}
+```
+Better as
+```
+fn main() {
+    regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
+}
+```
\ No newline at end of file
diff --git a/src/docs/single_element_loop.txt b/src/docs/single_element_loop.txt
new file mode 100644
index 00000000000..6f0c15a85f7
--- /dev/null
+++ b/src/docs/single_element_loop.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks whether a for loop has a single element.
+
+### Why is this bad?
+There is no reason to have a loop of a
+single element.
+
+### Example
+```
+let item1 = 2;
+for item in &[item1] {
+    println!("{}", item);
+}
+```
+
+Use instead:
+```
+let item1 = 2;
+let item = &item1;
+println!("{}", item);
+```
\ No newline at end of file
diff --git a/src/docs/single_match.txt b/src/docs/single_match.txt
new file mode 100644
index 00000000000..31dde4da848
--- /dev/null
+++ b/src/docs/single_match.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for matches with a single arm where an `if let`
+will usually suffice.
+
+### Why is this bad?
+Just readability – `if let` nests less than a `match`.
+
+### Example
+```
+match x {
+    Some(ref foo) => bar(foo),
+    _ => (),
+}
+```
+
+Use instead:
+```
+if let Some(ref foo) = x {
+    bar(foo);
+}
+```
\ No newline at end of file
diff --git a/src/docs/single_match_else.txt b/src/docs/single_match_else.txt
new file mode 100644
index 00000000000..29a447af09b
--- /dev/null
+++ b/src/docs/single_match_else.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for matches with two arms where an `if let else` will
+usually suffice.
+
+### Why is this bad?
+Just readability – `if let` nests less than a `match`.
+
+### Known problems
+Personal style preferences may differ.
+
+### Example
+Using `match`:
+
+```
+match x {
+    Some(ref foo) => bar(foo),
+    _ => bar(&other_ref),
+}
+```
+
+Using `if let` with `else`:
+
+```
+if let Some(ref foo) = x {
+    bar(foo);
+} else {
+    bar(&other_ref);
+}
+```
\ No newline at end of file
diff --git a/src/docs/size_of_in_element_count.txt b/src/docs/size_of_in_element_count.txt
new file mode 100644
index 00000000000..d893ec6a2a0
--- /dev/null
+++ b/src/docs/size_of_in_element_count.txt
@@ -0,0 +1,16 @@
+### What it does
+Detects expressions where
+`size_of::<T>` or `size_of_val::<T>` is used as a
+count of elements of type `T`
+
+### Why is this bad?
+These functions expect a count
+of `T` and not a number of bytes
+
+### Example
+```
+const SIZE: usize = 128;
+let x = [2u8; SIZE];
+let mut y = [2u8; SIZE];
+unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
+```
\ No newline at end of file
diff --git a/src/docs/skip_while_next.txt b/src/docs/skip_while_next.txt
new file mode 100644
index 00000000000..1ec8a3a28d5
--- /dev/null
+++ b/src/docs/skip_while_next.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for usage of `_.skip_while(condition).next()`.
+
+### Why is this bad?
+Readability, this can be written more concisely as
+`_.find(!condition)`.
+
+### Example
+```
+vec.iter().skip_while(|x| **x == 0).next();
+```
+
+Use instead:
+```
+vec.iter().find(|x| **x != 0);
+```
\ No newline at end of file
diff --git a/src/docs/slow_vector_initialization.txt b/src/docs/slow_vector_initialization.txt
new file mode 100644
index 00000000000..53442e17965
--- /dev/null
+++ b/src/docs/slow_vector_initialization.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks slow zero-filled vector initialization
+
+### Why is this bad?
+These structures are non-idiomatic and less efficient than simply using
+`vec![0; len]`.
+
+### Example
+```
+let mut vec1 = Vec::with_capacity(len);
+vec1.resize(len, 0);
+
+let mut vec1 = Vec::with_capacity(len);
+vec1.resize(vec1.capacity(), 0);
+
+let mut vec2 = Vec::with_capacity(len);
+vec2.extend(repeat(0).take(len));
+```
+
+Use instead:
+```
+let mut vec1 = vec![0; len];
+let mut vec2 = vec![0; len];
+```
\ No newline at end of file
diff --git a/src/docs/stable_sort_primitive.txt b/src/docs/stable_sort_primitive.txt
new file mode 100644
index 00000000000..6465dbee46b
--- /dev/null
+++ b/src/docs/stable_sort_primitive.txt
@@ -0,0 +1,31 @@
+### What it does
+When sorting primitive values (integers, bools, chars, as well
+as arrays, slices, and tuples of such items), it is typically better to
+use an unstable sort than a stable sort.
+
+### Why is this bad?
+Typically, using a stable sort consumes more memory and cpu cycles.
+Because values which compare equal are identical, preserving their
+relative order (the guarantee that a stable sort provides) means
+nothing, while the extra costs still apply.
+
+### Known problems
+
+As pointed out in
+[issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241),
+a stable sort can instead be significantly faster for certain scenarios
+(eg. when a sorted vector is extended with new data and resorted).
+
+For more information and benchmarking results, please refer to the
+issue linked above.
+
+### Example
+```
+let mut vec = vec![2, 1, 3];
+vec.sort();
+```
+Use instead:
+```
+let mut vec = vec![2, 1, 3];
+vec.sort_unstable();
+```
\ No newline at end of file
diff --git a/src/docs/std_instead_of_alloc.txt b/src/docs/std_instead_of_alloc.txt
new file mode 100644
index 00000000000..c2d32704e50
--- /dev/null
+++ b/src/docs/std_instead_of_alloc.txt
@@ -0,0 +1,18 @@
+### What it does
+
+Finds items imported through `std` when available through `alloc`.
+
+### Why is this bad?
+
+Crates which have `no_std` compatibility and require alloc may wish to ensure types are imported from
+alloc to ensure disabling `std` does not cause the crate to fail to compile. This lint is also useful
+for crates migrating to become `no_std` compatible.
+
+### Example
+```
+use std::vec::Vec;
+```
+Use instead:
+```
+use alloc::vec::Vec;
+```
\ No newline at end of file
diff --git a/src/docs/std_instead_of_core.txt b/src/docs/std_instead_of_core.txt
new file mode 100644
index 00000000000..f1e1518c6a6
--- /dev/null
+++ b/src/docs/std_instead_of_core.txt
@@ -0,0 +1,18 @@
+### What it does
+
+Finds items imported through `std` when available through `core`.
+
+### Why is this bad?
+
+Crates which have `no_std` compatibility may wish to ensure types are imported from core to ensure
+disabling `std` does not cause the crate to fail to compile. This lint is also useful for crates
+migrating to become `no_std` compatible.
+
+### Example
+```
+use std::hash::Hasher;
+```
+Use instead:
+```
+use core::hash::Hasher;
+```
\ No newline at end of file
diff --git a/src/docs/str_to_string.txt b/src/docs/str_to_string.txt
new file mode 100644
index 00000000000..a2475522374
--- /dev/null
+++ b/src/docs/str_to_string.txt
@@ -0,0 +1,18 @@
+### What it does
+This lint checks for `.to_string()` method calls on values of type `&str`.
+
+### Why is this bad?
+The `to_string` method is also used on other types to convert them to a string.
+When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better
+expressed with `.to_owned()`.
+
+### Example
+```
+// example code where clippy issues a warning
+let _ = "str".to_string();
+```
+Use instead:
+```
+// example code which does not raise clippy warning
+let _ = "str".to_owned();
+```
\ No newline at end of file
diff --git a/src/docs/string_add.txt b/src/docs/string_add.txt
new file mode 100644
index 00000000000..23dafd0d033
--- /dev/null
+++ b/src/docs/string_add.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for all instances of `x + _` where `x` is of type
+`String`, but only if [`string_add_assign`](#string_add_assign) does *not*
+match.
+
+### Why is this bad?
+It's not bad in and of itself. However, this particular
+`Add` implementation is asymmetric (the other operand need not be `String`,
+but `x` does), while addition as mathematically defined is symmetric, also
+the `String::push_str(_)` function is a perfectly good replacement.
+Therefore, some dislike it and wish not to have it in their code.
+
+That said, other people think that string addition, having a long tradition
+in other languages is actually fine, which is why we decided to make this
+particular lint `allow` by default.
+
+### Example
+```
+let x = "Hello".to_owned();
+x + ", World";
+```
+
+Use instead:
+```
+let mut x = "Hello".to_owned();
+x.push_str(", World");
+```
\ No newline at end of file
diff --git a/src/docs/string_add_assign.txt b/src/docs/string_add_assign.txt
new file mode 100644
index 00000000000..7438be855db
--- /dev/null
+++ b/src/docs/string_add_assign.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for string appends of the form `x = x + y` (without
+`let`!).
+
+### Why is this bad?
+It's not really bad, but some people think that the
+`.push_str(_)` method is more readable.
+
+### Example
+```
+let mut x = "Hello".to_owned();
+x = x + ", World";
+
+// More readable
+x += ", World";
+x.push_str(", World");
+```
\ No newline at end of file
diff --git a/src/docs/string_extend_chars.txt b/src/docs/string_extend_chars.txt
new file mode 100644
index 00000000000..619ea3e1186
--- /dev/null
+++ b/src/docs/string_extend_chars.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for the use of `.extend(s.chars())` where s is a
+`&str` or `String`.
+
+### Why is this bad?
+`.push_str(s)` is clearer
+
+### Example
+```
+let abc = "abc";
+let def = String::from("def");
+let mut s = String::new();
+s.extend(abc.chars());
+s.extend(def.chars());
+```
+The correct use would be:
+```
+let abc = "abc";
+let def = String::from("def");
+let mut s = String::new();
+s.push_str(abc);
+s.push_str(&def);
+```
\ No newline at end of file
diff --git a/src/docs/string_from_utf8_as_bytes.txt b/src/docs/string_from_utf8_as_bytes.txt
new file mode 100644
index 00000000000..9102d73471c
--- /dev/null
+++ b/src/docs/string_from_utf8_as_bytes.txt
@@ -0,0 +1,15 @@
+### What it does
+Check if the string is transformed to byte array and casted back to string.
+
+### Why is this bad?
+It's unnecessary, the string can be used directly.
+
+### Example
+```
+std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap();
+```
+
+Use instead:
+```
+&"Hello World!"[6..11];
+```
\ No newline at end of file
diff --git a/src/docs/string_lit_as_bytes.txt b/src/docs/string_lit_as_bytes.txt
new file mode 100644
index 00000000000..a125b97ed65
--- /dev/null
+++ b/src/docs/string_lit_as_bytes.txt
@@ -0,0 +1,39 @@
+### What it does
+Checks for the `as_bytes` method called on string literals
+that contain only ASCII characters.
+
+### Why is this bad?
+Byte string literals (e.g., `b"foo"`) can be used
+instead. They are shorter but less discoverable than `as_bytes()`.
+
+### Known problems
+`"str".as_bytes()` and the suggested replacement of `b"str"` are not
+equivalent because they have different types. The former is `&[u8]`
+while the latter is `&[u8; 3]`. That means in general they will have a
+different set of methods and different trait implementations.
+
+```
+fn f(v: Vec<u8>) {}
+
+f("...".as_bytes().to_owned()); // works
+f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec<u8>
+
+fn g(r: impl std::io::Read) {}
+
+g("...".as_bytes()); // works
+g(b"..."); // does not work
+```
+
+The actual equivalent of `"str".as_bytes()` with the same type is not
+`b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not
+more readable than a function call.
+
+### Example
+```
+let bstr = "a byte string".as_bytes();
+```
+
+Use instead:
+```
+let bstr = b"a byte string";
+```
\ No newline at end of file
diff --git a/src/docs/string_slice.txt b/src/docs/string_slice.txt
new file mode 100644
index 00000000000..3d9e49dd39e
--- /dev/null
+++ b/src/docs/string_slice.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for slice operations on strings
+
+### Why is this bad?
+UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character
+counts and string indices. This may lead to panics, and should warrant some test cases
+containing wide UTF-8 characters. This lint is most useful in code that should avoid
+panics at all costs.
+
+### Known problems
+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
+```
+&"Ölkanne"[1..];
+```
\ No newline at end of file
diff --git a/src/docs/string_to_string.txt b/src/docs/string_to_string.txt
new file mode 100644
index 00000000000..deb7eebe784
--- /dev/null
+++ b/src/docs/string_to_string.txt
@@ -0,0 +1,19 @@
+### What it does
+This lint checks for `.to_string()` method calls on values of type `String`.
+
+### Why is this bad?
+The `to_string` method is also used on other types to convert them to a string.
+When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`.
+
+### Example
+```
+// example code where clippy issues a warning
+let msg = String::from("Hello World");
+let _ = msg.to_string();
+```
+Use instead:
+```
+// example code which does not raise clippy warning
+let msg = String::from("Hello World");
+let _ = msg.clone();
+```
\ No newline at end of file
diff --git a/src/docs/strlen_on_c_strings.txt b/src/docs/strlen_on_c_strings.txt
new file mode 100644
index 00000000000..0454abf55a2
--- /dev/null
+++ b/src/docs/strlen_on_c_strings.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for usage of `libc::strlen` on a `CString` or `CStr` value,
+and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead.
+
+### Why is this bad?
+This avoids calling an unsafe `libc` function.
+Currently, it also avoids calculating the length.
+
+### Example
+```
+use std::ffi::CString;
+let cstring = CString::new("foo").expect("CString::new failed");
+let len = unsafe { libc::strlen(cstring.as_ptr()) };
+```
+Use instead:
+```
+use std::ffi::CString;
+let cstring = CString::new("foo").expect("CString::new failed");
+let len = cstring.as_bytes().len();
+```
\ No newline at end of file
diff --git a/src/docs/struct_excessive_bools.txt b/src/docs/struct_excessive_bools.txt
new file mode 100644
index 00000000000..9e197c78620
--- /dev/null
+++ b/src/docs/struct_excessive_bools.txt
@@ -0,0 +1,29 @@
+### What it does
+Checks for excessive
+use of bools in structs.
+
+### Why is this bad?
+Excessive bools in a struct
+is often a sign that it's used as a state machine,
+which is much better implemented as an enum.
+If it's not the case, excessive bools usually benefit
+from refactoring into two-variant enums for better
+readability and API.
+
+### Example
+```
+struct S {
+    is_pending: bool,
+    is_processing: bool,
+    is_finished: bool,
+}
+```
+
+Use instead:
+```
+enum S {
+    Pending,
+    Processing,
+    Finished,
+}
+```
\ No newline at end of file
diff --git a/src/docs/suboptimal_flops.txt b/src/docs/suboptimal_flops.txt
new file mode 100644
index 00000000000..f1c9c665b08
--- /dev/null
+++ b/src/docs/suboptimal_flops.txt
@@ -0,0 +1,50 @@
+### What it does
+Looks for floating-point expressions that
+can be expressed using built-in methods to improve both
+accuracy and performance.
+
+### Why is this bad?
+Negatively impacts accuracy and performance.
+
+### Example
+```
+use std::f32::consts::E;
+
+let a = 3f32;
+let _ = (2f32).powf(a);
+let _ = E.powf(a);
+let _ = a.powf(1.0 / 2.0);
+let _ = a.log(2.0);
+let _ = a.log(10.0);
+let _ = a.log(E);
+let _ = a.powf(2.0);
+let _ = a * 2.0 + 4.0;
+let _ = if a < 0.0 {
+    -a
+} else {
+    a
+};
+let _ = if a < 0.0 {
+    a
+} else {
+    -a
+};
+```
+
+is better expressed as
+
+```
+use std::f32::consts::E;
+
+let a = 3f32;
+let _ = a.exp2();
+let _ = a.exp();
+let _ = a.sqrt();
+let _ = a.log2();
+let _ = a.log10();
+let _ = a.ln();
+let _ = a.powi(2);
+let _ = a.mul_add(2.0, 4.0);
+let _ = a.abs();
+let _ = -a.abs();
+```
\ No newline at end of file
diff --git a/src/docs/suspicious_arithmetic_impl.txt b/src/docs/suspicious_arithmetic_impl.txt
new file mode 100644
index 00000000000..d67ff279346
--- /dev/null
+++ b/src/docs/suspicious_arithmetic_impl.txt
@@ -0,0 +1,17 @@
+### What it does
+Lints for suspicious operations in impls of arithmetic operators, e.g.
+subtracting elements in an Add impl.
+
+### Why is this bad?
+This is probably a typo or copy-and-paste error and not intended.
+
+### Example
+```
+impl Add for Foo {
+    type Output = Foo;
+
+    fn add(self, other: Foo) -> Foo {
+        Foo(self.0 - other.0)
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/suspicious_assignment_formatting.txt b/src/docs/suspicious_assignment_formatting.txt
new file mode 100644
index 00000000000..b889827cdf2
--- /dev/null
+++ b/src/docs/suspicious_assignment_formatting.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for use of the non-existent `=*`, `=!` and `=-`
+operators.
+
+### Why is this bad?
+This is either a typo of `*=`, `!=` or `-=` or
+confusing.
+
+### Example
+```
+a =- 42; // confusing, should it be `a -= 42` or `a = -42`?
+```
\ No newline at end of file
diff --git a/src/docs/suspicious_else_formatting.txt b/src/docs/suspicious_else_formatting.txt
new file mode 100644
index 00000000000..3cf2f74868e
--- /dev/null
+++ b/src/docs/suspicious_else_formatting.txt
@@ -0,0 +1,30 @@
+### What it does
+Checks for formatting of `else`. It lints if the `else`
+is followed immediately by a newline or the `else` seems to be missing.
+
+### Why is this bad?
+This is probably some refactoring remnant, even if the
+code is correct, it might look confusing.
+
+### Example
+```
+if foo {
+} { // looks like an `else` is missing here
+}
+
+if foo {
+} if bar { // looks like an `else` is missing here
+}
+
+if foo {
+} else
+
+{ // this is the `else` block of the previous `if`, but should it be?
+}
+
+if foo {
+} else
+
+if bar { // this is the `else` block of the previous `if`, but should it be?
+}
+```
\ No newline at end of file
diff --git a/src/docs/suspicious_map.txt b/src/docs/suspicious_map.txt
new file mode 100644
index 00000000000..d8fa52c43fb
--- /dev/null
+++ b/src/docs/suspicious_map.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for calls to `map` followed by a `count`.
+
+### Why is this bad?
+It looks suspicious. Maybe `map` was confused with `filter`.
+If the `map` call is intentional, this should be rewritten
+using `inspect`. Or, if you intend to drive the iterator to
+completion, you can just use `for_each` instead.
+
+### Example
+```
+let _ = (0..3).map(|x| x + 2).count();
+```
\ No newline at end of file
diff --git a/src/docs/suspicious_op_assign_impl.txt b/src/docs/suspicious_op_assign_impl.txt
new file mode 100644
index 00000000000..81abfbecae0
--- /dev/null
+++ b/src/docs/suspicious_op_assign_impl.txt
@@ -0,0 +1,15 @@
+### What it does
+Lints for suspicious operations in impls of OpAssign, e.g.
+subtracting elements in an AddAssign impl.
+
+### Why is this bad?
+This is probably a typo or copy-and-paste error and not intended.
+
+### Example
+```
+impl AddAssign for Foo {
+    fn add_assign(&mut self, other: Foo) {
+        *self = *self - other;
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/suspicious_operation_groupings.txt b/src/docs/suspicious_operation_groupings.txt
new file mode 100644
index 00000000000..81ede5d3da5
--- /dev/null
+++ b/src/docs/suspicious_operation_groupings.txt
@@ -0,0 +1,41 @@
+### What it does
+Checks for unlikely usages of binary operators that are almost
+certainly typos and/or copy/paste errors, given the other usages
+of binary operators nearby.
+
+### Why is this bad?
+They are probably bugs and if they aren't then they look like bugs
+and you should add a comment explaining why you are doing such an
+odd set of operations.
+
+### Known problems
+There may be some false positives if you are trying to do something
+unusual that happens to look like a typo.
+
+### Example
+```
+struct Vec3 {
+    x: f64,
+    y: f64,
+    z: f64,
+}
+
+impl Eq for Vec3 {}
+
+impl PartialEq for Vec3 {
+    fn eq(&self, other: &Self) -> bool {
+        // This should trigger the lint because `self.x` is compared to `other.y`
+        self.x == other.y && self.y == other.y && self.z == other.z
+    }
+}
+```
+Use instead:
+```
+// same as above except:
+impl PartialEq for Vec3 {
+    fn eq(&self, other: &Self) -> bool {
+        // Note we now compare other.x to self.x
+        self.x == other.x && self.y == other.y && self.z == other.z
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/suspicious_splitn.txt b/src/docs/suspicious_splitn.txt
new file mode 100644
index 00000000000..79a3dbfa6f4
--- /dev/null
+++ b/src/docs/suspicious_splitn.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for calls to [`splitn`]
+(https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
+related functions with either zero or one splits.
+
+### Why is this bad?
+These calls don't actually split the value and are
+likely to be intended as a different number.
+
+### Example
+```
+for x in s.splitn(1, ":") {
+    // ..
+}
+```
+
+Use instead:
+```
+for x in s.splitn(2, ":") {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/suspicious_to_owned.txt b/src/docs/suspicious_to_owned.txt
new file mode 100644
index 00000000000..8cbf61dc717
--- /dev/null
+++ b/src/docs/suspicious_to_owned.txt
@@ -0,0 +1,39 @@
+### What it does
+Checks for the usage of `_.to_owned()`, on a `Cow<'_, _>`.
+
+### Why is this bad?
+Calling `to_owned()` on a `Cow` creates a clone of the `Cow`
+itself, without taking ownership of the `Cow` contents (i.e.
+it's equivalent to calling `Cow::clone`).
+The similarly named `into_owned` method, on the other hand,
+clones the `Cow` contents, effectively turning any `Cow::Borrowed`
+into a `Cow::Owned`.
+
+Given the potential ambiguity, consider replacing `to_owned`
+with `clone` for better readability or, if getting a `Cow::Owned`
+was the original intent, using `into_owned` instead.
+
+### Example
+```
+let s = "Hello world!";
+let cow = Cow::Borrowed(s);
+
+let data = cow.to_owned();
+assert!(matches!(data, Cow::Borrowed(_)))
+```
+Use instead:
+```
+let s = "Hello world!";
+let cow = Cow::Borrowed(s);
+
+let data = cow.clone();
+assert!(matches!(data, Cow::Borrowed(_)))
+```
+or
+```
+let s = "Hello world!";
+let cow = Cow::Borrowed(s);
+
+let data = cow.into_owned();
+assert!(matches!(data, String))
+```
\ No newline at end of file
diff --git a/src/docs/suspicious_unary_op_formatting.txt b/src/docs/suspicious_unary_op_formatting.txt
new file mode 100644
index 00000000000..06fb09db76d
--- /dev/null
+++ b/src/docs/suspicious_unary_op_formatting.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks the formatting of a unary operator on the right hand side
+of a binary operator. It lints if there is no space between the binary and unary operators,
+but there is a space between the unary and its operand.
+
+### Why is this bad?
+This is either a typo in the binary operator or confusing.
+
+### Example
+```
+// &&! looks like a different operator
+if foo &&! bar {}
+```
+
+Use instead:
+```
+if foo && !bar {}
+```
\ No newline at end of file
diff --git a/src/docs/swap_ptr_to_ref.txt b/src/docs/swap_ptr_to_ref.txt
new file mode 100644
index 00000000000..0215d1e8a42
--- /dev/null
+++ b/src/docs/swap_ptr_to_ref.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for calls to `core::mem::swap` where either parameter is derived from a pointer
+
+### Why is this bad?
+When at least one parameter to `swap` is derived from a pointer it may overlap with the
+other. This would then lead to undefined behavior.
+
+### Example
+```
+unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) {
+    for (&x, &y) in x.iter().zip(y) {
+        core::mem::swap(&mut *x, &mut *y);
+    }
+}
+```
+Use instead:
+```
+unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) {
+    for (&x, &y) in x.iter().zip(y) {
+        core::ptr::swap(x, y);
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/tabs_in_doc_comments.txt b/src/docs/tabs_in_doc_comments.txt
new file mode 100644
index 00000000000..f83dbe2b73c
--- /dev/null
+++ b/src/docs/tabs_in_doc_comments.txt
@@ -0,0 +1,44 @@
+### What it does
+Checks doc comments for usage of tab characters.
+
+### Why is this bad?
+The rust style-guide promotes spaces instead of tabs for indentation.
+To keep a consistent view on the source, also doc comments should not have tabs.
+Also, explaining ascii-diagrams containing tabs can get displayed incorrectly when the
+display settings of the author and reader differ.
+
+### Example
+```
+///
+/// Struct to hold two strings:
+/// 	- first		one
+/// 	- second	one
+pub struct DoubleString {
+   ///
+   /// 	- First String:
+   /// 		- needs to be inside here
+   first_string: String,
+   ///
+   /// 	- Second String:
+   /// 		- needs to be inside here
+   second_string: String,
+}
+```
+
+Will be converted to:
+```
+///
+/// Struct to hold two strings:
+///     - first        one
+///     - second    one
+pub struct DoubleString {
+   ///
+   ///     - First String:
+   ///         - needs to be inside here
+   first_string: String,
+   ///
+   ///     - Second String:
+   ///         - needs to be inside here
+   second_string: String,
+}
+```
\ No newline at end of file
diff --git a/src/docs/temporary_assignment.txt b/src/docs/temporary_assignment.txt
new file mode 100644
index 00000000000..195b42cf0d4
--- /dev/null
+++ b/src/docs/temporary_assignment.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for construction of a structure or tuple just to
+assign a value in it.
+
+### Why is this bad?
+Readability. If the structure is only created to be
+updated, why not write the structure you want in the first place?
+
+### Example
+```
+(0, 0).0 = 1
+```
\ No newline at end of file
diff --git a/src/docs/to_digit_is_some.txt b/src/docs/to_digit_is_some.txt
new file mode 100644
index 00000000000..eee8375adf7
--- /dev/null
+++ b/src/docs/to_digit_is_some.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for `.to_digit(..).is_some()` on `char`s.
+
+### Why is this bad?
+This is a convoluted way of checking if a `char` is a digit. It's
+more straight forward to use the dedicated `is_digit` method.
+
+### Example
+```
+let is_digit = c.to_digit(radix).is_some();
+```
+can be written as:
+```
+let is_digit = c.is_digit(radix);
+```
\ No newline at end of file
diff --git a/src/docs/to_string_in_format_args.txt b/src/docs/to_string_in_format_args.txt
new file mode 100644
index 00000000000..34b20583585
--- /dev/null
+++ b/src/docs/to_string_in_format_args.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string)
+applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html)
+in a macro that does formatting.
+
+### Why is this bad?
+Since the type implements `Display`, the use of `to_string` is
+unnecessary.
+
+### Example
+```
+println!("error: something failed at {}", Location::caller().to_string());
+```
+Use instead:
+```
+println!("error: something failed at {}", Location::caller());
+```
\ No newline at end of file
diff --git a/src/docs/todo.txt b/src/docs/todo.txt
new file mode 100644
index 00000000000..661eb1ac5cf
--- /dev/null
+++ b/src/docs/todo.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for usage of `todo!`.
+
+### Why is this bad?
+This macro should not be present in production code
+
+### Example
+```
+todo!();
+```
\ No newline at end of file
diff --git a/src/docs/too_many_arguments.txt b/src/docs/too_many_arguments.txt
new file mode 100644
index 00000000000..4669f9f82e6
--- /dev/null
+++ b/src/docs/too_many_arguments.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for functions with too many parameters.
+
+### Why is this bad?
+Functions with lots of parameters are considered bad
+style and reduce readability (“what does the 5th parameter mean?”). Consider
+grouping some parameters into a new type.
+
+### Example
+```
+fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
+    // ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/too_many_lines.txt b/src/docs/too_many_lines.txt
new file mode 100644
index 00000000000..425db348bbd
--- /dev/null
+++ b/src/docs/too_many_lines.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for functions with a large amount of lines.
+
+### Why is this bad?
+Functions with a lot of lines are harder to understand
+due to having to look at a larger amount of code to understand what the
+function is doing. Consider splitting the body of the function into
+multiple functions.
+
+### Example
+```
+fn im_too_long() {
+    println!("");
+    // ... 100 more LoC
+    println!("");
+}
+```
\ No newline at end of file
diff --git a/src/docs/toplevel_ref_arg.txt b/src/docs/toplevel_ref_arg.txt
new file mode 100644
index 00000000000..96a9e2db8b7
--- /dev/null
+++ b/src/docs/toplevel_ref_arg.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for function arguments and let bindings denoted as
+`ref`.
+
+### Why is this bad?
+The `ref` declaration makes the function take an owned
+value, but turns the argument into a reference (which means that the value
+is destroyed when exiting the function). This adds not much value: either
+take a reference type, or take an owned value and create references in the
+body.
+
+For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The
+type of `x` is more obvious with the former.
+
+### Known problems
+If the argument is dereferenced within the function,
+removing the `ref` will lead to errors. This can be fixed by removing the
+dereferences, e.g., changing `*x` to `x` within the function.
+
+### Example
+```
+fn foo(ref _x: u8) {}
+```
+
+Use instead:
+```
+fn foo(_x: &u8) {}
+```
\ No newline at end of file
diff --git a/src/docs/trailing_empty_array.txt b/src/docs/trailing_empty_array.txt
new file mode 100644
index 00000000000..db1908cc96d
--- /dev/null
+++ b/src/docs/trailing_empty_array.txt
@@ -0,0 +1,22 @@
+### What it does
+Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute.
+
+### Why is this bad?
+Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjunction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed.
+
+### Example
+```
+struct RarelyUseful {
+    some_field: u32,
+    last: [u32; 0],
+}
+```
+
+Use instead:
+```
+#[repr(C)]
+struct MoreOftenUseful {
+    some_field: usize,
+    last: [u32; 0],
+}
+```
\ No newline at end of file
diff --git a/src/docs/trait_duplication_in_bounds.txt b/src/docs/trait_duplication_in_bounds.txt
new file mode 100644
index 00000000000..509736bb364
--- /dev/null
+++ b/src/docs/trait_duplication_in_bounds.txt
@@ -0,0 +1,37 @@
+### What it does
+Checks for cases where generics are being used and multiple
+syntax specifications for trait bounds are used simultaneously.
+
+### Why is this bad?
+Duplicate bounds makes the code
+less readable than specifying them only once.
+
+### Example
+```
+fn func<T: Clone + Default>(arg: T) where T: Clone + Default {}
+```
+
+Use instead:
+```
+fn func<T: Clone + Default>(arg: T) {}
+
+// or
+
+fn func<T>(arg: T) where T: Clone + Default {}
+```
+
+```
+fn foo<T: Default + Default>(bar: T) {}
+```
+Use instead:
+```
+fn foo<T: Default>(bar: T) {}
+```
+
+```
+fn foo<T>(bar: T) where T: Default + Default {}
+```
+Use instead:
+```
+fn foo<T>(bar: T) where T: Default {}
+```
\ No newline at end of file
diff --git a/src/docs/transmute_bytes_to_str.txt b/src/docs/transmute_bytes_to_str.txt
new file mode 100644
index 00000000000..75889b9c73a
--- /dev/null
+++ b/src/docs/transmute_bytes_to_str.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for transmutes from a `&[u8]` to a `&str`.
+
+### Why is this bad?
+Not every byte slice is a valid UTF-8 string.
+
+### Known problems
+- [`from_utf8`] which this lint suggests using is slower than `transmute`
+as it needs to validate the input.
+If you are certain that the input is always a valid UTF-8,
+use [`from_utf8_unchecked`] which is as fast as `transmute`
+but has a semantically meaningful name.
+- You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`.
+
+[`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html
+[`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html
+
+### Example
+```
+let b: &[u8] = &[1_u8, 2_u8];
+unsafe {
+    let _: &str = std::mem::transmute(b); // where b: &[u8]
+}
+
+// should be:
+let _ = std::str::from_utf8(b).unwrap();
+```
\ No newline at end of file
diff --git a/src/docs/transmute_float_to_int.txt b/src/docs/transmute_float_to_int.txt
new file mode 100644
index 00000000000..1877e5a465a
--- /dev/null
+++ b/src/docs/transmute_float_to_int.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes from a float to an integer.
+
+### Why is this bad?
+Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive
+and safe.
+
+### Example
+```
+unsafe {
+    let _: u32 = std::mem::transmute(1f32);
+}
+
+// should be:
+let _: u32 = 1f32.to_bits();
+```
\ No newline at end of file
diff --git a/src/docs/transmute_int_to_bool.txt b/src/docs/transmute_int_to_bool.txt
new file mode 100644
index 00000000000..07c10f8d0bc
--- /dev/null
+++ b/src/docs/transmute_int_to_bool.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes from an integer to a `bool`.
+
+### Why is this bad?
+This might result in an invalid in-memory representation of a `bool`.
+
+### Example
+```
+let x = 1_u8;
+unsafe {
+    let _: bool = std::mem::transmute(x); // where x: u8
+}
+
+// should be:
+let _: bool = x != 0;
+```
\ No newline at end of file
diff --git a/src/docs/transmute_int_to_char.txt b/src/docs/transmute_int_to_char.txt
new file mode 100644
index 00000000000..836d22d3f99
--- /dev/null
+++ b/src/docs/transmute_int_to_char.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for transmutes from an integer to a `char`.
+
+### Why is this bad?
+Not every integer is a Unicode scalar value.
+
+### Known problems
+- [`from_u32`] which this lint suggests using is slower than `transmute`
+as it needs to validate the input.
+If you are certain that the input is always a valid Unicode scalar value,
+use [`from_u32_unchecked`] which is as fast as `transmute`
+but has a semantically meaningful name.
+- You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`.
+
+[`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html
+[`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
+
+### Example
+```
+let x = 1_u32;
+unsafe {
+    let _: char = std::mem::transmute(x); // where x: u32
+}
+
+// should be:
+let _ = std::char::from_u32(x).unwrap();
+```
\ No newline at end of file
diff --git a/src/docs/transmute_int_to_float.txt b/src/docs/transmute_int_to_float.txt
new file mode 100644
index 00000000000..75cdc62e972
--- /dev/null
+++ b/src/docs/transmute_int_to_float.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes from an integer to a float.
+
+### Why is this bad?
+Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive
+and safe.
+
+### Example
+```
+unsafe {
+    let _: f32 = std::mem::transmute(1_u32); // where x: u32
+}
+
+// should be:
+let _: f32 = f32::from_bits(1_u32);
+```
\ No newline at end of file
diff --git a/src/docs/transmute_num_to_bytes.txt b/src/docs/transmute_num_to_bytes.txt
new file mode 100644
index 00000000000..a2c39a1b947
--- /dev/null
+++ b/src/docs/transmute_num_to_bytes.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes from a number to an array of `u8`
+
+### Why this is bad?
+Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
+is intuitive and safe.
+
+### Example
+```
+unsafe {
+    let x: [u8; 8] = std::mem::transmute(1i64);
+}
+
+// should be
+let x: [u8; 8] = 0i64.to_ne_bytes();
+```
\ No newline at end of file
diff --git a/src/docs/transmute_ptr_to_ptr.txt b/src/docs/transmute_ptr_to_ptr.txt
new file mode 100644
index 00000000000..65777db9861
--- /dev/null
+++ b/src/docs/transmute_ptr_to_ptr.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for transmutes from a pointer to a pointer, or
+from a reference to a reference.
+
+### Why is this bad?
+Transmutes are dangerous, and these can instead be
+written as casts.
+
+### Example
+```
+let ptr = &1u32 as *const u32;
+unsafe {
+    // pointer-to-pointer transmute
+    let _: *const f32 = std::mem::transmute(ptr);
+    // ref-ref transmute
+    let _: &f32 = std::mem::transmute(&1u32);
+}
+// These can be respectively written:
+let _ = ptr as *const f32;
+let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) };
+```
\ No newline at end of file
diff --git a/src/docs/transmute_ptr_to_ref.txt b/src/docs/transmute_ptr_to_ref.txt
new file mode 100644
index 00000000000..aca550f5036
--- /dev/null
+++ b/src/docs/transmute_ptr_to_ref.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for transmutes from a pointer to a reference.
+
+### Why is this bad?
+This can always be rewritten with `&` and `*`.
+
+### Known problems
+- `mem::transmute` in statics and constants is stable from Rust 1.46.0,
+while dereferencing raw pointer is not stable yet.
+If you need to do this in those places,
+you would have to use `transmute` instead.
+
+### Example
+```
+unsafe {
+    let _: &T = std::mem::transmute(p); // where p: *const T
+}
+
+// can be written:
+let _: &T = &*p;
+```
\ No newline at end of file
diff --git a/src/docs/transmute_undefined_repr.txt b/src/docs/transmute_undefined_repr.txt
new file mode 100644
index 00000000000..5ee6aaf4ca9
--- /dev/null
+++ b/src/docs/transmute_undefined_repr.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for transmutes between types which do not have a representation defined relative to
+each other.
+
+### Why is this bad?
+The results of such a transmute are not defined.
+
+### Known problems
+This lint has had multiple problems in the past and was moved to `nursery`. See issue
+[#8496](https://github.com/rust-lang/rust-clippy/issues/8496) for more details.
+
+### Example
+```
+struct Foo<T>(u32, T);
+let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
+```
+Use instead:
+```
+#[repr(C)]
+struct Foo<T>(u32, T);
+let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
+```
\ No newline at end of file
diff --git a/src/docs/transmutes_expressible_as_ptr_casts.txt b/src/docs/transmutes_expressible_as_ptr_casts.txt
new file mode 100644
index 00000000000..b68a8cda9c7
--- /dev/null
+++ b/src/docs/transmutes_expressible_as_ptr_casts.txt
@@ -0,0 +1,16 @@
+### What it does
+Checks for transmutes that could be a pointer cast.
+
+### Why is this bad?
+Readability. The code tricks people into thinking that
+something complex is going on.
+
+### Example
+
+```
+unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) };
+```
+Use instead:
+```
+p as *const [u16];
+```
\ No newline at end of file
diff --git a/src/docs/transmuting_null.txt b/src/docs/transmuting_null.txt
new file mode 100644
index 00000000000..f8bacfc0b90
--- /dev/null
+++ b/src/docs/transmuting_null.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for transmute calls which would receive a null pointer.
+
+### Why is this bad?
+Transmuting a null pointer is undefined behavior.
+
+### Known problems
+Not all cases can be detected at the moment of this writing.
+For example, variables which hold a null pointer and are then fed to a `transmute`
+call, aren't detectable yet.
+
+### Example
+```
+let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
+```
\ No newline at end of file
diff --git a/src/docs/trim_split_whitespace.txt b/src/docs/trim_split_whitespace.txt
new file mode 100644
index 00000000000..f7e3e7858f9
--- /dev/null
+++ b/src/docs/trim_split_whitespace.txt
@@ -0,0 +1,14 @@
+### What it does
+Warns about calling `str::trim` (or variants) before `str::split_whitespace`.
+
+### Why is this bad?
+`split_whitespace` already ignores leading and trailing whitespace.
+
+### Example
+```
+" A B C ".trim().split_whitespace();
+```
+Use instead:
+```
+" A B C ".split_whitespace();
+```
\ No newline at end of file
diff --git a/src/docs/trivial_regex.txt b/src/docs/trivial_regex.txt
new file mode 100644
index 00000000000..f71d667fd77
--- /dev/null
+++ b/src/docs/trivial_regex.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for trivial [regex](https://crates.io/crates/regex)
+creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`).
+
+### Why is this bad?
+Matching the regex can likely be replaced by `==` or
+`str::starts_with`, `str::ends_with` or `std::contains` or other `str`
+methods.
+
+### Known problems
+If the same regex is going to be applied to multiple
+inputs, the precomputations done by `Regex` construction can give
+significantly better performance than any of the `str`-based methods.
+
+### Example
+```
+Regex::new("^foobar")
+```
\ No newline at end of file
diff --git a/src/docs/trivially_copy_pass_by_ref.txt b/src/docs/trivially_copy_pass_by_ref.txt
new file mode 100644
index 00000000000..f54cce5e2bd
--- /dev/null
+++ b/src/docs/trivially_copy_pass_by_ref.txt
@@ -0,0 +1,43 @@
+### What it does
+Checks for functions taking arguments by reference, where
+the argument type is `Copy` and small enough to be more efficient to always
+pass by value.
+
+### Why is this bad?
+In many calling conventions instances of structs will
+be passed through registers if they fit into two or less general purpose
+registers.
+
+### Known problems
+This lint is target register size dependent, it is
+limited to 32-bit to try and reduce portability problems between 32 and
+64-bit, but if you are compiling for 8 or 16-bit targets then the limit
+will be different.
+
+The configuration option `trivial_copy_size_limit` can be set to override
+this limit for a project.
+
+This lint attempts to allow passing arguments by reference if a reference
+to that argument is returned. This is implemented by comparing the lifetime
+of the argument and return value for equality. However, this can cause
+false positives in cases involving multiple lifetimes that are bounded by
+each other.
+
+Also, it does not take account of other similar cases where getting memory addresses
+matters; namely, returning the pointer to the argument in question,
+and passing the argument, as both references and pointers,
+to a function that needs the memory address. For further details, refer to
+[this issue](https://github.com/rust-lang/rust-clippy/issues/5953)
+that explains a real case in which this false positive
+led to an **undefined behavior** introduced with unsafe code.
+
+### Example
+
+```
+fn foo(v: &u32) {}
+```
+
+Use instead:
+```
+fn foo(v: u32) {}
+```
\ No newline at end of file
diff --git a/src/docs/try_err.txt b/src/docs/try_err.txt
new file mode 100644
index 00000000000..e3d4ef3a09d
--- /dev/null
+++ b/src/docs/try_err.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for usages of `Err(x)?`.
+
+### Why is this bad?
+The `?` operator is designed to allow calls that
+can fail to be easily chained. For example, `foo()?.bar()` or
+`foo(bar()?)`. Because `Err(x)?` can't be used that way (it will
+always return), it is more clear to write `return Err(x)`.
+
+### Example
+```
+fn foo(fail: bool) -> Result<i32, String> {
+    if fail {
+      Err("failed")?;
+    }
+    Ok(0)
+}
+```
+Could be written:
+
+```
+fn foo(fail: bool) -> Result<i32, String> {
+    if fail {
+      return Err("failed".into());
+    }
+    Ok(0)
+}
+```
\ No newline at end of file
diff --git a/src/docs/type_complexity.txt b/src/docs/type_complexity.txt
new file mode 100644
index 00000000000..69cd8750050
--- /dev/null
+++ b/src/docs/type_complexity.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for types used in structs, parameters and `let`
+declarations above a certain complexity threshold.
+
+### Why is this bad?
+Too complex types make the code less readable. Consider
+using a `type` definition to simplify them.
+
+### Example
+```
+struct Foo {
+    inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,
+}
+```
\ No newline at end of file
diff --git a/src/docs/type_repetition_in_bounds.txt b/src/docs/type_repetition_in_bounds.txt
new file mode 100644
index 00000000000..18ed372fd13
--- /dev/null
+++ b/src/docs/type_repetition_in_bounds.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint warns about unnecessary type repetitions in trait bounds
+
+### Why is this bad?
+Repeating the type for every bound makes the code
+less readable than combining the bounds
+
+### Example
+```
+pub fn foo<T>(t: T) where T: Copy, T: Clone {}
+```
+
+Use instead:
+```
+pub fn foo<T>(t: T) where T: Copy + Clone {}
+```
\ No newline at end of file
diff --git a/src/docs/undocumented_unsafe_blocks.txt b/src/docs/undocumented_unsafe_blocks.txt
new file mode 100644
index 00000000000..f3af4753c5f
--- /dev/null
+++ b/src/docs/undocumented_unsafe_blocks.txt
@@ -0,0 +1,43 @@
+### What it does
+Checks for `unsafe` blocks and impls without a `// SAFETY: ` comment
+explaining why the unsafe operations performed inside
+the block are safe.
+
+Note the comment must appear on the line(s) preceding the unsafe block
+with nothing appearing in between. The following is ok:
+```
+foo(
+    // SAFETY:
+    // This is a valid safety comment
+    unsafe { *x }
+)
+```
+But neither of these are:
+```
+// SAFETY:
+// This is not a valid safety comment
+foo(
+    /* SAFETY: Neither is this */ unsafe { *x },
+);
+```
+
+### Why is this bad?
+Undocumented unsafe blocks and impls can make it difficult to
+read and maintain code, as well as uncover unsoundness
+and bugs.
+
+### Example
+```
+use std::ptr::NonNull;
+let a = &mut 42;
+
+let ptr = unsafe { NonNull::new_unchecked(a) };
+```
+Use instead:
+```
+use std::ptr::NonNull;
+let a = &mut 42;
+
+// SAFETY: references are guaranteed to be non-null.
+let ptr = unsafe { NonNull::new_unchecked(a) };
+```
\ No newline at end of file
diff --git a/src/docs/undropped_manually_drops.txt b/src/docs/undropped_manually_drops.txt
new file mode 100644
index 00000000000..85e3ec56653
--- /dev/null
+++ b/src/docs/undropped_manually_drops.txt
@@ -0,0 +1,22 @@
+### What it does
+Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`.
+
+### Why is this bad?
+The safe `drop` function does not drop the inner value of a `ManuallyDrop`.
+
+### Known problems
+Does not catch cases if the user binds `std::mem::drop`
+to a different name and calls it that way.
+
+### Example
+```
+struct S;
+drop(std::mem::ManuallyDrop::new(S));
+```
+Use instead:
+```
+struct S;
+unsafe {
+    std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S));
+}
+```
\ No newline at end of file
diff --git a/src/docs/unicode_not_nfc.txt b/src/docs/unicode_not_nfc.txt
new file mode 100644
index 00000000000..c660c51dadb
--- /dev/null
+++ b/src/docs/unicode_not_nfc.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for string literals that contain Unicode in a form
+that is not equal to its
+[NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms).
+
+### Why is this bad?
+If such a string is compared to another, the results
+may be surprising.
+
+### Example
+You may not see it, but "à"" and "à"" aren't the same string. The
+former when escaped is actually `"a\u{300}"` while the latter is `"\u{e0}"`.
\ No newline at end of file
diff --git a/src/docs/unimplemented.txt b/src/docs/unimplemented.txt
new file mode 100644
index 00000000000..7095594fb2e
--- /dev/null
+++ b/src/docs/unimplemented.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for usage of `unimplemented!`.
+
+### Why is this bad?
+This macro should not be present in production code
+
+### Example
+```
+unimplemented!();
+```
\ No newline at end of file
diff --git a/src/docs/uninit_assumed_init.txt b/src/docs/uninit_assumed_init.txt
new file mode 100644
index 00000000000..cca24093d40
--- /dev/null
+++ b/src/docs/uninit_assumed_init.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for `MaybeUninit::uninit().assume_init()`.
+
+### Why is this bad?
+For most types, this is undefined behavior.
+
+### Known problems
+For now, we accept empty tuples and tuples / arrays
+of `MaybeUninit`. There may be other types that allow uninitialized
+data, but those are not yet rigorously defined.
+
+### Example
+```
+// Beware the UB
+use std::mem::MaybeUninit;
+
+let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
+```
+
+Note that the following is OK:
+
+```
+use std::mem::MaybeUninit;
+
+let _: [MaybeUninit<bool>; 5] = unsafe {
+    MaybeUninit::uninit().assume_init()
+};
+```
\ No newline at end of file
diff --git a/src/docs/uninit_vec.txt b/src/docs/uninit_vec.txt
new file mode 100644
index 00000000000..cd50afe78f6
--- /dev/null
+++ b/src/docs/uninit_vec.txt
@@ -0,0 +1,41 @@
+### What it does
+Checks for `set_len()` call that creates `Vec` with uninitialized elements.
+This is commonly caused by calling `set_len()` right after allocating or
+reserving a buffer with `new()`, `default()`, `with_capacity()`, or `reserve()`.
+
+### Why is this bad?
+It creates a `Vec` with uninitialized data, which leads to
+undefined behavior with most safe operations. Notably, uninitialized
+`Vec<u8>` must not be used with generic `Read`.
+
+Moreover, calling `set_len()` on a `Vec` created with `new()` or `default()`
+creates out-of-bound values that lead to heap memory corruption when used.
+
+### Known Problems
+This lint only checks directly adjacent statements.
+
+### Example
+```
+let mut vec: Vec<u8> = Vec::with_capacity(1000);
+unsafe { vec.set_len(1000); }
+reader.read(&mut vec); // undefined behavior!
+```
+
+### How to fix?
+1. Use an initialized buffer:
+   ```rust,ignore
+   let mut vec: Vec<u8> = vec![0; 1000];
+   reader.read(&mut vec);
+   ```
+2. Wrap the content in `MaybeUninit`:
+   ```rust,ignore
+   let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
+   vec.set_len(1000);  // `MaybeUninit` can be uninitialized
+   ```
+3. If you are on 1.60.0 or later, `Vec::spare_capacity_mut()` is available:
+   ```rust,ignore
+   let mut vec: Vec<u8> = Vec::with_capacity(1000);
+   let remaining = vec.spare_capacity_mut();  // `&mut [MaybeUninit<u8>]`
+   // perform initialization with `remaining`
+   vec.set_len(...);  // Safe to call `set_len()` on initialized part
+   ```
\ No newline at end of file
diff --git a/src/docs/unit_arg.txt b/src/docs/unit_arg.txt
new file mode 100644
index 00000000000..eb83403bb27
--- /dev/null
+++ b/src/docs/unit_arg.txt
@@ -0,0 +1,14 @@
+### What it does
+Checks for passing a unit value as an argument to a function without using a
+unit literal (`()`).
+
+### Why is this bad?
+This is likely the result of an accidental semicolon.
+
+### Example
+```
+foo({
+    let a = bar();
+    baz(a);
+})
+```
\ No newline at end of file
diff --git a/src/docs/unit_cmp.txt b/src/docs/unit_cmp.txt
new file mode 100644
index 00000000000..6f3d62010dc
--- /dev/null
+++ b/src/docs/unit_cmp.txt
@@ -0,0 +1,33 @@
+### What it does
+Checks for comparisons to unit. This includes all binary
+comparisons (like `==` and `<`) and asserts.
+
+### Why is this bad?
+Unit is always equal to itself, and thus is just a
+clumsily written constant. Mostly this happens when someone accidentally
+adds semicolons at the end of the operands.
+
+### Example
+```
+if {
+    foo();
+} == {
+    bar();
+} {
+    baz();
+}
+```
+is equal to
+```
+{
+    foo();
+    bar();
+    baz();
+}
+```
+
+For asserts:
+```
+assert_eq!({ foo(); }, { bar(); });
+```
+will always succeed
\ No newline at end of file
diff --git a/src/docs/unit_hash.txt b/src/docs/unit_hash.txt
new file mode 100644
index 00000000000..a22d2994602
--- /dev/null
+++ b/src/docs/unit_hash.txt
@@ -0,0 +1,20 @@
+### What it does
+Detects `().hash(_)`.
+
+### Why is this bad?
+Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
+
+### Example
+```
+match my_enum {
+	Empty => ().hash(&mut state),
+	WithValue(x) => x.hash(&mut state),
+}
+```
+Use instead:
+```
+match my_enum {
+	Empty => 0_u8.hash(&mut state),
+	WithValue(x) => x.hash(&mut state),
+}
+```
\ No newline at end of file
diff --git a/src/docs/unit_return_expecting_ord.txt b/src/docs/unit_return_expecting_ord.txt
new file mode 100644
index 00000000000..781feac5afc
--- /dev/null
+++ b/src/docs/unit_return_expecting_ord.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for functions that expect closures of type
+Fn(...) -> Ord where the implemented closure returns the unit type.
+The lint also suggests to remove the semi-colon at the end of the statement if present.
+
+### Why is this bad?
+Likely, returning the unit type is unintentional, and
+could simply be caused by an extra semi-colon. Since () implements Ord
+it doesn't cause a compilation error.
+This is the same reasoning behind the unit_cmp lint.
+
+### Known problems
+If returning unit is intentional, then there is no
+way of specifying this without triggering needless_return lint
+
+### Example
+```
+let mut twins = vec!((1, 1), (2, 2));
+twins.sort_by_key(|x| { x.1; });
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_cast.txt b/src/docs/unnecessary_cast.txt
new file mode 100644
index 00000000000..603f2606099
--- /dev/null
+++ b/src/docs/unnecessary_cast.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for casts to the same type, casts of int literals to integer types
+and casts of float literals to float types.
+
+### Why is this bad?
+It's just unnecessary.
+
+### Example
+```
+let _ = 2i32 as i32;
+let _ = 0.5 as f32;
+```
+
+Better:
+
+```
+let _ = 2_i32;
+let _ = 0.5_f32;
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_filter_map.txt b/src/docs/unnecessary_filter_map.txt
new file mode 100644
index 00000000000..b19341ecf66
--- /dev/null
+++ b/src/docs/unnecessary_filter_map.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for `filter_map` calls that could be replaced by `filter` or `map`.
+More specifically it checks if the closure provided is only performing one of the
+filter or map operations and suggests the appropriate option.
+
+### Why is this bad?
+Complexity. The intent is also clearer if only a single
+operation is being performed.
+
+### Example
+```
+let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
+
+// As there is no transformation of the argument this could be written as:
+let _ = (0..3).filter(|&x| x > 2);
+```
+
+```
+let _ = (0..4).filter_map(|x| Some(x + 1));
+
+// As there is no conditional check on the argument this could be written as:
+let _ = (0..4).map(|x| x + 1);
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_find_map.txt b/src/docs/unnecessary_find_map.txt
new file mode 100644
index 00000000000..f9444dc48ad
--- /dev/null
+++ b/src/docs/unnecessary_find_map.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for `find_map` calls that could be replaced by `find` or `map`. More
+specifically it checks if the closure provided is only performing one of the
+find or map operations and suggests the appropriate option.
+
+### Why is this bad?
+Complexity. The intent is also clearer if only a single
+operation is being performed.
+
+### Example
+```
+let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None });
+
+// As there is no transformation of the argument this could be written as:
+let _ = (0..3).find(|&x| x > 2);
+```
+
+```
+let _ = (0..4).find_map(|x| Some(x + 1));
+
+// As there is no conditional check on the argument this could be written as:
+let _ = (0..4).map(|x| x + 1).next();
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_fold.txt b/src/docs/unnecessary_fold.txt
new file mode 100644
index 00000000000..e1b0e65f519
--- /dev/null
+++ b/src/docs/unnecessary_fold.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for using `fold` when a more succinct alternative exists.
+Specifically, this checks for `fold`s which could be replaced by `any`, `all`,
+`sum` or `product`.
+
+### Why is this bad?
+Readability.
+
+### Example
+```
+(0..3).fold(false, |acc, x| acc || x > 2);
+```
+
+Use instead:
+```
+(0..3).any(|x| x > 2);
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_join.txt b/src/docs/unnecessary_join.txt
new file mode 100644
index 00000000000..ee4e78601f8
--- /dev/null
+++ b/src/docs/unnecessary_join.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for use of `.collect::<Vec<String>>().join("")` on iterators.
+
+### Why is this bad?
+`.collect::<String>()` is more concise and might be more performant
+
+### Example
+```
+let vector = vec!["hello",  "world"];
+let output = vector.iter().map(|item| item.to_uppercase()).collect::<Vec<String>>().join("");
+println!("{}", output);
+```
+The correct use would be:
+```
+let vector = vec!["hello",  "world"];
+let output = vector.iter().map(|item| item.to_uppercase()).collect::<String>();
+println!("{}", output);
+```
+### Known problems
+While `.collect::<String>()` is sometimes more performant, there are cases where
+using `.collect::<String>()` over `.collect::<Vec<String>>().join("")`
+will prevent loop unrolling and will result in a negative performance impact.
+
+Additionally, differences have been observed between aarch64 and x86_64 assembly output,
+with aarch64 tending to producing faster assembly in more cases when using `.collect::<String>()`
\ No newline at end of file
diff --git a/src/docs/unnecessary_lazy_evaluations.txt b/src/docs/unnecessary_lazy_evaluations.txt
new file mode 100644
index 00000000000..208188ce971
--- /dev/null
+++ b/src/docs/unnecessary_lazy_evaluations.txt
@@ -0,0 +1,32 @@
+### What it does
+As the counterpart to `or_fun_call`, this lint looks for unnecessary
+lazily evaluated closures on `Option` and `Result`.
+
+This lint suggests changing the following functions, when eager evaluation results in
+simpler code:
+ - `unwrap_or_else` to `unwrap_or`
+ - `and_then` to `and`
+ - `or_else` to `or`
+ - `get_or_insert_with` to `get_or_insert`
+ - `ok_or_else` to `ok_or`
+
+### Why is this bad?
+Using eager evaluation is shorter and simpler in some cases.
+
+### Known problems
+It is possible, but not recommended for `Deref` and `Index` to have
+side effects. Eagerly evaluating them can change the semantics of the program.
+
+### Example
+```
+// example code where clippy issues a warning
+let opt: Option<u32> = None;
+
+opt.unwrap_or_else(|| 42);
+```
+Use instead:
+```
+let opt: Option<u32> = None;
+
+opt.unwrap_or(42);
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_mut_passed.txt b/src/docs/unnecessary_mut_passed.txt
new file mode 100644
index 00000000000..2f8bdd113df
--- /dev/null
+++ b/src/docs/unnecessary_mut_passed.txt
@@ -0,0 +1,17 @@
+### What it does
+Detects passing a mutable reference to a function that only
+requires an immutable reference.
+
+### Why is this bad?
+The mutable reference rules out all other references to
+the value. Also the code misleads about the intent of the call site.
+
+### Example
+```
+vec.push(&mut value);
+```
+
+Use instead:
+```
+vec.push(&value);
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_operation.txt b/src/docs/unnecessary_operation.txt
new file mode 100644
index 00000000000..7f455e264cb
--- /dev/null
+++ b/src/docs/unnecessary_operation.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for expression statements that can be reduced to a
+sub-expression.
+
+### Why is this bad?
+Expressions by themselves often have no side-effects.
+Having such expressions reduces readability.
+
+### Example
+```
+compute_array()[0];
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_owned_empty_strings.txt b/src/docs/unnecessary_owned_empty_strings.txt
new file mode 100644
index 00000000000..8cd9fba603e
--- /dev/null
+++ b/src/docs/unnecessary_owned_empty_strings.txt
@@ -0,0 +1,16 @@
+### What it does
+
+Detects cases of owned empty strings being passed as an argument to a function expecting `&str`
+
+### Why is this bad?
+
+This results in longer and less readable code
+
+### Example
+```
+vec!["1", "2", "3"].join(&String::new());
+```
+Use instead:
+```
+vec!["1", "2", "3"].join("");
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_self_imports.txt b/src/docs/unnecessary_self_imports.txt
new file mode 100644
index 00000000000..b909cd5a76d
--- /dev/null
+++ b/src/docs/unnecessary_self_imports.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for imports ending in `::{self}`.
+
+### Why is this bad?
+In most cases, this can be written much more cleanly by omitting `::{self}`.
+
+### Known problems
+Removing `::{self}` will cause any non-module items at the same path to also be imported.
+This might cause a naming conflict (https://github.com/rust-lang/rustfmt/issues/3568). This lint makes no attempt
+to detect this scenario and that is why it is a restriction lint.
+
+### Example
+```
+use std::io::{self};
+```
+Use instead:
+```
+use std::io;
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_sort_by.txt b/src/docs/unnecessary_sort_by.txt
new file mode 100644
index 00000000000..6913b62c48e
--- /dev/null
+++ b/src/docs/unnecessary_sort_by.txt
@@ -0,0 +1,21 @@
+### What it does
+Detects uses of `Vec::sort_by` passing in a closure
+which compares the two arguments, either directly or indirectly.
+
+### Why is this bad?
+It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
+possible) than to use `Vec::sort_by` and a more complicated
+closure.
+
+### Known problems
+If the suggested `Vec::sort_by_key` uses Reverse and it isn't already
+imported by a use statement, then it will need to be added manually.
+
+### Example
+```
+vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
+```
+Use instead:
+```
+vec.sort_by_key(|a| a.foo());
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_to_owned.txt b/src/docs/unnecessary_to_owned.txt
new file mode 100644
index 00000000000..5d4213bdaf8
--- /dev/null
+++ b/src/docs/unnecessary_to_owned.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for unnecessary calls to [`ToOwned::to_owned`](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned)
+and other `to_owned`-like functions.
+
+### Why is this bad?
+The unnecessary calls result in useless allocations.
+
+### Known problems
+`unnecessary_to_owned` can falsely trigger if `IntoIterator::into_iter` is applied to an
+owned copy of a resource and the resource is later used mutably. See
+[#8148](https://github.com/rust-lang/rust-clippy/issues/8148).
+
+### Example
+```
+let path = std::path::Path::new("x");
+foo(&path.to_string_lossy().to_string());
+fn foo(s: &str) {}
+```
+Use instead:
+```
+let path = std::path::Path::new("x");
+foo(&path.to_string_lossy());
+fn foo(s: &str) {}
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_unwrap.txt b/src/docs/unnecessary_unwrap.txt
new file mode 100644
index 00000000000..50ae845bb44
--- /dev/null
+++ b/src/docs/unnecessary_unwrap.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for calls of `unwrap[_err]()` that cannot fail.
+
+### Why is this bad?
+Using `if let` or `match` is more idiomatic.
+
+### Example
+```
+if option.is_some() {
+    do_something_with(option.unwrap())
+}
+```
+
+Could be written:
+
+```
+if let Some(value) = option {
+    do_something_with(value)
+}
+```
\ No newline at end of file
diff --git a/src/docs/unnecessary_wraps.txt b/src/docs/unnecessary_wraps.txt
new file mode 100644
index 00000000000..c0a23d49288
--- /dev/null
+++ b/src/docs/unnecessary_wraps.txt
@@ -0,0 +1,36 @@
+### What it does
+Checks for private functions that only return `Ok` or `Some`.
+
+### Why is this bad?
+It is not meaningful to wrap values when no `None` or `Err` is returned.
+
+### Known problems
+There can be false positives if the function signature is designed to
+fit some external requirement.
+
+### Example
+```
+fn get_cool_number(a: bool, b: bool) -> Option<i32> {
+    if a && b {
+        return Some(50);
+    }
+    if a {
+        Some(0)
+    } else {
+        Some(10)
+    }
+}
+```
+Use instead:
+```
+fn get_cool_number(a: bool, b: bool) -> i32 {
+    if a && b {
+        return 50;
+    }
+    if a {
+        0
+    } else {
+        10
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/unneeded_field_pattern.txt b/src/docs/unneeded_field_pattern.txt
new file mode 100644
index 00000000000..3cd00a0f3e3
--- /dev/null
+++ b/src/docs/unneeded_field_pattern.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for structure field patterns bound to wildcards.
+
+### Why is this bad?
+Using `..` instead is shorter and leaves the focus on
+the fields that are actually bound.
+
+### Example
+```
+let f = Foo { a: 0, b: 0, c: 0 };
+
+match f {
+    Foo { a: _, b: 0, .. } => {},
+    Foo { a: _, b: _, c: _ } => {},
+}
+```
+
+Use instead:
+```
+let f = Foo { a: 0, b: 0, c: 0 };
+
+match f {
+    Foo { b: 0, .. } => {},
+    Foo { .. } => {},
+}
+```
\ No newline at end of file
diff --git a/src/docs/unneeded_wildcard_pattern.txt b/src/docs/unneeded_wildcard_pattern.txt
new file mode 100644
index 00000000000..817061efd16
--- /dev/null
+++ b/src/docs/unneeded_wildcard_pattern.txt
@@ -0,0 +1,28 @@
+### What it does
+Checks for tuple patterns with a wildcard
+pattern (`_`) is next to a rest pattern (`..`).
+
+_NOTE_: While `_, ..` means there is at least one element left, `..`
+means there are 0 or more elements left. This can make a difference
+when refactoring, but shouldn't result in errors in the refactored code,
+since the wildcard pattern isn't used anyway.
+
+### Why is this bad?
+The wildcard pattern is unneeded as the rest pattern
+can match that element as well.
+
+### Example
+```
+match t {
+    TupleStruct(0, .., _) => (),
+    _ => (),
+}
+```
+
+Use instead:
+```
+match t {
+    TupleStruct(0, ..) => (),
+    _ => (),
+}
+```
\ No newline at end of file
diff --git a/src/docs/unnested_or_patterns.txt b/src/docs/unnested_or_patterns.txt
new file mode 100644
index 00000000000..49c45d4ee5e
--- /dev/null
+++ b/src/docs/unnested_or_patterns.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for unnested or-patterns, e.g., `Some(0) | Some(2)` and
+suggests replacing the pattern with a nested one, `Some(0 | 2)`.
+
+Another way to think of this is that it rewrites patterns in
+*disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*.
+
+### Why is this bad?
+In the example above, `Some` is repeated, which unnecessarily complicates the pattern.
+
+### Example
+```
+fn main() {
+    if let Some(0) | Some(2) = Some(0) {}
+}
+```
+Use instead:
+```
+fn main() {
+    if let Some(0 | 2) = Some(0) {}
+}
+```
\ No newline at end of file
diff --git a/src/docs/unreachable.txt b/src/docs/unreachable.txt
new file mode 100644
index 00000000000..10469ca7745
--- /dev/null
+++ b/src/docs/unreachable.txt
@@ -0,0 +1,10 @@
+### What it does
+Checks for usage of `unreachable!`.
+
+### Why is this bad?
+This macro can cause code to panic
+
+### Example
+```
+unreachable!();
+```
\ No newline at end of file
diff --git a/src/docs/unreadable_literal.txt b/src/docs/unreadable_literal.txt
new file mode 100644
index 00000000000..e168f90a84c
--- /dev/null
+++ b/src/docs/unreadable_literal.txt
@@ -0,0 +1,16 @@
+### What it does
+Warns if a long integral or floating-point constant does
+not contain underscores.
+
+### Why is this bad?
+Reading long numbers is difficult without separators.
+
+### Example
+```
+61864918973511
+```
+
+Use instead:
+```
+61_864_918_973_511
+```
\ No newline at end of file
diff --git a/src/docs/unsafe_derive_deserialize.txt b/src/docs/unsafe_derive_deserialize.txt
new file mode 100644
index 00000000000..f56c48044f4
--- /dev/null
+++ b/src/docs/unsafe_derive_deserialize.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks for deriving `serde::Deserialize` on a type that
+has methods using `unsafe`.
+
+### Why is this bad?
+Deriving `serde::Deserialize` will create a constructor
+that may violate invariants hold by another constructor.
+
+### Example
+```
+use serde::Deserialize;
+
+#[derive(Deserialize)]
+pub struct Foo {
+    // ..
+}
+
+impl Foo {
+    pub fn new() -> Self {
+        // setup here ..
+    }
+
+    pub unsafe fn parts() -> (&str, &str) {
+        // assumes invariants hold
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/unsafe_removed_from_name.txt b/src/docs/unsafe_removed_from_name.txt
new file mode 100644
index 00000000000..6f55c1815dd
--- /dev/null
+++ b/src/docs/unsafe_removed_from_name.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for imports that remove "unsafe" from an item's
+name.
+
+### Why is this bad?
+Renaming makes it less clear which traits and
+structures are unsafe.
+
+### Example
+```
+use std::cell::{UnsafeCell as TotallySafeCell};
+
+extern crate crossbeam;
+use crossbeam::{spawn_unsafe as spawn};
+```
\ No newline at end of file
diff --git a/src/docs/unseparated_literal_suffix.txt b/src/docs/unseparated_literal_suffix.txt
new file mode 100644
index 00000000000..d80248e34d0
--- /dev/null
+++ b/src/docs/unseparated_literal_suffix.txt
@@ -0,0 +1,18 @@
+### What it does
+Warns if literal suffixes are not separated by an
+underscore.
+To enforce unseparated literal suffix style,
+see the `separated_literal_suffix` lint.
+
+### Why is this bad?
+Suffix style should be consistent.
+
+### Example
+```
+123832i32
+```
+
+Use instead:
+```
+123832_i32
+```
\ No newline at end of file
diff --git a/src/docs/unsound_collection_transmute.txt b/src/docs/unsound_collection_transmute.txt
new file mode 100644
index 00000000000..29db9258e83
--- /dev/null
+++ b/src/docs/unsound_collection_transmute.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for transmutes between collections whose
+types have different ABI, size or alignment.
+
+### Why is this bad?
+This is undefined behavior.
+
+### Known problems
+Currently, we cannot know whether a type is a
+collection, so we just lint the ones that come with `std`.
+
+### Example
+```
+// different size, therefore likely out-of-bounds memory access
+// You absolutely do not want this in your code!
+unsafe {
+    std::mem::transmute::<_, Vec<u32>>(vec![2_u16])
+};
+```
+
+You must always iterate, map and collect the values:
+
+```
+vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>();
+```
\ No newline at end of file
diff --git a/src/docs/unused_async.txt b/src/docs/unused_async.txt
new file mode 100644
index 00000000000..26def11aa17
--- /dev/null
+++ b/src/docs/unused_async.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for functions that are declared `async` but have no `.await`s inside of them.
+
+### Why is this bad?
+Async functions with no async code create overhead, both mentally and computationally.
+Callers of async methods either need to be calling from an async function themselves or run it on an executor, both of which
+causes runtime overhead and hassle for the caller.
+
+### Example
+```
+async fn get_random_number() -> i64 {
+    4 // Chosen by fair dice roll. Guaranteed to be random.
+}
+let number_future = get_random_number();
+```
+
+Use instead:
+```
+fn get_random_number_improved() -> i64 {
+    4 // Chosen by fair dice roll. Guaranteed to be random.
+}
+let number_future = async { get_random_number_improved() };
+```
\ No newline at end of file
diff --git a/src/docs/unused_io_amount.txt b/src/docs/unused_io_amount.txt
new file mode 100644
index 00000000000..fbc4c299c7b
--- /dev/null
+++ b/src/docs/unused_io_amount.txt
@@ -0,0 +1,31 @@
+### What it does
+Checks for unused written/read amount.
+
+### Why is this bad?
+`io::Write::write(_vectored)` and
+`io::Read::read(_vectored)` are not guaranteed to
+process the entire buffer. They return how many bytes were processed, which
+might be smaller
+than a given buffer's length. If you don't need to deal with
+partial-write/read, use
+`write_all`/`read_exact` instead.
+
+When working with asynchronous code (either with the `futures`
+crate or with `tokio`), a similar issue exists for
+`AsyncWriteExt::write()` and `AsyncReadExt::read()` : these
+functions are also not guaranteed to process the entire
+buffer.  Your code should either handle partial-writes/reads, or
+call the `write_all`/`read_exact` methods on those traits instead.
+
+### Known problems
+Detects only common patterns.
+
+### Examples
+```
+use std::io;
+fn foo<W: io::Write>(w: &mut W) -> io::Result<()> {
+    // must be `w.write_all(b"foo")?;`
+    w.write(b"foo")?;
+    Ok(())
+}
+```
\ No newline at end of file
diff --git a/src/docs/unused_peekable.txt b/src/docs/unused_peekable.txt
new file mode 100644
index 00000000000..268de1ce3be
--- /dev/null
+++ b/src/docs/unused_peekable.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for the creation of a `peekable` iterator that is never `.peek()`ed
+
+### Why is this bad?
+Creating a peekable iterator without using any of its methods is likely a mistake,
+or just a leftover after a refactor.
+
+### Example
+```
+let collection = vec![1, 2, 3];
+let iter = collection.iter().peekable();
+
+for item in iter {
+    // ...
+}
+```
+
+Use instead:
+```
+let collection = vec![1, 2, 3];
+let iter = collection.iter();
+
+for item in iter {
+    // ...
+}
+```
\ No newline at end of file
diff --git a/src/docs/unused_rounding.txt b/src/docs/unused_rounding.txt
new file mode 100644
index 00000000000..70947aceee7
--- /dev/null
+++ b/src/docs/unused_rounding.txt
@@ -0,0 +1,17 @@
+### What it does
+
+Detects cases where a whole-number literal float is being rounded, using
+the `floor`, `ceil`, or `round` methods.
+
+### Why is this bad?
+
+This is unnecessary and confusing to the reader. Doing this is probably a mistake.
+
+### Example
+```
+let x = 1f32.ceil();
+```
+Use instead:
+```
+let x = 1f32;
+```
\ No newline at end of file
diff --git a/src/docs/unused_self.txt b/src/docs/unused_self.txt
new file mode 100644
index 00000000000..a8d0fc75989
--- /dev/null
+++ b/src/docs/unused_self.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks methods that contain a `self` argument but don't use it
+
+### Why is this bad?
+It may be clearer to define the method as an associated function instead
+of an instance method if it doesn't require `self`.
+
+### Example
+```
+struct A;
+impl A {
+    fn method(&self) {}
+}
+```
+
+Could be written:
+
+```
+struct A;
+impl A {
+    fn method() {}
+}
+```
\ No newline at end of file
diff --git a/src/docs/unused_unit.txt b/src/docs/unused_unit.txt
new file mode 100644
index 00000000000..48d16ca6552
--- /dev/null
+++ b/src/docs/unused_unit.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for unit (`()`) expressions that can be removed.
+
+### Why is this bad?
+Such expressions add no value, but can make the code
+less readable. Depending on formatting they can make a `break` or `return`
+statement look like a function call.
+
+### Example
+```
+fn return_unit() -> () {
+    ()
+}
+```
+is equivalent to
+```
+fn return_unit() {}
+```
\ No newline at end of file
diff --git a/src/docs/unusual_byte_groupings.txt b/src/docs/unusual_byte_groupings.txt
new file mode 100644
index 00000000000..9a1f132a611
--- /dev/null
+++ b/src/docs/unusual_byte_groupings.txt
@@ -0,0 +1,12 @@
+### What it does
+Warns if hexadecimal or binary literals are not grouped
+by nibble or byte.
+
+### Why is this bad?
+Negatively impacts readability.
+
+### Example
+```
+let x: u32 = 0xFFF_FFF;
+let y: u8 = 0b01_011_101;
+```
\ No newline at end of file
diff --git a/src/docs/unwrap_in_result.txt b/src/docs/unwrap_in_result.txt
new file mode 100644
index 00000000000..7497dd863d3
--- /dev/null
+++ b/src/docs/unwrap_in_result.txt
@@ -0,0 +1,39 @@
+### What it does
+Checks for functions of type `Result` that contain `expect()` or `unwrap()`
+
+### Why is this bad?
+These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics.
+
+### Known problems
+This can cause false positives in functions that handle both recoverable and non recoverable errors.
+
+### Example
+Before:
+```
+fn divisible_by_3(i_str: String) -> Result<(), String> {
+    let i = i_str
+        .parse::<i32>()
+        .expect("cannot divide the input by three");
+
+    if i % 3 != 0 {
+        Err("Number is not divisible by 3")?
+    }
+
+    Ok(())
+}
+```
+
+After:
+```
+fn divisible_by_3(i_str: String) -> Result<(), String> {
+    let i = i_str
+        .parse::<i32>()
+        .map_err(|e| format!("cannot divide the input by three: {}", e))?;
+
+    if i % 3 != 0 {
+        Err("Number is not divisible by 3")?
+    }
+
+    Ok(())
+}
+```
\ No newline at end of file
diff --git a/src/docs/unwrap_or_else_default.txt b/src/docs/unwrap_or_else_default.txt
new file mode 100644
index 00000000000..34b4cf08858
--- /dev/null
+++ b/src/docs/unwrap_or_else_default.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and
+`Result` values.
+
+### Why is this bad?
+Readability, these can be written as `_.unwrap_or_default`, which is
+simpler and more concise.
+
+### Examples
+```
+x.unwrap_or_else(Default::default);
+x.unwrap_or_else(u32::default);
+```
+
+Use instead:
+```
+x.unwrap_or_default();
+```
\ No newline at end of file
diff --git a/src/docs/unwrap_used.txt b/src/docs/unwrap_used.txt
new file mode 100644
index 00000000000..9b4713df515
--- /dev/null
+++ b/src/docs/unwrap_used.txt
@@ -0,0 +1,37 @@
+### What it does
+Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s.
+
+### Why is this bad?
+It is better to handle the `None` or `Err` case,
+or at least call `.expect(_)` with a more helpful message. Still, for a lot of
+quick-and-dirty code, `unwrap` is a good choice, which is why this lint is
+`Allow` by default.
+
+`result.unwrap()` will let the thread panic on `Err` values.
+Normally, you want to implement more sophisticated error handling,
+and propagate errors upwards with `?` operator.
+
+Even if you want to panic on errors, not all `Error`s implement good
+messages on display. Therefore, it may be beneficial to look at the places
+where they may get displayed. Activate this lint to do just that.
+
+### Examples
+```
+option.unwrap();
+result.unwrap();
+```
+
+Use instead:
+```
+option.expect("more helpful message");
+result.expect("more helpful message");
+```
+
+If [expect_used](#expect_used) is enabled, instead:
+```
+option?;
+
+// or
+
+result?;
+```
\ No newline at end of file
diff --git a/src/docs/upper_case_acronyms.txt b/src/docs/upper_case_acronyms.txt
new file mode 100644
index 00000000000..a1e39c7e10c
--- /dev/null
+++ b/src/docs/upper_case_acronyms.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for fully capitalized names and optionally names containing a capitalized acronym.
+
+### Why is this bad?
+In CamelCase, acronyms count as one word.
+See [naming conventions](https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case)
+for more.
+
+By default, the lint only triggers on fully-capitalized names.
+You can use the `upper-case-acronyms-aggressive: true` config option to enable linting
+on all camel case names
+
+### Known problems
+When two acronyms are contiguous, the lint can't tell where
+the first acronym ends and the second starts, so it suggests to lowercase all of
+the letters in the second acronym.
+
+### Example
+```
+struct HTTPResponse;
+```
+Use instead:
+```
+struct HttpResponse;
+```
\ No newline at end of file
diff --git a/src/docs/use_debug.txt b/src/docs/use_debug.txt
new file mode 100644
index 00000000000..94d4a6fd29a
--- /dev/null
+++ b/src/docs/use_debug.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for use of `Debug` formatting. The purpose of this
+lint is to catch debugging remnants.
+
+### Why is this bad?
+The purpose of the `Debug` trait is to facilitate
+debugging Rust code. It should not be used in user-facing output.
+
+### Example
+```
+println!("{:?}", foo);
+```
\ No newline at end of file
diff --git a/src/docs/use_self.txt b/src/docs/use_self.txt
new file mode 100644
index 00000000000..bd37ed1e002
--- /dev/null
+++ b/src/docs/use_self.txt
@@ -0,0 +1,31 @@
+### What it does
+Checks for unnecessary repetition of structure name when a
+replacement with `Self` is applicable.
+
+### Why is this bad?
+Unnecessary repetition. Mixed use of `Self` and struct
+name
+feels inconsistent.
+
+### Known problems
+- Unaddressed false negative in fn bodies of trait implementations
+- False positive with associated types in traits (#4140)
+
+### Example
+```
+struct Foo;
+impl Foo {
+    fn new() -> Foo {
+        Foo {}
+    }
+}
+```
+could be
+```
+struct Foo;
+impl Foo {
+    fn new() -> Self {
+        Self {}
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/used_underscore_binding.txt b/src/docs/used_underscore_binding.txt
new file mode 100644
index 00000000000..ed67c41eb0d
--- /dev/null
+++ b/src/docs/used_underscore_binding.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for the use of bindings with a single leading
+underscore.
+
+### Why is this bad?
+A single leading underscore is usually used to indicate
+that a binding will not be used. Using such a binding breaks this
+expectation.
+
+### Known problems
+The lint does not work properly with desugaring and
+macro, it has been allowed in the mean time.
+
+### Example
+```
+let _x = 0;
+let y = _x + 1; // Here we are using `_x`, even though it has a leading
+                // underscore. We should rename `_x` to `x`
+```
\ No newline at end of file
diff --git a/src/docs/useless_asref.txt b/src/docs/useless_asref.txt
new file mode 100644
index 00000000000..f777cd3775e
--- /dev/null
+++ b/src/docs/useless_asref.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for usage of `.as_ref()` or `.as_mut()` where the
+types before and after the call are the same.
+
+### Why is this bad?
+The call is unnecessary.
+
+### Example
+```
+let x: &[i32] = &[1, 2, 3, 4, 5];
+do_stuff(x.as_ref());
+```
+The correct use would be:
+```
+let x: &[i32] = &[1, 2, 3, 4, 5];
+do_stuff(x);
+```
\ No newline at end of file
diff --git a/src/docs/useless_attribute.txt b/src/docs/useless_attribute.txt
new file mode 100644
index 00000000000..e02d4c90789
--- /dev/null
+++ b/src/docs/useless_attribute.txt
@@ -0,0 +1,36 @@
+### What it does
+Checks for `extern crate` and `use` items annotated with
+lint attributes.
+
+This lint permits lint attributes for lints emitted on the items themself.
+For `use` items these lints are:
+* deprecated
+* unreachable_pub
+* unused_imports
+* clippy::enum_glob_use
+* clippy::macro_use_imports
+* clippy::wildcard_imports
+
+For `extern crate` items these lints are:
+* `unused_imports` on items with `#[macro_use]`
+
+### Why is this bad?
+Lint attributes have no effect on crate imports. Most
+likely a `!` was forgotten.
+
+### Example
+```
+#[deny(dead_code)]
+extern crate foo;
+#[forbid(dead_code)]
+use foo::bar;
+```
+
+Use instead:
+```
+#[allow(unused_imports)]
+use foo::baz;
+#[allow(unused_imports)]
+#[macro_use]
+extern crate baz;
+```
\ No newline at end of file
diff --git a/src/docs/useless_conversion.txt b/src/docs/useless_conversion.txt
new file mode 100644
index 00000000000..06000a7ad98
--- /dev/null
+++ b/src/docs/useless_conversion.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls
+which uselessly convert to the same type.
+
+### Why is this bad?
+Redundant code.
+
+### Example
+```
+// format!() returns a `String`
+let s: String = format!("hello").into();
+```
+
+Use instead:
+```
+let s: String = format!("hello");
+```
\ No newline at end of file
diff --git a/src/docs/useless_format.txt b/src/docs/useless_format.txt
new file mode 100644
index 00000000000..eb4819da1e9
--- /dev/null
+++ b/src/docs/useless_format.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for the use of `format!("string literal with no
+argument")` and `format!("{}", foo)` where `foo` is a string.
+
+### Why is this bad?
+There is no point of doing that. `format!("foo")` can
+be replaced by `"foo".to_owned()` if you really need a `String`. The even
+worse `&format!("foo")` is often encountered in the wild. `format!("{}",
+foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()`
+if `foo: &str`.
+
+### Examples
+```
+let foo = "foo";
+format!("{}", foo);
+```
+
+Use instead:
+```
+let foo = "foo";
+foo.to_owned();
+```
\ No newline at end of file
diff --git a/src/docs/useless_let_if_seq.txt b/src/docs/useless_let_if_seq.txt
new file mode 100644
index 00000000000..c6dcd57eb2e
--- /dev/null
+++ b/src/docs/useless_let_if_seq.txt
@@ -0,0 +1,39 @@
+### What it does
+Checks for variable declarations immediately followed by a
+conditional affectation.
+
+### Why is this bad?
+This is not idiomatic Rust.
+
+### Example
+```
+let foo;
+
+if bar() {
+    foo = 42;
+} else {
+    foo = 0;
+}
+
+let mut baz = None;
+
+if bar() {
+    baz = Some(42);
+}
+```
+
+should be written
+
+```
+let foo = if bar() {
+    42
+} else {
+    0
+};
+
+let baz = if bar() {
+    Some(42)
+} else {
+    None
+};
+```
\ No newline at end of file
diff --git a/src/docs/useless_transmute.txt b/src/docs/useless_transmute.txt
new file mode 100644
index 00000000000..1d3a1758814
--- /dev/null
+++ b/src/docs/useless_transmute.txt
@@ -0,0 +1,12 @@
+### What it does
+Checks for transmutes to the original type of the object
+and transmutes that could be a cast.
+
+### Why is this bad?
+Readability. The code tricks people into thinking that
+something complex is going on.
+
+### Example
+```
+core::intrinsics::transmute(t); // where the result type is the same as `t`'s
+```
\ No newline at end of file
diff --git a/src/docs/useless_vec.txt b/src/docs/useless_vec.txt
new file mode 100644
index 00000000000..ee5afc99e4b
--- /dev/null
+++ b/src/docs/useless_vec.txt
@@ -0,0 +1,18 @@
+### What it does
+Checks for usage of `&vec![..]` when using `&[..]` would
+be possible.
+
+### Why is this bad?
+This is less efficient.
+
+### Example
+```
+fn foo(_x: &[u8]) {}
+
+foo(&vec![1, 2]);
+```
+
+Use instead:
+```
+foo(&[1, 2]);
+```
\ No newline at end of file
diff --git a/src/docs/vec_box.txt b/src/docs/vec_box.txt
new file mode 100644
index 00000000000..701b1c9ce9b
--- /dev/null
+++ b/src/docs/vec_box.txt
@@ -0,0 +1,26 @@
+### What it does
+Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code.
+Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
+
+### Why is this bad?
+`Vec` already keeps its contents in a separate area on
+the heap. So if you `Box` its contents, you just add another level of indirection.
+
+### Known problems
+Vec<Box<T: Sized>> makes sense if T is a large type (see [#3530](https://github.com/rust-lang/rust-clippy/issues/3530),
+1st comment).
+
+### Example
+```
+struct X {
+    values: Vec<Box<i32>>,
+}
+```
+
+Better:
+
+```
+struct X {
+    values: Vec<i32>,
+}
+```
\ No newline at end of file
diff --git a/src/docs/vec_init_then_push.txt b/src/docs/vec_init_then_push.txt
new file mode 100644
index 00000000000..445f2874796
--- /dev/null
+++ b/src/docs/vec_init_then_push.txt
@@ -0,0 +1,23 @@
+### What it does
+Checks for calls to `push` immediately after creating a new `Vec`.
+
+If the `Vec` is created using `with_capacity` this will only lint if the capacity is a
+constant and the number of pushes is greater than or equal to the initial capacity.
+
+If the `Vec` is extended after the initial sequence of pushes and it was default initialized
+then this will only lint after there were at least four pushes. This number may change in
+the future.
+
+### Why is this bad?
+The `vec![]` macro is both more performant and easier to read than
+multiple `push` calls.
+
+### Example
+```
+let mut v = Vec::new();
+v.push(0);
+```
+Use instead:
+```
+let v = vec![0];
+```
\ No newline at end of file
diff --git a/src/docs/vec_resize_to_zero.txt b/src/docs/vec_resize_to_zero.txt
new file mode 100644
index 00000000000..0b92686772b
--- /dev/null
+++ b/src/docs/vec_resize_to_zero.txt
@@ -0,0 +1,15 @@
+### What it does
+Finds occurrences of `Vec::resize(0, an_int)`
+
+### Why is this bad?
+This is probably an argument inversion mistake.
+
+### Example
+```
+vec!(1, 2, 3, 4, 5).resize(0, 5)
+```
+
+Use instead:
+```
+vec!(1, 2, 3, 4, 5).clear()
+```
\ No newline at end of file
diff --git a/src/docs/verbose_bit_mask.txt b/src/docs/verbose_bit_mask.txt
new file mode 100644
index 00000000000..87a84702925
--- /dev/null
+++ b/src/docs/verbose_bit_mask.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for bit masks that can be replaced by a call
+to `trailing_zeros`
+
+### Why is this bad?
+`x.trailing_zeros() > 4` is much clearer than `x & 15
+== 0`
+
+### Known problems
+llvm generates better code for `x & 15 == 0` on x86
+
+### Example
+```
+if x & 0b1111 == 0 { }
+```
\ No newline at end of file
diff --git a/src/docs/verbose_file_reads.txt b/src/docs/verbose_file_reads.txt
new file mode 100644
index 00000000000..9703df423a5
--- /dev/null
+++ b/src/docs/verbose_file_reads.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for use of File::read_to_end and File::read_to_string.
+
+### Why is this bad?
+`fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values.
+See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html)
+
+### Example
+```
+let mut f = File::open("foo.txt").unwrap();
+let mut bytes = Vec::new();
+f.read_to_end(&mut bytes).unwrap();
+```
+Can be written more concisely as
+```
+let mut bytes = fs::read("foo.txt").unwrap();
+```
\ No newline at end of file
diff --git a/src/docs/vtable_address_comparisons.txt b/src/docs/vtable_address_comparisons.txt
new file mode 100644
index 00000000000..4a34e4ba78e
--- /dev/null
+++ b/src/docs/vtable_address_comparisons.txt
@@ -0,0 +1,17 @@
+### What it does
+Checks for comparisons with an address of a trait vtable.
+
+### Why is this bad?
+Comparing trait objects pointers compares an vtable addresses which
+are not guaranteed to be unique and could vary between different code generation units.
+Furthermore vtables for different types could have the same address after being merged
+together.
+
+### Example
+```
+let a: Rc<dyn Trait> = ...
+let b: Rc<dyn Trait> = ...
+if Rc::ptr_eq(&a, &b) {
+    ...
+}
+```
\ No newline at end of file
diff --git a/src/docs/while_immutable_condition.txt b/src/docs/while_immutable_condition.txt
new file mode 100644
index 00000000000..71800701f48
--- /dev/null
+++ b/src/docs/while_immutable_condition.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks whether variables used within while loop condition
+can be (and are) mutated in the body.
+
+### Why is this bad?
+If the condition is unchanged, entering the body of the loop
+will lead to an infinite loop.
+
+### Known problems
+If the `while`-loop is in a closure, the check for mutation of the
+condition variables in the body can cause false negatives. For example when only `Upvar` `a` is
+in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger.
+
+### Example
+```
+let i = 0;
+while i > 10 {
+    println!("let me loop forever!");
+}
+```
\ No newline at end of file
diff --git a/src/docs/while_let_loop.txt b/src/docs/while_let_loop.txt
new file mode 100644
index 00000000000..ab7bf60975e
--- /dev/null
+++ b/src/docs/while_let_loop.txt
@@ -0,0 +1,25 @@
+### What it does
+Detects `loop + match` combinations that are easier
+written as a `while let` loop.
+
+### Why is this bad?
+The `while let` loop is usually shorter and more
+readable.
+
+### Known problems
+Sometimes the wrong binding is displayed ([#383](https://github.com/rust-lang/rust-clippy/issues/383)).
+
+### Example
+```
+loop {
+    let x = match y {
+        Some(x) => x,
+        None => break,
+    };
+    // .. do something with x
+}
+// is easier written as
+while let Some(x) = y {
+    // .. do something with x
+};
+```
\ No newline at end of file
diff --git a/src/docs/while_let_on_iterator.txt b/src/docs/while_let_on_iterator.txt
new file mode 100644
index 00000000000..af053c54119
--- /dev/null
+++ b/src/docs/while_let_on_iterator.txt
@@ -0,0 +1,20 @@
+### What it does
+Checks for `while let` expressions on iterators.
+
+### Why is this bad?
+Readability. A simple `for` loop is shorter and conveys
+the intent better.
+
+### Example
+```
+while let Some(val) = iter.next() {
+    ..
+}
+```
+
+Use instead:
+```
+for val in &mut iter {
+    ..
+}
+```
\ No newline at end of file
diff --git a/src/docs/wildcard_dependencies.txt b/src/docs/wildcard_dependencies.txt
new file mode 100644
index 00000000000..2affaf9740d
--- /dev/null
+++ b/src/docs/wildcard_dependencies.txt
@@ -0,0 +1,13 @@
+### What it does
+Checks for wildcard dependencies in the `Cargo.toml`.
+
+### Why is this bad?
+[As the edition guide says](https://rust-lang-nursery.github.io/edition-guide/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.html),
+it is highly unlikely that you work with any possible version of your dependency,
+and wildcard dependencies would cause unnecessary breakage in the ecosystem.
+
+### Example
+```
+[dependencies]
+regex = "*"
+```
\ No newline at end of file
diff --git a/src/docs/wildcard_enum_match_arm.txt b/src/docs/wildcard_enum_match_arm.txt
new file mode 100644
index 00000000000..09807c01c65
--- /dev/null
+++ b/src/docs/wildcard_enum_match_arm.txt
@@ -0,0 +1,25 @@
+### What it does
+Checks for wildcard enum matches using `_`.
+
+### Why is this bad?
+New enum variants added by library updates can be missed.
+
+### Known problems
+Suggested replacements may be incorrect if guards exhaustively cover some
+variants, and also may not use correct path to enum if it's not present in the current scope.
+
+### Example
+```
+match x {
+    Foo::A(_) => {},
+    _ => {},
+}
+```
+
+Use instead:
+```
+match x {
+    Foo::A(_) => {},
+    Foo::B(_) => {},
+}
+```
\ No newline at end of file
diff --git a/src/docs/wildcard_imports.txt b/src/docs/wildcard_imports.txt
new file mode 100644
index 00000000000..bd56aa5b082
--- /dev/null
+++ b/src/docs/wildcard_imports.txt
@@ -0,0 +1,45 @@
+### What it does
+Checks for wildcard imports `use _::*`.
+
+### Why is this bad?
+wildcard imports can pollute the namespace. This is especially bad if
+you try to import something through a wildcard, that already has been imported by name from
+a different source:
+
+```
+use crate1::foo; // Imports a function named foo
+use crate2::*; // Has a function named foo
+
+foo(); // Calls crate1::foo
+```
+
+This can lead to confusing error messages at best and to unexpected behavior at worst.
+
+### Exceptions
+Wildcard imports are allowed from modules named `prelude`. Many crates (including the standard library)
+provide modules named "prelude" specifically designed for wildcard import.
+
+`use super::*` is allowed in test modules. This is defined as any module with "test" in the name.
+
+These exceptions can be disabled using the `warn-on-all-wildcard-imports` configuration flag.
+
+### Known problems
+If macros are imported through the wildcard, this macro is not included
+by the suggestion and has to be added by hand.
+
+Applying the suggestion when explicit imports of the things imported with a glob import
+exist, may result in `unused_imports` warnings.
+
+### Example
+```
+use crate1::*;
+
+foo();
+```
+
+Use instead:
+```
+use crate1::foo;
+
+foo();
+```
\ No newline at end of file
diff --git a/src/docs/wildcard_in_or_patterns.txt b/src/docs/wildcard_in_or_patterns.txt
new file mode 100644
index 00000000000..70468ca41e0
--- /dev/null
+++ b/src/docs/wildcard_in_or_patterns.txt
@@ -0,0 +1,22 @@
+### What it does
+Checks for wildcard pattern used with others patterns in same match arm.
+
+### Why is this bad?
+Wildcard pattern already covers any other pattern as it will match anyway.
+It makes the code less readable, especially to spot wildcard pattern use in match arm.
+
+### Example
+```
+match s {
+    "a" => {},
+    "bar" | _ => {},
+}
+```
+
+Use instead:
+```
+match s {
+    "a" => {},
+    _ => {},
+}
+```
\ No newline at end of file
diff --git a/src/docs/write_literal.txt b/src/docs/write_literal.txt
new file mode 100644
index 00000000000..9c41a48f9f7
--- /dev/null
+++ b/src/docs/write_literal.txt
@@ -0,0 +1,21 @@
+### What it does
+This lint warns about the use of literals as `write!`/`writeln!` args.
+
+### Why is this bad?
+Using literals as `writeln!` args is inefficient
+(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
+(i.e., just put the literal in the format string)
+
+### Known problems
+Will also warn with macro calls as arguments that expand to literals
+-- e.g., `writeln!(buf, "{}", env!("FOO"))`.
+
+### Example
+```
+writeln!(buf, "{}", "foo");
+```
+
+Use instead:
+```
+writeln!(buf, "foo");
+```
\ No newline at end of file
diff --git a/src/docs/write_with_newline.txt b/src/docs/write_with_newline.txt
new file mode 100644
index 00000000000..22845fd6515
--- /dev/null
+++ b/src/docs/write_with_newline.txt
@@ -0,0 +1,18 @@
+### What it does
+This lint warns when you use `write!()` with a format
+string that
+ends in a newline.
+
+### Why is this bad?
+You should use `writeln!()` instead, which appends the
+newline.
+
+### Example
+```
+write!(buf, "Hello {}!\n", name);
+```
+
+Use instead:
+```
+writeln!(buf, "Hello {}!", name);
+```
\ No newline at end of file
diff --git a/src/docs/writeln_empty_string.txt b/src/docs/writeln_empty_string.txt
new file mode 100644
index 00000000000..3b3aeb79a48
--- /dev/null
+++ b/src/docs/writeln_empty_string.txt
@@ -0,0 +1,16 @@
+### What it does
+This lint warns when you use `writeln!(buf, "")` to
+print a newline.
+
+### Why is this bad?
+You should use `writeln!(buf)`, which is simpler.
+
+### Example
+```
+writeln!(buf, "");
+```
+
+Use instead:
+```
+writeln!(buf);
+```
\ No newline at end of file
diff --git a/src/docs/wrong_self_convention.txt b/src/docs/wrong_self_convention.txt
new file mode 100644
index 00000000000..d6b69ab87f8
--- /dev/null
+++ b/src/docs/wrong_self_convention.txt
@@ -0,0 +1,39 @@
+### What it does
+Checks for methods with certain name prefixes and which
+doesn't match how self is taken. The actual rules are:
+
+|Prefix |Postfix     |`self` taken                   | `self` type  |
+|-------|------------|-------------------------------|--------------|
+|`as_`  | none       |`&self` or `&mut self`         | any          |
+|`from_`| none       | none                          | any          |
+|`into_`| none       |`self`                         | any          |
+|`is_`  | none       |`&mut self` or `&self` or none | any          |
+|`to_`  | `_mut`     |`&mut self`                    | any          |
+|`to_`  | not `_mut` |`self`                         | `Copy`       |
+|`to_`  | not `_mut` |`&self`                        | not `Copy`   |
+
+Note: Clippy doesn't trigger methods with `to_` prefix in:
+- Traits definition.
+Clippy can not tell if a type that implements a trait is `Copy` or not.
+- Traits implementation, when `&self` is taken.
+The method signature is controlled by the trait and often `&self` is required for all types that implement the trait
+(see e.g. the `std::string::ToString` trait).
+
+Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required.
+
+Please find more info here:
+https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
+
+### Why is this bad?
+Consistency breeds readability. If you follow the
+conventions, your users won't be surprised that they, e.g., need to supply a
+mutable reference to a `as_..` function.
+
+### Example
+```
+impl X {
+    fn as_str(self) -> &'static str {
+        // ..
+    }
+}
+```
\ No newline at end of file
diff --git a/src/docs/wrong_transmute.txt b/src/docs/wrong_transmute.txt
new file mode 100644
index 00000000000..9fc71e0e382
--- /dev/null
+++ b/src/docs/wrong_transmute.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for transmutes that can't ever be correct on any
+architecture.
+
+### Why is this bad?
+It's basically guaranteed to be undefined behavior.
+
+### Known problems
+When accessing C, users might want to store pointer
+sized objects in `extradata` arguments to save an allocation.
+
+### Example
+```
+let ptr: *const T = core::intrinsics::transmute('x')
+```
\ No newline at end of file
diff --git a/src/docs/zero_divided_by_zero.txt b/src/docs/zero_divided_by_zero.txt
new file mode 100644
index 00000000000..394de20c0c0
--- /dev/null
+++ b/src/docs/zero_divided_by_zero.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for `0.0 / 0.0`.
+
+### Why is this bad?
+It's less readable than `f32::NAN` or `f64::NAN`.
+
+### Example
+```
+let nan = 0.0f32 / 0.0;
+```
+
+Use instead:
+```
+let nan = f32::NAN;
+```
\ No newline at end of file
diff --git a/src/docs/zero_prefixed_literal.txt b/src/docs/zero_prefixed_literal.txt
new file mode 100644
index 00000000000..5c558872536
--- /dev/null
+++ b/src/docs/zero_prefixed_literal.txt
@@ -0,0 +1,32 @@
+### What it does
+Warns if an integral constant literal starts with `0`.
+
+### Why is this bad?
+In some languages (including the infamous C language
+and most of its
+family), this marks an octal constant. In Rust however, this is a decimal
+constant. This could
+be confusing for both the writer and a reader of the constant.
+
+### Example
+
+In Rust:
+```
+fn main() {
+    let a = 0123;
+    println!("{}", a);
+}
+```
+
+prints `123`, while in C:
+
+```
+#include <stdio.h>
+
+int main() {
+    int a = 0123;
+    printf("%d\n", a);
+}
+```
+
+prints `83` (as `83 == 0o123` while `123 == 0o173`).
\ No newline at end of file
diff --git a/src/docs/zero_ptr.txt b/src/docs/zero_ptr.txt
new file mode 100644
index 00000000000..e768a023660
--- /dev/null
+++ b/src/docs/zero_ptr.txt
@@ -0,0 +1,16 @@
+### What it does
+Catch casts from `0` to some pointer type
+
+### Why is this bad?
+This generally means `null` and is better expressed as
+{`std`, `core`}`::ptr::`{`null`, `null_mut`}.
+
+### Example
+```
+let a = 0 as *const u32;
+```
+
+Use instead:
+```
+let a = std::ptr::null::<u32>();
+```
\ No newline at end of file
diff --git a/src/docs/zero_sized_map_values.txt b/src/docs/zero_sized_map_values.txt
new file mode 100644
index 00000000000..0502bdbf395
--- /dev/null
+++ b/src/docs/zero_sized_map_values.txt
@@ -0,0 +1,24 @@
+### What it does
+Checks for maps with zero-sized value types anywhere in the code.
+
+### Why is this bad?
+Since there is only a single value for a zero-sized type, a map
+containing zero sized values is effectively a set. Using a set in that case improves
+readability and communicates intent more clearly.
+
+### Known problems
+* A zero-sized type cannot be recovered later if it contains private fields.
+* This lints the signature of public items
+
+### Example
+```
+fn unique_words(text: &str) -> HashMap<&str, ()> {
+    todo!();
+}
+```
+Use instead:
+```
+fn unique_words(text: &str) -> HashSet<&str> {
+    todo!();
+}
+```
\ No newline at end of file
diff --git a/src/docs/zst_offset.txt b/src/docs/zst_offset.txt
new file mode 100644
index 00000000000..5810455ee95
--- /dev/null
+++ b/src/docs/zst_offset.txt
@@ -0,0 +1,11 @@
+### What it does
+Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to
+zero-sized types
+
+### Why is this bad?
+This is a no-op, and likely unintended
+
+### Example
+```
+unsafe { (&() as *const ()).offset(1) };
+```
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 9ee4a40cbf2..4a32e0e54a8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,6 +7,8 @@ use std::env;
 use std::path::PathBuf;
 use std::process::{self, Command};
 
+mod docs;
+
 const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.
 
 Usage:
@@ -17,6 +19,7 @@ Common options:
     --fix                    Automatically apply lint suggestions. This flag implies `--no-deps`
     -h, --help               Print this message
     -V, --version            Print version info and exit
+    --explain LINT           Print the documentation for a given lint
 
 Other options are the same as `cargo check`.
 
@@ -54,6 +57,16 @@ pub fn main() {
         return;
     }
 
+    if let Some(pos) = env::args().position(|a| a == "--explain") {
+        if let Some(mut lint) = env::args().nth(pos + 1) {
+            lint.make_ascii_lowercase();
+            docs::explain(&lint.strip_prefix("clippy::").unwrap_or(&lint).replace('-', "_"));
+        } else {
+            show_help();
+        }
+        return;
+    }
+
     if let Err(code) = process(env::args().skip(2)) {
         process::exit(code);
     }

From 584000a792b1016677fe4e0e78706d14a8034eb2 Mon Sep 17 00:00:00 2001
From: Lukas Lueg <lukas.lueg@gmail.com>
Date: Tue, 30 Aug 2022 22:27:21 +0200
Subject: [PATCH 17/34] Use `approx_ty_size` for `large_enum_variant`

---
 clippy_lints/src/large_enum_variant.rs |  98 ++++++----
 src/docs/large_enum_variant.txt        |   7 +-
 tests/ui/large_enum_variant.rs         |  24 +++
 tests/ui/large_enum_variant.stderr     | 258 ++++++++++++++++---------
 tests/ui/result_large_err.rs           |   1 +
 tests/ui/result_large_err.stderr       |  22 +--
 6 files changed, 269 insertions(+), 141 deletions(-)

diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs
index c58df126d62..eb13d0869c0 100644
--- a/clippy_lints/src/large_enum_variant.rs
+++ b/clippy_lints/src/large_enum_variant.rs
@@ -1,13 +1,12 @@
 //! lint when there is a large size difference between variants on an enum
 
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{diagnostics::span_lint_and_then, ty::is_copy};
+use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size, ty::is_copy};
 use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{Adt, Ty};
+use rustc_middle::ty::{Adt, AdtDef, GenericArg, List, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 
@@ -17,7 +16,7 @@ declare_clippy_lint! {
     /// `enum`s.
     ///
     /// ### Why is this bad?
-    /// Enum size is bounded by the largest variant. Having a
+    /// Enum size is bounded by the largest variant. Having one
     /// large variant can penalize the memory layout of that enum.
     ///
     /// ### Known problems
@@ -33,8 +32,9 @@ declare_clippy_lint! {
     /// use case it may be possible to store the large data in an auxiliary
     /// structure (e.g. Arena or ECS).
     ///
-    /// The lint will ignore generic types if the layout depends on the
-    /// generics, even if the size difference will be large anyway.
+    /// The lint will ignore the impact of generic types to the type layout by
+    /// assuming every type parameter is zero-sized. Depending on your use case,
+    /// this may lead to a false positive.
     ///
     /// ### Example
     /// ```rust
@@ -83,6 +83,38 @@ struct VariantInfo {
     fields_size: Vec<FieldInfo>,
 }
 
+fn variants_size<'tcx>(
+    cx: &LateContext<'tcx>,
+    adt: AdtDef<'tcx>,
+    subst: &'tcx List<GenericArg<'tcx>>,
+) -> Vec<VariantInfo> {
+    let mut variants_size = adt
+        .variants()
+        .iter()
+        .enumerate()
+        .map(|(i, variant)| {
+            let mut fields_size = variant
+                .fields
+                .iter()
+                .enumerate()
+                .map(|(i, f)| FieldInfo {
+                    ind: i,
+                    size: approx_ty_size(cx, f.ty(cx.tcx, subst)),
+                })
+                .collect::<Vec<_>>();
+            fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
+
+            VariantInfo {
+                ind: i,
+                size: fields_size.iter().map(|info| info.size).sum(),
+                fields_size,
+            }
+        })
+        .collect::<Vec<_>>();
+    variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
+    variants_size
+}
+
 impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
@@ -92,36 +124,14 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
             let ty = cx.tcx.type_of(item.def_id);
-            let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
+            let (adt, subst) = match ty.kind() {
+                Adt(adt, subst) => (adt, subst),
+                _ => panic!("already checked whether this is an enum"),
+            };
             if adt.variants().len() <= 1 {
                 return;
             }
-            let mut variants_size: Vec<VariantInfo> = Vec::new();
-            for (i, variant) in adt.variants().iter().enumerate() {
-                let mut fields_size = Vec::new();
-                for (i, f) in variant.fields.iter().enumerate() {
-                    let ty = cx.tcx.type_of(f.did);
-                    // don't lint variants which have a field of generic type.
-                    match cx.layout_of(ty) {
-                        Ok(l) => {
-                            let fsize = l.size.bytes();
-                            fields_size.push(FieldInfo { ind: i, size: fsize });
-                        },
-                        Err(_) => {
-                            return;
-                        },
-                    }
-                }
-                let size: u64 = fields_size.iter().map(|info| info.size).sum();
-
-                variants_size.push(VariantInfo {
-                    ind: i,
-                    size,
-                    fields_size,
-                });
-            }
-
-            variants_size.sort_by(|a, b| (b.size.cmp(&a.size)));
+            let variants_size = variants_size(cx, *adt, subst);
 
             let mut difference = variants_size[0].size - variants_size[1].size;
             if difference > self.maximum_size_difference_allowed {
@@ -129,20 +139,30 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
                 span_lint_and_then(
                     cx,
                     LARGE_ENUM_VARIANT,
-                    def.variants[variants_size[0].ind].span,
+                    item.span,
                     "large size difference between variants",
                     |diag| {
                         diag.span_label(
-                            def.variants[variants_size[0].ind].span,
-                            &format!("this variant is {} bytes", variants_size[0].size),
+                            item.span,
+                            format!("the entire enum is at least {} bytes", approx_ty_size(cx, ty)),
                         );
-                        diag.span_note(
+                        diag.span_label(
+                            def.variants[variants_size[0].ind].span,
+                            format!("the largest variant contains at least {} bytes", variants_size[0].size),
+                        );
+                        diag.span_label(
                             def.variants[variants_size[1].ind].span,
-                            &format!("and the second-largest variant is {} bytes:", variants_size[1].size),
+                            &if variants_size[1].fields_size.is_empty() {
+                                "the second-largest variant carries no data at all".to_owned()
+                            } else {
+                                format!(
+                                    "the second-largest variant contains at least {} bytes",
+                                    variants_size[1].size
+                                )
+                            },
                         );
 
                         let fields = def.variants[variants_size[0].ind].data.fields();
-                        variants_size[0].fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
                         let mut applicability = Applicability::MaybeIncorrect;
                         if is_copy(cx, ty) || maybe_copy(cx, ty) {
                             diag.span_note(
diff --git a/src/docs/large_enum_variant.txt b/src/docs/large_enum_variant.txt
index 787e8e027e1..1f95430790d 100644
--- a/src/docs/large_enum_variant.txt
+++ b/src/docs/large_enum_variant.txt
@@ -3,7 +3,7 @@ Checks for large size differences between variants on
 `enum`s.
 
 ### Why is this bad?
-Enum size is bounded by the largest variant. Having a
+Enum size is bounded by the largest variant. Having one
 large variant can penalize the memory layout of that enum.
 
 ### Known problems
@@ -19,8 +19,9 @@ still be `Clone`, but that is worse ergonomically. Depending on the
 use case it may be possible to store the large data in an auxiliary
 structure (e.g. Arena or ECS).
 
-The lint will ignore generic types if the layout depends on the
-generics, even if the size difference will be large anyway.
+The lint will ignore the impact of generic types to the type layout by
+assuming every type parameter is zero-sized. Depending on your use case,
+this may lead to a false positive.
 
 ### Example
 ```
diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs
index 23152a13322..717009e4c4c 100644
--- a/tests/ui/large_enum_variant.rs
+++ b/tests/ui/large_enum_variant.rs
@@ -130,6 +130,30 @@ impl<T: Copy> Clone for SomeGenericPossiblyCopyEnum<T> {
 
 impl<T: Copy> Copy for SomeGenericPossiblyCopyEnum<T> {}
 
+enum LargeEnumWithGenerics<T> {
+    Small,
+    Large((T, [u8; 512])),
+}
+
+struct Foo<T> {
+    foo: T,
+}
+
+enum WithGenerics {
+    Large([Foo<u64>; 64]),
+    Small(u8),
+}
+
+enum PossiblyLargeEnumWithConst<const U: usize> {
+    SmallBuffer([u8; 4]),
+    MightyBuffer([u16; U]),
+}
+
+enum LargeEnumOfConst {
+    Ok,
+    Error(PossiblyLargeEnumWithConst<256>),
+}
+
 fn main() {
     large_enum_variant!();
 }
diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr
index 0248327262d..e1ed2460e08 100644
--- a/tests/ui/large_enum_variant.stderr
+++ b/tests/ui/large_enum_variant.stderr
@@ -1,143 +1,177 @@
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:12:5
+  --> $DIR/large_enum_variant.rs:10:1
    |
-LL |     B([i32; 8000]),
-   |     ^^^^^^^^^^^^^^ this variant is 32000 bytes
+LL | / enum LargeEnum {
+LL | |     A(i32),
+   | |     ------ the second-largest variant contains at least 4 bytes
+LL | |     B([i32; 8000]),
+   | |     -------------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
    |
    = note: `-D clippy::large-enum-variant` implied by `-D warnings`
-note: and the second-largest variant is 4 bytes:
-  --> $DIR/large_enum_variant.rs:11:5
-   |
-LL |     A(i32),
-   |     ^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     B(Box<[i32; 8000]>),
    |       ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:36:5
+  --> $DIR/large_enum_variant.rs:34:1
    |
-LL |     ContainingLargeEnum(LargeEnum),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
+LL | / enum LargeEnum2 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     ContainingLargeEnum(LargeEnum),
+   | |     ------------------------------ the largest variant contains at least 32004 bytes
+LL | | }
+   | |_^ the entire enum is at least 32008 bytes
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:35:5
-   |
-LL |     VariantOk(i32, u32),
-   |     ^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     ContainingLargeEnum(Box<LargeEnum>),
    |                         ~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:40:5
+  --> $DIR/large_enum_variant.rs:39:1
    |
-LL |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70004 bytes
+LL | / enum LargeEnum3 {
+LL | |     ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]),
+   | |     --------------------------------------------------------- the largest variant contains at least 70004 bytes
+LL | |     VoidVariant,
+LL | |     StructLikeLittle { x: i32, y: i32 },
+   | |     ----------------------------------- the second-largest variant contains at least 8 bytes
+LL | | }
+   | |_^ the entire enum is at least 70008 bytes
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:42:5
-   |
-LL |     StructLikeLittle { x: i32, y: i32 },
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>),
    |                                     ~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:47:5
+  --> $DIR/large_enum_variant.rs:45:1
    |
-LL |     StructLikeLarge { x: [i32; 8000], y: i32 },
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes
+LL | / enum LargeEnum4 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     StructLikeLarge { x: [i32; 8000], y: i32 },
+   | |     ------------------------------------------ the largest variant contains at least 32004 bytes
+LL | | }
+   | |_^ the entire enum is at least 32008 bytes
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:46:5
-   |
-LL |     VariantOk(i32, u32),
-   |     ^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     StructLikeLarge { x: Box<[i32; 8000]>, y: i32 },
    |                          ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:52:5
+  --> $DIR/large_enum_variant.rs:50:1
    |
-LL |     StructLikeLarge2 { x: [i32; 8000] },
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32000 bytes
+LL | / enum LargeEnum5 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     StructLikeLarge2 { x: [i32; 8000] },
+   | |     ----------------------------------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:51:5
-   |
-LL |     VariantOk(i32, u32),
-   |     ^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     StructLikeLarge2 { x: Box<[i32; 8000]> },
    |                           ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:68:5
+  --> $DIR/large_enum_variant.rs:66:1
    |
-LL |     B([u8; 1255]),
-   |     ^^^^^^^^^^^^^ this variant is 1255 bytes
+LL | / enum LargeEnum7 {
+LL | |     A,
+LL | |     B([u8; 1255]),
+   | |     ------------- the largest variant contains at least 1255 bytes
+LL | |     C([u8; 200]),
+   | |     ------------ the second-largest variant contains at least 200 bytes
+LL | | }
+   | |_^ the entire enum is at least 1256 bytes
    |
-note: and the second-largest variant is 200 bytes:
-  --> $DIR/large_enum_variant.rs:69:5
-   |
-LL |     C([u8; 200]),
-   |     ^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     B(Box<[u8; 1255]>),
    |       ~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:74:5
+  --> $DIR/large_enum_variant.rs:72:1
    |
-LL |     ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70128 bytes
+LL | / enum LargeEnum8 {
+LL | |     VariantOk(i32, u32),
+   | |     ------------------- the second-largest variant contains at least 8 bytes
+LL | |     ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]),
+   | |     ------------------------------------------------------------------------- the largest variant contains at least 70128 bytes
+LL | | }
+   | |_^ the entire enum is at least 70132 bytes
    |
-note: and the second-largest variant is 8 bytes:
-  --> $DIR/large_enum_variant.rs:73:5
-   |
-LL |     VariantOk(i32, u32),
-   |     ^^^^^^^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]),
    |                                ~~~~~~~~~~~~~~~~            ~~~~~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:79:5
+  --> $DIR/large_enum_variant.rs:77:1
    |
-LL |     B(Struct2),
-   |     ^^^^^^^^^^ this variant is 32000 bytes
+LL | / enum LargeEnum9 {
+LL | |     A(Struct<()>),
+   | |     ------------- the second-largest variant contains at least 4 bytes
+LL | |     B(Struct2),
+   | |     ---------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32004 bytes
    |
-note: and the second-largest variant is 4 bytes:
-  --> $DIR/large_enum_variant.rs:78:5
-   |
-LL |     A(Struct<()>),
-   |     ^^^^^^^^^^^^^
 help: consider boxing the large fields to reduce the total size of the enum
    |
 LL |     B(Box<Struct2>),
    |       ~~~~~~~~~~~~
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:104:5
+  --> $DIR/large_enum_variant.rs:82:1
    |
-LL |     B([u128; 4000]),
-   |     ^^^^^^^^^^^^^^^ this variant is 64000 bytes
+LL | / enum LargeEnumOk2<T> {
+LL | |     A(T),
+   | |     ---- the second-largest variant contains at least 0 bytes
+LL | |     B(Struct2),
+   | |     ---------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32000 bytes
    |
-note: and the second-largest variant is 1 bytes:
-  --> $DIR/large_enum_variant.rs:103:5
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     B(Box<Struct2>),
+   |       ~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:87:1
+   |
+LL | / enum LargeEnumOk3<T> {
+LL | |     A(Struct<T>),
+   | |     ------------ the second-largest variant contains at least 4 bytes
+LL | |     B(Struct2),
+   | |     ---------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32000 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     B(Box<Struct2>),
+   |       ~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:102:1
+   |
+LL | / enum CopyableLargeEnum {
+LL | |     A(bool),
+   | |     ------- the second-largest variant contains at least 1 bytes
+LL | |     B([u128; 4000]),
+   | |     --------------- the largest variant contains at least 64000 bytes
+LL | | }
+   | |_^ the entire enum is at least 64008 bytes
    |
-LL |     A(bool),
-   |     ^^^^^^^
 note: boxing a variant would require the type no longer be `Copy`
   --> $DIR/large_enum_variant.rs:102:6
    |
@@ -150,16 +184,16 @@ LL |     B([u128; 4000]),
    |     ^^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:109:5
+  --> $DIR/large_enum_variant.rs:107:1
    |
-LL |     B([u128; 4000]),
-   |     ^^^^^^^^^^^^^^^ this variant is 64000 bytes
+LL | / enum ManuallyCopyLargeEnum {
+LL | |     A(bool),
+   | |     ------- the second-largest variant contains at least 1 bytes
+LL | |     B([u128; 4000]),
+   | |     --------------- the largest variant contains at least 64000 bytes
+LL | | }
+   | |_^ the entire enum is at least 64008 bytes
    |
-note: and the second-largest variant is 1 bytes:
-  --> $DIR/large_enum_variant.rs:108:5
-   |
-LL |     A(bool),
-   |     ^^^^^^^
 note: boxing a variant would require the type no longer be `Copy`
   --> $DIR/large_enum_variant.rs:107:6
    |
@@ -172,16 +206,16 @@ LL |     B([u128; 4000]),
    |     ^^^^^^^^^^^^^^^
 
 error: large size difference between variants
-  --> $DIR/large_enum_variant.rs:122:5
+  --> $DIR/large_enum_variant.rs:120:1
    |
-LL |     B([u64; 4000]),
-   |     ^^^^^^^^^^^^^^ this variant is 32000 bytes
+LL | / enum SomeGenericPossiblyCopyEnum<T> {
+LL | |     A(bool, std::marker::PhantomData<T>),
+   | |     ------------------------------------ the second-largest variant contains at least 1 bytes
+LL | |     B([u64; 4000]),
+   | |     -------------- the largest variant contains at least 32000 bytes
+LL | | }
+   | |_^ the entire enum is at least 32008 bytes
    |
-note: and the second-largest variant is 1 bytes:
-  --> $DIR/large_enum_variant.rs:121:5
-   |
-LL |     A(bool, std::marker::PhantomData<T>),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: boxing a variant would require the type no longer be `Copy`
   --> $DIR/large_enum_variant.rs:120:6
    |
@@ -193,5 +227,53 @@ help: consider boxing the large fields to reduce the total size of the enum
 LL |     B([u64; 4000]),
    |     ^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:133:1
+   |
+LL | / enum LargeEnumWithGenerics<T> {
+LL | |     Small,
+   | |     ----- the second-largest variant carries no data at all
+LL | |     Large((T, [u8; 512])),
+   | |     --------------------- the largest variant contains at least 512 bytes
+LL | | }
+   | |_^ the entire enum is at least 512 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Large(Box<(T, [u8; 512])>),
+   |           ~~~~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:142:1
+   |
+LL | / enum WithGenerics {
+LL | |     Large([Foo<u64>; 64]),
+   | |     --------------------- the largest variant contains at least 512 bytes
+LL | |     Small(u8),
+   | |     --------- the second-largest variant contains at least 1 bytes
+LL | | }
+   | |_^ the entire enum is at least 520 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Large(Box<[Foo<u64>; 64]>),
+   |           ~~~~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:152:1
+   |
+LL | / enum LargeEnumOfConst {
+LL | |     Ok,
+   | |     -- the second-largest variant carries no data at all
+LL | |     Error(PossiblyLargeEnumWithConst<256>),
+   | |     -------------------------------------- the largest variant contains at least 514 bytes
+LL | | }
+   | |_^ the entire enum is at least 514 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Error(Box<PossiblyLargeEnumWithConst<256>>),
+   |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 16 previous errors
 
diff --git a/tests/ui/result_large_err.rs b/tests/ui/result_large_err.rs
index 78d8f76fe66..f7df3b85655 100644
--- a/tests/ui/result_large_err.rs
+++ b/tests/ui/result_large_err.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::result_large_err)]
+#![allow(clippy::large_enum_variant)]
 
 pub fn small_err() -> Result<(), u128> {
     Ok(())
diff --git a/tests/ui/result_large_err.stderr b/tests/ui/result_large_err.stderr
index 0f1f39d72cb..ef19f2854ab 100644
--- a/tests/ui/result_large_err.stderr
+++ b/tests/ui/result_large_err.stderr
@@ -1,5 +1,5 @@
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:7:23
+  --> $DIR/result_large_err.rs:8:23
    |
 LL | pub fn large_err() -> Result<(), [u8; 512]> {
    |                       ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -8,7 +8,7 @@ LL | pub fn large_err() -> Result<(), [u8; 512]> {
    = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:18:21
+  --> $DIR/result_large_err.rs:19:21
    |
 LL |     pub fn ret() -> Result<(), Self> {
    |                     ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
@@ -16,7 +16,7 @@ LL |     pub fn ret() -> Result<(), Self> {
    = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:23:26
+  --> $DIR/result_large_err.rs:24:26
    |
 LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes
@@ -24,7 +24,7 @@ LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> {
    = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:28:45
+  --> $DIR/result_large_err.rs:29:45
    |
 LL | pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
    |                                             ^^^^^^^ the `Err`-variant is at least 240 bytes
@@ -32,7 +32,7 @@ LL | pub fn large_err_via_type_alias<T>(x: T) -> Fdlr<T> {
    = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box<FullyDefinedLargeError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:36:34
+  --> $DIR/result_large_err.rs:37:34
    |
 LL | pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeError)> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 256 bytes
@@ -40,7 +40,7 @@ LL | pub fn param_large_error<R>() -> Result<(), (u128, R, FullyDefinedLargeErro
    = help: try reducing the size of `(u128, R, FullyDefinedLargeError)`, for example by boxing large elements or replacing it with `Box<(u128, R, FullyDefinedLargeError)>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:47:34
+  --> $DIR/result_large_err.rs:48:34
    |
 LL |     pub fn large_enum_error() -> Result<(), Self> {
    |                                  ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 513 bytes
@@ -48,7 +48,7 @@ LL |     pub fn large_enum_error() -> Result<(), Self> {
    = help: try reducing the size of `LargeErrorVariants<()>`, for example by boxing large elements or replacing it with `Box<LargeErrorVariants<()>>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:53:25
+  --> $DIR/result_large_err.rs:54:25
    |
 LL |     fn large_error() -> Result<(), [u8; 512]> {
    |                         ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -56,7 +56,7 @@ LL |     fn large_error() -> Result<(), [u8; 512]> {
    = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:72:29
+  --> $DIR/result_large_err.rs:73:29
    |
 LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -64,7 +64,7 @@ LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> {
    = help: try reducing the size of `FullyDefinedUnionError`, for example by boxing large elements or replacing it with `Box<FullyDefinedUnionError>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:81:40
+  --> $DIR/result_large_err.rs:82:40
    |
 LL | pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes
@@ -72,7 +72,7 @@ LL | pub fn param_large_union<T: Copy>() -> Result<(), UnionError<T>> {
    = help: try reducing the size of `UnionError<T>`, for example by boxing large elements or replacing it with `Box<UnionError<T>>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:90:34
+  --> $DIR/result_large_err.rs:91:34
    |
 LL | pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes
@@ -80,7 +80,7 @@ LL | pub fn array_error_subst<U>() -> Result<(), ArrayError<i32, U>> {
    = help: try reducing the size of `ArrayError<i32, U>`, for example by boxing large elements or replacing it with `Box<ArrayError<i32, U>>`
 
 error: the `Err`-variant returned from this function is very large
-  --> $DIR/result_large_err.rs:94:31
+  --> $DIR/result_large_err.rs:95:31
    |
 LL | pub fn array_error<T, U>() -> Result<(), ArrayError<(i32, T), U>> {
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes

From 750a2d57bde6fca3bbd856410fe4fb54c4c068dc Mon Sep 17 00:00:00 2001
From: Michael Wright <mikerite@lavabit.com>
Date: Sat, 3 Sep 2022 17:00:44 +0200
Subject: [PATCH 18/34] Fix `unnecessary_to_owned` false positive

Fixes #9351.

Note that this commit reworks that fix for #9317. The change
is to check that the type implements `AsRef<str>` before regarding
`to_string` as an equivalent of `to_owned`. This was suggested
by Jarcho in the #9317 issue comments.

The benefit of this is that it moves some complexity out of
`check_other_call_arg` and simplifies the module as a whole.
---
 .../src/methods/unnecessary_to_owned.rs       | 205 ++++++++++++------
 tests/ui/unnecessary_to_owned.fixed           |  60 +++++
 tests/ui/unnecessary_to_owned.rs              |  60 +++++
 tests/ui/unnecessary_to_owned.stderr          |   8 +-
 4 files changed, 262 insertions(+), 71 deletions(-)

diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index 44bf8435294..d59b26c3144 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -1,21 +1,25 @@
 use super::implicit_clone::is_clone_like;
 use super::unnecessary_iter_cloned::{self, is_into_iter};
+use crate::rustc_middle::ty::Subst;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{
-    get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, peel_mid_ty_refs,
-};
-use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item};
+use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
+use clippy_utils::visitors::find_all_ret_expressions;
+use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
 use clippy_utils::{meets_msrv, msrvs};
 use rustc_errors::Applicability;
-use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind};
+use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
+use rustc_middle::ty::EarlyBinder;
+use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
 use rustc_semver::RustcVersion;
 use rustc_span::{sym, Symbol};
+use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
+use rustc_typeck::check::{FnCtxt, Inherited};
 use std::cmp::max;
 
 use super::UNNECESSARY_TO_OWNED;
@@ -33,7 +37,7 @@ pub fn check<'tcx>(
         then {
             if is_cloned_or_copied(cx, method_name, method_def_id) {
                 unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
-            } else if is_to_owned_like(cx, method_name, method_def_id) {
+            } else if is_to_owned_like(cx, expr, method_name, method_def_id) {
                 // At this point, we know the call is of a `to_owned`-like function. The functions
                 // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary
                 // based on its context, that is, whether it is a referent in an `AddrOf` expression, an
@@ -245,12 +249,12 @@ fn check_other_call_arg<'tcx>(
 ) -> bool {
     if_chain! {
         if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
-        if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call);
+        if let Some((callee_def_id, _, call_args)) = get_callee_substs_and_args(cx, maybe_call);
         let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
         if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id);
         if let Some(input) = fn_sig.inputs().get(i);
         let (input, n_refs) = peel_mid_ty_refs(*input);
-        if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input);
+        if let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input);
         if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait();
         if let [trait_predicate] = trait_predicates
             .iter()
@@ -258,52 +262,13 @@ fn check_other_call_arg<'tcx>(
             .collect::<Vec<_>>()[..];
         if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
         if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef);
+        if trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id;
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
-        // If the callee has type parameters, they could appear in `projection_predicate.ty` or the
-        // types of `trait_predicate.trait_ref.substs`.
-        if if trait_predicate.def_id() == deref_trait_id {
-            if let [projection_predicate] = projection_predicates[..] {
-                let normalized_ty =
-                    cx.tcx
-                        .subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
-                implements_trait(cx, receiver_ty, deref_trait_id, &[])
-                    && get_associated_type(cx, receiver_ty, deref_trait_id, "Target")
-                        .map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
-            } else {
-                false
-            }
-        } else if trait_predicate.def_id() == as_ref_trait_id {
-            let composed_substs = compose_substs(
-                cx,
-                &trait_predicate.trait_ref.substs.iter().skip(1).collect::<Vec<_>>()[..],
-                call_substs,
-            );
-            // if `expr` is a `String` and generic target is [u8], skip
-            // (https://github.com/rust-lang/rust-clippy/issues/9317).
-            if let [subst] = composed_substs[..]
-                && let GenericArgKind::Type(arg_ty) = subst.unpack()
-                && arg_ty.is_slice()
-                && let inner_ty = arg_ty.builtin_index().unwrap()
-                && let ty::Uint(ty::UintTy::U8) = inner_ty.kind()
-                && let self_ty = cx.typeck_results().expr_ty(expr).peel_refs()
-                && is_type_diagnostic_item(cx, self_ty, sym::String) {
-                false
-            } else {
-                implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs)
-            }
-        } else {
-            false
-        };
+        if can_change_type(cx, maybe_arg, receiver_ty);
         // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match
         // `Target = T`.
         if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id;
         let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 });
-        // If the trait is `AsRef` and the input type variable `T` occurs in the output type, then
-        // `T` must not be instantiated with a reference
-        // (https://github.com/rust-lang/rust-clippy/issues/8507).
-        if (n_refs == 0 && !receiver_ty.is_ref())
-            || trait_predicate.def_id() != as_ref_trait_id
-            || !fn_sig.output().contains(input);
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
             span_lint_and_sugg(
@@ -389,22 +354,102 @@ fn get_input_traits_and_projections<'tcx>(
     (trait_predicates, projection_predicates)
 }
 
-/// Composes two substitutions by applying the latter to the types of the former.
-fn compose_substs<'tcx>(
-    cx: &LateContext<'tcx>,
-    left: &[GenericArg<'tcx>],
-    right: SubstsRef<'tcx>,
-) -> Vec<GenericArg<'tcx>> {
-    left.iter()
-        .map(|arg| {
-            if let GenericArgKind::Type(arg_ty) = arg.unpack() {
-                let normalized_ty = cx.tcx.subst_and_normalize_erasing_regions(right, cx.param_env, arg_ty);
-                GenericArg::from(normalized_ty)
-            } else {
-                *arg
+fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool {
+    for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
+        match node {
+            Node::Stmt(_) => return true,
+            Node::Block(..) => continue,
+            Node::Item(item) => {
+                if let ItemKind::Fn(_, _, body_id) = &item.kind
+                && let output_ty = return_ty(cx, item.hir_id())
+                && let local_def_id = cx.tcx.hir().local_def_id(item.hir_id())
+                && Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
+                    let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.hir_id());
+                    fn_ctxt.can_coerce(ty, output_ty)
+                }) {
+                    if has_lifetime(output_ty) && has_lifetime(ty) {
+                        return false;
+                    }
+                    let body = cx.tcx.hir().body(*body_id);
+                    let body_expr = &body.value;
+                    let mut count = 0;
+                    return find_all_ret_expressions(cx, body_expr, |_| { count += 1; count <= 1 });
+                }
             }
-        })
-        .collect()
+            Node::Expr(parent_expr) => {
+                if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, parent_expr) {
+                    let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+                    if let Some(arg_index) = call_args.iter().position(|arg| arg.hir_id == expr.hir_id)
+                        && let Some(param_ty) = fn_sig.inputs().get(arg_index)
+                        && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
+                    {
+                        if fn_sig
+                            .inputs()
+                            .iter()
+                            .enumerate()
+                            .filter(|(i, _)| *i != arg_index)
+                            .any(|(_, ty)| ty.contains(*param_ty))
+                        {
+                            return false;
+                        }
+
+                        let mut trait_predicates = cx.tcx.param_env(callee_def_id)
+                            .caller_bounds().iter().filter(|predicate| {
+                            if let PredicateKind::Trait(trait_predicate) =  predicate.kind().skip_binder()
+                                && trait_predicate.trait_ref.self_ty() == *param_ty {
+                                    true
+                                } else {
+                                false
+                            }
+                        });
+
+                        let new_subst = cx.tcx.mk_substs(
+                            call_substs.iter()
+                                .enumerate()
+                                .map(|(i, t)|
+                                     if i == (*param_index as usize) {
+                                         GenericArg::from(ty)
+                                     } else {
+                                         t
+                                     }));
+
+                        if trait_predicates.any(|predicate| {
+                            let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst);
+                            let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate);
+                            !cx.tcx
+                                .infer_ctxt()
+                                .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
+                        }) {
+                            return false;
+                        }
+
+                        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) {
+                                expr = parent_expr;
+                                ty = new_ty;
+                                continue;
+                            }
+                            return false;
+                        }
+
+                        return true;
+                    }
+                } else if let ExprKind::Block(..) = parent_expr.kind {
+                    continue;
+                }
+                return false;
+            },
+            _ => return false,
+        }
+    }
+
+    false
+}
+
+fn has_lifetime(ty: Ty<'_>) -> bool {
+    ty.walk().any(|t| matches!(t.unpack(), GenericArgKind::Lifetime(_)))
 }
 
 /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`.
@@ -415,10 +460,10 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id:
 
 /// Returns true if the named method can be used to convert the receiver to its "owned"
 /// representation.
-fn is_to_owned_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
+fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool {
     is_clone_like(cx, method_name.as_str(), method_def_id)
         || is_cow_into_owned(cx, method_name, method_def_id)
-        || is_to_string(cx, method_name, method_def_id)
+        || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id)
 }
 
 /// Returns true if the named method is `Cow::into_owned`.
@@ -426,7 +471,27 @@ fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: D
     method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow)
 }
 
-/// Returns true if the named method is `ToString::to_string`.
-fn is_to_string(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
-    method_name == sym::to_string && is_diag_trait_item(cx, method_def_id, sym::ToString)
+/// Returns true if the named method is `ToString::to_string` and it's called on a type that
+/// is string-like i.e. implements `AsRef<str>` or `Deref<str>`.
+fn is_to_string_on_string_like<'a>(
+    cx: &LateContext<'_>,
+    call_expr: &'a Expr<'a>,
+    method_name: Symbol,
+    method_def_id: DefId,
+) -> bool {
+    if method_name != sym::to_string || !is_diag_trait_item(cx, method_def_id, sym::ToString) {
+        return false;
+    }
+
+    if let Some(substs) = cx.typeck_results().node_substs_opt(call_expr.hir_id)
+        && let [generic_arg] = substs.as_slice()
+        && let GenericArgKind::Type(ty) = generic_arg.unpack()
+        && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
+        && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
+        && (implements_trait(cx, ty, deref_trait_id, &[cx.tcx.types.str_.into()]) ||
+            implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) {
+            true
+        } else {
+            false
+        }
 }
diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed
index 9cd5bc73b1e..a920c63b199 100644
--- a/tests/ui/unnecessary_to_owned.fixed
+++ b/tests/ui/unnecessary_to_owned.fixed
@@ -357,3 +357,63 @@ mod issue_9317 {
         consume(b.to_string());
     }
 }
+
+mod issue_9351 {
+    #![allow(dead_code)]
+
+    use std::ops::Deref;
+    use std::path::{Path, PathBuf};
+
+    fn require_deref_path<T: Deref<Target = std::path::Path>>(x: T) -> T {
+        x
+    }
+
+    fn generic_arg_used_elsewhere<T: AsRef<Path>>(_x: T, _y: T) {}
+
+    fn id<T: AsRef<str>>(x: T) -> T {
+        x
+    }
+
+    fn predicates_are_satisfied(_x: impl std::fmt::Write) {}
+
+    // Should lint
+    fn single_return() -> impl AsRef<str> {
+        id("abc")
+    }
+
+    // Should not lint
+    fn multiple_returns(b: bool) -> impl AsRef<str> {
+        if b {
+            return String::new();
+        }
+
+        id("abc".to_string())
+    }
+
+    struct S1(String);
+
+    // Should not lint
+    fn fields1() -> S1 {
+        S1(id("abc".to_string()))
+    }
+
+    struct S2 {
+        s: String,
+    }
+
+    // Should not lint
+    fn fields2() {
+        let mut s = S2 { s: "abc".into() };
+        s.s = id("abc".to_string());
+    }
+
+    pub fn main() {
+        let path = std::path::Path::new("x");
+        let path_buf = path.to_owned();
+
+        // Should not lint.
+        let _x: PathBuf = require_deref_path(path.to_owned());
+        generic_arg_used_elsewhere(path.to_owned(), path_buf);
+        predicates_are_satisfied(id("abc".to_string()));
+    }
+}
diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs
index 7f62ba3ab5d..2128bdacdda 100644
--- a/tests/ui/unnecessary_to_owned.rs
+++ b/tests/ui/unnecessary_to_owned.rs
@@ -357,3 +357,63 @@ mod issue_9317 {
         consume(b.to_string());
     }
 }
+
+mod issue_9351 {
+    #![allow(dead_code)]
+
+    use std::ops::Deref;
+    use std::path::{Path, PathBuf};
+
+    fn require_deref_path<T: Deref<Target = std::path::Path>>(x: T) -> T {
+        x
+    }
+
+    fn generic_arg_used_elsewhere<T: AsRef<Path>>(_x: T, _y: T) {}
+
+    fn id<T: AsRef<str>>(x: T) -> T {
+        x
+    }
+
+    fn predicates_are_satisfied(_x: impl std::fmt::Write) {}
+
+    // Should lint
+    fn single_return() -> impl AsRef<str> {
+        id("abc".to_string())
+    }
+
+    // Should not lint
+    fn multiple_returns(b: bool) -> impl AsRef<str> {
+        if b {
+            return String::new();
+        }
+
+        id("abc".to_string())
+    }
+
+    struct S1(String);
+
+    // Should not lint
+    fn fields1() -> S1 {
+        S1(id("abc".to_string()))
+    }
+
+    struct S2 {
+        s: String,
+    }
+
+    // Should not lint
+    fn fields2() {
+        let mut s = S2 { s: "abc".into() };
+        s.s = id("abc".to_string());
+    }
+
+    pub fn main() {
+        let path = std::path::Path::new("x");
+        let path_buf = path.to_owned();
+
+        // Should not lint.
+        let _x: PathBuf = require_deref_path(path.to_owned());
+        generic_arg_used_elsewhere(path.to_owned(), path_buf);
+        predicates_are_satisfied(id("abc".to_string()));
+    }
+}
diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr
index 243b4599dba..7deb90b06f3 100644
--- a/tests/ui/unnecessary_to_owned.stderr
+++ b/tests/ui/unnecessary_to_owned.stderr
@@ -509,5 +509,11 @@ error: unnecessary use of `to_string`
 LL |         Box::new(build(y.to_string()))
    |                        ^^^^^^^^^^^^^ help: use: `y`
 
-error: aborting due to 78 previous errors
+error: unnecessary use of `to_string`
+  --> $DIR/unnecessary_to_owned.rs:381:12
+   |
+LL |         id("abc".to_string())
+   |            ^^^^^^^^^^^^^^^^^ help: use: `"abc"`
+
+error: aborting due to 79 previous errors
 

From 2cc20e32451cd6ee3b1336616d6ef7990de96009 Mon Sep 17 00:00:00 2001
From: kraktus <56031107+kraktus@users.noreply.github.com>
Date: Sun, 4 Sep 2022 16:29:30 +0200
Subject: [PATCH 19/34] fix wording for `derivable_impls`

---
 clippy_lints/src/derivable_impls.rs | 2 +-
 src/docs/derivable_impls.txt        | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs
index 4d7f4076d7b..ef9eeecc6a9 100644
--- a/clippy_lints/src/derivable_impls.rs
+++ b/clippy_lints/src/derivable_impls.rs
@@ -40,7 +40,7 @@ declare_clippy_lint! {
     ///
     /// ### Known problems
     /// Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925)
-    /// in generic types and the user defined `impl` maybe is more generalized or
+    /// in generic types and the user defined `impl` may be more generalized or
     /// specialized than what derive will produce. This lint can't detect the manual `impl`
     /// has exactly equal bounds, and therefore this lint is disabled for types with
     /// generic parameters.
diff --git a/src/docs/derivable_impls.txt b/src/docs/derivable_impls.txt
index 8e4a80a672c..5cee43956cc 100644
--- a/src/docs/derivable_impls.txt
+++ b/src/docs/derivable_impls.txt
@@ -29,7 +29,7 @@ struct Foo {
 
 ### Known problems
 Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925)
-in generic types and the user defined `impl` maybe is more generalized or
+in generic types and the user defined `impl` may be more generalized or
 specialized than what derive will produce. This lint can't detect the manual `impl`
 has exactly equal bounds, and therefore this lint is disabled for types with
 generic parameters.
\ No newline at end of file

From f0e586c2511019a58ad3e56be16bba76dfc7eba8 Mon Sep 17 00:00:00 2001
From: relrelb <relrelbachar@gmail.com>
Date: Tue, 16 Aug 2022 23:26:03 +0300
Subject: [PATCH 20/34] Suggest `Entry::or_default` for
 `Entry::or_insert(Default::default())`

Unlike past similar work done in #6228, expand the existing `or_fun_call`
lint to detect `or_insert` calls with a `T::new()` or `T::default()`
argument, much like currently done for `unwrap_or` calls. In that case,
suggest the use of `or_default`, which is more idiomatic.

Note that even with this change, `or_insert_with(T::default)` calls
aren't detected as candidates for `or_default()`, in the same manner
that currently `unwrap_or_else(T::default)` calls aren't detected as
candidates for `unwrap_or_default()`.

Also, as a nearby cleanup, change `KNOW_TYPES` from `static` to `const`,
since as far as I understand it's preferred (should Clippy have a lint
for that?).

Fixes #3812.
---
 clippy_lints/src/methods/mod.rs         |  5 +++--
 clippy_lints/src/methods/or_fun_call.rs | 13 +++++++++----
 src/docs/or_fun_call.txt                |  5 +++--
 tests/ui/or_fun_call.fixed              |  8 ++++----
 tests/ui/or_fun_call.stderr             | 26 ++++++++++++++++++++++++-
 5 files changed, 44 insertions(+), 13 deletions(-)

diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index a0d190a58af..b7d2d980db8 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -825,8 +825,9 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
-    /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
-    /// `unwrap_or_default` instead.
+    /// `.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`,
+    /// `.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()`
+    /// etc. instead.
     ///
     /// ### Why is this bad?
     /// The function will always be called and potentially
diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs
index 6af134019a4..c97f714680e 100644
--- a/clippy_lints/src/methods/or_fun_call.rs
+++ b/clippy_lints/src/methods/or_fun_call.rs
@@ -22,7 +22,8 @@ pub(super) fn check<'tcx>(
     name: &str,
     args: &'tcx [hir::Expr<'_>],
 ) {
-    /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
+    /// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`,
+    /// `or_insert(T::new())` or `or_insert(T::default())`.
     #[allow(clippy::too_many_arguments)]
     fn check_unwrap_or_default(
         cx: &LateContext<'_>,
@@ -42,7 +43,11 @@ pub(super) fn check<'tcx>(
 
         if_chain! {
             if !or_has_args;
-            if name == "unwrap_or";
+            if let Some(sugg) = match name {
+                "unwrap_or" => Some("unwrap_or_default"),
+                "or_insert" => Some("or_default"),
+                _ => None,
+            };
             if let hir::ExprKind::Path(ref qpath) = fun.kind;
             if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
             let path = last_path_segment(qpath).ident.name;
@@ -58,7 +63,7 @@ pub(super) fn check<'tcx>(
                     method_span.with_hi(span.hi()),
                     &format!("use of `{}` followed by a call to `{}`", name, path),
                     "try this",
-                    "unwrap_or_default()".to_string(),
+                    format!("{}()", sugg),
                     Applicability::MachineApplicable,
                 );
 
@@ -82,7 +87,7 @@ pub(super) fn check<'tcx>(
         fun_span: Option<Span>,
     ) {
         // (path, fn_has_argument, methods, suffix)
-        static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
+        const KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
             (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
             (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
             (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
diff --git a/src/docs/or_fun_call.txt b/src/docs/or_fun_call.txt
index 5605e96c98e..6ce77cc268c 100644
--- a/src/docs/or_fun_call.txt
+++ b/src/docs/or_fun_call.txt
@@ -1,7 +1,8 @@
 ### What it does
 Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,
-etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or
-`unwrap_or_default` instead.
+`.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`,
+`.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()`
+etc. instead.
 
 ### Why is this bad?
 The function will always be called and potentially
diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed
index 18ea4e55029..5991188ab63 100644
--- a/tests/ui/or_fun_call.fixed
+++ b/tests/ui/or_fun_call.fixed
@@ -79,16 +79,16 @@ fn or_fun_call() {
     without_default.unwrap_or_else(Foo::new);
 
     let mut map = HashMap::<u64, String>::new();
-    map.entry(42).or_insert(String::new());
+    map.entry(42).or_default();
 
     let mut map_vec = HashMap::<u64, Vec<i32>>::new();
-    map_vec.entry(42).or_insert(vec![]);
+    map_vec.entry(42).or_default();
 
     let mut btree = BTreeMap::<u64, String>::new();
-    btree.entry(42).or_insert(String::new());
+    btree.entry(42).or_default();
 
     let mut btree_vec = BTreeMap::<u64, Vec<i32>>::new();
-    btree_vec.entry(42).or_insert(vec![]);
+    btree_vec.entry(42).or_default();
 
     let stringy = Some(String::new());
     let _ = stringy.unwrap_or_default();
diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr
index 887f23ac976..e3dab4cb147 100644
--- a/tests/ui/or_fun_call.stderr
+++ b/tests/ui/or_fun_call.stderr
@@ -66,6 +66,30 @@ error: use of `unwrap_or` followed by a function call
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
 
+error: use of `or_insert` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:82:19
+   |
+LL |     map.entry(42).or_insert(String::new());
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+
+error: use of `or_insert` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:85:23
+   |
+LL |     map_vec.entry(42).or_insert(vec![]);
+   |                       ^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+
+error: use of `or_insert` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:88:21
+   |
+LL |     btree.entry(42).or_insert(String::new());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+
+error: use of `or_insert` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:91:25
+   |
+LL |     btree_vec.entry(42).or_insert(vec![]);
+   |                         ^^^^^^^^^^^^^^^^^ help: try this: `or_default()`
+
 error: use of `unwrap_or` followed by a call to `new`
   --> $DIR/or_fun_call.rs:94:21
    |
@@ -132,5 +156,5 @@ error: use of `unwrap_or` followed by a call to `new`
 LL |         .unwrap_or(String::new());
    |          ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
 
-error: aborting due to 22 previous errors
+error: aborting due to 26 previous errors
 

From 25f6f188345bb2fc5d826ea8eb9346a1d51ce98c Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Tue, 30 Aug 2022 15:10:28 +1000
Subject: [PATCH 21/34] Make `hir::PathSegment::res` non-optional.

---
 clippy_lints/src/operators/op_ref.rs | 2 +-
 clippy_lints/src/ref_option_ref.rs   | 3 +--
 clippy_lints/src/trait_bounds.rs     | 2 +-
 3 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/clippy_lints/src/operators/op_ref.rs b/clippy_lints/src/operators/op_ref.rs
index 1805672e372..1085e608944 100644
--- a/clippy_lints/src/operators/op_ref.rs
+++ b/clippy_lints/src/operators/op_ref.rs
@@ -185,7 +185,7 @@ fn in_impl<'tcx>(
         if let ItemKind::Impl(item) = &item.kind;
         if let Some(of_trait) = &item.of_trait;
         if let Some(seg) = of_trait.path.segments.last();
-        if let Some(Res::Def(_, trait_id)) = seg.res;
+        if let Res::Def(_, trait_id) = seg.res;
         if trait_id == bin_op;
         if let Some(generic_args) = seg.args;
         if let Some(GenericArg::Type(other_ty)) = generic_args.args.last();
diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs
index 909d6971a54..42514f861be 100644
--- a/clippy_lints/src/ref_option_ref.rs
+++ b/clippy_lints/src/ref_option_ref.rs
@@ -43,8 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
             if mut_ty.mutbl == Mutability::Not;
             if let TyKind::Path(ref qpath) = &mut_ty.ty.kind;
             let last = last_path_segment(qpath);
-            if let Some(res) = last.res;
-            if let Some(def_id) = res.opt_def_id();
+            if let Some(def_id) = last.res.opt_def_id();
 
             if cx.tcx.is_diagnostic_item(sym::Option, def_id);
             if let Some(params) = last_path_segment(qpath).args ;
diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 2ffa022b04f..a25be93b8d6 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                 if !bound_predicate.span.from_expansion();
                 if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
                 if let Some(PathSegment {
-                    res: Some(Res::SelfTy{ trait_: Some(def_id), alias_to: _ }), ..
+                    res: Res::SelfTy{ trait_: Some(def_id), alias_to: _ }, ..
                 }) = segments.first();
                 if let Some(
                     Node::Item(

From 2d4349c22d855f4735f89d5fcfc397ecb11f5b9c Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote <n.nethercote@gmail.com>
Date: Mon, 5 Sep 2022 14:03:53 +1000
Subject: [PATCH 22/34] Pack `Term` in the same way as `GenericArg`.

This shrinks the `PredicateS` type, which is instanted frequently.
---
 clippy_lints/src/dereference.rs                  | 2 +-
 clippy_lints/src/methods/mod.rs                  | 6 +++---
 clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index 1506ea604f0..7e29257e36a 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -1174,7 +1174,7 @@ fn replace_types<'tcx>(
         if replaced.insert(param_ty.index) {
             for projection_predicate in projection_predicates {
                 if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx)
-                    && let ty::Term::Ty(term_ty) = projection_predicate.term
+                    && let Some(term_ty) = projection_predicate.term.ty()
                     && let ty::Param(term_param_ty) = term_ty.kind()
                 {
                     let item_def_id = projection_predicate.projection_ty.item_def_id;
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index a0d190a58af..46ffe59b2d1 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -3302,9 +3302,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 // one of the associated types must be Self
                 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
                     if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
-                        let assoc_ty = match projection_predicate.term {
-                            ty::Term::Ty(ty) => ty,
-                            ty::Term::Const(_c) => continue,
+                        let assoc_ty = match projection_predicate.term.unpack() {
+                            ty::TermKind::Ty(ty) => ty,
+                            ty::TermKind::Const(_c) => continue,
                         };
                         // walk the associated type and check for Self
                         if let Some(self_adt) = self_ty.ty_adt_def() {
diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index 44bf8435294..2dcb191555a 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -268,7 +268,7 @@ fn check_other_call_arg<'tcx>(
                         .subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
                 implements_trait(cx, receiver_ty, deref_trait_id, &[])
                     && get_associated_type(cx, receiver_ty, deref_trait_id, "Target")
-                        .map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
+                        .map_or(false, |ty| ty::TermKind::Ty(ty) == normalized_ty.unpack())
             } else {
                 false
             }

From 4bcaddeeb23544eb2c86b600c3d775e2773758c2 Mon Sep 17 00:00:00 2001
From: Takayuki Maeda <takoyaki0316@gmail.com>
Date: Thu, 1 Sep 2022 18:43:35 +0900
Subject: [PATCH 23/34] separate the receiver from arguments in HIR under
 /clippy

---
 .../development/common_tools_writing_lints.md |   2 +-
 .../src/assertions_on_result_states.rs        |   2 +-
 clippy_lints/src/blocks_in_if_conditions.rs   |   5 +-
 clippy_lints/src/booleans.rs                  |   6 +-
 .../src/casts/cast_abs_to_unsigned.rs         |   4 +-
 .../src/casts/cast_possible_truncation.rs     |   6 +-
 clippy_lints/src/casts/cast_ptr_alignment.rs  |   4 +-
 clippy_lints/src/casts/cast_sign_loss.rs      |   4 +-
 clippy_lints/src/default_numeric_fallback.rs  |  23 ++--
 clippy_lints/src/dereference.rs               |  47 ++++----
 clippy_lints/src/doc.rs                       |   2 +-
 clippy_lints/src/entry.rs                     |   4 +-
 clippy_lints/src/eta_reduction.rs             |  25 +++--
 clippy_lints/src/explicit_write.rs            |   4 +-
 clippy_lints/src/fallible_impl_from.rs        |   2 +-
 clippy_lints/src/floating_point_arithmetic.rs |  79 +++++++-------
 clippy_lints/src/format_args.rs               |  20 ++--
 clippy_lints/src/format_impl.rs               |   2 +-
 clippy_lints/src/format_push_string.rs        |   2 +-
 clippy_lints/src/functions/must_use.rs        |  20 +++-
 .../src/functions/not_unsafe_ptr_arg_deref.rs |   3 +-
 clippy_lints/src/if_let_mutex.rs              |   2 +-
 clippy_lints/src/infinite_iter.rs             | 100 +++++++++---------
 clippy_lints/src/len_zero.rs                  |  10 +-
 clippy_lints/src/loops/manual_memcpy.rs       |   4 +-
 clippy_lints/src/loops/missing_spin_loop.rs   |   2 +-
 clippy_lints/src/loops/mod.rs                 |   2 +-
 clippy_lints/src/loops/needless_collect.rs    |  14 +--
 clippy_lints/src/loops/needless_range_loop.rs |  11 +-
 clippy_lints/src/loops/never_loop.rs          |   5 +-
 clippy_lints/src/loops/same_item_push.rs      |   5 +-
 clippy_lints/src/loops/single_element_loop.rs |  33 +++---
 clippy_lints/src/loops/while_let_loop.rs      |   9 +-
 .../src/loops/while_let_on_iterator.rs        |   2 +-
 clippy_lints/src/manual_bits.rs               |   2 +-
 clippy_lints/src/manual_retain.rs             |  22 ++--
 clippy_lints/src/manual_string_new.rs         |  13 +--
 clippy_lints/src/manual_strip.rs              |   4 +-
 clippy_lints/src/map_unit_fn.rs               |  11 +-
 clippy_lints/src/match_result_ok.rs           |   2 +-
 .../src/matches/match_str_case_mismatch.rs    |   2 +-
 .../src/matches/redundant_pattern_match.rs    |   2 +-
 .../matches/significant_drop_in_scrutinee.rs  |   5 +-
 clippy_lints/src/methods/bytecount.rs         |   6 +-
 clippy_lints/src/methods/chars_cmp.rs         |   4 +-
 .../src/methods/chars_cmp_with_unwrap.rs      |   2 +-
 clippy_lints/src/methods/clone_on_copy.rs     |  14 ++-
 clippy_lints/src/methods/clone_on_ref_ptr.rs  |  12 ++-
 .../src/methods/collapsible_str_replace.rs    |   6 +-
 clippy_lints/src/methods/expect_fun_call.rs   |  24 ++---
 clippy_lints/src/methods/extend_with_drain.rs |   2 +-
 clippy_lints/src/methods/filter_map.rs        |  12 +--
 clippy_lints/src/methods/get_last_with_len.rs |   2 +-
 .../src/methods/inefficient_to_string.rs      |  14 ++-
 clippy_lints/src/methods/into_iter_on_ref.rs  |   4 +-
 clippy_lints/src/methods/iter_with_drain.rs   |   2 +-
 clippy_lints/src/methods/map_clone.rs         |   2 +-
 clippy_lints/src/methods/mod.rs               |  96 +++++++++--------
 clippy_lints/src/methods/open_options.rs      |  10 +-
 .../src/methods/option_as_ref_deref.rs        |   7 +-
 clippy_lints/src/methods/or_fun_call.rs       |   7 +-
 .../src/methods/range_zip_with_len.rs         |   2 +-
 .../src/methods/single_char_add_str.rs        |   6 +-
 .../src/methods/single_char_insert_string.rs  |   8 +-
 .../src/methods/single_char_pattern.rs        |  58 +++++-----
 .../src/methods/single_char_push_string.rs    |   6 +-
 clippy_lints/src/methods/str_splitn.rs        |   6 +-
 .../src/methods/string_extend_chars.rs        |   2 +-
 .../src/methods/unnecessary_iter_cloned.rs    |   2 +-
 .../src/methods/unnecessary_lazy_eval.rs      |   2 +-
 .../src/methods/unnecessary_sort_by.rs        |   8 +-
 .../src/methods/unnecessary_to_owned.rs       |  22 ++--
 clippy_lints/src/methods/utils.rs             |   6 +-
 clippy_lints/src/minmax.rs                    |  35 +++---
 clippy_lints/src/mut_reference.rs             |  14 ++-
 clippy_lints/src/needless_for_each.rs         |   4 +-
 .../src/non_octal_unix_permissions.rs         |   2 +-
 clippy_lints/src/only_used_in_recursion.rs    |   4 +-
 clippy_lints/src/operators/cmp_owned.rs       |   2 +-
 clippy_lints/src/operators/duration_subsec.rs |   2 +-
 clippy_lints/src/operators/float_cmp.rs       |   2 +-
 clippy_lints/src/ptr.rs                       |   7 +-
 clippy_lints/src/ptr_offset_with_cast.rs      |   2 +-
 clippy_lints/src/question_mark.rs             |   2 +-
 clippy_lints/src/read_zero_byte_vec.rs        |   2 +-
 clippy_lints/src/size_of_in_element_count.rs  |   2 +-
 .../src/slow_vector_initialization.rs         |  10 +-
 clippy_lints/src/strings.rs                   |  28 ++---
 clippy_lints/src/strlen_on_c_strings.rs       |   2 +-
 clippy_lints/src/to_digit_is_some.rs          |  10 +-
 clippy_lints/src/uninit_vec.rs                |   4 +-
 clippy_lints/src/unit_return_expecting_ord.rs |   3 +-
 clippy_lints/src/unit_types/let_unit_value.rs |  13 ++-
 clippy_lints/src/unit_types/unit_arg.rs       |  39 +++----
 clippy_lints/src/unused_io_amount.rs          |   8 +-
 clippy_lints/src/unused_peekable.rs           |   3 +-
 clippy_lints/src/unwrap.rs                    |  10 +-
 clippy_lints/src/unwrap_in_result.rs          |   4 +-
 clippy_lints/src/useless_conversion.rs        |   2 +-
 clippy_lints/src/utils/author.rs              |   7 +-
 clippy_lints/src/utils/internal_lints.rs      |   2 +-
 clippy_lints/src/vec_init_then_push.rs        |   4 +-
 clippy_utils/src/check_proc_macro.rs          |   4 +-
 clippy_utils/src/diagnostics.rs               |   8 +-
 clippy_utils/src/eager_or_lazy.rs             |  18 ++--
 clippy_utils/src/hir_utils.rs                 |  13 ++-
 clippy_utils/src/lib.rs                       |  26 ++---
 clippy_utils/src/ptr.rs                       |   2 +-
 clippy_utils/src/sugg.rs                      |  24 +++--
 clippy_utils/src/visitors.rs                  |   8 +-
 tests/ui/author/struct.stdout                 |   6 +-
 111 files changed, 662 insertions(+), 558 deletions(-)

diff --git a/book/src/development/common_tools_writing_lints.md b/book/src/development/common_tools_writing_lints.md
index 15e00c7d7ce..2bc275ceff0 100644
--- a/book/src/development/common_tools_writing_lints.md
+++ b/book/src/development/common_tools_writing_lints.md
@@ -66,7 +66,7 @@ Starting with an `expr`, you can check whether it is calling a specific method
 impl<'tcx> LateLintPass<'tcx> for MyStructLint {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         // Check our expr is calling a method
-        if let hir::ExprKind::MethodCall(path, _, [_self_arg, ..]) = &expr.kind
+        if let hir::ExprKind::MethodCall(path, _, _self_arg, ..) = &expr.kind
             // Check the name of this method is `some_method`
             && path.ident.name == sym!(some_method)
             // Optionally, check the type of the self argument.
diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs
index 6a6554f968b..7cd198ace86 100644
--- a/clippy_lints/src/assertions_on_result_states.rs
+++ b/clippy_lints/src/assertions_on_result_states.rs
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
             && matches!(cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::assert_macro))
             && let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn)
             && matches!(panic_expn, PanicExpn::Empty)
-            && let ExprKind::MethodCall(method_segment, [recv], _) = condition.kind
+            && let ExprKind::MethodCall(method_segment, recv, [], _) = condition.kind
             && let result_type_with_refs = cx.typeck_results().expr_ty(recv)
             && let result_type = result_type_with_refs.peel_refs()
             && is_type_diagnostic_item(cx, result_type, sym::Result)
diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs
index ad206b5fb30..d9e2c9c8578 100644
--- a/clippy_lints/src/blocks_in_if_conditions.rs
+++ b/clippy_lints/src/blocks_in_if_conditions.rs
@@ -55,7 +55,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
             // do not lint if the closure is called using an iterator (see #1141)
             if_chain! {
                 if let Some(parent) = get_parent_expr(self.cx, expr);
-                if let ExprKind::MethodCall(_, [self_arg, ..], _) = &parent.kind;
+                if let ExprKind::MethodCall(_, self_arg, ..) = &parent.kind;
                 let caller = self.cx.typeck_results().expr_ty(self_arg);
                 if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator);
                 if implements_trait(self.cx, caller, iter_id, &[]);
@@ -117,7 +117,8 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
                             );
                         }
                     } else {
-                        let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
+                        let span =
+                            block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
                         if span.from_expansion() || expr.span.from_expansion() {
                             return;
                         }
diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs
index 6eb78d21e82..656d639f0ef 100644
--- a/clippy_lints/src/booleans.rs
+++ b/clippy_lints/src/booleans.rs
@@ -270,8 +270,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
                 ))
             })
         },
-        ExprKind::MethodCall(path, args, _) if args.len() == 1 => {
-            let type_of_receiver = cx.typeck_results().expr_ty(&args[0]);
+        ExprKind::MethodCall(path, receiver, [], _) => {
+            let type_of_receiver = cx.typeck_results().expr_ty(receiver);
             if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option)
                 && !is_type_diagnostic_item(cx, type_of_receiver, sym::Result)
             {
@@ -285,7 +285,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
                     let path: &str = path.ident.name.as_str();
                     a == path
                 })
-                .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, args[0].span)?, neg_method)))
+                .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, receiver.span)?, neg_method)))
         },
         _ => None,
     }
diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index 6426e8c25ac..3f1edabe6c5 100644
--- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -20,7 +20,7 @@ pub(super) fn check(
     if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
         && let ty::Int(from) = cast_from.kind()
         && let ty::Uint(to) = cast_to.kind()
-        && let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind
+        && let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind
         && method_path.ident.name.as_str() == "abs"
     {
         let span = if from.bit_width() == to.bit_width() {
@@ -37,7 +37,7 @@ pub(super) fn check(
             span,
             &format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
             "replace with",
-            format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()),
+            format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()),
             Applicability::MachineApplicable,
         );
     }
diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs
index 64f87c80f8d..406547a4454 100644
--- a/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -44,7 +44,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
                 .saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))),
             _ => nbits,
         },
-        ExprKind::MethodCall(method, [left, right], _) => {
+        ExprKind::MethodCall(method, left, [right], _) => {
             if signed {
                 return nbits;
             }
@@ -55,7 +55,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
             };
             apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
         },
-        ExprKind::MethodCall(method, [_, lo, hi], _) => {
+        ExprKind::MethodCall(method, _, [lo, hi], _) => {
             if method.ident.as_str() == "clamp" {
                 //FIXME: make this a diagnostic item
                 if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
@@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
             }
             nbits
         },
-        ExprKind::MethodCall(method, [_value], _) => {
+        ExprKind::MethodCall(method, _value, [], _) => {
             if method.ident.name.as_str() == "signum" {
                 0 // do not lint if cast comes from a `signum` function
             } else {
diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs
index d476a1a7646..da7b12f6726 100644
--- a/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
             cx.typeck_results().expr_ty(expr),
         );
         lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
-    } else if let ExprKind::MethodCall(method_path, [self_arg, ..], _) = &expr.kind {
+    } else if let ExprKind::MethodCall(method_path, self_arg, ..) = &expr.kind {
         if method_path.ident.name == sym!(cast)
             && let Some(generic_args) = method_path.args
             && let [GenericArg::Type(cast_to)] = generic_args.args
@@ -64,7 +64,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
         return false;
     };
     match parent.kind {
-        ExprKind::MethodCall(name, [self_arg, ..], _) if self_arg.hir_id == e.hir_id => {
+        ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => {
             if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
                 && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
                 && let Some(def_id) = cx.tcx.impl_of_method(def_id)
diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs
index 75f70b77ed4..5b59350be04 100644
--- a/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/clippy_lints/src/casts/cast_sign_loss.rs
@@ -41,14 +41,14 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
             }
 
             // Don't lint for the result of methods that always return non-negative values.
-            if let ExprKind::MethodCall(path, _, _) = cast_op.kind {
+            if let ExprKind::MethodCall(path, ..) = cast_op.kind {
                 let mut method_name = path.ident.name.as_str();
                 let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
 
                 if_chain! {
                     if method_name == "unwrap";
                     if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]);
-                    if let ExprKind::MethodCall(inner_path, _, _) = &arglist[0][0].kind;
+                    if let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind;
                     then {
                         method_name = inner_path.ident.name.as_str();
                     }
diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs
index fb418a3251f..64c5de51042 100644
--- a/clippy_lints/src/default_numeric_fallback.rs
+++ b/clippy_lints/src/default_numeric_fallback.rs
@@ -69,10 +69,7 @@ struct NumericFallbackVisitor<'a, 'tcx> {
 
 impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
     fn new(cx: &'a LateContext<'tcx>) -> Self {
-        Self {
-            ty_bounds: vec![TyBound::Nothing],
-            cx,
-        }
+        Self { ty_bounds: vec![TyBound::Nothing], cx }
     }
 
     /// Check whether a passed literal has potential to cause fallback or not.
@@ -129,19 +126,21 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                     }
                     return;
                 }
-            },
+            }
 
-            ExprKind::MethodCall(_, args, _) => {
+            ExprKind::MethodCall(_, receiver, args, _) => {
                 if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
                     let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
-                    for (expr, bound) in iter::zip(*args, fn_sig.inputs()) {
+                    for (expr, bound) in
+                        iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs())
+                    {
                         self.ty_bounds.push(TyBound::Ty(*bound));
                         self.visit_expr(expr);
                         self.ty_bounds.pop();
                     }
                     return;
                 }
-            },
+            }
 
             ExprKind::Struct(_, fields, base) => {
                 let ty = self.cx.typeck_results().expr_ty(expr);
@@ -176,15 +175,15 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                         return;
                     }
                 }
-            },
+            }
 
             ExprKind::Lit(lit) => {
                 let ty = self.cx.typeck_results().expr_ty(expr);
                 self.check_lit(lit, ty, expr.hir_id);
                 return;
-            },
+            }
 
-            _ => {},
+            _ => {}
         }
 
         walk_expr(self, expr);
@@ -198,7 +197,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                 } else {
                     self.ty_bounds.push(TyBound::Nothing);
                 }
-            },
+            }
 
             _ => self.ty_bounds.push(TyBound::Nothing),
         }
diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index 1506ea604f0..fd6ed36cb19 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -581,7 +581,7 @@ fn try_parse_ref_op<'tcx>(
     expr: &'tcx Expr<'_>,
 ) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
     let (def_id, arg) = match expr.kind {
-        ExprKind::MethodCall(_, [arg], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
+        ExprKind::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
         ExprKind::Call(
             Expr {
                 kind: ExprKind::Path(path),
@@ -796,16 +796,19 @@ fn walk_parents<'tcx>(
                             },
                         })
                     }),
-                ExprKind::MethodCall(_, args, _) => {
+                ExprKind::MethodCall(_, receiver, args, _) => {
                     let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
-                    args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
-                        if i == 0 {
-                            // Check for calls to trait methods where the trait is implemented on a reference.
-                            // Two cases need to be handled:
-                            // * `self` methods on `&T` will never have auto-borrow
-                            // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
-                            //   priority.
-                            if e.hir_id != child_id {
+                    std::iter::once(receiver)
+                        .chain(args.iter())
+                        .position(|arg| arg.hir_id == child_id)
+                        .map(|i| {
+                            if i == 0 {
+                                // Check for calls to trait methods where the trait is implemented on a reference.
+                                // Two cases need to be handled:
+                                // * `self` methods on `&T` will never have auto-borrow
+                                // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
+                                //   priority.
+                                if e.hir_id != child_id {
                                 Position::ReborrowStable(precedence)
                             } else if let Some(trait_id) = cx.tcx.trait_of_item(id)
                                 && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
@@ -834,20 +837,20 @@ fn walk_parents<'tcx>(
                             } else {
                                 Position::MethodReceiver
                             }
-                        } else {
-                            let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
-                            if let ty::Param(param_ty) = ty.kind() {
-                                needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv)
                             } else {
-                                ty_auto_deref_stability(
-                                    cx,
-                                    cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
-                                    precedence,
-                                )
-                                .position_for_arg()
+                                let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
+                                if let ty::Param(param_ty) = ty.kind() {
+                                    needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv)
+                                } else {
+                                    ty_auto_deref_stability(
+                                        cx,
+                                        cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
+                                        precedence,
+                                    )
+                                    .position_for_arg()
+                                }
                             }
-                        }
-                    })
+                        })
                 },
                 ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
                 ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs
index da111e7378e..512872cedc1 100644
--- a/clippy_lints/src/doc.rs
+++ b/clippy_lints/src/doc.rs
@@ -828,7 +828,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
 
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-            let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+            let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
             {
diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs
index 4e3ae4c9614..e70df3f53c7 100644
--- a/clippy_lints/src/entry.rs
+++ b/clippy_lints/src/entry.rs
@@ -245,8 +245,8 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio
     match expr.kind {
         ExprKind::MethodCall(
             _,
+            map,
             [
-                map,
                 Expr {
                     kind: ExprKind::AddrOf(_, _, key),
                     span: key_span,
@@ -280,7 +280,7 @@ struct InsertExpr<'tcx> {
     value: &'tcx Expr<'tcx>,
 }
 fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
-    if let ExprKind::MethodCall(_, [map, key, value], _) = expr.kind {
+    if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind {
         let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
         if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) {
             Some(InsertExpr { map, key, value })
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index 4f9ff97f1fd..1c0a93c71fd 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
             if !is_adjusted(cx, &body.value);
             if let ExprKind::Call(callee, args) = body.value.kind;
             if let ExprKind::Path(_) = callee.kind;
-            if check_inputs(cx, body.params, args);
+            if check_inputs(cx, body.params, None, args);
             let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
             let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
                 .map_or(callee_ty, |id| cx.tcx.type_of(id));
@@ -146,8 +146,8 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
 
         if_chain!(
             if !is_adjusted(cx, &body.value);
-            if let ExprKind::MethodCall(path, args, _) = body.value.kind;
-            if check_inputs(cx, body.params, args);
+            if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind;
+            if check_inputs(cx, body.params, Some(receiver), args);
             let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
             let substs = cx.typeck_results().node_substs(body.value.hir_id);
             let call_ty = cx.tcx.bound_type_of(method_def_id).subst(cx.tcx, substs);
@@ -167,12 +167,17 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
     }
 }
 
-fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_>]) -> bool {
-    if params.len() != call_args.len() {
+fn check_inputs(
+    cx: &LateContext<'_>,
+    params: &[Param<'_>],
+    receiver: Option<&Expr<'_>>,
+    call_args: &[Expr<'_>],
+) -> bool {
+    if receiver.map_or(params.len() != call_args.len(), |_| params.len() != call_args.len() + 1) {
         return false;
     }
     let binding_modes = cx.typeck_results().pat_binding_modes();
-    std::iter::zip(params, call_args).all(|(param, arg)| {
+    let check_inputs = |param: &Param<'_>, arg| {
         match param.pat.kind {
             PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
             _ => return false,
@@ -200,7 +205,13 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_
             },
             _ => false,
         }
-    })
+    };
+    if let Some(receiver) = receiver {
+        std::iter::zip(params, std::iter::once(receiver).chain(call_args.iter()))
+            .all(|(param, arg)| check_inputs(param, arg))
+    } else {
+        std::iter::zip(params, call_args).all(|(param, arg)| check_inputs(param, arg))
+    }
 }
 
 fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs
index 5bf4313b41a..9c76f63f5f7 100644
--- a/clippy_lints/src/explicit_write.rs
+++ b/clippy_lints/src/explicit_write.rs
@@ -45,10 +45,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             // match call to unwrap
-            if let ExprKind::MethodCall(unwrap_fun, [write_call], _) = expr.kind;
+            if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind;
             if unwrap_fun.ident.name == sym::unwrap;
             // match call to write_fmt
-            if let ExprKind::MethodCall(write_fun, [write_recv, write_arg], _) = look_in_block(cx, &write_call.kind);
+            if let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind);
             if write_fun.ident.name == sym!(write_fmt);
             // match calls to std::io::stdout() / std::io::stderr ()
             if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {
diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs
index b88e53aeca6..790eea63f58 100644
--- a/clippy_lints/src/fallible_impl_from.rs
+++ b/clippy_lints/src/fallible_impl_from.rs
@@ -84,7 +84,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h
 
             // check for `unwrap`
             if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-                let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+                let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
                 if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                     || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
                 {
diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs
index bb50e8fcabb..728db41d600 100644
--- a/clippy_lints/src/floating_point_arithmetic.rs
+++ b/clippy_lints/src/floating_point_arithmetic.rs
@@ -164,15 +164,15 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
     suggestion.maybe_par()
 }
 
-fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
-    if let Some(method) = get_specialized_log_method(cx, &args[1]) {
+fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
+    if let Some(method) = get_specialized_log_method(cx, &args[0]) {
         span_lint_and_sugg(
             cx,
             SUBOPTIMAL_FLOPS,
             expr.span,
             "logarithm for bases 2, 10 and e can be computed more accurately",
             "consider using",
-            format!("{}.{}()", Sugg::hir(cx, &args[0], "..").maybe_par(), method),
+            format!("{}.{}()", Sugg::hir(cx, receiver, "..").maybe_par(), method),
             Applicability::MachineApplicable,
         );
     }
@@ -180,14 +180,14 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
 
 // TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and
 // suggest usage of `(x + (y - 1)).ln_1p()` instead
-fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
+fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
     if let ExprKind::Binary(
         Spanned {
             node: BinOpKind::Add, ..
         },
         lhs,
         rhs,
-    ) = &args[0].kind
+    ) = receiver.kind
     {
         let recv = match (
             constant(cx, cx.typeck_results(), lhs),
@@ -235,9 +235,9 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
     }
 }
 
-fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
+fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
     // Check receiver
-    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) {
+    if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) {
         let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
             "exp"
         } else if F32(2.0) == value || F64(2.0) == value {
@@ -252,24 +252,24 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
             expr.span,
             "exponent for bases 2 and e can be computed more accurately",
             "consider using",
-            format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method),
+            format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method),
             Applicability::MachineApplicable,
         );
     }
 
     // Check argument
-    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
+    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,
                 "square-root of a number can be computed more efficiently and accurately",
-                format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
+                format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
             )
         } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
             (
                 IMPRECISE_FLOPS,
                 "cube-root of a number can be computed more accurately",
-                format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..").maybe_par()),
+                format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
             )
         } else if let Some(exponent) = get_integer_from_float_constant(&value) {
             (
@@ -277,7 +277,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                 "exponentiation with integer powers can be computed more efficiently",
                 format!(
                     "{}.powi({})",
-                    Sugg::hir(cx, &args[0], "..").maybe_par(),
+                    Sugg::hir(cx, receiver, "..").maybe_par(),
                     numeric_literal::format(&exponent.to_string(), None, false)
                 ),
             )
@@ -297,13 +297,14 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
     }
 }
 
-fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
-    if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) {
+fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
+    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) {
-                    if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = grandparent.kind {
-                        if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
+                    if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind
+                    {
+                        if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
                             return;
                         }
                     }
@@ -327,8 +328,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                         "consider using",
                         format!(
                             "{}.mul_add({}, {})",
-                            Sugg::hir(cx, &args[0], "..").maybe_par(),
-                            Sugg::hir(cx, &args[0], ".."),
+                            Sugg::hir(cx, receiver, "..").maybe_par(),
+                            Sugg::hir(cx, receiver, ".."),
                             Sugg::hir(cx, other_addend, ".."),
                         ),
                         Applicability::MachineApplicable,
@@ -339,14 +340,14 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
     }
 }
 
-fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
+fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
     if let ExprKind::Binary(
         Spanned {
             node: BinOpKind::Add, ..
         },
         add_lhs,
         add_rhs,
-    ) = args[0].kind
+    ) = receiver.kind
     {
         // check if expression of the form x * x + y * y
         if_chain! {
@@ -363,12 +364,12 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
         if_chain! {
             if let ExprKind::MethodCall(
                 PathSegment { ident: lmethod_name, .. },
-                [largs_0, largs_1, ..],
+                largs_0, [largs_1, ..],
                 _
             ) = &add_lhs.kind;
             if let ExprKind::MethodCall(
                 PathSegment { ident: rmethod_name, .. },
-                [rargs_0, rargs_1, ..],
+                rargs_0, [rargs_1, ..],
                 _
             ) = &add_rhs.kind;
             if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi";
@@ -384,8 +385,8 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option<String> {
     None
 }
 
-fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
-    if let Some(message) = detect_hypot(cx, args) {
+fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
+    if let Some(message) = detect_hypot(cx, receiver) {
         span_lint_and_sugg(
             cx,
             IMPRECISE_FLOPS,
@@ -406,7 +407,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
         if cx.typeck_results().expr_ty(lhs).is_floating_point();
         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 let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind;
         if cx.typeck_results().expr_ty(self_arg).is_floating_point();
         if path.ident.name.as_str() == "exp";
         then {
@@ -450,8 +451,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
     ) = &expr.kind
     {
         if let Some(parent) = get_parent_expr(cx, expr) {
-            if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = parent.kind {
-                if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() {
+            if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind {
+                if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
                     return;
                 }
             }
@@ -586,14 +587,14 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
 
 fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool {
     if_chain! {
-        if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, args_a, _) = expr_a.kind;
-        if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, args_b, _) = expr_b.kind;
+        if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind;
+        if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind;
         then {
             return method_name_a.as_str() == method_name_b.as_str() &&
                 args_a.len() == args_b.len() &&
                 (
                     ["ln", "log2", "log10"].contains(&method_name_a.as_str()) ||
-                    method_name_a.as_str() == "log" && args_a.len() == 2 && eq_expr_value(cx, &args_a[1], &args_b[1])
+                    method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0])
                 );
         }
     }
@@ -612,8 +613,8 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
             rhs,
         ) = &expr.kind;
         if are_same_base_logs(cx, lhs, rhs);
-        if let ExprKind::MethodCall(_, [largs_self, ..], _) = &lhs.kind;
-        if let ExprKind::MethodCall(_, [rargs_self, ..], _) = &rhs.kind;
+        if let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind;
+        if let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind;
         then {
             span_lint_and_sugg(
                 cx,
@@ -711,16 +712,16 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
             return;
         }
 
-        if let ExprKind::MethodCall(path, args, _) = &expr.kind {
-            let recv_ty = cx.typeck_results().expr_ty(&args[0]);
+        if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
+            let recv_ty = cx.typeck_results().expr_ty(receiver);
 
             if recv_ty.is_floating_point() {
                 match path.ident.name.as_str() {
-                    "ln" => check_ln1p(cx, expr, args),
-                    "log" => check_log_base(cx, expr, args),
-                    "powf" => check_powf(cx, expr, args),
-                    "powi" => check_powi(cx, expr, args),
-                    "sqrt" => check_hypot(cx, expr, args),
+                    "ln" => check_ln1p(cx, expr, receiver),
+                    "log" => check_log_base(cx, expr, receiver, args),
+                    "powf" => check_powf(cx, expr, receiver, args),
+                    "powi" => check_powi(cx, expr, receiver, args),
+                    "sqrt" => check_hypot(cx, expr, receiver),
                     _ => {},
                 }
             }
diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs
index 9fb9fd99748..2a55c48cf77 100644
--- a/clippy_lints/src/format_args.rs
+++ b/clippy_lints/src/format_args.rs
@@ -99,7 +99,12 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
     }
 }
 
-fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) {
+fn check_format_in_format_args(
+    cx: &LateContext<'_>,
+    call_site: Span,
+    name: Symbol,
+    arg: &Expr<'_>,
+) {
     let expn_data = arg.span.ctxt().outer_expn_data();
     if expn_data.call_site.from_expansion() {
         return;
@@ -126,7 +131,7 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb
 fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
     if_chain! {
         if !value.span.from_expansion();
-        if let ExprKind::MethodCall(_, [receiver], _) = value.kind;
+        if let ExprKind::MethodCall(_, receiver, [], _) = value.kind;
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
         if is_diag_trait_item(cx, method_def_id, sym::ToString);
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
@@ -177,10 +182,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex
 
 // Returns true if `hir_id` is referred to by multiple format params
 fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool {
-    args.params()
-        .filter(|param| param.value.hir_id == hir_id)
-        .at_most_one()
-        .is_err()
+    args.params().filter(|param| param.value.hir_id == hir_id).at_most_one().is_err()
 }
 
 fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
@@ -190,11 +192,7 @@ where
     let mut n_total = 0;
     let mut n_needed = 0;
     loop {
-        if let Some(Adjustment {
-            kind: Adjust::Deref(overloaded_deref),
-            target,
-        }) = iter.next()
-        {
+        if let Some(Adjustment { kind: Adjust::Deref(overloaded_deref), target }) = iter.next() {
             n_total += 1;
             if overloaded_deref.is_some() {
                 n_needed = n_total;
diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs
index d8bc0bf08f2..b628fd9f758 100644
--- a/clippy_lints/src/format_impl.rs
+++ b/clippy_lints/src/format_impl.rs
@@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl {
 fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
         // Get the hir_id of the object we are calling the method on
-        if let ExprKind::MethodCall(path, [ref self_arg, ..], _) = expr.kind;
+        if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind;
         // Is the method to_string() ?
         if path.ident.name == sym::to_string;
         // Is the method a part of the ToString trait? (i.e. not to_string() implemented
diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs
index ebf5ab086dc..9b9f1872bfc 100644
--- a/clippy_lints/src/format_push_string.rs
+++ b/clippy_lints/src/format_push_string.rs
@@ -54,7 +54,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 impl<'tcx> LateLintPass<'tcx> for FormatPushString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let arg = match expr.kind {
-            ExprKind::MethodCall(_, [_, arg], _) => {
+            ExprKind::MethodCall(_, _, [arg], _) => {
                 if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) &&
                 match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
                     arg
diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs
index 6672a6cb0b5..a17b23f5edc 100644
--- a/clippy_lints/src/functions/must_use.rs
+++ b/clippy_lints/src/functions/must_use.rs
@@ -212,7 +212,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
             return;
         }
         match expr.kind {
-            Call(_, args) | MethodCall(_, args, _) => {
+            Call(_, args) => {
                 let mut tys = DefIdSet::default();
                 for arg in args {
                     if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
@@ -230,6 +230,24 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
                     tys.clear();
                 }
             },
+            MethodCall(_, receiver, args, _) => {
+                let mut tys = DefIdSet::default();
+                for arg in std::iter::once(receiver).chain(args.iter()) {
+                    if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id())
+                        && is_mutable_ty(
+                            self.cx,
+                            self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg),
+                            arg.span,
+                            &mut tys,
+                        )
+                        && is_mutated_static(arg)
+                    {
+                        self.mutates_static = true;
+                        return;
+                    }
+                    tys.clear();
+                }
+            },
             Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
                 self.mutates_static |= is_mutated_static(target);
             },
diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 565a1c871d7..3bbfa52e810 100644
--- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -88,11 +88,12 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
                     }
                 }
             },
-            hir::ExprKind::MethodCall(_, args, _) => {
+            hir::ExprKind::MethodCall(_, receiver, args, _) => {
                 let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap();
                 let base_type = self.cx.tcx.type_of(def_id);
 
                 if type_is_unsafe_function(self.cx, base_type) {
+                    self.check_arg(receiver);
                     for arg in args {
                         self.check_arg(arg);
                     }
diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs
index 4d703d691ac..9ea8c494cfc 100644
--- a/clippy_lints/src/if_let_mutex.rs
+++ b/clippy_lints/src/if_let_mutex.rs
@@ -129,7 +129,7 @@ impl<'tcx, 'l> ArmVisitor<'tcx, 'l> {
 
 fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     if_chain! {
-        if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+        if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
         if path.ident.as_str() == "lock";
         let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
         if is_type_diagnostic_item(cx, ty, sym::Mutex);
diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs
index 01c7eef4e04..fca3cb46a2e 100644
--- a/clippy_lints/src/infinite_iter.rs
+++ b/clippy_lints/src/infinite_iter.rs
@@ -123,43 +123,43 @@ use self::Heuristic::{All, Always, Any, First};
 /// is an upper bound, e.g., some methods can return a possibly
 /// infinite iterator at worst, e.g., `take_while`.
 const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [
-    ("zip", 2, All, Infinite),
-    ("chain", 2, Any, Infinite),
-    ("cycle", 1, Always, Infinite),
-    ("map", 2, First, Infinite),
-    ("by_ref", 1, First, Infinite),
-    ("cloned", 1, First, Infinite),
-    ("rev", 1, First, Infinite),
-    ("inspect", 1, First, Infinite),
-    ("enumerate", 1, First, Infinite),
-    ("peekable", 2, First, Infinite),
-    ("fuse", 1, First, Infinite),
-    ("skip", 2, First, Infinite),
-    ("skip_while", 1, First, Infinite),
-    ("filter", 2, First, Infinite),
-    ("filter_map", 2, First, Infinite),
-    ("flat_map", 2, First, Infinite),
-    ("unzip", 1, First, Infinite),
-    ("take_while", 2, First, MaybeInfinite),
-    ("scan", 3, First, MaybeInfinite),
+    ("zip", 1, All, Infinite),
+    ("chain", 1, Any, Infinite),
+    ("cycle", 0, Always, Infinite),
+    ("map", 1, First, Infinite),
+    ("by_ref", 0, First, Infinite),
+    ("cloned", 0, First, Infinite),
+    ("rev", 0, First, Infinite),
+    ("inspect", 0, First, Infinite),
+    ("enumerate", 0, First, Infinite),
+    ("peekable", 1, First, Infinite),
+    ("fuse", 0, First, Infinite),
+    ("skip", 1, First, Infinite),
+    ("skip_while", 0, First, Infinite),
+    ("filter", 1, First, Infinite),
+    ("filter_map", 1, First, Infinite),
+    ("flat_map", 1, First, Infinite),
+    ("unzip", 0, First, Infinite),
+    ("take_while", 1, First, MaybeInfinite),
+    ("scan", 2, First, MaybeInfinite),
 ];
 
 fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
     match expr.kind {
-        ExprKind::MethodCall(method, args, _) => {
+        ExprKind::MethodCall(method, receiver, args, _) => {
             for &(name, len, heuristic, cap) in &HEURISTICS {
                 if method.ident.name.as_str() == name && args.len() == len {
                     return (match heuristic {
                         Always => Infinite,
-                        First => is_infinite(cx, &args[0]),
-                        Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])),
-                        All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])),
+                        First => is_infinite(cx, receiver),
+                        Any => is_infinite(cx, receiver).or(is_infinite(cx, &args[0])),
+                        All => is_infinite(cx, receiver).and(is_infinite(cx, &args[0])),
                     })
                     .and(cap);
                 }
             }
-            if method.ident.name == sym!(flat_map) && args.len() == 2 {
-                if let ExprKind::Closure(&Closure { body, .. }) = args[1].kind {
+            if method.ident.name == sym!(flat_map) && args.len() == 1 {
+                if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind {
                     let body = cx.tcx.hir().body(body);
                     return is_infinite(cx, &body.value);
                 }
@@ -179,29 +179,29 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
 /// the names and argument lengths of methods that *may* exhaust their
 /// iterators
 const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [
-    ("find", 2),
-    ("rfind", 2),
-    ("position", 2),
-    ("rposition", 2),
-    ("any", 2),
-    ("all", 2),
+    ("find", 1),
+    ("rfind", 1),
+    ("position", 1),
+    ("rposition", 1),
+    ("any", 1),
+    ("all", 1),
 ];
 
 /// the names and argument lengths of methods that *always* exhaust
 /// their iterators
 const COMPLETING_METHODS: [(&str, usize); 12] = [
-    ("count", 1),
-    ("fold", 3),
-    ("for_each", 2),
-    ("partition", 2),
-    ("max", 1),
-    ("max_by", 2),
-    ("max_by_key", 2),
-    ("min", 1),
-    ("min_by", 2),
-    ("min_by_key", 2),
-    ("sum", 1),
-    ("product", 1),
+    ("count", 0),
+    ("fold", 2),
+    ("for_each", 1),
+    ("partition", 1),
+    ("max", 0),
+    ("max_by", 1),
+    ("max_by_key", 1),
+    ("min", 0),
+    ("min_by", 1),
+    ("min_by_key", 1),
+    ("sum", 0),
+    ("product", 0),
 ];
 
 /// the paths of types that are known to be infinitely allocating
@@ -218,26 +218,26 @@ const INFINITE_COLLECTORS: &[Symbol] = &[
 
 fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
     match expr.kind {
-        ExprKind::MethodCall(method, args, _) => {
+        ExprKind::MethodCall(method, receiver, args, _) => {
             for &(name, len) in &COMPLETING_METHODS {
                 if method.ident.name.as_str() == name && args.len() == len {
-                    return is_infinite(cx, &args[0]);
+                    return is_infinite(cx, receiver);
                 }
             }
             for &(name, len) in &POSSIBLY_COMPLETING_METHODS {
                 if method.ident.name.as_str() == name && args.len() == len {
-                    return MaybeInfinite.and(is_infinite(cx, &args[0]));
+                    return MaybeInfinite.and(is_infinite(cx, receiver));
                 }
             }
-            if method.ident.name == sym!(last) && args.len() == 1 {
+            if method.ident.name == sym!(last) {
                 let not_double_ended = cx
                     .tcx
                     .get_diagnostic_item(sym::DoubleEndedIterator)
                     .map_or(false, |id| {
-                        !implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), id, &[])
+                        !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[])
                     });
                 if not_double_ended {
-                    return is_infinite(cx, &args[0]);
+                    return is_infinite(cx, receiver);
                 }
             } else if method.ident.name == sym!(collect) {
                 let ty = cx.typeck_results().expr_ty(expr);
@@ -245,7 +245,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                     .iter()
                     .any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item))
                 {
-                    return is_infinite(cx, &args[0]);
+                    return is_infinite(cx, receiver);
                 }
             }
         },
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index 246f5aad8fb..25f366bfe6a 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -370,7 +370,7 @@ fn check_for_is_empty<'tcx>(
 }
 
 fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
-    if let (&ExprKind::MethodCall(method_path, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
+    if let (&ExprKind::MethodCall(method_path, receiver, ..), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
         // check if we are in an is_empty() method
         if let Some(name) = get_item_name(cx, method) {
             if name.as_str() == "is_empty" {
@@ -378,7 +378,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
             }
         }
 
-        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to);
+        check_len(cx, span, method_path.ident.name, receiver, &lit.node, op, compare_to);
     } else {
         check_empty_expr(cx, span, method, lit, op);
     }
@@ -388,7 +388,7 @@ fn check_len(
     cx: &LateContext<'_>,
     span: Span,
     method_name: Symbol,
-    args: &[Expr<'_>],
+    receiver: &Expr<'_>,
     lit: &LitKind,
     op: &str,
     compare_to: u32,
@@ -399,7 +399,7 @@ fn check_len(
             return;
         }
 
-        if method_name == sym::len && args.len() == 1 && has_is_empty(cx, &args[0]) {
+        if method_name == sym::len && has_is_empty(cx, receiver) {
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
                 cx,
@@ -410,7 +410,7 @@ fn check_len(
                 format!(
                     "{}{}.is_empty()",
                     op,
-                    snippet_with_applicability(cx, args[0].span, "_", &mut applicability)
+                    snippet_with_applicability(cx, receiver.span, "_", &mut applicability)
                 ),
                 applicability,
             );
diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs
index a65df48e413..3fc569af89e 100644
--- a/clippy_lints/src/loops/manual_memcpy.rs
+++ b/clippy_lints/src/loops/manual_memcpy.rs
@@ -119,7 +119,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
 
     let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
         if_chain! {
-            if let ExprKind::MethodCall(method, [recv], _) = end.kind;
+            if let ExprKind::MethodCall(method, recv, [], _) = end.kind;
             if method.ident.name == sym::len;
             if path_to_local(recv) == path_to_local(base);
             then {
@@ -341,7 +341,7 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti
 
 fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
     if_chain! {
-        if let ExprKind::MethodCall(method, [arg], _) = expr.kind;
+        if let ExprKind::MethodCall(method, arg, [], _) = expr.kind;
         if method.ident.name == sym::clone;
         then { arg } else { expr }
     }
diff --git a/clippy_lints/src/loops/missing_spin_loop.rs b/clippy_lints/src/loops/missing_spin_loop.rs
index 0696afa3922..8412875b11b 100644
--- a/clippy_lints/src/loops/missing_spin_loop.rs
+++ b/clippy_lints/src/loops/missing_spin_loop.rs
@@ -33,7 +33,7 @@ fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
     if_chain! {
         if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind;
-        if let ExprKind::MethodCall(method, [callee, ..], _) = unpack_cond(cond).kind;
+        if let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind;
         if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name);
         if let ty::Adt(def, _substs) = cx.typeck_results().expr_ty(callee).kind();
         if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did());
diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs
index ed270bd490d..74f3bda9f43 100644
--- a/clippy_lints/src/loops/mod.rs
+++ b/clippy_lints/src/loops/mod.rs
@@ -742,7 +742,7 @@ fn check_for_loop<'tcx>(
 fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
     let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
 
-    if let ExprKind::MethodCall(method, [self_arg], _) = arg.kind {
+    if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
         let method_name = method.ident.as_str();
         // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
         match method_name {
diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs
index 6d987f393fa..6e6faa79adc 100644
--- a/clippy_lints/src/loops/needless_collect.rs
+++ b/clippy_lints/src/loops/needless_collect.rs
@@ -25,11 +25,11 @@ pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
 }
 fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
     if_chain! {
-        if let ExprKind::MethodCall(method, args, _) = expr.kind;
-        if let ExprKind::MethodCall(chain_method, _, _) = args[0].kind;
-        if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
+        if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind;
+        if let ExprKind::MethodCall(chain_method, ..) = receiver.kind;
+        if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator);
         then {
-            let ty = cx.typeck_results().expr_ty(&args[0]);
+            let ty = cx.typeck_results().expr_ty(receiver);
             let mut applicability = Applicability::MaybeIncorrect;
             let is_empty_sugg = "next().is_none()".to_string();
             let method_name = method.ident.name.as_str();
@@ -41,7 +41,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
                     "len" => "count()".to_string(),
                     "is_empty" => is_empty_sugg,
                     "contains" => {
-                        let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability);
+                        let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability);
                         let (arg, pred) = contains_arg
                             .strip_prefix('&')
                             .map_or(("&x", &*contains_arg), |s| ("x", s));
@@ -80,7 +80,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
                 if let StmtKind::Local(local) = stmt.kind;
                 if let PatKind::Binding(_, id, ..) = local.pat.kind;
                 if let Some(init_expr) = local.init;
-                if let ExprKind::MethodCall(method_name, &[ref iter_source], ..) = init_expr.kind;
+                if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind;
                 if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
                 let ty = cx.typeck_results().expr_ty(init_expr);
                 if is_type_diagnostic_item(cx, ty, sym::Vec) ||
@@ -203,7 +203,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         // Check function calls on our collection
-        if let ExprKind::MethodCall(method_name, [recv, args @ ..], _) = &expr.kind {
+        if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind {
             if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
                 self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
                 self.visit_expr(recv);
diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs
index 7ca4a7c4ebf..ffcf83e4605 100644
--- a/clippy_lints/src/loops/needless_range_loop.rs
+++ b/clippy_lints/src/loops/needless_range_loop.rs
@@ -188,7 +188,7 @@ pub(super) fn check<'tcx>(
 
 fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
     if_chain! {
-        if let ExprKind::MethodCall(method, [recv], _) = expr.kind;
+        if let ExprKind::MethodCall(method, recv, [], _) = expr.kind;
         if method.ident.name == sym::len;
         if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind;
         if path.segments.len() == 1;
@@ -301,7 +301,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if_chain! {
             // a range index op
-            if let ExprKind::MethodCall(meth, [args_0, args_1, ..], _) = &expr.kind;
+            if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind;
             if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX))
                 || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT));
             if !self.check(args_1, args_0, expr);
@@ -356,9 +356,12 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
                     self.visit_expr(expr);
                 }
             },
-            ExprKind::MethodCall(_, args, _) => {
+            ExprKind::MethodCall(_, receiver, args, _) => {
                 let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
-                for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) {
+                for (ty, expr) in iter::zip(
+                    self.cx.tcx.fn_sig(def_id).inputs().skip_binder(),
+                    std::iter::once(receiver).chain(args.iter()),
+                ) {
                     self.prefer_mutable = false;
                     if let ty::Ref(_, _, mutbl) = *ty.kind() {
                         if mutbl == Mutability::Mut {
diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs
index 5448360049d..116e589cad6 100644
--- a/clippy_lints/src/loops/never_loop.rs
+++ b/clippy_lints/src/loops/never_loop.rs
@@ -120,8 +120,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
         | ExprKind::Repeat(e, _)
         | ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id),
         ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id),
-        ExprKind::Array(es) | ExprKind::MethodCall(_, es, _) | ExprKind::Tup(es) => {
-            never_loop_expr_all(&mut es.iter(), main_loop_id)
+        ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), main_loop_id),
+        ExprKind::MethodCall(_, receiver, es, _) => {
+            never_loop_expr_all(&mut std::iter::once(receiver).chain(es.iter()), main_loop_id)
         },
         ExprKind::Struct(_, fields, base) => {
             let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id);
diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs
index 1439f1f4c75..23f47091f77 100644
--- a/clippy_lints/src/loops/same_item_push.rs
+++ b/clippy_lints/src/loops/same_item_push.rs
@@ -180,10 +180,9 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(&
     if_chain! {
             // Extract method being called
             if let StmtKind::Semi(semi_stmt) = &stmt.kind;
-            if let ExprKind::MethodCall(path, args, _) = &semi_stmt.kind;
+            if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind;
             // Figure out the parameters for the method call
-            if let Some(self_expr) = args.get(0);
-            if let Some(pushed_item) = args.get(1);
+            if let Some(pushed_item) = args.get(0);
             // Check that the method being called is push() on a Vec
             if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
             if path.ident.name.as_str() == "push";
diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs
index a0bd7ad0ac6..f4b47808dfa 100644
--- a/clippy_lints/src/loops/single_element_loop.rs
+++ b/clippy_lints/src/loops/single_element_loop.rs
@@ -35,32 +35,29 @@ pub(super) fn check<'tcx>(
         ) => (arg, "&mut "),
         ExprKind::MethodCall(
             method,
-            [
-                Expr {
-                    kind: ExprKind::Array([arg]),
-                    ..
-                },
-            ],
+            Expr {
+                kind: ExprKind::Array([arg]),
+                ..
+            },
+            [],
             _,
         ) if method.ident.name == rustc_span::sym::iter => (arg, "&"),
         ExprKind::MethodCall(
             method,
-            [
-                Expr {
-                    kind: ExprKind::Array([arg]),
-                    ..
-                },
-            ],
+            Expr {
+                kind: ExprKind::Array([arg]),
+                ..
+            },
+            [],
             _,
         ) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "),
         ExprKind::MethodCall(
             method,
-            [
-                Expr {
-                    kind: ExprKind::Array([arg]),
-                    ..
-                },
-            ],
+            Expr {
+                kind: ExprKind::Array([arg]),
+                ..
+            },
+            [],
             _,
         ) if method.ident.name == rustc_span::sym::into_iter => (arg, ""),
         // Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise.
diff --git a/clippy_lints/src/loops/while_let_loop.rs b/clippy_lints/src/loops/while_let_loop.rs
index ca617859db4..735d704a43c 100644
--- a/clippy_lints/src/loops/while_let_loop.rs
+++ b/clippy_lints/src/loops/while_let_loop.rs
@@ -11,7 +11,14 @@ use rustc_lint::LateContext;
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
     let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) {
         ([stmt, stmts @ ..], expr) => {
-            if let StmtKind::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind {
+            if let StmtKind::Local(&Local {
+                init: Some(e),
+                els: None,
+                ..
+            })
+            | StmtKind::Semi(e)
+            | StmtKind::Expr(e) = stmt.kind
+            {
                 (e, !stmts.is_empty() || expr.is_some())
             } else {
                 return;
diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs
index e9e215e662f..2c54033f859 100644
--- a/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let Res::Def(_, pat_did) = pat_path.res;
         if match_def_path(cx, pat_did, &paths::OPTION_SOME);
         // check for call to `Iterator::next`
-        if let ExprKind::MethodCall(method_name, [iter_expr], _) = let_expr.kind;
+        if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind;
         if method_name.ident.name == sym::next;
         if is_trait_method(cx, let_expr, sym::Iterator);
         if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr);
diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs
index 940601a44fb..6655c92b1da 100644
--- a/clippy_lints/src/manual_bits.rs
+++ b/clippy_lints/src/manual_bits.rs
@@ -134,7 +134,7 @@ fn create_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, base_sugg: String) -> Stri
 fn is_ty_conversion(expr: &Expr<'_>) -> bool {
     if let ExprKind::Cast(..) = expr.kind {
         true
-    } else if let ExprKind::MethodCall(path, [_], _) = expr.kind
+    } else if let ExprKind::MethodCall(path, _, [], _) = expr.kind
         && path.ident.name == rustc_span::sym::try_into
     {
         // This is only called for `usize` which implements `TryInto`. Therefore,
diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs
index 42d2577cc31..f28c37d3dca 100644
--- a/clippy_lints/src/manual_retain.rs
+++ b/clippy_lints/src/manual_retain.rs
@@ -66,9 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if let Some(parent_expr) = get_parent_expr(cx, expr)
             && let Assign(left_expr, collect_expr, _) = &parent_expr.kind
-            && let hir::ExprKind::MethodCall(seg, _, _) = &collect_expr.kind
+            && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind
             && seg.args.is_none()
-            && let hir::ExprKind::MethodCall(_, [target_expr], _) = &collect_expr.kind
+            && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
             && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
             && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) {
             check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv);
@@ -87,10 +87,10 @@ fn check_into_iter(
     target_expr: &hir::Expr<'_>,
     msrv: Option<RustcVersion>,
 ) {
-    if let hir::ExprKind::MethodCall(_, [into_iter_expr, _], _) = &target_expr.kind
+    if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind
         && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
         && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
-        && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &into_iter_expr.kind
+        && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind
         && let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
         && match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER)
         && match_acceptable_type(cx, left_expr, msrv)
@@ -106,14 +106,14 @@ fn check_iter(
     target_expr: &hir::Expr<'_>,
     msrv: Option<RustcVersion>,
 ) {
-    if let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind
+    if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
         && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
         && (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED)
             || match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED))
-        && let hir::ExprKind::MethodCall(_, [iter_expr, _], _) = &filter_expr.kind
+        && let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind
         && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
         && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
-        && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &iter_expr.kind
+        && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &iter_expr.kind
         && let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id)
         && match_acceptable_def_path(cx, iter_expr_def_id)
         && match_acceptable_type(cx, left_expr, msrv)
@@ -130,13 +130,13 @@ fn check_to_owned(
     msrv: Option<RustcVersion>,
 ) {
     if meets_msrv(msrv,  msrvs::STRING_RETAIN)
-        && let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind
+        && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
         && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
         && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
-        && let hir::ExprKind::MethodCall(_, [chars_expr, _], _) = &filter_expr.kind
+        && let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind
         && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
         && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
-        && let hir::ExprKind::MethodCall(_, [str_expr], _) = &chars_expr.kind
+        && let hir::ExprKind::MethodCall(_, str_expr, [], _) = &chars_expr.kind
         && let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
         && match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS)
         && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
@@ -147,7 +147,7 @@ fn check_to_owned(
 }
 
 fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) {
-    if let hir::ExprKind::MethodCall(_, [_, closure], _) = filter_expr.kind
+    if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind
         && let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind
         && let filter_body = cx.tcx.hir().body(body)
         && let [filter_params] = filter_body.params
diff --git a/clippy_lints/src/manual_string_new.rs b/clippy_lints/src/manual_string_new.rs
index a90eaa8fdcb..6acfb2ae347 100644
--- a/clippy_lints/src/manual_string_new.rs
+++ b/clippy_lints/src/manual_string_new.rs
@@ -55,8 +55,8 @@ impl LateLintPass<'_> for ManualStringNew {
             ExprKind::Call(func, args) => {
                 parse_call(cx, expr.span, func, args);
             },
-            ExprKind::MethodCall(path_segment, args, _) => {
-                parse_method_call(cx, expr.span, path_segment, args);
+            ExprKind::MethodCall(path_segment, receiver, ..) => {
+                parse_method_call(cx, expr.span, path_segment, receiver);
             },
             _ => (),
         }
@@ -88,14 +88,9 @@ fn warn_then_suggest(cx: &LateContext<'_>, span: Span) {
 }
 
 /// Tries to parse an expression as a method call, emitting the warning if necessary.
-fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, args: &[Expr<'_>]) {
-    if args.is_empty() {
-        // When parsing TryFrom::try_from(...).expect(...), we will have more than 1 arg.
-        return;
-    }
-
+fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, receiver: &Expr<'_>) {
     let ident = path_segment.ident.as_str();
-    let method_arg_kind = &args[0].kind;
+    let method_arg_kind = &receiver.kind;
     if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) {
         warn_then_suggest(cx, span);
     } else if let ExprKind::Call(func, args) = method_arg_kind {
diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs
index dfb3efc4e28..7941c8c9c7e 100644
--- a/clippy_lints/src/manual_strip.rs
+++ b/clippy_lints/src/manual_strip.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
 
         if_chain! {
             if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
-            if let ExprKind::MethodCall(_, [target_arg, pattern], _) = cond.kind;
+            if let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind;
             if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id);
             if let ExprKind::Path(target_path) = &target_arg.kind;
             then {
@@ -132,7 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
 // Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
 fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     if_chain! {
-        if let ExprKind::MethodCall(_, [arg], _) = expr.kind;
+        if let ExprKind::MethodCall(_, arg, [], _) = expr.kind;
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if match_def_path(cx, method_def_id, &paths::STR_LEN);
         then {
diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs
index 6db852c3ffe..33d74481529 100644
--- a/clippy_lints/src/map_unit_fn.rs
+++ b/clippy_lints/src/map_unit_fn.rs
@@ -200,8 +200,13 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String {
     )
 }
 
-fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) {
-    let var_arg = &map_args[0];
+fn lint_map_unit_fn(
+    cx: &LateContext<'_>,
+    stmt: &hir::Stmt<'_>,
+    expr: &hir::Expr<'_>,
+    map_args: (&hir::Expr<'_>, &[hir::Expr<'_>]),
+) {
+    let var_arg = &map_args.0;
 
     let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) {
         ("Option", "Some", OPTION_MAP_UNIT_FN)
@@ -210,7 +215,7 @@ fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr
     } else {
         return;
     };
-    let fn_arg = &map_args[1];
+    let fn_arg = &map_args.1[0];
 
     if is_unit_function(cx, fn_arg) {
         let mut applicability = Applicability::MachineApplicable;
diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs
index 3349b85f134..8588ab1ed8d 100644
--- a/clippy_lints/src/match_result_ok.rs
+++ b/clippy_lints/src/match_result_ok.rs
@@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
             };
 
         if_chain! {
-            if let ExprKind::MethodCall(ok_path, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
+            if let ExprKind::MethodCall(ok_path, result_types_0, ..) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
             if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _)  = let_pat.kind; //get operation
             if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized;
             if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs
index fa3b8d1fcea..1e80b6cf2d8 100644
--- a/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -48,7 +48,7 @@ struct MatchExprVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
         match ex.kind {
-            ExprKind::MethodCall(segment, [receiver], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
+            ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {},
             _ => walk_expr(self, ex),
         }
     }
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 8499e050af2..f7443471e31 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -120,7 +120,7 @@ fn find_sugg_for_if_let<'tcx>(
     // check that `while_let_on_iterator` lint does not trigger
     if_chain! {
         if keyword == "while";
-        if let ExprKind::MethodCall(method_path, _, _) = let_expr.kind;
+        if let ExprKind::MethodCall(method_path, ..) = let_expr.kind;
         if method_path.ident.name == sym::next;
         if is_trait_method(cx, let_expr, sym::Iterator);
         then {
diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index b0b15b3f54c..86a9df03497 100644
--- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
         self.is_chain_end = false;
 
         match ex.kind {
-            ExprKind::MethodCall(_, [ref expr, ..], _) => {
+            ExprKind::MethodCall(_, expr, ..) => {
                 self.visit_expr(expr);
             }
             ExprKind::Binary(_, left, right) => {
@@ -331,8 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
             ExprKind::Index(..) |
             ExprKind::Ret(..) |
             ExprKind::Repeat(..) |
-            ExprKind::Yield(..) |
-            ExprKind::MethodCall(..) => walk_expr(self, ex),
+            ExprKind::Yield(..) => walk_expr(self, ex),
             ExprKind::AddrOf(_, _, _) |
             ExprKind::Block(_, _) |
             ExprKind::Break(_, _) |
diff --git a/clippy_lints/src/methods/bytecount.rs b/clippy_lints/src/methods/bytecount.rs
index 6a7c63d76f7..fef90f6eba4 100644
--- a/clippy_lints/src/methods/bytecount.rs
+++ b/clippy_lints/src/methods/bytecount.rs
@@ -42,11 +42,11 @@ pub(super) fn check<'tcx>(
         if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
         if !is_local_used(cx, needle, arg_id);
         then {
-            let haystack = if let ExprKind::MethodCall(path, args, _) =
+            let haystack = if let ExprKind::MethodCall(path, receiver, [], _) =
                     filter_recv.kind {
                 let p = path.ident.name;
-                if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
-                    &args[0]
+                if p == sym::iter || p == sym!(iter_mut) {
+                    receiver
                 } else {
                     filter_recv
                 }
diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs
index f7b79f0839b..51aec21527a 100644
--- a/clippy_lints/src/methods/chars_cmp.rs
+++ b/clippy_lints/src/methods/chars_cmp.rs
@@ -23,7 +23,7 @@ pub(super) fn check(
         if Some(id) == cx.tcx.lang_items().option_some_variant();
         then {
             let mut applicability = Applicability::MachineApplicable;
-            let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
+            let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0].0).peel_refs();
 
             if *self_ty.kind() != ty::Str {
                 return false;
@@ -37,7 +37,7 @@ pub(super) fn check(
                 "like this",
                 format!("{}{}.{}({})",
                         if info.eq { "" } else { "!" },
-                        snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
+                        snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
                         suggest,
                         snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)),
                 applicability,
diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
index a7c0e43923e..b85bfec2b12 100644
--- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
+++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
                 "like this",
                 format!("{}{}.{}('{}')",
                         if info.eq { "" } else { "!" },
-                        snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
+                        snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability),
                         suggest,
                         c.escape_default()),
                 applicability,
diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs
index 60e1355f9b9..9ae6297ec2f 100644
--- a/clippy_lints/src/methods/clone_on_copy.rs
+++ b/clippy_lints/src/methods/clone_on_copy.rs
@@ -14,9 +14,15 @@ use super::CLONE_ON_COPY;
 
 /// Checks for the `CLONE_ON_COPY` lint.
 #[allow(clippy::too_many_lines)]
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, args: &[Expr<'_>]) {
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    method_name: Symbol,
+    receiver: &Expr<'_>,
+    args: &[Expr<'_>],
+) {
     let arg = match args {
-        [arg] if method_name == sym::clone => arg,
+        [] if method_name == sym::clone => receiver,
         _ => return,
     };
     if cx
@@ -81,7 +87,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
                 // &*x is a nop, &x.clone() is not
                 ExprKind::AddrOf(..) => return,
                 // (*x).func() is useless, x.clone().func() can work in case func borrows self
-                ExprKind::MethodCall(_, [self_arg, ..], _)
+                ExprKind::MethodCall(_, self_arg, ..)
                     if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
                 {
                     return;
@@ -91,7 +97,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
                     hir_callee.kind,
                     ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _))
                 ),
-                ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
+                ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id => true,
                 ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
                 | ExprKind::Field(..)
                 | ExprKind::Index(..) => true,
diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs
index 6417bc81304..7098d564cfc 100644
--- a/clippy_lints/src/methods/clone_on_ref_ptr.rs
+++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs
@@ -10,11 +10,17 @@ use rustc_span::symbol::{sym, Symbol};
 
 use super::CLONE_ON_REF_PTR;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
-    if !(args.len() == 1 && method_name == sym::clone) {
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    method_name: Symbol,
+    receiver: &hir::Expr<'_>,
+    args: &[hir::Expr<'_>],
+) {
+    if !(args.is_empty() && method_name == sym::clone) {
         return;
     }
-    let arg = &args[0];
+    let arg = receiver;
     let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs();
 
     if let ty::Adt(_, subst) = obj_ty.kind() {
diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs
index 561033be5b6..501646863fe 100644
--- a/clippy_lints/src/methods/collapsible_str_replace.rs
+++ b/clippy_lints/src/methods/collapsible_str_replace.rs
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
         // If the parent node's `to` argument is the same as the `to` argument
         // of the last replace call in the current chain, don't lint as it was already linted
         if let Some(parent) = get_parent_expr(cx, expr)
-            && let Some(("replace", [_, current_from, current_to], _)) = method_call(parent)
+            && let Some(("replace", _, [current_from, current_to], _)) = method_call(parent)
             && eq_expr_value(cx, to, current_to)
             && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind()
         {
@@ -48,7 +48,7 @@ fn collect_replace_calls<'tcx>(
     let mut from_args = VecDeque::new();
 
     let _: Option<()> = for_each_expr(expr, |e| {
-        if let Some(("replace", [_, from, to], _)) = method_call(e) {
+        if let Some(("replace", _, [from, to], _)) = method_call(e) {
             if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() {
                 methods.push_front(e);
                 from_args.push_front(from);
@@ -78,7 +78,7 @@ fn check_consecutive_replace_calls<'tcx>(
         .collect();
     let app = Applicability::MachineApplicable;
     let earliest_replace_call = replace_methods.methods.front().unwrap();
-    if let Some((_, [..], span_lo)) = method_call(earliest_replace_call) {
+    if let Some((_, _, [..], span_lo)) = method_call(earliest_replace_call) {
         span_lint_and_sugg(
             cx,
             COLLAPSIBLE_STR_REPLACE,
diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs
index 6f2307d8f18..bd846d71d46 100644
--- a/clippy_lints/src/methods/expect_fun_call.rs
+++ b/clippy_lints/src/methods/expect_fun_call.rs
@@ -19,6 +19,7 @@ pub(super) fn check<'tcx>(
     expr: &hir::Expr<'_>,
     method_span: Span,
     name: &str,
+    receiver: &'tcx hir::Expr<'tcx>,
     args: &'tcx [hir::Expr<'tcx>],
 ) {
     // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
@@ -28,16 +29,13 @@ pub(super) fn check<'tcx>(
         loop {
             arg_root = match &arg_root.kind {
                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
-                hir::ExprKind::MethodCall(method_name, call_args, _) => {
-                    if call_args.len() == 1
-                        && (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref)
-                        && {
-                            let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
-                            let base_type = arg_type.peel_refs();
-                            *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
-                        }
-                    {
-                        &call_args[0]
+                hir::ExprKind::MethodCall(method_name, receiver, [], ..) => {
+                    if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && {
+                        let arg_type = cx.typeck_results().expr_ty(receiver);
+                        let base_type = arg_type.peel_refs();
+                        *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String)
+                    } {
+                        receiver
                     } else {
                         break;
                     }
@@ -114,11 +112,11 @@ pub(super) fn check<'tcx>(
         }
     }
 
-    if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) {
+    if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) {
         return;
     }
 
-    let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]);
+    let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver);
     let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) {
         "||"
     } else if is_type_diagnostic_item(cx, receiver_type, sym::Result) {
@@ -127,7 +125,7 @@ pub(super) fn check<'tcx>(
         return;
     };
 
-    let arg_root = get_arg_root(cx, &args[1]);
+    let arg_root = get_arg_root(cx, &args[0]);
 
     let span_replace_word = method_span.with_hi(expr.span.hi());
 
diff --git a/clippy_lints/src/methods/extend_with_drain.rs b/clippy_lints/src/methods/extend_with_drain.rs
index a15fe609402..37b28463527 100644
--- a/clippy_lints/src/methods/extend_with_drain.rs
+++ b/clippy_lints/src/methods/extend_with_drain.rs
@@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
     if_chain! {
         if is_type_diagnostic_item(cx, ty, sym::Vec);
         //check source object
-        if let ExprKind::MethodCall(src_method, [drain_vec, drain_arg], _) = &arg.kind;
+        if let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind;
         if src_method.ident.as_str() == "drain";
         let src_ty = cx.typeck_results().expr_ty(drain_vec);
         //check if actual src type is mutable for code suggestion
diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs
index 692e22a7c5c..9dc839afc62 100644
--- a/clippy_lints/src/methods/filter_map.rs
+++ b/clippy_lints/src/methods/filter_map.rs
@@ -28,11 +28,11 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
             let closure_expr = peel_blocks(&body.value);
             let arg_id = body.params[0].pat.hir_id;
             match closure_expr.kind {
-                hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, args, _) => {
+                hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
                     if_chain! {
                     if ident.name == method_name;
-                    if let hir::ExprKind::Path(path) = &args[0].kind;
-                    if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id);
+                    if let hir::ExprKind::Path(path) = &receiver.kind;
+                    if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
                     then {
                         return arg_id == *local
                     }
@@ -106,7 +106,7 @@ pub(super) fn check<'tcx>(
             };
             // closure ends with is_some() or is_ok()
             if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
-            if let ExprKind::MethodCall(path, [filter_arg], _) = filter_body.value.kind;
+            if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
             if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
             if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
                 Some(false)
@@ -123,13 +123,13 @@ pub(super) fn check<'tcx>(
             if let [map_param] = map_body.params;
             if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
             // closure ends with expect() or unwrap()
-            if let ExprKind::MethodCall(seg, [map_arg, ..], _) = map_body.value.kind;
+            if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
             if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
 
             // .filter(..).map(|y| f(y).copied().unwrap())
             //                     ~~~~
             let map_arg_peeled = match map_arg.kind {
-                ExprKind::MethodCall(method, [original_arg], _) if acceptable_methods(method) => {
+                ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
                     original_arg
                 },
                 _ => map_arg,
diff --git a/clippy_lints/src/methods/get_last_with_len.rs b/clippy_lints/src/methods/get_last_with_len.rs
index 23368238ef5..02aada87202 100644
--- a/clippy_lints/src/methods/get_last_with_len.rs
+++ b/clippy_lints/src/methods/get_last_with_len.rs
@@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg:
     ) = arg.kind
 
         // LHS of subtraction is "x.len()"
-        && let ExprKind::MethodCall(lhs_path, [lhs_recv], _) = &lhs.kind
+        && let ExprKind::MethodCall(lhs_path, lhs_recv, [], _) = &lhs.kind
         && lhs_path.ident.name == sym::len
 
         // RHS of subtraction is 1
diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs
index f52170df662..e1c9b5248a8 100644
--- a/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/clippy_lints/src/methods/inefficient_to_string.rs
@@ -12,13 +12,19 @@ use rustc_span::symbol::{sym, Symbol};
 use super::INEFFICIENT_TO_STRING;
 
 /// Checks for the `INEFFICIENT_TO_STRING` lint
-pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
+pub fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &hir::Expr<'_>,
+    method_name: Symbol,
+    receiver: &hir::Expr<'_>,
+    args: &[hir::Expr<'_>],
+) {
     if_chain! {
-        if args.len() == 1 && method_name == sym::to_string;
+        if args.is_empty() && method_name == sym::to_string;
         if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
         if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id);
-        let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
+        let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver);
         let self_ty = substs.type_at(0);
         let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty);
         if deref_count >= 1;
@@ -35,7 +41,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy
                         self_ty, deref_self_ty
                     ));
                     let mut applicability = Applicability::MachineApplicable;
-                    let arg_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
+                    let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability);
                     diag.span_suggestion(
                         expr.span,
                         "try dereferencing the receiver",
diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs
index da13b4ba37a..11e76841e9f 100644
--- a/clippy_lints/src/methods/into_iter_on_ref.rs
+++ b/clippy_lints/src/methods/into_iter_on_ref.rs
@@ -16,9 +16,9 @@ pub(super) fn check(
     expr: &hir::Expr<'_>,
     method_span: Span,
     method_name: Symbol,
-    args: &[hir::Expr<'_>],
+    receiver: &hir::Expr<'_>,
 ) {
-    let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]);
+    let self_ty = cx.typeck_results().expr_ty_adjusted(receiver);
     if_chain! {
         if let ty::Ref(..) = self_ty.kind();
         if method_name == sym::into_iter;
diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs
index 152072e09c7..a669cbbbcc6 100644
--- a/clippy_lints/src/methods/iter_with_drain.rs
+++ b/clippy_lints/src/methods/iter_with_drain.rs
@@ -35,7 +35,7 @@ fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) -
         && range.end.map_or(true, |e| {
             if range.limits == RangeLimits::HalfOpen
                 && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind
-                && let ExprKind::MethodCall(name, [self_arg], _) = e.kind
+                && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind
                 && name.ident.name == sym::len
                 && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
             {
diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs
index ffedda95ff8..e04bb1c5079 100644
--- a/clippy_lints/src/methods/map_clone.rs
+++ b/clippy_lints/src/methods/map_clone.rs
@@ -48,7 +48,7 @@ pub(super) fn check<'tcx>(
                                 }
                             }
                         },
-                        hir::ExprKind::MethodCall(method, [obj], _) => if_chain! {
+                        hir::ExprKind::MethodCall(method, obj, [], _) => if_chain! {
                             if ident_eq(name, obj) && method.ident.name == sym::clone;
                             if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id);
                             if let Some(trait_id) = cx.tcx.trait_of_item(fn_id);
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index a0d190a58af..16fdd36c026 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -3161,11 +3161,13 @@ impl_lint_pass!(Methods => [
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
-fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> {
-    if let ExprKind::MethodCall(path, args, _) = recv.kind {
-        if !args.iter().any(|e| e.span.from_expansion()) {
+fn method_call<'tcx>(
+    recv: &'tcx hir::Expr<'tcx>,
+) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span)> {
+    if let ExprKind::MethodCall(path, receiver, args, _) = recv.kind {
+        if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
             let name = path.ident.name.as_str();
-            return Some((name, args, path.ident.span));
+            return Some((name, receiver, args, path.ident.span));
         }
     }
     None
@@ -3183,17 +3185,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             hir::ExprKind::Call(func, args) => {
                 from_iter_instead_of_collect::check(cx, expr, args, func);
             },
-            hir::ExprKind::MethodCall(method_call, args, _) => {
+            hir::ExprKind::MethodCall(method_call, receiver, args, _) => {
                 let method_span = method_call.ident.span;
-                or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
-                expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
-                clone_on_copy::check(cx, expr, method_call.ident.name, args);
-                clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args);
-                inefficient_to_string::check(cx, expr, method_call.ident.name, args);
-                single_char_add_str::check(cx, expr, args);
-                into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args);
-                single_char_pattern::check(cx, expr, method_call.ident.name, args);
-                unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv);
+                or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
+                expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
+                clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args);
+                clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args);
+                inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args);
+                single_char_add_str::check(cx, expr, receiver, args);
+                into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
+                single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args);
+                unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);
             },
             hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
                 let mut info = BinaryExprInfo {
@@ -3379,7 +3381,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 impl Methods {
     #[allow(clippy::too_many_lines)]
     fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
+        if let Some((name, recv, [args @ ..], span)) = method_call(expr) {
             match (name, args) {
                 ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
                     zst_offset::check(cx, expr, recv);
@@ -3399,13 +3401,13 @@ impl Methods {
                 ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
                 ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
                 ("collect", []) => match method_call(recv) {
-                    Some((name @ ("cloned" | "copied"), [recv2], _)) => {
+                    Some((name @ ("cloned" | "copied"), recv2, [], _)) => {
                         iter_cloned_collect::check(cx, name, expr, recv2);
                     },
-                    Some(("map", [m_recv, m_arg], _)) => {
+                    Some(("map", m_recv, [m_arg], _)) => {
                         map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
                     },
-                    Some(("take", [take_self_arg, take_arg], _)) => {
+                    Some(("take", take_self_arg, [take_arg], _)) => {
                         if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
                             manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
                         }
@@ -3413,26 +3415,26 @@ impl Methods {
                     _ => {},
                 },
                 ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
-                    Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
-                    Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
+                    Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false),
+                    Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _)) => {
                         iter_count::check(cx, expr, recv2, name2);
                     },
-                    Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
-                    Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg),
-                    Some(("bytes", [recv2], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
+                    Some(("map", _, [arg], _)) => suspicious_map::check(cx, expr, recv, arg),
+                    Some(("filter", recv2, [arg], _)) => bytecount::check(cx, expr, recv2, arg),
+                    Some(("bytes", recv2, [], _)) => bytes_count_to_len::check(cx, expr, recv, recv2),
                     _ => {},
                 },
                 ("drain", [arg]) => {
                     iter_with_drain::check(cx, expr, recv, span, arg);
                 },
                 ("ends_with", [arg]) => {
-                    if let ExprKind::MethodCall(_, _, span) = expr.kind {
+                    if let ExprKind::MethodCall(.., span) = expr.kind {
                         case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
                     }
                 },
                 ("expect", [_]) => match method_call(recv) {
-                    Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
-                    Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
+                    Some(("ok", recv, [], _)) => ok_expect::check(cx, expr, recv),
+                    Some(("err", recv, [], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
                     _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
                 },
                 ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
@@ -3452,13 +3454,13 @@ impl Methods {
                     flat_map_option::check(cx, expr, arg, span);
                 },
                 ("flatten", []) => match method_call(recv) {
-                    Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
-                    Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
+                    Some(("map", recv, [map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
+                    Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
                     _ => {},
                 },
                 ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
                 ("for_each", [_]) => {
-                    if let Some(("inspect", [_, _], span2)) = method_call(recv) {
+                    if let Some(("inspect", _, [_], span2)) = method_call(recv) {
                         inspect_for_each::check(cx, expr, span2);
                     }
                 },
@@ -3478,12 +3480,12 @@ impl Methods {
                     iter_on_single_or_empty_collections::check(cx, expr, name, recv);
                 },
                 ("join", [join_arg]) => {
-                    if let Some(("collect", _, span)) = method_call(recv) {
+                    if let Some(("collect", _, _, span)) = method_call(recv) {
                         unnecessary_join::check(cx, expr, recv, join_arg, span);
                     }
                 },
                 ("last", []) | ("skip", [_]) => {
-                    if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+                    if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) {
                         if let ("cloned", []) = (name2, args2) {
                             iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
                         }
@@ -3498,7 +3500,7 @@ impl Methods {
                     } else {
                         map_err_ignore::check(cx, expr, m_arg);
                     }
-                    if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
+                    if let Some((name, recv2, [args @ ..], span2)) = method_call(recv) {
                         match (name, args) {
                             ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
                             ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
@@ -3518,7 +3520,7 @@ impl Methods {
                     manual_ok_or::check(cx, expr, recv, def, map);
                 },
                 ("next", []) => {
-                    if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
+                    if let Some((name2, recv2, [args2 @ ..], _)) = method_call(recv) {
                         match (name2, args2) {
                             ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
                             ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
@@ -3531,10 +3533,10 @@ impl Methods {
                     }
                 },
                 ("nth", [n_arg]) => match method_call(recv) {
-                    Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
-                    Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
-                    Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
-                    Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
+                    Some(("bytes", recv2, [], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+                    Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
+                    Some(("iter", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
+                    Some(("iter_mut", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
                     _ => iter_nth_zero::check(cx, expr, recv, n_arg),
                 },
                 ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
@@ -3591,7 +3593,7 @@ impl Methods {
                 },
                 ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
                 ("take", [_arg]) => {
-                    if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+                    if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) {
                         if let ("cloned", []) = (name2, args2) {
                             iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
                         }
@@ -3614,13 +3616,13 @@ impl Methods {
                 },
                 ("unwrap", []) => {
                     match method_call(recv) {
-                        Some(("get", [recv, get_arg], _)) => {
+                        Some(("get", recv, [get_arg], _)) => {
                             get_unwrap::check(cx, expr, recv, get_arg, false);
                         },
-                        Some(("get_mut", [recv, get_arg], _)) => {
+                        Some(("get_mut", recv, [get_arg], _)) => {
                             get_unwrap::check(cx, expr, recv, get_arg, true);
                         },
-                        Some(("or", [recv, or_arg], or_span)) => {
+                        Some(("or", recv, [or_arg], or_span)) => {
                             or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
                         },
                         _ => {},
@@ -3629,19 +3631,19 @@ impl Methods {
                 },
                 ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
                 ("unwrap_or", [u_arg]) => match method_call(recv) {
-                    Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
+                    Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _)) => {
                         manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
                     },
-                    Some(("map", [m_recv, m_arg], span)) => {
+                    Some(("map", m_recv, [m_arg], span)) => {
                         option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
                     },
-                    Some(("then_some", [t_recv, t_arg], _)) => {
+                    Some(("then_some", t_recv, [t_arg], _)) => {
                         obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
                     },
                     _ => {},
                 },
                 ("unwrap_or_else", [u_arg]) => match method_call(recv) {
-                    Some(("map", [recv, map_arg], _))
+                    Some(("map", recv, [map_arg], _))
                         if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
                     _ => {
                         unwrap_or_else_default::check(cx, expr, recv, u_arg);
@@ -3649,7 +3651,7 @@ impl Methods {
                     },
                 },
                 ("zip", [arg]) => {
-                    if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind
+                    if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
                         && name.ident.name == sym::iter
                     {
                         range_zip_with_len::check(cx, expr, iter_recv, arg);
@@ -3662,7 +3664,7 @@ impl Methods {
 }
 
 fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
-    if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call(recv) {
+    if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span)) = method_call(recv) {
         search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
     }
 }
diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs
index c3112823e34..903fa306f93 100644
--- a/clippy_lints/src/methods/open_options.rs
+++ b/clippy_lints/src/methods/open_options.rs
@@ -36,12 +36,12 @@ enum OpenOption {
 }
 
 fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) {
-    if let ExprKind::MethodCall(path, arguments, _) = argument.kind {
-        let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs();
+    if let ExprKind::MethodCall(path, receiver, arguments, _) = argument.kind {
+        let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
 
         // 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.len() >= 2 {
-            let argument_option = match arguments[1].kind {
+        if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 1 {
+            let argument_option = match arguments[0].kind {
                 ExprKind::Lit(ref span) => {
                     if let Spanned {
                         node: LitKind::Bool(lit),
@@ -77,7 +77,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
                 _ => (),
             }
 
-            get_open_options(cx, &arguments[0], options);
+            get_open_options(cx, receiver, options);
         }
     }
 }
diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs
index 20cad0f181e..81c67b4ca6a 100644
--- a/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -56,13 +56,12 @@ pub(super) fn check<'tcx>(
             let closure_expr = peel_blocks(&closure_body.value);
 
             match &closure_expr.kind {
-                hir::ExprKind::MethodCall(_, args, _) => {
+                hir::ExprKind::MethodCall(_, receiver, [], _) => {
                     if_chain! {
-                        if args.len() == 1;
-                        if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id);
+                        if path_to_local_id(receiver, closure_body.params[0].pat.hir_id);
                         let adj = cx
                             .typeck_results()
-                            .expr_adjustments(&args[0])
+                            .expr_adjustments(receiver)
                             .iter()
                             .map(|x| &x.kind)
                             .collect::<Box<[_]>>();
diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs
index 6af134019a4..76876d86629 100644
--- a/clippy_lints/src/methods/or_fun_call.rs
+++ b/clippy_lints/src/methods/or_fun_call.rs
@@ -20,6 +20,7 @@ pub(super) fn check<'tcx>(
     expr: &hir::Expr<'_>,
     method_span: Span,
     name: &str,
+    receiver: &'tcx hir::Expr<'_>,
     args: &'tcx [hir::Expr<'_>],
 ) {
     /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
@@ -144,7 +145,7 @@ pub(super) fn check<'tcx>(
         }
     }
 
-    if let [self_arg, arg] = args {
+    if let [arg] = args {
         let inner_arg = if let hir::ExprKind::Block(
             hir::Block {
                 stmts: [],
@@ -163,11 +164,11 @@ pub(super) fn check<'tcx>(
                 let or_has_args = !or_args.is_empty();
                 if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
                     let fun_span = if or_has_args { None } else { Some(fun.span) };
-                    check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span);
+                    check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span);
                 }
             },
             hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
-                check_general_case(cx, name, method_span, self_arg, arg, expr.span, None);
+                check_general_case(cx, name, method_span, receiver, arg, expr.span, None);
             },
             _ => (),
         }
diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs
index 00a2a0d14d1..867a3b40237 100644
--- a/clippy_lints/src/methods/range_zip_with_len.rs
+++ b/clippy_lints/src/methods/range_zip_with_len.rs
@@ -16,7 +16,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
         if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
         if is_integer_const(cx, start, 0);
         // `.len()` call
-        if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind;
+        if let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind;
         if len_path.ident.name == sym::len;
         // `.iter()` and `.len()` called on same `Path`
         if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind;
diff --git a/clippy_lints/src/methods/single_char_add_str.rs b/clippy_lints/src/methods/single_char_add_str.rs
index 9a5fabcf7cd..81450fd8c6c 100644
--- a/clippy_lints/src/methods/single_char_add_str.rs
+++ b/clippy_lints/src/methods/single_char_add_str.rs
@@ -3,12 +3,12 @@ use clippy_utils::{match_def_path, paths};
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
         if match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
-            single_char_push_string::check(cx, expr, args);
+            single_char_push_string::check(cx, expr, receiver, args);
         } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) {
-            single_char_insert_string::check(cx, expr, args);
+            single_char_insert_string::check(cx, expr, receiver, args);
         }
     }
 }
diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs
index 6cdc954c03b..18b6b5be175 100644
--- a/clippy_lints/src/methods/single_char_insert_string.rs
+++ b/clippy_lints/src/methods/single_char_insert_string.rs
@@ -8,12 +8,12 @@ use rustc_lint::LateContext;
 use super::SINGLE_CHAR_ADD_STR;
 
 /// lint for length-1 `str`s as argument for `insert_str`
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     let mut applicability = Applicability::MachineApplicable;
-    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) {
+    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
         let base_string_snippet =
-            snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability);
-        let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability);
+            snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability);
+        let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
         let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string);
         span_lint_and_sugg(
             cx,
diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs
index bf9006c6906..4221c52d5cd 100644
--- a/clippy_lints/src/methods/single_char_pattern.rs
+++ b/clippy_lints/src/methods/single_char_pattern.rs
@@ -10,37 +10,43 @@ use rustc_span::symbol::Symbol;
 use super::SINGLE_CHAR_PATTERN;
 
 const PATTERN_METHODS: [(&str, usize); 24] = [
-    ("contains", 1),
-    ("starts_with", 1),
-    ("ends_with", 1),
-    ("find", 1),
-    ("rfind", 1),
-    ("split", 1),
-    ("split_inclusive", 1),
-    ("rsplit", 1),
-    ("split_terminator", 1),
-    ("rsplit_terminator", 1),
-    ("splitn", 2),
-    ("rsplitn", 2),
-    ("split_once", 1),
-    ("rsplit_once", 1),
-    ("matches", 1),
-    ("rmatches", 1),
-    ("match_indices", 1),
-    ("rmatch_indices", 1),
-    ("strip_prefix", 1),
-    ("strip_suffix", 1),
-    ("trim_start_matches", 1),
-    ("trim_end_matches", 1),
-    ("replace", 1),
-    ("replacen", 1),
+    ("contains", 0),
+    ("starts_with", 0),
+    ("ends_with", 0),
+    ("find", 0),
+    ("rfind", 0),
+    ("split", 0),
+    ("split_inclusive", 0),
+    ("rsplit", 0),
+    ("split_terminator", 0),
+    ("rsplit_terminator", 0),
+    ("splitn", 1),
+    ("rsplitn", 1),
+    ("split_once", 0),
+    ("rsplit_once", 0),
+    ("matches", 0),
+    ("rmatches", 0),
+    ("match_indices", 0),
+    ("rmatch_indices", 0),
+    ("strip_prefix", 0),
+    ("strip_suffix", 0),
+    ("trim_start_matches", 0),
+    ("trim_end_matches", 0),
+    ("replace", 0),
+    ("replacen", 0),
 ];
 
 /// lint for length-1 `str`s for methods in `PATTERN_METHODS`
-pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) {
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    _expr: &hir::Expr<'_>,
+    method_name: Symbol,
+    receiver: &hir::Expr<'_>,
+    args: &[hir::Expr<'_>],
+) {
     for &(method, pos) in &PATTERN_METHODS {
         if_chain! {
-            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(&args[0]).kind();
+            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind();
             if *ty.kind() == ty::Str;
             if method_name.as_str() == method && args.len() > pos;
             let arg = &args[pos];
diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs
index 0237d39cbdb..9ea6751956a 100644
--- a/clippy_lints/src/methods/single_char_push_string.rs
+++ b/clippy_lints/src/methods/single_char_push_string.rs
@@ -8,11 +8,11 @@ use rustc_lint::LateContext;
 use super::SINGLE_CHAR_ADD_STR;
 
 /// lint for length-1 `str`s as argument for `push_str`
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
     let mut applicability = Applicability::MachineApplicable;
-    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
+    if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) {
         let base_string_snippet =
-            snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability);
+            snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
         let sugg = format!("{}.push({})", base_string_snippet, extension_string);
         span_lint_and_sugg(
             cx,
diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs
index 4ac738272d0..8f2f4752514 100644
--- a/clippy_lints/src/methods/str_splitn.rs
+++ b/clippy_lints/src/methods/str_splitn.rs
@@ -292,7 +292,7 @@ fn parse_iter_usage<'tcx>(
 ) -> Option<IterUsage> {
     let (kind, span) = match iter.next() {
         Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
-            let (name, args) = if let ExprKind::MethodCall(name, [_, args @ ..], _) = e.kind {
+            let (name, args) = if let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind {
                 (name, args)
             } else {
                 return None;
@@ -327,7 +327,7 @@ fn parse_iter_usage<'tcx>(
                         } else {
                             if_chain! {
                                 if let Some((_, Node::Expr(next_expr))) = iter.next();
-                                if let ExprKind::MethodCall(next_name, [_], _) = next_expr.kind;
+                                if let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind;
                                 if next_name.ident.name == sym::next;
                                 if next_expr.span.ctxt() == ctxt;
                                 if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id);
@@ -367,7 +367,7 @@ fn parse_iter_usage<'tcx>(
                 }
             },
             _ if e.span.ctxt() != ctxt => (None, span),
-            ExprKind::MethodCall(name, [_], _)
+            ExprKind::MethodCall(name, _, [], _)
                 if name.ident.name == sym::unwrap
                     && cx
                         .typeck_results()
diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs
index d06658f2a5e..143dcee3505 100644
--- a/clippy_lints/src/methods/string_extend_chars.rs
+++ b/clippy_lints/src/methods/string_extend_chars.rs
@@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         return;
     }
     if let Some(arglists) = method_chain_args(arg, &["chars"]) {
-        let target = &arglists[0][0];
+        let target = &arglists[0].0;
         let self_ty = cx.typeck_results().expr_ty(target).peel_refs();
         let ref_str = if *self_ty.kind() == ty::Str {
             ""
diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index 19037093e20..95138c0e25b 100644
--- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -43,7 +43,7 @@ pub fn check_for_loop_iter(
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
             let snippet = if_chain! {
-                if let ExprKind::MethodCall(maybe_iter_method_name, [collection], _) = receiver.kind;
+                if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind;
                 if maybe_iter_method_name.ident.name == sym::iter;
 
                 if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 1876c7fb9d0..a187a8d6016 100644
--- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(
                 // This is a duplicate of what's happening in clippy_lints::methods::method_call,
                 // which isn't ideal, We want to get the method call span,
                 // but prefer to avoid changing the signature of the function itself.
-                if let hir::ExprKind::MethodCall(_, _, span) = expr.kind {
+                if let hir::ExprKind::MethodCall(.., span) = expr.kind {
                     span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
                         diag.span_suggestion(
                             span,
diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs
index 1966990bd77..6f25acca1de 100644
--- a/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -50,9 +50,13 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident
         // The two exprs are method calls.
         // Check to see that the function is the same and the arguments are mirrored
         // This is enough because the receiver of the method is listed in the arguments
-        (ExprKind::MethodCall(left_segment, left_args, _), ExprKind::MethodCall(right_segment, right_args, _)) => {
+        (
+            ExprKind::MethodCall(left_segment, left_receiver, left_args, _),
+            ExprKind::MethodCall(right_segment, right_receiver, right_args, _),
+        ) => {
             left_segment.ident == right_segment.ident
                 && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident))
+                && mirrored_exprs(left_receiver, a_ident, right_receiver, b_ident)
         },
         // Two tuples with mirrored contents
         (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => {
@@ -125,7 +129,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
             Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
             Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
         ] = &closure_body.params;
-        if let ExprKind::MethodCall(method_path, [left_expr, right_expr], _) = closure_body.value.kind;
+        if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind;
         if method_path.ident.name == sym::cmp;
         if is_trait_method(cx, &closure_body.value, sym::Ord);
         then {
diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index 44bf8435294..9dceb9af2f2 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -24,12 +24,13 @@ pub fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
     method_name: Symbol,
-    args: &'tcx [Expr<'tcx>],
+    receiver: &'tcx Expr<'_>,
+    args: &'tcx [Expr<'_>],
     msrv: Option<RustcVersion>,
 ) {
     if_chain! {
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
-        if let [receiver] = args;
+        if args.is_empty();
         then {
             if is_cloned_or_copied(cx, method_name, method_def_id) {
                 unnecessary_iter_cloned::check(cx, expr, method_name, receiver);
@@ -245,9 +246,14 @@ fn check_other_call_arg<'tcx>(
 ) -> bool {
     if_chain! {
         if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr);
-        if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call);
+        if let Some((callee_def_id, call_substs, call_receiver, call_args)) = get_callee_substs_and_args(cx, maybe_call);
         let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
-        if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id);
+        let index = if let Some(call_receiver) = call_receiver {
+            std::iter::once(call_receiver).chain(call_args.iter()).position(|arg| arg.hir_id == maybe_arg.hir_id)
+        } else {
+            call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id)
+        };
+        if let Some(i) = index;
         if let Some(input) = fn_sig.inputs().get(i);
         let (input, n_refs) = peel_mid_ty_refs(*input);
         if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input);
@@ -342,22 +348,22 @@ fn skip_addr_of_ancestors<'tcx>(
 fn get_callee_substs_and_args<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
-) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> {
+) -> Option<(DefId, SubstsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> {
     if_chain! {
         if let ExprKind::Call(callee, args) = expr.kind;
         let callee_ty = cx.typeck_results().expr_ty(callee);
         if let ty::FnDef(callee_def_id, _) = callee_ty.kind();
         then {
             let substs = cx.typeck_results().node_substs(callee.hir_id);
-            return Some((*callee_def_id, substs, args));
+            return Some((*callee_def_id, substs, None, args));
         }
     }
     if_chain! {
-        if let ExprKind::MethodCall(_, args, _) = expr.kind;
+        if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind;
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         then {
             let substs = cx.typeck_results().node_substs(expr.hir_id);
-            return Some((method_def_id, substs, args));
+            return Some((method_def_id, substs, Some(receiver), args));
         }
     }
     None
diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs
index 3015531e843..ae6b165fdc3 100644
--- a/clippy_lints/src/methods/utils.rs
+++ b/clippy_lints/src/methods/utils.rs
@@ -28,7 +28,7 @@ pub(super) fn derefs_to_slice<'tcx>(
         }
     }
 
-    if let hir::ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind {
+    if let hir::ExprKind::MethodCall(path, self_arg, ..) = &expr.kind {
         if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) {
             Some(self_arg)
         } else {
@@ -139,9 +139,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
                         self.addr_of_exprs.push(parent);
                         return;
                     },
-                    ExprKind::MethodCall(_, args, _) => {
+                    ExprKind::MethodCall(.., args, _) => {
                         if_chain! {
-                            if args.iter().skip(1).all(|arg| !self.is_binding(arg));
+                            if args.iter().all(|arg| !self.is_binding(arg));
                             if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id);
                             let method_ty = self.cx.tcx.type_of(method_def_id);
                             let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder();
diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs
index a081cde8572..c618f6b5d92 100644
--- a/clippy_lints/src/minmax.rs
+++ b/clippy_lints/src/minmax.rs
@@ -75,23 +75,22 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
                     .qpath_res(qpath, path.hir_id)
                     .opt_def_id()
                     .and_then(|def_id| match cx.tcx.get_diagnostic_name(def_id) {
-                        Some(sym::cmp_min) => fetch_const(cx, args, MinMax::Min),
-                        Some(sym::cmp_max) => fetch_const(cx, args, MinMax::Max),
+                        Some(sym::cmp_min) => fetch_const(cx, None, args, MinMax::Min),
+                        Some(sym::cmp_max) => fetch_const(cx, None, args, MinMax::Max),
                         _ => None,
                     })
             } else {
                 None
             }
         },
-        ExprKind::MethodCall(path, args, _) => {
+        ExprKind::MethodCall(path, receiver, args @ [_], _) => {
             if_chain! {
-                if let [obj, _] = args;
-                if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
+                if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD);
                 then {
                     if path.ident.name == sym!(max) {
-                        fetch_const(cx, args, MinMax::Max)
+                        fetch_const(cx, Some(receiver), args, MinMax::Max)
                     } else if path.ident.name == sym!(min) {
-                        fetch_const(cx, args, MinMax::Min)
+                        fetch_const(cx, Some(receiver), args, MinMax::Min)
                     } else {
                         None
                     }
@@ -104,16 +103,26 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
     }
 }
 
-fn fetch_const<'a>(cx: &LateContext<'_>, args: &'a [Expr<'a>], m: MinMax) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
-    if args.len() != 2 {
+fn fetch_const<'a>(
+    cx: &LateContext<'_>,
+    receiver: Option<&'a Expr<'a>>,
+    args: &'a [Expr<'a>],
+    m: MinMax,
+) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
+    if (receiver.is_some() && args.len() != 1) || (receiver.is_none() && args.len() != 2) {
         return None;
     }
-    constant_simple(cx, cx.typeck_results(), &args[0]).map_or_else(
-        || constant_simple(cx, cx.typeck_results(), &args[1]).map(|c| (m, c, &args[0])),
+    let (arg0, arg1) = if let Some(receiver) = receiver {
+        (receiver, &args[0])
+    } else {
+        (&args[0], &args[1])
+    };
+    constant_simple(cx, cx.typeck_results(), arg0).map_or_else(
+        || constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)),
         |c| {
-            if constant_simple(cx, cx.typeck_results(), &args[1]).is_none() {
+            if constant_simple(cx, cx.typeck_results(), arg1).is_none() {
                 // otherwise ignore
-                Some((m, c, &args[1]))
+                Some((m, c, arg1))
             } else {
                 None
             }
diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs
index f434a655f8a..82dc03ef5c5 100644
--- a/clippy_lints/src/mut_reference.rs
+++ b/clippy_lints/src/mut_reference.rs
@@ -43,18 +43,24 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
                 if let ExprKind::Path(ref path) = fn_expr.kind {
                     check_arguments(
                         cx,
-                        arguments,
+                        arguments.iter().collect(),
                         cx.typeck_results().expr_ty(fn_expr),
                         &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
                         "function",
                     );
                 }
             },
-            ExprKind::MethodCall(path, arguments, _) => {
+            ExprKind::MethodCall(path, receiver, arguments, _) => {
                 let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
                 let substs = cx.typeck_results().node_substs(e.hir_id);
                 let method_type = cx.tcx.bound_type_of(def_id).subst(cx.tcx, substs);
-                check_arguments(cx, arguments, method_type, path.ident.as_str(), "method");
+                check_arguments(
+                    cx,
+                    std::iter::once(receiver).chain(arguments.iter()).collect(),
+                    method_type,
+                    path.ident.as_str(),
+                    "method",
+                );
             },
             _ => (),
         }
@@ -63,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
 
 fn check_arguments<'tcx>(
     cx: &LateContext<'tcx>,
-    arguments: &[Expr<'_>],
+    arguments: Vec<&Expr<'_>>,
     type_definition: Ty<'tcx>,
     name: &str,
     fn_kind: &str,
diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs
index 10e188ecb79..f8cc3fbb3cd 100644
--- a/clippy_lints/src/needless_for_each.rs
+++ b/clippy_lints/src/needless_for_each.rs
@@ -56,12 +56,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
 
         if_chain! {
             // Check the method name is `for_each`.
-            if let ExprKind::MethodCall(method_name, [for_each_recv, for_each_arg], _) = expr.kind;
+            if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind;
             if method_name.ident.name == Symbol::intern("for_each");
             // Check `for_each` is an associated function of `Iterator`.
             if is_trait_method(cx, expr, sym::Iterator);
             // Checks the receiver of `for_each` is also a method call.
-            if let ExprKind::MethodCall(_, [iter_recv], _) = for_each_recv.kind;
+            if let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind;
             // Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or
             // `v.foo().iter().for_each()` must be skipped.
             if matches!(
diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs
index ed022b9d529..25fb4f0f4cf 100644
--- a/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/clippy_lints/src/non_octal_unix_permissions.rs
@@ -43,7 +43,7 @@ declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]);
 impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         match &expr.kind {
-            ExprKind::MethodCall(path, [func, param], _) => {
+            ExprKind::MethodCall(path, func, [param], _) => {
                 let obj_ty = cx.typeck_results().expr_ty(func).peel_refs();
 
                 if_chain! {
diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs
index 774a3540d1e..17d5fa2152b 100644
--- a/clippy_lints/src/only_used_in_recursion.rs
+++ b/clippy_lints/src/only_used_in_recursion.rs
@@ -304,13 +304,13 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                             }
                             return;
                         },
-                        ExprKind::MethodCall(_, args, _)
+                        ExprKind::MethodCall(_, receiver, args, _)
                             if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| {
                                 id == param.fn_id
                                     && has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id))
                             }) =>
                         {
-                            if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) {
+                            if let Some(idx) = std::iter::once(receiver).chain(args.iter()).position(|arg| arg.hir_id == child_id) {
                                 param.uses.push(Usage::new(span, idx));
                             }
                             return;
diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs
index e1f9b5906f6..638a514ff9b 100644
--- a/clippy_lints/src/operators/cmp_owned.rs
+++ b/clippy_lints/src/operators/cmp_owned.rs
@@ -38,7 +38,7 @@ fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'t
 fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
     let typeck = cx.typeck_results();
     let (arg, arg_span) = match expr.kind {
-        ExprKind::MethodCall(.., [arg], _)
+        ExprKind::MethodCall(_, arg, [], _)
             if typeck
                 .type_dependent_def_id(expr.hir_id)
                 .and_then(|id| cx.tcx.trait_of_item(id))
diff --git a/clippy_lints/src/operators/duration_subsec.rs b/clippy_lints/src/operators/duration_subsec.rs
index 0d067d1e196..827a2b26709 100644
--- a/clippy_lints/src/operators/duration_subsec.rs
+++ b/clippy_lints/src/operators/duration_subsec.rs
@@ -17,7 +17,7 @@ pub(crate) fn check<'tcx>(
     right: &'tcx Expr<'_>,
 ) {
     if op == BinOpKind::Div
-        && let ExprKind::MethodCall(method_path, [self_arg], _) = left.kind
+        && 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)
     {
diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs
index 0ef793443ff..97ddcdb2479 100644
--- a/clippy_lints/src/operators/float_cmp.rs
+++ b/clippy_lints/src/operators/float_cmp.rs
@@ -113,7 +113,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     }
 
     if_chain! {
-        if let ExprKind::MethodCall(method_name, [ref self_arg, ..], _) = expr.kind;
+        if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
         if sym!(signum) == method_name.ident.name;
         // Check that the receiver of the signum() is a float (expressions[0] is the receiver of
         // the method call)
diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs
index 3c5ea2d9414..63c9faf0396 100644
--- a/clippy_lints/src/ptr.rs
+++ b/clippy_lints/src/ptr.rs
@@ -591,8 +591,11 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
                             set_skip_flag();
                         }
                     },
-                    ExprKind::MethodCall(name, expr_args @ [self_arg, ..], _) => {
-                        let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
+                    ExprKind::MethodCall(name, self_arg, expr_args, _) => {
+                        let i = std::iter::once(self_arg)
+                            .chain(expr_args.iter())
+                            .position(|arg| arg.hir_id == child_id)
+                            .unwrap_or(0);
                         if i == 0 {
                             // Check if the method can be renamed.
                             let name = name.ident.as_str();
diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs
index b907f38afbb..4dc65da3ea1 100644
--- a/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/clippy_lints/src/ptr_offset_with_cast.rs
@@ -93,7 +93,7 @@ fn expr_as_ptr_offset_call<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
 ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> {
-    if let ExprKind::MethodCall(path_segment, [arg_0, arg_1, ..], _) = &expr.kind {
+    if let ExprKind::MethodCall(path_segment, arg_0, [arg_1, ..], _) = &expr.kind {
         if is_expr_ty_raw_ptr(cx, arg_0) {
             if path_segment.ident.name == sym::offset {
                 return Some((arg_0, arg_1, Method::Offset));
diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs
index b432ccb1ee3..6fddbd419bc 100644
--- a/clippy_lints/src/question_mark.rs
+++ b/clippy_lints/src/question_mark.rs
@@ -86,7 +86,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex
     if_chain! {
         if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
         if !is_else_clause(cx.tcx, expr);
-        if let ExprKind::MethodCall(segment, [caller, ..], _) = &cond.kind;
+        if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind;
         let caller_ty = cx.typeck_results().expr_ty(caller);
         let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else);
         if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block);
diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs
index 9538a810473..94dec191103 100644
--- a/clippy_lints/src/read_zero_byte_vec.rs
+++ b/clippy_lints/src/read_zero_byte_vec.rs
@@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
                 // finds use of `_.read(&mut v)`
                 let mut read_found = false;
                 let mut visitor = expr_visitor_no_bodies(|expr| {
-                    if let ExprKind::MethodCall(path, [_self, arg], _) = expr.kind
+                    if let ExprKind::MethodCall(path, _self, [arg], _) = expr.kind
                         && let PathSegment { ident: read_or_read_exact, .. } = *path
                         && matches!(read_or_read_exact.as_str(), "read" | "read_exact")
                         && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind
diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs
index bfb9f0d01e1..ac4e29e9dfd 100644
--- a/clippy_lints/src/size_of_in_element_count.rs
+++ b/clippy_lints/src/size_of_in_element_count.rs
@@ -108,7 +108,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
     };
     if_chain! {
         // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods
-        if let ExprKind::MethodCall(method_path, [ptr_self, .., count], _) = expr.kind;
+        if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind;
         let method_ident = method_path.ident.as_str();
         if METHODS.iter().any(|m| *m == method_ident);
 
diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs
index b59a25e3a40..b3578218467 100644
--- a/clippy_lints/src/slow_vector_initialization.rs
+++ b/clippy_lints/src/slow_vector_initialization.rs
@@ -201,7 +201,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) {
         if_chain! {
             if self.initialization_found;
-            if let ExprKind::MethodCall(path, [self_arg, extend_arg], _) = expr.kind;
+            if let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind;
             if path_to_local_id(self_arg, self.vec_alloc.local_id);
             if path.ident.name == sym!(extend);
             if self.is_repeat_take(extend_arg);
@@ -215,7 +215,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     /// Checks if the given expression is resizing a vector with 0
     fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
         if self.initialization_found
-            && let ExprKind::MethodCall(path, [self_arg, len_arg, fill_arg], _) = expr.kind
+            && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
             && path_to_local_id(self_arg, self.vec_alloc.local_id)
             && path.ident.name == sym!(resize)
             // Check that is filled with 0
@@ -224,7 +224,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
                 // Check that len expression is equals to `with_capacity` expression
                 if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
                     self.slow_expression = Some(InitializationType::Resize(expr));
-                } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" {
+                } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
                     self.slow_expression = Some(InitializationType::Resize(expr));
                 }
             }
@@ -233,7 +233,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     /// Returns `true` if give expression is `repeat(0).take(...)`
     fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
         if_chain! {
-            if let ExprKind::MethodCall(take_path, [recv, len_arg, ..], _) = expr.kind;
+            if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind;
             if take_path.ident.name == sym!(take);
             // Check that take is applied to `repeat(0)`
             if self.is_repeat_zero(recv);
@@ -241,7 +241,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
                 // Check that len expression is equals to `with_capacity` expression
                 if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
                     return true;
-                } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" {
+                } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
                     return true;
                 }
             }
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index 22eb06b3646..662d399ca53 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -262,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
             let (method_names, expressions, _) = method_calls(left, 1);
             if method_names.len() == 1;
             if expressions.len() == 1;
-            if expressions[0].len() == 1;
+            if expressions[0].1.is_empty();
             if method_names[0] == sym!(as_bytes);
 
             // Check for slicer
@@ -270,7 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
 
             then {
                 let mut applicability = Applicability::MachineApplicable;
-                let string_expression = &expressions[0][0];
+                let string_expression = &expressions[0].0;
 
                 let snippet_app = snippet_with_applicability(
                     cx,
@@ -291,12 +291,12 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         }
 
         if_chain! {
-            if let ExprKind::MethodCall(path, args, _) = &e.kind;
+            if let ExprKind::MethodCall(path, receiver, ..) = &e.kind;
             if path.ident.name == sym!(as_bytes);
-            if let ExprKind::Lit(lit) = &args[0].kind;
+            if let ExprKind::Lit(lit) = &receiver.kind;
             if let LitKind::Str(lit_content, _) = &lit.node;
             then {
-                let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#);
+                let callsite = snippet(cx, receiver.span.source_callsite(), r#""foo""#);
                 let mut applicability = Applicability::MachineApplicable;
                 if callsite.starts_with("include_str!") {
                     span_lint_and_sugg(
@@ -305,7 +305,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
                         e.span,
                         "calling `as_bytes()` on `include_str!(..)`",
                         "consider using `include_bytes!(..)` instead",
-                        snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen(
+                        snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen(
                             "include_str",
                             "include_bytes",
                             1,
@@ -314,7 +314,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
                     );
                 } else if lit_content.as_str().is_ascii()
                     && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT
-                    && !args[0].span.from_expansion()
+                    && !receiver.span.from_expansion()
                 {
                     span_lint_and_sugg(
                         cx,
@@ -324,7 +324,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
                         "consider using a byte string literal instead",
                         format!(
                             "b{}",
-                            snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability)
+                            snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability)
                         ),
                         applicability,
                     );
@@ -333,9 +333,9 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         }
 
         if_chain! {
-            if let ExprKind::MethodCall(path, [recv], _) = &e.kind;
+            if let ExprKind::MethodCall(path, recv, [], _) = &e.kind;
             if path.ident.name == sym!(into_bytes);
-            if let ExprKind::MethodCall(path, [recv], _) = &recv.kind;
+            if let ExprKind::MethodCall(path, recv, [], _) = &recv.kind;
             if matches!(path.ident.name.as_str(), "to_owned" | "to_string");
             if let ExprKind::Lit(lit) = &recv.kind;
             if let LitKind::Str(lit_content, _) = &lit.node;
@@ -393,7 +393,7 @@ declare_lint_pass!(StrToString => [STR_TO_STRING]);
 impl<'tcx> LateLintPass<'tcx> for StrToString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
         if_chain! {
-            if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+            if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
             if path.ident.name == sym::to_string;
             let ty = cx.typeck_results().expr_ty(self_arg);
             if let ty::Ref(_, ty, ..) = ty.kind();
@@ -443,7 +443,7 @@ declare_lint_pass!(StringToString => [STRING_TO_STRING]);
 impl<'tcx> LateLintPass<'tcx> for StringToString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
         if_chain! {
-            if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
+            if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind;
             if path.ident.name == sym::to_string;
             let ty = cx.typeck_results().expr_ty(self_arg);
             if is_type_diagnostic_item(cx, ty, sym::String);
@@ -487,11 +487,11 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
         let tyckres = cx.typeck_results();
         if_chain! {
-            if let ExprKind::MethodCall(path, [split_recv], split_ws_span) = expr.kind;
+            if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind;
             if path.ident.name == sym!(split_whitespace);
             if let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id);
             if cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id);
-            if let ExprKind::MethodCall(path, [_trim_recv], trim_span) = split_recv.kind;
+            if let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind;
             if let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str();
             if let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id);
             if is_one_of_trim_diagnostic_items(cx, trim_def_id);
diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs
index 7bc9cf742e6..78403d9fdb7 100644
--- a/clippy_lints/src/strlen_on_c_strings.rs
+++ b/clippy_lints/src/strlen_on_c_strings.rs
@@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
             if let ExprKind::Path(path) = &func.kind;
             if let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id();
             if match_libc_symbol(cx, did, "strlen");
-            if let ExprKind::MethodCall(path, [self_arg], _) = recv.kind;
+            if let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind;
             if !recv.span.from_expansion();
             if path.ident.name == sym::as_ptr;
             then {
diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs
index aa6c01b3a7c..651201f34ed 100644
--- a/clippy_lints/src/to_digit_is_some.rs
+++ b/clippy_lints/src/to_digit_is_some.rs
@@ -39,19 +39,17 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]);
 impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if_chain! {
-            if let hir::ExprKind::MethodCall(is_some_path, is_some_args, _) = &expr.kind;
+            if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind;
             if is_some_path.ident.name.as_str() == "is_some";
-            if let [to_digit_expr] = &**is_some_args;
             then {
                 let match_result = match &to_digit_expr.kind {
-                    hir::ExprKind::MethodCall(to_digits_path, to_digit_args, _) => {
+                    hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => {
                         if_chain! {
-                            if let [char_arg, radix_arg] = &**to_digit_args;
                             if to_digits_path.ident.name.as_str() == "to_digit";
                             let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg);
                             if *char_arg_ty.kind() == ty::Char;
                             then {
-                                Some((true, char_arg, radix_arg))
+                                Some((true, *char_arg, radix_arg))
                             } else {
                                 None
                             }
@@ -59,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
                     }
                     hir::ExprKind::Call(to_digits_call, to_digit_args) => {
                         if_chain! {
-                            if let [char_arg, radix_arg] = &**to_digit_args;
+                            if let [char_arg, radix_arg] = *to_digit_args;
                             if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind;
                             if let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id);
                             if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id();
diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs
index 9a41603f2f4..3f99bd3f315 100644
--- a/clippy_lints/src/uninit_vec.rs
+++ b/clippy_lints/src/uninit_vec.rs
@@ -177,7 +177,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt
                     });
                 }
             },
-            ExprKind::MethodCall(path, [self_expr, _], _) if is_reserve(cx, path, self_expr) => {
+            ExprKind::MethodCall(path, self_expr, [_], _) if is_reserve(cx, path, self_expr) => {
                 return Some(TargetVec {
                     location: VecLocation::Expr(self_expr),
                     init_kind: None,
@@ -211,7 +211,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
         }
     });
     match expr.kind {
-        ExprKind::MethodCall(path, [self_expr, _], _) => {
+        ExprKind::MethodCall(path, self_expr, [_], _) => {
             let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
             if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" {
                 Some((self_expr, expr.span))
diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs
index b0fce91abeb..851eef7b332 100644
--- a/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/clippy_lints/src/unit_return_expecting_ord.rs
@@ -144,8 +144,9 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa
 
 impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if let ExprKind::MethodCall(_, args, _) = expr.kind {
+        if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind {
             let arg_indices = get_args_to_check(cx, expr);
+            let args = std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>();
             for (i, trait_name) in arg_indices {
                 if i < args.len() {
                     match check_arg(cx, &args[i]) {
diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs
index aec028d5c48..35824b03170 100644
--- a/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/clippy_lints/src/unit_types/let_unit_value.rs
@@ -128,7 +128,7 @@ fn needs_inferred_result_ty(
     locals_to_check: &mut Vec<HirId>,
     seen_locals: &mut HirIdSet,
 ) -> bool {
-    let (id, args) = match e.kind {
+    let (id, receiver, args) = match e.kind {
         ExprKind::Call(
             Expr {
                 kind: ExprKind::Path(ref path),
@@ -137,11 +137,11 @@ fn needs_inferred_result_ty(
             },
             args,
         ) => match cx.qpath_res(path, *hir_id) {
-            Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, args),
+            Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, None, args),
             _ => return false,
         },
-        ExprKind::MethodCall(_, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) {
-            Some(id) => (id, args),
+        ExprKind::MethodCall(_, receiver, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) {
+            Some(id) => (id, Some(receiver), args),
             None => return false,
         },
         ExprKind::Path(QPath::Resolved(None, path)) => {
@@ -156,6 +156,11 @@ fn needs_inferred_result_ty(
     };
     let sig = cx.tcx.fn_sig(id).skip_binder();
     if let ty::Param(output_ty) = *sig.output().kind() {
+        let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver {
+            std::iter::once(receiver).chain(args.iter()).collect()
+        } else {
+            args.iter().collect()
+        };
         sig.inputs().iter().zip(args).all(|(&ty, arg)| {
             !ty.is_param(output_ty.index) || each_value_source_needs_inference(cx, arg, locals_to_check, seen_locals)
         })
diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs
index 16da2f11b81..7ffb53dcf45 100644
--- a/clippy_lints/src/unit_types/unit_arg.rs
+++ b/clippy_lints/src/unit_types/unit_arg.rs
@@ -30,26 +30,27 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         }
     }
 
-    match expr.kind {
-        ExprKind::Call(_, args) | ExprKind::MethodCall(_, args, _) => {
-            let args_to_recover = args
-                .iter()
-                .filter(|arg| {
-                    if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) {
-                        !matches!(
-                            &arg.kind,
-                            ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
-                        )
-                    } else {
-                        false
-                    }
-                })
-                .collect::<Vec<_>>();
-            if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
-                lint_unit_args(cx, expr, &args_to_recover);
+    let args: Vec<_> = match expr.kind {
+        ExprKind::Call(_, args) => args.iter().collect(),
+        ExprKind::MethodCall(_, receiver, args, _) => std::iter::once(receiver).chain(args.iter()).collect(),
+        _ => return,
+    };
+
+    let args_to_recover = args
+        .into_iter()
+        .filter(|arg| {
+            if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) {
+                !matches!(
+                    &arg.kind,
+                    ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..)
+                )
+            } else {
+                false
             }
-        },
-        _ => (),
+        })
+        .collect::<Vec<_>>();
+    if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
+        lint_unit_args(cx, expr, &args_to_recover.as_slice());
     }
 }
 
diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs
index 323cf83ffcf..b38d71784fc 100644
--- a/clippy_lints/src/unused_io_amount.rs
+++ b/clippy_lints/src/unused_io_amount.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
                     check_map_error(cx, res, expr);
                 }
             },
-            hir::ExprKind::MethodCall(path, [ref arg_0, ..], _) => match path.ident.as_str() {
+            hir::ExprKind::MethodCall(path, arg_0, ..) => match path.ident.as_str() {
                 "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => {
                     check_map_error(cx, arg_0, expr);
                 },
@@ -94,9 +94,9 @@ fn try_remove_await<'a>(expr: &'a hir::Expr<'a>) -> Option<&hir::Expr<'a>> {
 
 fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
     let mut call = call;
-    while let hir::ExprKind::MethodCall(path, args, _) = call.kind {
+    while let hir::ExprKind::MethodCall(path, receiver, ..) = call.kind {
         if matches!(path.ident.as_str(), "or" | "or_else" | "ok") {
-            call = &args[0];
+            call = receiver;
         } else {
             break;
         }
@@ -110,7 +110,7 @@ fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<
 }
 
 fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>, is_await: bool) {
-    if let hir::ExprKind::MethodCall(path, _, _) = call.kind {
+    if let hir::ExprKind::MethodCall(path, ..) = call.kind {
         let symbol = path.ident.as_str();
         let read_trait = if is_await {
             match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT)
diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs
index ac73173697e..7fbfecf96ec 100644
--- a/clippy_lints/src/unused_peekable.rs
+++ b/clippy_lints/src/unused_peekable.rs
@@ -149,7 +149,8 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
                                     ident: method_name_ident,
                                     ..
                                 },
-                                [self_arg, remaining_args @ ..],
+                                self_arg,
+                                [remaining_args @ ..],
                                 _,
                             ) => {
                                 let method_name = method_name_ident.name.as_str();
diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs
index d3f9e5abfd7..9092156be15 100644
--- a/clippy_lints/src/unwrap.rs
+++ b/clippy_lints/src/unwrap.rs
@@ -154,13 +154,13 @@ fn collect_unwrap_info<'tcx>(
         return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false);
     } else {
         if_chain! {
-            if let ExprKind::MethodCall(method_name, args, _) = &expr.kind;
-            if let Some(local_id) = path_to_local(&args[0]);
-            let ty = cx.typeck_results().expr_ty(&args[0]);
+            if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind;
+            if let Some(local_id) = path_to_local(receiver);
+            let ty = cx.typeck_results().expr_ty(receiver);
             let name = method_name.ident.as_str();
             if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name);
             then {
-                assert!(args.len() == 1);
+                assert!(args.len() == 0);
                 let unwrappable = match name {
                     "is_some" | "is_ok" => true,
                     "is_err" | "is_none" => false,
@@ -231,7 +231,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
         } else {
             // find `unwrap[_err]()` calls:
             if_chain! {
-                if let ExprKind::MethodCall(method_name, [self_arg, ..], _) = expr.kind;
+                if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind;
                 if let Some(id) = path_to_local(self_arg);
                 if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name);
                 let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name);
diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs
index b32be238cd5..b3ca15f7648 100644
--- a/clippy_lints/src/unwrap_in_result.rs
+++ b/clippy_lints/src/unwrap_in_result.rs
@@ -83,7 +83,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // check for `expect`
         if let Some(arglists) = method_chain_args(expr, &["expect"]) {
-            let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+            let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
             {
@@ -93,7 +93,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
 
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
-            let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+            let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
             {
diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs
index b6738e2891d..f1b6463ad0f 100644
--- a/clippy_lints/src/useless_conversion.rs
+++ b/clippy_lints/src/useless_conversion.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                 }
             },
 
-            ExprKind::MethodCall(name, .., [recv, ..], _) => {
+            ExprKind::MethodCall(name, recv, ..) => {
                 if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(recv);
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index 3ffcaa90af3..fec4ee93e7b 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -402,10 +402,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 self.expr(func);
                 self.slice(args, |e| self.expr(e));
             },
-            ExprKind::MethodCall(method_name, args, _) => {
-                bind!(self, method_name, args);
-                kind!("MethodCall({method_name}, {args}, _)");
+            ExprKind::MethodCall(method_name, receiver, args, _) => {
+                bind!(self, method_name, receiver, args);
+                kind!("MethodCall({method_name}, {receiver}, {args}, _)");
                 self.ident(field!(method_name.ident));
+                self.expr(receiver);
                 self.slice(args, |e| self.expr(e));
             },
             ExprKind::Tup(elements) => {
diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs
index eb34085a2ab..ae1c11ef83c 100644
--- a/clippy_lints/src/utils/internal_lints.rs
+++ b/clippy_lints/src/utils/internal_lints.rs
@@ -687,7 +687,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
             if let ["expn_data", "outer_expn"] = method_names.as_slice();
             let args = arg_lists[1];
             if args.len() == 1;
-            let self_arg = &args[0];
+            let self_arg = &args.0;
             let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
             if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
             then {
diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs
index 35db45e2b0c..542c6a37d56 100644
--- a/clippy_lints/src/vec_init_then_push.rs
+++ b/clippy_lints/src/vec_init_then_push.rs
@@ -100,7 +100,7 @@ impl VecPushSearcher {
                         || get_parent_expr(cx, last_place)
                             .map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _)));
                 },
-                ExprKind::MethodCall(_, [recv, ..], _)
+                ExprKind::MethodCall(_, recv, ..)
                     if recv.hir_id == e.hir_id
                         && adjusted_mut == Mutability::Mut
                         && !adjusted_ty.peel_refs().is_slice() =>
@@ -201,7 +201,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let Some(searcher) = self.searcher.take() {
             if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
-                && let ExprKind::MethodCall(name, [self_arg, _], _) = expr.kind
+                && let ExprKind::MethodCall(name, self_arg, [_], _) = expr.kind
                 && path_to_local_id(self_arg, searcher.local_id)
                 && name.ident.as_str() == "push"
             {
diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs
index 8335ffae81e..e8d2d579f09 100644
--- a/clippy_utils/src/check_proc_macro.rs
+++ b/clippy_utils/src/check_proc_macro.rs
@@ -118,9 +118,9 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
         ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1),
         ExprKind::Lit(ref 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(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
         ExprKind::Call(first, [.., last])
-        | ExprKind::MethodCall(_, [first, .., last], _)
+        | ExprKind::MethodCall(_, first, [.., last], _)
         | ExprKind::Binary(_, first, last)
         | ExprKind::Tup([first, .., last])
         | ExprKind::Assign(first, last, _)
diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs
index 7f55db3b31f..ad95369b9ef 100644
--- a/clippy_utils/src/diagnostics.rs
+++ b/clippy_utils/src/diagnostics.rs
@@ -155,13 +155,7 @@ where
     });
 }
 
-pub fn span_lint_hir(
-    cx: &LateContext<'_>,
-    lint: &'static Lint,
-    hir_id: HirId,
-    sp: Span,
-    msg: &str,
-) {
+pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
     cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
         let mut diag = diag.build(msg);
         docs_link(&mut diag, lint);
diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs
index 730724b95b9..124a00d8178 100644
--- a/clippy_utils/src/eager_or_lazy.rs
+++ b/clippy_utils/src/eager_or_lazy.rs
@@ -45,12 +45,7 @@ impl ops::BitOrAssign for EagernessSuggestion {
 }
 
 /// Determine the eagerness of the given function call.
-fn fn_eagerness<'tcx>(
-    cx: &LateContext<'tcx>,
-    fn_id: DefId,
-    name: Symbol,
-    args: &'tcx [Expr<'_>],
-) -> EagernessSuggestion {
+fn fn_eagerness<'tcx>(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion {
     use EagernessSuggestion::{Eager, Lazy, NoChange};
     let name = name.as_str();
 
@@ -59,7 +54,7 @@ fn fn_eagerness<'tcx>(
         None => return Lazy,
     };
 
-    if (name.starts_with("as_") || name == "len" || name == "is_empty") && args.len() == 1 {
+    if (name.starts_with("as_") || name == "len" || name == "is_empty") && have_one_arg {
         if matches!(
             cx.tcx.crate_name(fn_id.krate),
             sym::std | sym::core | sym::alloc | sym::proc_macro
@@ -127,10 +122,11 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                     },
                     Res::Def(_, id) => match path {
                         QPath::Resolved(_, p) => {
-                            self.eagerness |= fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, args);
+                            self.eagerness |=
+                                fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, !args.is_empty());
                         },
                         QPath::TypeRelative(_, name) => {
-                            self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, args);
+                            self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, !args.is_empty());
                         },
                         QPath::LangItem(..) => self.eagerness = Lazy,
                     },
@@ -141,12 +137,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                     self.eagerness |= NoChange;
                     return;
                 },
-                ExprKind::MethodCall(name, args, _) => {
+                ExprKind::MethodCall(name, ..) => {
                     self.eagerness |= self
                         .cx
                         .typeck_results()
                         .type_dependent_def_id(e.hir_id)
-                        .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, args));
+                        .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, true));
                 },
                 ExprKind::Index(_, e) => {
                     let ty = self.cx.typeck_results().expr_ty_adjusted(e);
diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs
index 1834e2a2de8..6cb6544df4b 100644
--- a/clippy_utils/src/hir_utils.rs
+++ b/clippy_utils/src/hir_utils.rs
@@ -282,8 +282,14 @@ impl HirEqInterExpr<'_, '_, '_> {
                             && self.eq_expr(l.body, r.body)
                     })
             },
-            (&ExprKind::MethodCall(l_path, l_args, _), &ExprKind::MethodCall(r_path, r_args, _)) => {
-                self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
+            (
+                &ExprKind::MethodCall(l_path, l_receiver, l_args, _),
+                &ExprKind::MethodCall(r_path, r_receiver, r_args, _),
+            ) => {
+                self.inner.allow_side_effects
+                    && self.eq_path_segment(l_path, r_path)
+                    && self.eq_expr(l_receiver, r_receiver)
+                    && self.eq_exprs(l_args, r_args)
             },
             (&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => {
                 self.eq_expr(le, re) && self.eq_array_length(ll, rl)
@@ -743,8 +749,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
 
                 s.hash(&mut self.s);
             },
-            ExprKind::MethodCall(path, args, ref _fn_span) => {
+            ExprKind::MethodCall(path, receiver, args, ref _fn_span) => {
                 self.hash_name(path.ident.name);
+                self.hash_expr(receiver);
                 self.hash_exprs(args);
             },
             ExprKind::ConstBlock(ref l_id) => {
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index f3a08e98688..ed1f8af989f 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -1036,21 +1036,21 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'
 pub fn method_calls<'tcx>(
     expr: &'tcx Expr<'tcx>,
     max_depth: usize,
-) -> (Vec<Symbol>, Vec<&'tcx [Expr<'tcx>]>, Vec<Span>) {
+) -> (Vec<Symbol>, Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>, Vec<Span>) {
     let mut method_names = Vec::with_capacity(max_depth);
     let mut arg_lists = Vec::with_capacity(max_depth);
     let mut spans = Vec::with_capacity(max_depth);
 
     let mut current = expr;
     for _ in 0..max_depth {
-        if let ExprKind::MethodCall(path, args, _) = &current.kind {
-            if args.iter().any(|e| e.span.from_expansion()) {
+        if let ExprKind::MethodCall(path, receiver, args, _) = &current.kind {
+            if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
                 break;
             }
             method_names.push(path.ident.name);
-            arg_lists.push(&**args);
+            arg_lists.push((*receiver, &**args));
             spans.push(path.ident.span);
-            current = &args[0];
+            current = receiver;
         } else {
             break;
         }
@@ -1065,18 +1065,18 @@ pub fn method_calls<'tcx>(
 /// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
 /// containing the `Expr`s for
 /// `.bar()` and `.baz()`
-pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<&'a [Expr<'a>]>> {
+pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<(&'a Expr<'a>, &'a [Expr<'a>])>> {
     let mut current = expr;
     let mut matched = Vec::with_capacity(methods.len());
     for method_name in methods.iter().rev() {
         // method chains are stored last -> first
-        if let ExprKind::MethodCall(path, args, _) = current.kind {
+        if let ExprKind::MethodCall(path, receiver, args, _) = current.kind {
             if path.ident.name.as_str() == *method_name {
-                if args.iter().any(|e| e.span.from_expansion()) {
+                if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) {
                     return None;
                 }
-                matched.push(args); // build up `matched` backwards
-                current = &args[0]; // go to parent expression
+                matched.push((receiver, args)); // build up `matched` backwards
+                current = receiver; // go to parent expression
             } else {
                 return None;
             }
@@ -1239,8 +1239,10 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>(
                                     ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(())
                                 })
                             },
-                            ExprKind::MethodCall(_, args, _) => {
-                                let i = args.iter().position(|arg| arg.hir_id == id)?;
+                            ExprKind::MethodCall(_, receiver, args, _) => {
+                                let i = std::iter::once(receiver)
+                                    .chain(args.iter())
+                                    .position(|arg| arg.hir_id == id)?;
                                 let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
                                 let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
                                 ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(())
diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs
index 649b7b9940a..0226f74906b 100644
--- a/clippy_utils/src/ptr.rs
+++ b/clippy_utils/src/ptr.rs
@@ -36,7 +36,7 @@ fn extract_clone_suggestions<'tcx>(
         if abort {
             return false;
         }
-        if let ExprKind::MethodCall(seg, [recv], _) = expr.kind {
+        if let ExprKind::MethodCall(seg, recv, [], _) = expr.kind {
             if path_to_local_id(recv, id) {
                 if seg.ident.name.as_str() == "capacity" {
                     abort = true;
diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs
index 081c98e2f3c..cca71bbf76e 100644
--- a/clippy_utils/src/sugg.rs
+++ b/clippy_utils/src/sugg.rs
@@ -373,12 +373,14 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
         | AssocOp::LessEqual
         | AssocOp::NotEqual
         | AssocOp::Greater
-        | AssocOp::GreaterEqual => format!(
-            "{} {} {}",
-            lhs,
-            op.to_ast_binop().expect("Those are AST ops").to_string(),
-            rhs
-        ),
+        | AssocOp::GreaterEqual => {
+            format!(
+                "{} {} {}",
+                lhs,
+                op.to_ast_binop().expect("Those are AST ops").to_string(),
+                rhs
+            )
+        },
         AssocOp::Assign => format!("{} = {}", lhs, rhs),
         AssocOp::AssignOp(op) => {
             format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs)
@@ -868,15 +870,15 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
     /// indicates whether the function from `parent_expr` takes its args by double reference
     fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool {
         let ty = match parent_expr.kind {
-            ExprKind::MethodCall(_, call_args, _) => {
+            ExprKind::MethodCall(_, receiver, call_args, _) => {
                 if let Some(sig) = self
                     .cx
                     .typeck_results()
                     .type_dependent_def_id(parent_expr.hir_id)
                     .map(|did| self.cx.tcx.fn_sig(did).skip_binder())
                 {
-                    call_args
-                        .iter()
+                    std::iter::once(receiver)
+                        .chain(call_args.iter())
                         .position(|arg| arg.hir_id == cmt_hir_id)
                         .map(|i| sig.inputs()[i])
                 } else {
@@ -933,14 +935,14 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
                     match &parent_expr.kind {
                         // given expression is the self argument and will be handled completely by the compiler
                         // i.e.: `|x| x.is_something()`
-                        ExprKind::MethodCall(_, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => {
+                        ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => {
                             let _ = write!(self.suggestion_start, "{}{}", start_snip, ident_str_with_proj);
                             self.next_pos = span.hi();
                             return;
                         },
                         // item is used in a call
                         // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)`
-                        ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, [_, call_args @ ..], _) => {
+                        ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [call_args @ ..], _) => {
                             let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id);
                             let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind();
 
diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs
index bae8ad9f565..6a62002a4d1 100644
--- a/clippy_utils/src/visitors.rs
+++ b/clippy_utils/src/visitors.rs
@@ -620,7 +620,13 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
                     helper(typeck, true, arg, f)?;
                 }
             },
-            ExprKind::MethodCall(_, args, _) | ExprKind::Tup(args) | ExprKind::Array(args) => {
+            ExprKind::MethodCall(_, receiver, args, _) => {
+                helper(typeck, true, receiver, f)?;
+                for arg in args {
+                    helper(typeck, true, arg, f)?;
+                }
+            },
+            ExprKind::Tup(args) | ExprKind::Array(args) => {
                 for arg in args {
                     helper(typeck, true, arg, f)?;
                 }
diff --git a/tests/ui/author/struct.stdout b/tests/ui/author/struct.stdout
index 5e78b7c9de7..b5bbc9e213c 100644
--- a/tests/ui/author/struct.stdout
+++ b/tests/ui/author/struct.stdout
@@ -53,11 +53,11 @@ if_chain! {
     }
 }
 if_chain! {
-    if let ExprKind::MethodCall(method_name, args, _) = expr.kind;
+    if let ExprKind::MethodCall(method_name, receiver, args, _) = expr.kind;
     if method_name.ident.as_str() == "test";
-    if args.len() == 1;
-    if let ExprKind::Path(ref qpath) = args[0].kind;
+    if let ExprKind::Path(ref qpath) = receiver.kind;
     if match_qpath(qpath, &["test_method_call"]);
+    if args.is_empty();
     then {
         // report your lint here
     }

From 097ef517fedd6c1c9ab4d35309b83e6b62ab703c Mon Sep 17 00:00:00 2001
From: Takayuki Maeda <takoyaki0316@gmail.com>
Date: Fri, 2 Sep 2022 22:48:14 +0900
Subject: [PATCH 24/34] refactor: remove unnecessary variables

---
 clippy_lints/src/dereference.rs              | 94 ++++++++++----------
 clippy_lints/src/infinite_iter.rs            | 10 +--
 clippy_lints/src/len_zero.rs                 |  7 +-
 clippy_lints/src/methods/clone_on_copy.rs    |  5 +-
 clippy_lints/src/methods/clone_on_ref_ptr.rs |  5 +-
 clippy_lints/src/methods/mod.rs              | 10 +--
 clippy_lints/src/minmax.rs                   | 10 +--
 clippy_lints/src/unused_peekable.rs          |  2 +-
 8 files changed, 67 insertions(+), 76 deletions(-)

diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index fd6ed36cb19..6ee9e2e9754 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -798,57 +798,55 @@ fn walk_parents<'tcx>(
                     }),
                 ExprKind::MethodCall(_, receiver, args, _) => {
                     let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
-                    std::iter::once(receiver)
-                        .chain(args.iter())
+                    if receiver.hir_id == child_id {
+                        // Check for calls to trait methods where the trait is implemented on a reference.
+                        // Two cases need to be handled:
+                        // * `self` methods on `&T` will never have auto-borrow
+                        // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
+                        //   priority.
+                        if e.hir_id != child_id {
+                            return Some(Position::ReborrowStable(precedence))
+                        } else if let Some(trait_id) = cx.tcx.trait_of_item(id)
+                            && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
+                            && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
+                            && let subs = match cx
+                                .typeck_results()
+                                .node_substs_opt(parent.hir_id)
+                                .and_then(|subs| subs.get(1..))
+                            {
+                                Some(subs) => cx.tcx.mk_substs(subs.iter().copied()),
+                                None => cx.tcx.mk_substs(std::iter::empty::<ty::subst::GenericArg<'_>>()),
+                            } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
+                                // Trait methods taking `&self`
+                                sub_ty
+                            } else {
+                                // Trait methods taking `self`
+                                arg_ty
+                            } && impl_ty.is_ref()
+                            && cx.tcx.infer_ctxt().enter(|infcx|
+                                infcx
+                                    .type_implements_trait(trait_id, impl_ty, subs, cx.param_env)
+                                    .must_apply_modulo_regions()
+                            )
+                        {
+                            return Some(Position::MethodReceiverRefImpl)
+                        } else {
+                            return Some(Position::MethodReceiver)
+                        }
+                    }
+                    args.iter()
                         .position(|arg| arg.hir_id == child_id)
                         .map(|i| {
-                            if i == 0 {
-                                // Check for calls to trait methods where the trait is implemented on a reference.
-                                // Two cases need to be handled:
-                                // * `self` methods on `&T` will never have auto-borrow
-                                // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
-                                //   priority.
-                                if e.hir_id != child_id {
-                                Position::ReborrowStable(precedence)
-                            } else if let Some(trait_id) = cx.tcx.trait_of_item(id)
-                                && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
-                                && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
-                                && let subs = match cx
-                                    .typeck_results()
-                                    .node_substs_opt(parent.hir_id)
-                                    .and_then(|subs| subs.get(1..))
-                                {
-                                    Some(subs) => cx.tcx.mk_substs(subs.iter().copied()),
-                                    None => cx.tcx.mk_substs(std::iter::empty::<ty::subst::GenericArg<'_>>()),
-                                } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() {
-                                    // Trait methods taking `&self`
-                                    sub_ty
-                                } else {
-                                    // Trait methods taking `self`
-                                    arg_ty
-                                } && impl_ty.is_ref()
-                                && cx.tcx.infer_ctxt().enter(|infcx|
-                                    infcx
-                                        .type_implements_trait(trait_id, impl_ty, subs, cx.param_env)
-                                        .must_apply_modulo_regions()
+                            let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
+                            if let ty::Param(param_ty) = ty.kind() {
+                                needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv)
+                            } else {
+                                ty_auto_deref_stability(
+                                    cx,
+                                    cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)),
+                                    precedence,
                                 )
-                            {
-                                Position::MethodReceiverRefImpl
-                            } else {
-                                Position::MethodReceiver
-                            }
-                            } else {
-                                let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i];
-                                if let ty::Param(param_ty) = ty.kind() {
-                                    needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv)
-                                } else {
-                                    ty_auto_deref_stability(
-                                        cx,
-                                        cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
-                                        precedence,
-                                    )
-                                    .position_for_arg()
-                                }
+                                .position_for_arg()
                             }
                         })
                 },
diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs
index fca3cb46a2e..d55a8e1ead1 100644
--- a/clippy_lints/src/infinite_iter.rs
+++ b/clippy_lints/src/infinite_iter.rs
@@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter {
             MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"),
             Finite => {
                 return;
-            },
+            }
         };
         span_lint(cx, lint, expr.span, msg);
     }
@@ -229,11 +229,9 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                     return MaybeInfinite.and(is_infinite(cx, receiver));
                 }
             }
-            if method.ident.name == sym!(last) {
-                let not_double_ended = cx
-                    .tcx
-                    .get_diagnostic_item(sym::DoubleEndedIterator)
-                    .map_or(false, |id| {
+            if method.ident.name == sym!(last) && args.is_empty() {
+                let not_double_ended =
+                    cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator).map_or(false, |id| {
                         !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[])
                     });
                 if not_double_ended {
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index 25f366bfe6a..3cbdaff407b 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -370,7 +370,7 @@ fn check_for_is_empty<'tcx>(
 }
 
 fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
-    if let (&ExprKind::MethodCall(method_path, receiver, ..), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
+    if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) {
         // check if we are in an is_empty() method
         if let Some(name) = get_item_name(cx, method) {
             if name.as_str() == "is_empty" {
@@ -378,7 +378,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
             }
         }
 
-        check_len(cx, span, method_path.ident.name, receiver, &lit.node, op, compare_to);
+        check_len(cx, span, method_path.ident.name, receiver, args, &lit.node, op, compare_to);
     } else {
         check_empty_expr(cx, span, method, lit, op);
     }
@@ -389,6 +389,7 @@ fn check_len(
     span: Span,
     method_name: Symbol,
     receiver: &Expr<'_>,
+    args: &[Expr<'_>],
     lit: &LitKind,
     op: &str,
     compare_to: u32,
@@ -399,7 +400,7 @@ fn check_len(
             return;
         }
 
-        if method_name == sym::len && has_is_empty(cx, receiver) {
+        if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) {
             let mut applicability = Applicability::MachineApplicable;
             span_lint_and_sugg(
                 cx,
diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs
index 9ae6297ec2f..25a9e6dafea 100644
--- a/clippy_lints/src/methods/clone_on_copy.rs
+++ b/clippy_lints/src/methods/clone_on_copy.rs
@@ -21,10 +21,7 @@ pub(super) fn check(
     receiver: &Expr<'_>,
     args: &[Expr<'_>],
 ) {
-    let arg = match args {
-        [] if method_name == sym::clone => receiver,
-        _ => return,
-    };
+    let arg = if method_name == sym::clone && args.is_empty() { receiver } else { return };
     if cx
         .typeck_results()
         .type_dependent_def_id(expr.hir_id)
diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs
index 7098d564cfc..f82ca891200 100644
--- a/clippy_lints/src/methods/clone_on_ref_ptr.rs
+++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs
@@ -20,8 +20,7 @@ pub(super) fn check(
     if !(args.is_empty() && method_name == sym::clone) {
         return;
     }
-    let arg = receiver;
-    let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs();
+    let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
 
     if let ty::Adt(_, subst) = obj_ty.kind() {
         let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
@@ -34,7 +33,7 @@ pub(super) fn check(
             return;
         };
 
-        let snippet = snippet_with_macro_callsite(cx, arg.span, "..");
+        let snippet = snippet_with_macro_callsite(cx, receiver.span, "..");
 
         span_lint_and_sugg(
             cx,
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 16fdd36c026..fc9ba15d82a 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -3381,7 +3381,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 impl Methods {
     #[allow(clippy::too_many_lines)]
     fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let Some((name, recv, [args @ ..], span)) = method_call(expr) {
+        if let Some((name, recv, args, span)) = method_call(expr) {
             match (name, args) {
                 ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
                     zst_offset::check(cx, expr, recv);
@@ -3485,7 +3485,7 @@ impl Methods {
                     }
                 },
                 ("last", []) | ("skip", [_]) => {
-                    if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) {
+                    if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
                         if let ("cloned", []) = (name2, args2) {
                             iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
                         }
@@ -3500,7 +3500,7 @@ impl Methods {
                     } else {
                         map_err_ignore::check(cx, expr, m_arg);
                     }
-                    if let Some((name, recv2, [args @ ..], span2)) = method_call(recv) {
+                    if let Some((name, recv2, args, span2)) = method_call(recv) {
                         match (name, args) {
                             ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
                             ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
@@ -3520,7 +3520,7 @@ impl Methods {
                     manual_ok_or::check(cx, expr, recv, def, map);
                 },
                 ("next", []) => {
-                    if let Some((name2, recv2, [args2 @ ..], _)) = method_call(recv) {
+                    if let Some((name2, recv2, args2, _)) = method_call(recv) {
                         match (name2, args2) {
                             ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
                             ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
@@ -3593,7 +3593,7 @@ impl Methods {
                 },
                 ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
                 ("take", [_arg]) => {
-                    if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) {
+                    if let Some((name2, recv2, args2, _span2)) = method_call(recv) {
                         if let ("cloned", []) = (name2, args2) {
                             iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
                         }
diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs
index c618f6b5d92..44b21e7b080 100644
--- a/clippy_lints/src/minmax.rs
+++ b/clippy_lints/src/minmax.rs
@@ -109,14 +109,12 @@ fn fetch_const<'a>(
     args: &'a [Expr<'a>],
     m: MinMax,
 ) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
-    if (receiver.is_some() && args.len() != 1) || (receiver.is_none() && args.len() != 2) {
+    let mut args = receiver.into_iter().chain(args.into_iter());
+    let arg0 = args.next()?;
+    let arg1 = args.next()?;
+    if args.next().is_some() {
         return None;
     }
-    let (arg0, arg1) = if let Some(receiver) = receiver {
-        (receiver, &args[0])
-    } else {
-        (&args[0], &args[1])
-    };
     constant_simple(cx, cx.typeck_results(), arg0).map_or_else(
         || constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)),
         |c| {
diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs
index 7fbfecf96ec..cfc181e435b 100644
--- a/clippy_lints/src/unused_peekable.rs
+++ b/clippy_lints/src/unused_peekable.rs
@@ -150,7 +150,7 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> {
                                     ..
                                 },
                                 self_arg,
-                                [remaining_args @ ..],
+                                remaining_args,
                                 _,
                             ) => {
                                 let method_name = method_name_ident.name.as_str();

From 8931da40e304f071d01ed59a312561a7d0a6e024 Mon Sep 17 00:00:00 2001
From: Takayuki Maeda <takoyaki0316@gmail.com>
Date: Mon, 5 Sep 2022 14:26:00 +0900
Subject: [PATCH 25/34] use `propagate_through_exprs` instead of
 `propagate_through_expr`

fix `ExprKind` static_assert_size

fix hir-stats
---
 clippy_lints/src/eta_reduction.rs | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index 1c0a93c71fd..1342a4697b9 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -206,12 +206,8 @@ fn check_inputs(
             _ => false,
         }
     };
-    if let Some(receiver) = receiver {
-        std::iter::zip(params, std::iter::once(receiver).chain(call_args.iter()))
-            .all(|(param, arg)| check_inputs(param, arg))
-    } else {
-        std::iter::zip(params, call_args).all(|(param, arg)| check_inputs(param, arg))
-    }
+    std::iter::zip(params, receiver.into_iter().chain(call_args.iter()))
+        .all(|(param, arg)| check_inputs(param, arg))
 }
 
 fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {

From b21d9d307b5fdb1e423d786f9899757b42957b07 Mon Sep 17 00:00:00 2001
From: xphoniex <xphoniex@users.noreply.github.com>
Date: Tue, 6 Sep 2022 04:38:29 +0000
Subject: [PATCH 26/34] Suggest `unwrap_or_default` when closure returns
 `"".to_string`

Signed-off-by: xphoniex <xphoniex@users.noreply.github.com>
---
 .../src/methods/unwrap_or_else_default.rs     | 24 +++++++++++++++++--
 tests/ui/unwrap_or_else_default.fixed         |  3 +++
 tests/ui/unwrap_or_else_default.rs            |  3 +++
 tests/ui/unwrap_or_else_default.stderr        |  8 ++++++-
 4 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs
index f3af281d6ca..d3630b7d08e 100644
--- a/clippy_lints/src/methods/unwrap_or_else_default.rs
+++ b/clippy_lints/src/methods/unwrap_or_else_default.rs
@@ -5,10 +5,11 @@ use clippy_utils::{
     diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability,
     ty::is_type_diagnostic_item,
 };
+use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_span::{sym, symbol};
 
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
@@ -25,7 +26,7 @@ pub(super) fn check<'tcx>(
 
     if_chain! {
         if is_option || is_result;
-        if is_default_equivalent_call(cx, u_arg);
+        if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg);
         then {
             let mut applicability = Applicability::MachineApplicable;
 
@@ -44,3 +45,22 @@ pub(super) fn check<'tcx>(
         }
     }
 }
+
+fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
+    if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
+        let body = cx.tcx.hir().body(body);
+
+        if body.params.is_empty()
+            && let hir::Expr{ kind, .. } = &body.value
+            && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, [self_arg], _) = kind
+            && ident == &symbol::Ident::from_str("to_string")
+            && let hir::Expr{ kind, .. } = self_arg
+            && let hir::ExprKind::Lit(lit) = kind
+            && let LitKind::Str(symbol::kw::Empty, _) = lit.node
+        {
+            return true;
+        }
+    }
+
+    false
+}
diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed
index c2b9bd2c881..84f779569ff 100644
--- a/tests/ui/unwrap_or_else_default.fixed
+++ b/tests/ui/unwrap_or_else_default.fixed
@@ -69,6 +69,9 @@ fn unwrap_or_else_default() {
 
     let with_default_type: Option<Vec<u64>> = None;
     with_default_type.unwrap_or_default();
+
+    let empty_string = None::<String>;
+    empty_string.unwrap_or_default();
 }
 
 fn main() {}
diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs
index d55664990ae..1735bd5808e 100644
--- a/tests/ui/unwrap_or_else_default.rs
+++ b/tests/ui/unwrap_or_else_default.rs
@@ -69,6 +69,9 @@ fn unwrap_or_else_default() {
 
     let with_default_type: Option<Vec<u64>> = None;
     with_default_type.unwrap_or_else(Vec::new);
+
+    let empty_string = None::<String>;
+    empty_string.unwrap_or_else(|| "".to_string());
 }
 
 fn main() {}
diff --git a/tests/ui/unwrap_or_else_default.stderr b/tests/ui/unwrap_or_else_default.stderr
index 53e31d85edf..d2b9212223f 100644
--- a/tests/ui/unwrap_or_else_default.stderr
+++ b/tests/ui/unwrap_or_else_default.stderr
@@ -30,5 +30,11 @@ error: use of `.unwrap_or_else(..)` to construct default value
 LL |     with_default_type.unwrap_or_else(Vec::new);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
 
-error: aborting due to 5 previous errors
+error: use of `.unwrap_or_else(..)` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:74:5
+   |
+LL |     empty_string.unwrap_or_else(|| "".to_string());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()`
+
+error: aborting due to 6 previous errors
 

From e1b3483ee807716e579324f0d107b5365e81d30f Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Thu, 30 Jun 2022 08:16:05 +0000
Subject: [PATCH 27/34] Lower the assume intrinsic to a MIR statement

---
 clippy_utils/src/qualify_min_const_fn.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs
index 74c222bbcbe..1c12da7f741 100644
--- a/clippy_utils/src/qualify_min_const_fn.rs
+++ b/clippy_utils/src/qualify_min_const_fn.rs
@@ -211,6 +211,9 @@ fn check_statement<'tcx>(
         StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
             check_place(tcx, **place, span, body)
         },
+        StatementKind::Assume(box op) => {
+            check_operand(tcx, op, span, body)
+        },
 
         StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
             check_operand(tcx, dst, span, body)?;

From 9cbbd4a80e2bb633c6cfc53a3e9cb08b1910ce5f Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Tue, 12 Jul 2022 10:05:00 +0000
Subject: [PATCH 28/34] Generalize the Assume intrinsic statement to a general
 Intrinsic statement

---
 clippy_utils/src/qualify_min_const_fn.rs | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs
index 1c12da7f741..b22a9c81746 100644
--- a/clippy_utils/src/qualify_min_const_fn.rs
+++ b/clippy_utils/src/qualify_min_const_fn.rs
@@ -7,7 +7,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::{
     Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
-    TerminatorKind,
+    TerminatorKind, NonDivergingIntrinsic
 };
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
@@ -211,15 +211,19 @@ fn check_statement<'tcx>(
         StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
             check_place(tcx, **place, span, body)
         },
-        StatementKind::Assume(box op) => {
+
+        StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
             check_operand(tcx, op, span, body)
         },
 
-        StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
+        StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+            rustc_middle::mir::CopyNonOverlapping { dst, src, count },
+        )) => {
             check_operand(tcx, dst, span, body)?;
             check_operand(tcx, src, span, body)?;
             check_operand(tcx, count, span, body)
         },
+
         // These are all NOPs
         StatementKind::StorageLive(_)
         | StatementKind::StorageDead(_)

From 0d078c9fd6881a011713d810773aec03e17d793f Mon Sep 17 00:00:00 2001
From: Caio <c410.f3r@gmail.com>
Date: Wed, 7 Sep 2022 10:00:45 -0300
Subject: [PATCH 29/34] [Arithmetic] Consider literals

---
 clippy_lints/src/operators/arithmetic.rs | 118 +++++++++++++++++------
 clippy_lints/src/operators/mod.rs        |  22 +++--
 src/docs/arithmetic.txt                  |  21 ++--
 tests/ui/arithmetic.fixed                |  27 ------
 tests/ui/arithmetic.rs                   |  38 +++++++-
 tests/ui/arithmetic.stderr               |  22 +++++
 6 files changed, 168 insertions(+), 80 deletions(-)
 delete mode 100644 tests/ui/arithmetic.fixed
 create mode 100644 tests/ui/arithmetic.stderr

diff --git a/clippy_lints/src/operators/arithmetic.rs b/clippy_lints/src/operators/arithmetic.rs
index 800cf249f5c..27eef92deef 100644
--- a/clippy_lints/src/operators/arithmetic.rs
+++ b/clippy_lints/src/operators/arithmetic.rs
@@ -5,13 +5,21 @@
 
 use super::ARITHMETIC;
 use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
+use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty;
 use rustc_session::impl_lint_pass;
-use rustc_span::source_map::Span;
+use rustc_span::source_map::{Span, Spanned};
 
-const HARD_CODED_ALLOWED: &[&str] = &["std::num::Saturating", "std::string::String", "std::num::Wrapping"];
+const HARD_CODED_ALLOWED: &[&str] = &[
+    "f32",
+    "f64",
+    "std::num::Saturating",
+    "std::string::String",
+    "std::num::Wrapping",
+];
 
 #[derive(Debug)]
 pub struct Arithmetic {
@@ -34,6 +42,27 @@ impl Arithmetic {
         }
     }
 
+    /// Checks assign operators (+=, -=, *=, /=) of integers in a non-constant environment that
+    /// won't overflow.
+    fn has_valid_assign_op(op: &Spanned<hir::BinOpKind>, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool {
+        if !Self::is_literal_integer(rhs, rhs_refs) {
+            return false;
+        }
+        if let hir::BinOpKind::Div | hir::BinOpKind::Mul = op.node
+            && let hir::ExprKind::Lit(ref lit) = rhs.kind
+            && let ast::LitKind::Int(1, _) = lit.node
+        {
+            return true;
+        }
+        false
+    }
+
+    /// Checks "raw" binary operators (+, -, *, /) of integers in a non-constant environment
+    /// already handled by the CTFE.
+    fn has_valid_bin_op(lhs: &hir::Expr<'_>, lhs_refs: Ty<'_>, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool {
+        Self::is_literal_integer(lhs, lhs_refs) && Self::is_literal_integer(rhs, rhs_refs)
+    }
+
     /// Checks if the given `expr` has any of the inner `allowed` elements.
     fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
         self.allowed.contains(
@@ -46,40 +75,66 @@ impl Arithmetic {
         )
     }
 
+    /// Explicit integers like `1` or `i32::MAX`. Does not take into consideration references.
+    fn is_literal_integer(expr: &hir::Expr<'_>, expr_refs: Ty<'_>) -> bool {
+        let is_integral = expr_refs.is_integral();
+        let is_literal = matches!(expr.kind, hir::ExprKind::Lit(_));
+        is_integral && is_literal
+    }
+
     fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
         span_lint(cx, ARITHMETIC, expr.span, "arithmetic detected");
         self.expr_span = Some(expr.span);
     }
+
+    /// Manages when the lint should be triggered. Operations in constant environments, hard coded
+    /// types, custom allowed types and non-constant operations that won't overflow are ignored.
+    fn manage_bin_ops(
+        &mut self,
+        cx: &LateContext<'_>,
+        expr: &hir::Expr<'_>,
+        op: &Spanned<hir::BinOpKind>,
+        lhs: &hir::Expr<'_>,
+        rhs: &hir::Expr<'_>,
+    ) {
+        if constant_simple(cx, cx.typeck_results(), expr).is_some() {
+            return;
+        }
+        if !matches!(
+            op.node,
+            hir::BinOpKind::Add
+                | hir::BinOpKind::Sub
+                | hir::BinOpKind::Mul
+                | hir::BinOpKind::Div
+                | hir::BinOpKind::Rem
+                | hir::BinOpKind::Shl
+                | hir::BinOpKind::Shr
+        ) {
+            return;
+        };
+        if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) {
+            return;
+        }
+        let lhs_refs = cx.typeck_results().expr_ty(lhs).peel_refs();
+        let rhs_refs = cx.typeck_results().expr_ty(rhs).peel_refs();
+        let has_valid_assign_op = Self::has_valid_assign_op(op, rhs, rhs_refs);
+        if has_valid_assign_op || Self::has_valid_bin_op(lhs, lhs_refs, rhs, rhs_refs) {
+            return;
+        }
+        self.issue_lint(cx, expr);
+    }
 }
 
 impl<'tcx> LateLintPass<'tcx> for Arithmetic {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if self.expr_span.is_some() {
-            return;
-        }
-        if let Some(span) = self.const_span && span.contains(expr.span) {
+        if self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) {
             return;
         }
         match &expr.kind {
             hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => {
-                let (
-                    hir::BinOpKind::Add
-                    | hir::BinOpKind::Sub
-                    | hir::BinOpKind::Mul
-                    | hir::BinOpKind::Div
-                    | hir::BinOpKind::Rem
-                    | hir::BinOpKind::Shl
-                    | hir::BinOpKind::Shr
-                ) = op.node else {
-                    return;
-                };
-                if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) {
-                    return;
-                }
-                self.issue_lint(cx, expr);
+                self.manage_bin_ops(cx, expr, op, lhs, rhs);
             },
             hir::ExprKind::Unary(hir::UnOp::Neg, _) => {
-                // CTFE already takes care of things like `-1` that do not overflow.
                 if constant_simple(cx, cx.typeck_results(), expr).is_none() {
                     self.issue_lint(cx, expr);
                 }
@@ -89,16 +144,15 @@ impl<'tcx> LateLintPass<'tcx> for Arithmetic {
     }
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
-        let body_owner = cx.tcx.hir().body_owner_def_id(body.id());
-        match cx.tcx.hir().body_owner_kind(body_owner) {
-            hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
-                let body_span = cx.tcx.def_span(body_owner);
-                if let Some(span) = self.const_span && span.contains(body_span) {
-                    return;
-                }
-                self.const_span = Some(body_span);
-            },
-            hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {},
+        let body_owner = cx.tcx.hir().body_owner(body.id());
+        let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner);
+        let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
+        if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind {
+            let body_span = cx.tcx.hir().span_with_body(body_owner);
+            if let Some(span) = self.const_span && span.contains(body_span) {
+                return;
+            }
+            self.const_span = Some(body_span);
         }
     }
 
diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs
index bb6d99406b4..c7b0633b79c 100644
--- a/clippy_lints/src/operators/mod.rs
+++ b/clippy_lints/src/operators/mod.rs
@@ -61,25 +61,29 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for any kind of arithmetic operation of any type.
+    /// Checks any kind of arithmetic operation of any type.
     ///
     /// Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
     /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
-    /// or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered
-    /// away.
+    /// or can panic (`/`, `%`).
+    ///
+    /// Known safe built-in types like `Wrapping` or `Saturing`, floats, operations in constant
+    /// environments, allowed types and non-constant operations that won't overflow are ignored.
     ///
     /// ### 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.
+    /// For integers, overflow will trigger a panic in debug builds or wrap the result in
+    /// release mode; division by zero will cause a panic in either mode. As a result, it is
+    /// desirable to explicitly call checked, wrapping or saturating arithmetic methods.
     ///
     /// #### Example
     /// ```rust
-    /// # let a = 0;
-    /// a + 1;
+    /// // `n` can be any number, including `i32::MAX`.
+    /// fn foo(n: i32) -> i32 {
+    ///   n + 1
+    /// }
     /// ```
     ///
-    /// Third-party types also tend to overflow.
+    /// Third-party types can also overflow or present unwanted side-effects.
     ///
     /// #### Example
     /// ```ignore,rust
diff --git a/src/docs/arithmetic.txt b/src/docs/arithmetic.txt
index 0b3f07d9505..f04125060fb 100644
--- a/src/docs/arithmetic.txt
+++ b/src/docs/arithmetic.txt
@@ -1,22 +1,27 @@
 ### What it does
-Checks for any kind of arithmetic operation of any type.
+Checks any kind of arithmetic operation of any type.
 
 Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
 Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
-or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered
-away.
+or can panic (`/`, `%`).
+
+Known safe built-in types like `Wrapping` or `Saturing`, floats, operations in constant
+environments, allowed types and non-constant operations that won't overflow are ignored.
 
 ### 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.
+For integers, overflow will trigger a panic in debug builds or wrap the result in
+release mode; division by zero will cause a panic in either mode. As a result, it is
+desirable to explicitly call checked, wrapping or saturating arithmetic methods.
 
 #### Example
 ```
-a + 1;
+// `n` can be any number, including `i32::MAX`.
+fn foo(n: i32) -> i32 {
+  n + 1
+}
 ```
 
-Third-party types also tend to overflow.
+Third-party types can also overflow or present unwanted side-effects.
 
 #### Example
 ```
diff --git a/tests/ui/arithmetic.fixed b/tests/ui/arithmetic.fixed
deleted file mode 100644
index a2a1c4394c2..00000000000
--- a/tests/ui/arithmetic.fixed
+++ /dev/null
@@ -1,27 +0,0 @@
-// run-rustfix
-
-#![allow(clippy::unnecessary_owned_empty_strings)]
-#![feature(saturating_int_impl)]
-#![warn(clippy::arithmetic)]
-
-use core::num::{Saturating, Wrapping};
-
-pub fn hard_coded_allowed() {
-    let _ = Saturating(0u32) + Saturating(0u32);
-    let _ = String::new() + "";
-    let _ = Wrapping(0u32) + Wrapping(0u32);
-
-    let saturating: Saturating<u32> = Saturating(0u32);
-    let string: String = String::new();
-    let wrapping: Wrapping<u32> = Wrapping(0u32);
-
-    let inferred_saturating = saturating + saturating;
-    let inferred_string = string + "";
-    let inferred_wrapping = wrapping + wrapping;
-
-    let _ = inferred_saturating + inferred_saturating;
-    let _ = inferred_string + "";
-    let _ = inferred_wrapping + inferred_wrapping;
-}
-
-fn main() {}
diff --git a/tests/ui/arithmetic.rs b/tests/ui/arithmetic.rs
index a2a1c4394c2..a9ac46e9a19 100644
--- a/tests/ui/arithmetic.rs
+++ b/tests/ui/arithmetic.rs
@@ -1,12 +1,13 @@
-// run-rustfix
-
-#![allow(clippy::unnecessary_owned_empty_strings)]
-#![feature(saturating_int_impl)]
+#![allow(clippy::assign_op_pattern, clippy::unnecessary_owned_empty_strings)]
+#![feature(inline_const, saturating_int_impl)]
 #![warn(clippy::arithmetic)]
 
 use core::num::{Saturating, Wrapping};
 
 pub fn hard_coded_allowed() {
+    let _ = 1f32 + 1f32;
+    let _ = 1f64 + 1f64;
+
     let _ = Saturating(0u32) + Saturating(0u32);
     let _ = String::new() + "";
     let _ = Wrapping(0u32) + Wrapping(0u32);
@@ -24,4 +25,33 @@ pub fn hard_coded_allowed() {
     let _ = inferred_wrapping + inferred_wrapping;
 }
 
+#[rustfmt::skip]
+pub fn non_overflowing_ops() {
+    const _: i32 = { let mut n = 1; n += 1; n };
+    let _ = const { let mut n = 1; n += 1; n };
+
+    const _: i32 = { let mut n = 1; n = n + 1; n };
+    let _ = const { let mut n = 1; n = n + 1; n };
+
+    const _: i32 = { let mut n = 1; n = 1 + n; n };
+    let _ = const { let mut n = 1; n = 1 + n; n };
+
+    const _: i32 = 1 + 1;
+    let _ = 1 + 1;
+    let _ = const { 1 + 1 };
+
+    let mut _a = 1;
+    _a *= 1;
+    _a /= 1;
+}
+
+#[rustfmt::skip]
+pub fn overflowing_ops() {
+    let mut _a = 1; _a += 1;
+
+    let mut _b = 1; _b = _b + 1;
+
+    let mut _c = 1; _c = 1 + _c;
+}
+
 fn main() {}
diff --git a/tests/ui/arithmetic.stderr b/tests/ui/arithmetic.stderr
new file mode 100644
index 00000000000..a51cf6ba600
--- /dev/null
+++ b/tests/ui/arithmetic.stderr
@@ -0,0 +1,22 @@
+error: arithmetic detected
+  --> $DIR/arithmetic.rs:50:21
+   |
+LL |     let mut _a = 1; _a += 1;
+   |                     ^^^^^^^
+   |
+   = note: `-D clippy::arithmetic` implied by `-D warnings`
+
+error: arithmetic detected
+  --> $DIR/arithmetic.rs:52:26
+   |
+LL |     let mut _b = 1; _b = _b + 1;
+   |                          ^^^^^^
+
+error: arithmetic detected
+  --> $DIR/arithmetic.rs:54:26
+   |
+LL |     let mut _c = 1; _c = 1 + _c;
+   |                          ^^^^^^
+
+error: aborting due to 3 previous errors
+

From 15859323ea424b4fb9556d9d45c8b5d374e57f9e Mon Sep 17 00:00:00 2001
From: Jason Newcomb <jsnewcomb@pm.me>
Date: Wed, 7 Sep 2022 15:26:44 -0400
Subject: [PATCH 30/34] Fix hang in `vec_init_then_push`

---
 clippy_lints/src/vec_init_then_push.rs | 2 +-
 tests/ui/vec_init_then_push.rs         | 6 ++++++
 tests/ui/vec_init_then_push.stderr     | 9 ++++++++-
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs
index 35db45e2b0c..d77a21d668e 100644
--- a/clippy_lints/src/vec_init_then_push.rs
+++ b/clippy_lints/src/vec_init_then_push.rs
@@ -86,7 +86,7 @@ impl VecPushSearcher {
                 },
                 ExprKind::Unary(UnOp::Deref, _) | ExprKind::Index(..) if !needs_mut => {
                     let mut last_place = parent;
-                    while let Some(parent) = get_parent_expr(cx, parent) {
+                    while let Some(parent) = get_parent_expr(cx, last_place) {
                         if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..))
                             || matches!(parent.kind, ExprKind::Index(e, _) if e.hir_id == last_place.hir_id)
                         {
diff --git a/tests/ui/vec_init_then_push.rs b/tests/ui/vec_init_then_push.rs
index 531745424a7..8dd098a5b54 100644
--- a/tests/ui/vec_init_then_push.rs
+++ b/tests/ui/vec_init_then_push.rs
@@ -104,3 +104,9 @@ fn _cond_push_with_large_start(x: bool) -> Vec<u32> {
 
     v2
 }
+
+fn f() {
+    let mut v = Vec::new();
+    v.push((0i32, 0i32));
+    let y = v[0].0.abs();
+}
diff --git a/tests/ui/vec_init_then_push.stderr b/tests/ui/vec_init_then_push.stderr
index 50b029fc337..a9da1c52019 100644
--- a/tests/ui/vec_init_then_push.stderr
+++ b/tests/ui/vec_init_then_push.stderr
@@ -62,5 +62,12 @@ LL | |     v2.push(1);
 LL | |     v2.push(0);
    | |_______________^ help: consider using the `vec![]` macro: `let mut v2 = vec![..];`
 
-error: aborting due to 7 previous errors
+error: calls to `push` immediately after creation
+  --> $DIR/vec_init_then_push.rs:109:5
+   |
+LL | /     let mut v = Vec::new();
+LL | |     v.push((0i32, 0i32));
+   | |_________________________^ help: consider using the `vec![]` macro: `let v = vec![..];`
+
+error: aborting due to 8 previous errors
 

From 51d8b6c6643abb048987bd0befdeb6f46db0f6b5 Mon Sep 17 00:00:00 2001
From: Caio <c410.f3r@gmail.com>
Date: Thu, 8 Sep 2022 12:04:55 -0300
Subject: [PATCH 31/34] Rename the `arithmetic` lint

---
 CHANGELOG.md                                         |  2 +-
 clippy_lints/src/lib.register_lints.rs               |  2 +-
 clippy_lints/src/lib.register_restriction.rs         |  2 +-
 clippy_lints/src/lib.rs                              |  8 ++++++--
 .../{arithmetic.rs => arithmetic_side_effects.rs}    | 12 ++++++------
 clippy_lints/src/operators/mod.rs                    | 10 +++++-----
 clippy_lints/src/utils/conf.rs                       |  2 +-
 src/docs.rs                                          |  2 +-
 .../{arithmetic.txt => arithmetic_side_effects.txt}  |  2 +-
 tests/ui-toml/arithmetic_allowed/clippy.toml         |  1 -
 .../arithmetic_side_effects_allowed.rs}              |  2 +-
 .../arithmetic_side_effects_allowed/clippy.toml      |  1 +
 .../ui-toml/toml_unknown_key/conf_unknown_key.stderr |  2 +-
 .../ui/{arithmetic.rs => arithmetic_side_effects.rs} |  2 +-
 ...thmetic.stderr => arithmetic_side_effects.stderr} |  8 ++++----
 15 files changed, 31 insertions(+), 27 deletions(-)
 rename clippy_lints/src/operators/{arithmetic.rs => arithmetic_side_effects.rs} (95%)
 rename src/docs/{arithmetic.txt => arithmetic_side_effects.txt} (91%)
 delete mode 100644 tests/ui-toml/arithmetic_allowed/clippy.toml
 rename tests/ui-toml/{arithmetic_allowed/arithmetic_allowed.rs => arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs} (89%)
 create mode 100644 tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml
 rename tests/ui/{arithmetic.rs => arithmetic_side_effects.rs} (97%)
 rename tests/ui/{arithmetic.stderr => arithmetic_side_effects.stderr} (63%)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 257add86b6e..d847e4c7494 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3583,7 +3583,7 @@ Released 2018-09-13
 [`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range
 [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
 [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
-[`arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic
+[`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects
 [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
 [`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore
 [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index 13b573beea1..962e6722006 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -437,7 +437,7 @@ store.register_lints(&[
     octal_escapes::OCTAL_ESCAPES,
     only_used_in_recursion::ONLY_USED_IN_RECURSION,
     operators::ABSURD_EXTREME_COMPARISONS,
-    operators::ARITHMETIC,
+    operators::ARITHMETIC_SIDE_EFFECTS,
     operators::ASSIGN_OP_PATTERN,
     operators::BAD_BIT_MASK,
     operators::CMP_NAN,
diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs
index dd1e1e1a8e3..6eb9b3d3b9b 100644
--- a/clippy_lints/src/lib.register_restriction.rs
+++ b/clippy_lints/src/lib.register_restriction.rs
@@ -50,7 +50,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION),
     LintId::of(module_style::MOD_MODULE_FILES),
     LintId::of(module_style::SELF_NAMED_MODULE_FILES),
-    LintId::of(operators::ARITHMETIC),
+    LintId::of(operators::ARITHMETIC_SIDE_EFFECTS),
     LintId::of(operators::FLOAT_ARITHMETIC),
     LintId::of(operators::FLOAT_CMP_CONST),
     LintId::of(operators::INTEGER_ARITHMETIC),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index a26e129f094..7633bf347c3 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -544,8 +544,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         store.register_late_pass(|| Box::new(utils::internal_lints::MsrvAttrImpl));
     }
 
-    let arithmetic_allowed = conf.arithmetic_allowed.clone();
-    store.register_late_pass(move || Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone())));
+    let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone();
+    store.register_late_pass(move || {
+        Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(
+            arithmetic_side_effects_allowed.clone(),
+        ))
+    });
     store.register_late_pass(|| Box::new(utils::dump_hir::DumpHir));
     store.register_late_pass(|| Box::new(utils::author::Author));
     let await_holding_invalid_types = conf.await_holding_invalid_types.clone();
diff --git a/clippy_lints/src/operators/arithmetic.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs
similarity index 95%
rename from clippy_lints/src/operators/arithmetic.rs
rename to clippy_lints/src/operators/arithmetic_side_effects.rs
index 27eef92deef..83b69fbb311 100644
--- a/clippy_lints/src/operators/arithmetic.rs
+++ b/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -3,7 +3,7 @@
     clippy::match_same_arms
 )]
 
-use super::ARITHMETIC;
+use super::ARITHMETIC_SIDE_EFFECTS;
 use clippy_utils::{consts::constant_simple, diagnostics::span_lint};
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashSet;
@@ -22,16 +22,16 @@ const HARD_CODED_ALLOWED: &[&str] = &[
 ];
 
 #[derive(Debug)]
-pub struct Arithmetic {
+pub struct ArithmeticSideEffects {
     allowed: FxHashSet<String>,
     // Used to check whether expressions are constants, such as in enum discriminants and consts
     const_span: Option<Span>,
     expr_span: Option<Span>,
 }
 
-impl_lint_pass!(Arithmetic => [ARITHMETIC]);
+impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]);
 
-impl Arithmetic {
+impl ArithmeticSideEffects {
     #[must_use]
     pub fn new(mut allowed: FxHashSet<String>) -> Self {
         allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from));
@@ -83,7 +83,7 @@ impl Arithmetic {
     }
 
     fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
-        span_lint(cx, ARITHMETIC, expr.span, "arithmetic detected");
+        span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, "arithmetic detected");
         self.expr_span = Some(expr.span);
     }
 
@@ -125,7 +125,7 @@ impl Arithmetic {
     }
 }
 
-impl<'tcx> LateLintPass<'tcx> for Arithmetic {
+impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) {
             return;
diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs
index c7b0633b79c..c32b4df4f75 100644
--- a/clippy_lints/src/operators/mod.rs
+++ b/clippy_lints/src/operators/mod.rs
@@ -21,7 +21,7 @@ mod ptr_eq;
 mod self_assignment;
 mod verbose_bit_mask;
 
-pub(crate) mod arithmetic;
+pub(crate) mod arithmetic_side_effects;
 
 use rustc_hir::{Body, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
@@ -92,11 +92,11 @@ declare_clippy_lint! {
     /// ```
     ///
     /// ### Allowed types
-    /// Custom allowed types can be specified through the "arithmetic-allowed" filter.
+    /// Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter.
     #[clippy::version = "1.64.0"]
-    pub ARITHMETIC,
+    pub ARITHMETIC_SIDE_EFFECTS,
     restriction,
-    "any arithmetic expression that could overflow or panic"
+    "any arithmetic expression that can cause side effects like overflows or panics"
 }
 
 declare_clippy_lint! {
@@ -789,7 +789,7 @@ pub struct Operators {
 }
 impl_lint_pass!(Operators => [
     ABSURD_EXTREME_COMPARISONS,
-    ARITHMETIC,
+    ARITHMETIC_SIDE_EFFECTS,
     INTEGER_ARITHMETIC,
     FLOAT_ARITHMETIC,
     ASSIGN_OP_PATTERN,
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 84e65d5fa0b..a8500beb257 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -208,7 +208,7 @@ define_Conf! {
     /// Lint: Arithmetic.
     ///
     /// Suppress checking of the passed type names.
-    (arithmetic_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
+    (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
     /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
diff --git a/src/docs.rs b/src/docs.rs
index 69243bf4d9c..f3a5048e7fa 100644
--- a/src/docs.rs
+++ b/src/docs.rs
@@ -26,7 +26,7 @@ docs! {
     "almost_complete_letter_range",
     "almost_swapped",
     "approx_constant",
-    "arithmetic",
+    "arithmetic_side_effects",
     "as_conversions",
     "as_underscore",
     "assertions_on_constants",
diff --git a/src/docs/arithmetic.txt b/src/docs/arithmetic_side_effects.txt
similarity index 91%
rename from src/docs/arithmetic.txt
rename to src/docs/arithmetic_side_effects.txt
index f04125060fb..6c7d51a4989 100644
--- a/src/docs/arithmetic.txt
+++ b/src/docs/arithmetic_side_effects.txt
@@ -30,4 +30,4 @@ let _n = Decimal::MAX + Decimal::MAX;
 ```
 
 ### Allowed types
-Custom allowed types can be specified through the "arithmetic-allowed" filter.
\ No newline at end of file
+Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter.
\ No newline at end of file
diff --git a/tests/ui-toml/arithmetic_allowed/clippy.toml b/tests/ui-toml/arithmetic_allowed/clippy.toml
deleted file mode 100644
index cc40570b12a..00000000000
--- a/tests/ui-toml/arithmetic_allowed/clippy.toml
+++ /dev/null
@@ -1 +0,0 @@
-arithmetic-allowed = ["Point"]
diff --git a/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
similarity index 89%
rename from tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs
rename to tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
index 195fabdbf71..1aed09b7c7b 100644
--- a/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs
+++ b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::arithmetic)]
+#![warn(clippy::arithmetic_side_effects)]
 
 use core::ops::Add;
 
diff --git a/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml b/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml
new file mode 100644
index 00000000000..e736256f29a
--- /dev/null
+++ b/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml
@@ -0,0 +1 @@
+arithmetic-side-effects-allowed = ["Point"]
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 a52a0b5289f..f27f78d15d3 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -3,7 +3,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            allow-expect-in-tests
            allow-unwrap-in-tests
            allowed-scripts
-           arithmetic-allowed
+           arithmetic-side-effects-allowed
            array-size-threshold
            avoid-breaking-exported-api
            await-holding-invalid-types
diff --git a/tests/ui/arithmetic.rs b/tests/ui/arithmetic_side_effects.rs
similarity index 97%
rename from tests/ui/arithmetic.rs
rename to tests/ui/arithmetic_side_effects.rs
index a9ac46e9a19..f5390c74642 100644
--- a/tests/ui/arithmetic.rs
+++ b/tests/ui/arithmetic_side_effects.rs
@@ -1,6 +1,6 @@
 #![allow(clippy::assign_op_pattern, clippy::unnecessary_owned_empty_strings)]
 #![feature(inline_const, saturating_int_impl)]
-#![warn(clippy::arithmetic)]
+#![warn(clippy::arithmetic_side_effects)]
 
 use core::num::{Saturating, Wrapping};
 
diff --git a/tests/ui/arithmetic.stderr b/tests/ui/arithmetic_side_effects.stderr
similarity index 63%
rename from tests/ui/arithmetic.stderr
rename to tests/ui/arithmetic_side_effects.stderr
index a51cf6ba600..6c4c8bdec0f 100644
--- a/tests/ui/arithmetic.stderr
+++ b/tests/ui/arithmetic_side_effects.stderr
@@ -1,19 +1,19 @@
 error: arithmetic detected
-  --> $DIR/arithmetic.rs:50:21
+  --> $DIR/arithmetic_side_effects.rs:50:21
    |
 LL |     let mut _a = 1; _a += 1;
    |                     ^^^^^^^
    |
-   = note: `-D clippy::arithmetic` implied by `-D warnings`
+   = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
 
 error: arithmetic detected
-  --> $DIR/arithmetic.rs:52:26
+  --> $DIR/arithmetic_side_effects.rs:52:26
    |
 LL |     let mut _b = 1; _b = _b + 1;
    |                          ^^^^^^
 
 error: arithmetic detected
-  --> $DIR/arithmetic.rs:54:26
+  --> $DIR/arithmetic_side_effects.rs:54:26
    |
 LL |     let mut _c = 1; _c = 1 + _c;
    |                          ^^^^^^

From 2c5524f835ccd163dd3de9bd39b2cdc21337bf9c Mon Sep 17 00:00:00 2001
From: Alex Macleod <alex@macleod.io>
Date: Thu, 8 Sep 2022 15:29:26 +0000
Subject: [PATCH 32/34] Update cargo in lintcheck_crates.toml

---
 lintcheck/lintcheck_crates.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lintcheck/lintcheck_crates.toml b/lintcheck/lintcheck_crates.toml
index 4fbae8614ca..ebbe9c9ae67 100644
--- a/lintcheck/lintcheck_crates.toml
+++ b/lintcheck/lintcheck_crates.toml
@@ -1,6 +1,6 @@
 [crates]
 # some of these are from cargotest
-cargo = {name = "cargo", versions = ['0.49.0']}
+cargo = {name = "cargo", versions = ['0.64.0']}
 iron = {name = "iron", versions = ['0.6.1']}
 ripgrep = {name = "ripgrep", versions = ['12.1.1']}
 xsv = {name = "xsv", versions = ['0.13.0']}

From a6d8afd958e35cb0f424de8be11c42116133e23a Mon Sep 17 00:00:00 2001
From: Michael Wright <mikerite@lavabit.com>
Date: Thu, 8 Sep 2022 20:04:43 +0200
Subject: [PATCH 33/34] Fix `range_{plus,minus}_one` bad suggestions

Fixes #9431.

The current `range_plus_one` and `range_minus_one` suggestions
are completely incorrect when macros are involved.

This commit resolves this by disabling the lints for any range
expression that is expanded from a macro. The reasons for this
are that it is very difficult to create a correct suggestion in
this case and that false negatives are less important for
pedantic lints.
---
 clippy_lints/src/ranges.rs           | 11 +++--------
 tests/ui/range_plus_minus_one.fixed  | 19 +++++++++++++++++++
 tests/ui/range_plus_minus_one.rs     | 19 +++++++++++++++++++
 tests/ui/range_plus_minus_one.stderr | 18 +++++++++---------
 4 files changed, 50 insertions(+), 17 deletions(-)

diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs
index 490f345d297..918d624eec6 100644
--- a/clippy_lints/src/ranges.rs
+++ b/clippy_lints/src/ranges.rs
@@ -350,6 +350,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R
 // exclusive range plus one: `x..(y+1)`
 fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
+        if expr.span.can_be_used_for_suggestions();
         if let Some(higher::Range {
             start,
             end: Some(end),
@@ -357,14 +358,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
         }) = higher::Range::hir(expr);
         if let Some(y) = y_plus_one(cx, end);
         then {
-            let span = if expr.span.from_expansion() {
-                expr.span
-                    .ctxt()
-                    .outer_expn_data()
-                    .call_site
-            } else {
-                expr.span
-            };
+            let span = expr.span;
             span_lint_and_then(
                 cx,
                 RANGE_PLUS_ONE,
@@ -399,6 +393,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
 // inclusive range minus one: `x..=(y-1)`
 fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
+        if expr.span.can_be_used_for_suggestions();
         if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::Range::hir(expr);
         if let Some(y) = y_minus_one(cx, end);
         then {
diff --git a/tests/ui/range_plus_minus_one.fixed b/tests/ui/range_plus_minus_one.fixed
index 40d7791df28..a16a3e54d45 100644
--- a/tests/ui/range_plus_minus_one.fixed
+++ b/tests/ui/range_plus_minus_one.fixed
@@ -6,6 +6,22 @@ fn f() -> usize {
     42
 }
 
+macro_rules! macro_plus_one {
+    ($m: literal) => {
+        for i in 0..$m + 1 {
+            println!("{}", i);
+        }
+    };
+}
+
+macro_rules! macro_minus_one {
+    ($m: literal) => {
+        for i in 0..=$m - 1 {
+            println!("{}", i);
+        }
+    };
+}
+
 #[warn(clippy::range_plus_one)]
 #[warn(clippy::range_minus_one)]
 fn main() {
@@ -39,4 +55,7 @@ fn main() {
 
     let mut vec: Vec<()> = std::vec::Vec::new();
     vec.drain(..);
+
+    macro_plus_one!(5);
+    macro_minus_one!(5);
 }
diff --git a/tests/ui/range_plus_minus_one.rs b/tests/ui/range_plus_minus_one.rs
index a8ddd9b5f75..bd6cb4d21be 100644
--- a/tests/ui/range_plus_minus_one.rs
+++ b/tests/ui/range_plus_minus_one.rs
@@ -6,6 +6,22 @@ fn f() -> usize {
     42
 }
 
+macro_rules! macro_plus_one {
+    ($m: literal) => {
+        for i in 0..$m + 1 {
+            println!("{}", i);
+        }
+    };
+}
+
+macro_rules! macro_minus_one {
+    ($m: literal) => {
+        for i in 0..=$m - 1 {
+            println!("{}", i);
+        }
+    };
+}
+
 #[warn(clippy::range_plus_one)]
 #[warn(clippy::range_minus_one)]
 fn main() {
@@ -39,4 +55,7 @@ fn main() {
 
     let mut vec: Vec<()> = std::vec::Vec::new();
     vec.drain(..);
+
+    macro_plus_one!(5);
+    macro_minus_one!(5);
 }
diff --git a/tests/ui/range_plus_minus_one.stderr b/tests/ui/range_plus_minus_one.stderr
index fb4f1658597..0223696243b 100644
--- a/tests/ui/range_plus_minus_one.stderr
+++ b/tests/ui/range_plus_minus_one.stderr
@@ -1,5 +1,5 @@
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:15:14
+  --> $DIR/range_plus_minus_one.rs:31:14
    |
 LL |     for _ in 0..3 + 1 {}
    |              ^^^^^^^^ help: use: `0..=3`
@@ -7,25 +7,25 @@ LL |     for _ in 0..3 + 1 {}
    = note: `-D clippy::range-plus-one` implied by `-D warnings`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:18:14
+  --> $DIR/range_plus_minus_one.rs:34:14
    |
 LL |     for _ in 0..1 + 5 {}
    |              ^^^^^^^^ help: use: `0..=5`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:21:14
+  --> $DIR/range_plus_minus_one.rs:37:14
    |
 LL |     for _ in 1..1 + 1 {}
    |              ^^^^^^^^ help: use: `1..=1`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:27:14
+  --> $DIR/range_plus_minus_one.rs:43:14
    |
 LL |     for _ in 0..(1 + f()) {}
    |              ^^^^^^^^^^^^ help: use: `0..=f()`
 
 error: an exclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:31:13
+  --> $DIR/range_plus_minus_one.rs:47:13
    |
 LL |     let _ = ..=11 - 1;
    |             ^^^^^^^^^ help: use: `..11`
@@ -33,25 +33,25 @@ LL |     let _ = ..=11 - 1;
    = note: `-D clippy::range-minus-one` implied by `-D warnings`
 
 error: an exclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:32:13
+  --> $DIR/range_plus_minus_one.rs:48:13
    |
 LL |     let _ = ..=(11 - 1);
    |             ^^^^^^^^^^^ help: use: `..11`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:33:13
+  --> $DIR/range_plus_minus_one.rs:49:13
    |
 LL |     let _ = (1..11 + 1);
    |             ^^^^^^^^^^^ help: use: `(1..=11)`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:34:13
+  --> $DIR/range_plus_minus_one.rs:50:13
    |
 LL |     let _ = (f() + 1)..(f() + 1);
    |             ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())`
 
 error: an inclusive range would be more readable
-  --> $DIR/range_plus_minus_one.rs:38:14
+  --> $DIR/range_plus_minus_one.rs:54:14
    |
 LL |     for _ in 1..ONE + ONE {}
    |              ^^^^^^^^^^^^ help: use: `1..=ONE`

From df536c9086471c1484c29d904aff9091d762e151 Mon Sep 17 00:00:00 2001
From: Philipp Krones <hello@philkrones.com>
Date: Thu, 8 Sep 2022 21:27:37 +0200
Subject: [PATCH 34/34] Bump nightly version -> 2022-09-08

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

diff --git a/rust-toolchain b/rust-toolchain
index 85b60fefd60..b6976366daf 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-08-27"
+channel = "nightly-2022-09-08"
 components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]