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] 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()