about summary refs log tree commit diff
diff options
context:
space:
mode:
authorflip1995 <hello@philkrones.com>2022-10-23 15:18:45 +0200
committerflip1995 <hello@philkrones.com>2022-10-23 15:18:45 +0200
commitda9755b6ba108b04eb9dfc771d0a6dd2f86f911b (patch)
tree047004632ca9dee93a27bc5e0d5fa63b4c990966
parente64f1110c062f61746f222059439529a43ccf6dc (diff)
parent4f142aa1058f14f153f8bfd2d82f04ddb9982388 (diff)
downloadrust-da9755b6ba108b04eb9dfc771d0a6dd2f86f911b.tar.gz
rust-da9755b6ba108b04eb9dfc771d0a6dd2f86f911b.zip
Merge commit '4f142aa1058f14f153f8bfd2d82f04ddb9982388' into clippyup
-rw-r--r--src/tools/clippy/.github/workflows/clippy.yml1
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml1
-rw-r--r--src/tools/clippy/.github/workflows/clippy_dev.yml2
-rw-r--r--src/tools/clippy/CHANGELOG.md6
-rw-r--r--src/tools/clippy/CONTRIBUTING.md2
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md23
-rw-r--r--src/tools/clippy/book/src/development/basics.md7
-rw-r--r--src/tools/clippy/clippy_dev/src/serve.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/setup/intellij.rs17
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs96
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs57
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/comparison_chain.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs65
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_methods.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs165
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs176
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_all.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_complexity.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_internal.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_lints.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_nursery.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_restriction.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_style.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_filter.rs153
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_map.rs318
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs277
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs40
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_trait_methods.rs98
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/partial_pub_fields.rs81
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs454
-rw-r--r--src/tools/clippy/clippy_lints/src/ref_option_ref.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/utils.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/types/rc_buffer.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs117
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs1576
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs245
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs77
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs164
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs239
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs108
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs342
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs63
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs343
-rw-r--r--src/tools/clippy/clippy_utils/src/attrs.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs44
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs48
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs43
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs52
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/mod.rs164
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs241
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_origin.rs59
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs29
-rw-r--r--src/tools/clippy/clippy_utils/src/numeric_literal.rs7
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs36
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs13
-rw-r--r--src/tools/clippy/lintcheck/src/config.rs5
-rw-r--r--src/tools/clippy/lintcheck/src/driver.rs2
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs162
-rw-r--r--src/tools/clippy/lintcheck/src/recursive.rs8
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/docs.rs6
-rw-r--r--src/tools/clippy/src/docs/as_ptr_cast_mut.txt19
-rw-r--r--src/tools/clippy/src/docs/box_default.txt6
-rw-r--r--src/tools/clippy/src/docs/cast_nan_to_int.txt15
-rw-r--r--src/tools/clippy/src/docs/manual_filter.txt21
-rw-r--r--src/tools/clippy/src/docs/missing_trait_methods.txt40
-rw-r--r--src/tools/clippy/src/docs/partial_pub_fields.txt27
-rw-r--r--src/tools/clippy/src/docs/unused_format_specs.txt24
-rw-r--r--src/tools/clippy/tests/compile-test.rs2
-rw-r--r--src/tools/clippy/tests/dogfood.rs9
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.stderr2
-rw-r--r--src/tools/clippy/tests/ui-internal/invalid_paths.rs2
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed6
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs6
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs16
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr27
-rw-r--r--src/tools/clippy/tests/ui/as_ptr_cast_mut.rs37
-rw-r--r--src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr16
-rw-r--r--src/tools/clippy/tests/ui/author.stdout24
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.stdout116
-rw-r--r--src/tools/clippy/tests/ui/author/call.stdout28
-rw-r--r--src/tools/clippy/tests/ui/author/if.stdout92
-rw-r--r--src/tools/clippy/tests/ui/author/issue_3849.stdout24
-rw-r--r--src/tools/clippy/tests/ui/author/loop.stdout202
-rw-r--r--src/tools/clippy/tests/ui/author/matches.stdout72
-rw-r--r--src/tools/clippy/tests/ui/author/repeat.stdout20
-rw-r--r--src/tools/clippy/tests/ui/author/struct.stdout112
-rw-r--r--src/tools/clippy/tests/ui/box_default.fixed57
-rw-r--r--src/tools/clippy/tests/ui/box_default.rs28
-rw-r--r--src/tools/clippy/tests/ui/box_default.stderr83
-rw-r--r--src/tools/clippy/tests/ui/box_default_no_std.rs33
-rw-r--r--src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed18
-rw-r--r--src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs18
-rw-r--r--src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr42
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_bool.fixed13
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_bool.rs13
-rw-r--r--src/tools/clippy/tests/ui/cast_lossless_bool.stderr34
-rw-r--r--src/tools/clippy/tests/ui/cast_nan_to_int.rs18
-rw-r--r--src/tools/clippy/tests/ui/cast_nan_to_int.stderr51
-rw-r--r--src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed16
-rw-r--r--src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs16
-rw-r--r--src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr8
-rw-r--r--src/tools/clippy/tests/ui/checked_conversions.fixed16
-rw-r--r--src/tools/clippy/tests/ui/checked_conversions.rs16
-rw-r--r--src/tools/clippy/tests/ui/checked_conversions.stderr40
-rw-r--r--src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed24
-rw-r--r--src/tools/clippy/tests/ui/cloned_instead_of_copied.rs24
-rw-r--r--src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr30
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match.rs21
-rw-r--r--src/tools/clippy/tests/ui/collapsible_match.stderr34
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9625.rs4
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed9
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs9
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr34
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed10
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs10
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr34
-rw-r--r--src/tools/clippy/tests/ui/err_expect.fixed17
-rw-r--r--src/tools/clippy/tests/ui/err_expect.rs17
-rw-r--r--src/tools/clippy/tests/ui/err_expect.stderr10
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next_fixable.fixed16
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next_fixable.rs16
-rw-r--r--src/tools/clippy/tests/ui/filter_map_next_fixable.stderr10
-rw-r--r--src/tools/clippy/tests/ui/format_args.fixed3
-rw-r--r--src/tools/clippy/tests/ui/format_args.rs3
-rw-r--r--src/tools/clippy/tests/ui/format_args.stderr60
-rw-r--r--src/tools/clippy/tests/ui/from_over_into.fixed87
-rw-r--r--src/tools/clippy/tests/ui/from_over_into.rs66
-rw-r--r--src/tools/clippy/tests/ui/from_over_into.stderr70
-rw-r--r--src/tools/clippy/tests/ui/from_over_into_unfixable.rs35
-rw-r--r--src/tools/clippy/tests/ui/from_over_into_unfixable.stderr29
-rw-r--r--src/tools/clippy/tests/ui/implicit_saturating_sub.fixed50
-rw-r--r--src/tools/clippy/tests/ui/implicit_saturating_sub.rs50
-rw-r--r--src/tools/clippy/tests/ui/implicit_saturating_sub.stderr46
-rw-r--r--src/tools/clippy/tests/ui/literals.rs7
-rw-r--r--src/tools/clippy/tests/ui/literals.stderr35
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.fixed39
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.stderr67
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2021.fixed4
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.rs4
-rw-r--r--src/tools/clippy/tests/ui/manual_clamp.rs27
-rw-r--r--src/tools/clippy/tests/ui/manual_clamp.stderr85
-rw-r--r--src/tools/clippy/tests/ui/manual_filter.fixed119
-rw-r--r--src/tools/clippy/tests/ui/manual_filter.rs243
-rw-r--r--src/tools/clippy/tests/ui/manual_filter.stderr191
-rw-r--r--src/tools/clippy/tests/ui/manual_rem_euclid.fixed30
-rw-r--r--src/tools/clippy/tests/ui/manual_rem_euclid.rs30
-rw-r--r--src/tools/clippy/tests/ui/manual_rem_euclid.stderr30
-rw-r--r--src/tools/clippy/tests/ui/manual_strip.rs19
-rw-r--r--src/tools/clippy/tests/ui/manual_strip.stderr47
-rw-r--r--src/tools/clippy/tests/ui/map_unwrap_or.rs20
-rw-r--r--src/tools/clippy/tests/ui/map_unwrap_or.stderr30
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed16
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs19
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr38
-rw-r--r--src/tools/clippy/tests/ui/match_overlapping_arm.rs1
-rw-r--r--src/tools/clippy/tests/ui/match_overlapping_arm.stderr32
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.fixed9
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.rs8
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.stderr19
-rw-r--r--src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr35
-rw-r--r--src/tools/clippy/tests/ui/match_wild_err_arm.rs3
-rw-r--r--src/tools/clippy/tests/ui/match_wild_err_arm.stderr (renamed from src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr)8
-rw-r--r--src/tools/clippy/tests/ui/mem_replace.fixed18
-rw-r--r--src/tools/clippy/tests/ui/mem_replace.rs18
-rw-r--r--src/tools/clippy/tests/ui/mem_replace.stderr46
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_attr.rs239
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_attr.stderr46
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs14
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr44
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.rs11
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.stderr38
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_no_patch.rs14
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_outer_attr.rs4
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_outer_attr.stderr8
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs12
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr12
-rw-r--r--src/tools/clippy/tests/ui/missing_trait_methods.rs50
-rw-r--r--src/tools/clippy/tests/ui/missing_trait_methods.stderr27
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed62
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs60
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.stderr96
-rw-r--r--src/tools/clippy/tests/ui/option_as_ref_deref.fixed17
-rw-r--r--src/tools/clippy/tests/ui/option_as_ref_deref.rs17
-rw-r--r--src/tools/clippy/tests/ui/option_as_ref_deref.stderr42
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed11
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs11
-rw-r--r--src/tools/clippy/tests/ui/partial_pub_fields.rs40
-rw-r--r--src/tools/clippy/tests/ui/partial_pub_fields.stderr35
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs30
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.stderr20
-rw-r--r--src/tools/clippy/tests/ui/range_contains.fixed26
-rw-r--r--src/tools/clippy/tests/ui/range_contains.rs26
-rw-r--r--src/tools/clippy/tests/ui/range_contains.stderr48
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.fixed16
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.rs16
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.stderr22
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed13
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.rs13
-rw-r--r--src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr40
-rw-r--r--src/tools/clippy/tests/ui/ref_option_ref.rs5
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args.fixed13
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args.rs13
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args.stderr40
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed29
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.stderr15
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed29
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr51
-rw-r--r--src/tools/clippy/tests/ui/uninlined_format_args_panic.rs29
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.fixed4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.rs4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.fixed2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns.fixed16
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns.rs16
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns.stderr13
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs.fixed18
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs.rs18
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs.stderr54
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs_unfixable.rs30
-rw-r--r--src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr69
-rw-r--r--src/tools/clippy/tests/ui/use_self.fixed33
-rw-r--r--src/tools/clippy/tests/ui/use_self.rs33
-rw-r--r--src/tools/clippy/tests/ui/use_self.stderr90
-rw-r--r--src/tools/clippy/tests/versioncheck.rs2
-rw-r--r--src/tools/clippy/util/gh-pages/index.html6
-rw-r--r--src/tools/clippy/util/gh-pages/script.js15
284 files changed, 8511 insertions, 4206 deletions
diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml
index fac2c99714d..b9921301197 100644
--- a/src/tools/clippy/.github/workflows/clippy.yml
+++ b/src/tools/clippy/.github/workflows/clippy.yml
@@ -25,6 +25,7 @@ env:
   CARGO_TARGET_DIR: '${{ github.workspace }}/target'
   NO_FMT_TEST: 1
   CARGO_INCREMENTAL: 0
+  CARGO_UNSTABLE_SPARSE_REGISTRY: true
 
 jobs:
   base:
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 30607af4901..6448b2d4068 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -11,6 +11,7 @@ env:
   CARGO_TARGET_DIR: '${{ github.workspace }}/target'
   NO_FMT_TEST: 1
   CARGO_INCREMENTAL: 0
+  CARGO_UNSTABLE_SPARSE_REGISTRY: true
 
 defaults:
   run:
diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml
index 22051093c9c..14f20212add 100644
--- a/src/tools/clippy/.github/workflows/clippy_dev.yml
+++ b/src/tools/clippy/.github/workflows/clippy_dev.yml
@@ -15,6 +15,8 @@ on:
 
 env:
   RUST_BACKTRACE: 1
+  CARGO_INCREMENTAL: 0
+  CARGO_UNSTABLE_SPARSE_REGISTRY: true
 
 jobs:
   clippy_dev:
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 42615179f70..2d7bda27e4f 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -3735,6 +3735,7 @@ Released 2018-09-13
 [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
 [`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects
 [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
+[`as_ptr_cast_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_ptr_cast_mut
 [`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore
 [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
 [`assertions_on_result_states`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_result_states
@@ -3772,6 +3773,7 @@ Released 2018-09-13
 [`cast_enum_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_enum_constructor
 [`cast_enum_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_enum_truncation
 [`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless
+[`cast_nan_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_nan_to_int
 [`cast_possible_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_truncation
 [`cast_possible_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_wrap
 [`cast_precision_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_precision_loss
@@ -3988,6 +3990,7 @@ Released 2018-09-13
 [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
 [`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits
 [`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp
+[`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter
 [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
 [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find
 [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
@@ -4046,6 +4049,7 @@ Released 2018-09-13
 [`missing_panics_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc
 [`missing_safety_doc`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_safety_doc
 [`missing_spin_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_spin_loop
+[`missing_trait_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_trait_methods
 [`mistyped_literal_suffixes`]: https://rust-lang.github.io/rust-clippy/master/index.html#mistyped_literal_suffixes
 [`mixed_case_hex_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_case_hex_literals
 [`mixed_read_write_in_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#mixed_read_write_in_expression
@@ -4131,6 +4135,7 @@ Released 2018-09-13
 [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
 [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
+[`partial_pub_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#partial_pub_fields
 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
 [`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
@@ -4312,6 +4317,7 @@ Released 2018-09-13
 [`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice
 [`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async
 [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
+[`unused_format_specs`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_format_specs
 [`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
diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md
index 6c977b2caca..85f94a74ad9 100644
--- a/src/tools/clippy/CONTRIBUTING.md
+++ b/src/tools/clippy/CONTRIBUTING.md
@@ -29,7 +29,7 @@ All contributors are expected to follow the [Rust Code of Conduct].
 
 ## The Clippy book
 
-If you're new to Clippy and don't know where to start the [Clippy book] includes
+If you're new to Clippy and don't know where to start, the [Clippy book] includes
 a [developer guide] and is a good place to start your journey.
 
 [Clippy book]: https://doc.rust-lang.org/nightly/clippy/index.html
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index b1e843bc7f4..3c3f368a529 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -478,8 +478,27 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
 ```
 
 Once the `msrv` is added to the lint, a relevant test case should be added to
-`tests/ui/min_rust_version_attr.rs` which verifies that the lint isn't emitted
-if the project's MSRV is lower.
+the lint's test file, `tests/ui/manual_strip.rs` in this example. It should
+have a case for the version below the MSRV and one with the same contents but
+for the MSRV version itself.
+
+```rust
+#![feature(custom_inner_attributes)]
+
+...
+
+fn msrv_1_44() {
+    #![clippy::msrv = "1.44"]
+
+    /* something that would trigger the lint */
+}
+
+fn msrv_1_45() {
+    #![clippy::msrv = "1.45"]
+
+    /* something that would trigger the lint */
+}
+```
 
 As a last step, the lint should be added to the lint documentation. This is done
 in `clippy_lints/src/utils/conf.rs`:
diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md
index 44ba6e32755..6fb53236e6f 100644
--- a/src/tools/clippy/book/src/development/basics.md
+++ b/src/tools/clippy/book/src/development/basics.md
@@ -69,7 +69,7 @@ the reference file with:
 cargo dev bless
 ```
 
-For example, this is necessary, if you fix a typo in an error message of a lint
+For example, this is necessary if you fix a typo in an error message of a lint,
 or if you modify a test file to add a test case.
 
 > _Note:_ This command may update more files than you intended. In that case
@@ -101,8 +101,9 @@ cargo dev setup intellij
 cargo dev dogfood
 ```
 
-More about intellij command usage and reasons
-[here](https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#intellij-rust)
+More about [intellij] command usage and reasons.
+
+[intellij]: https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#intellij-rust
 
 ## lintcheck
 
diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs
index 2e0794f12fa..535c25e69f1 100644
--- a/src/tools/clippy/clippy_dev/src/serve.rs
+++ b/src/tools/clippy/clippy_dev/src/serve.rs
@@ -49,7 +49,7 @@ fn mtime(path: impl AsRef<Path>) -> SystemTime {
             .into_iter()
             .flatten()
             .flatten()
-            .map(|entry| mtime(&entry.path()))
+            .map(|entry| mtime(entry.path()))
             .max()
             .unwrap_or(SystemTime::UNIX_EPOCH)
     } else {
diff --git a/src/tools/clippy/clippy_dev/src/setup/intellij.rs b/src/tools/clippy/clippy_dev/src/setup/intellij.rs
index b64e79733eb..efdb158c21e 100644
--- a/src/tools/clippy/clippy_dev/src/setup/intellij.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/intellij.rs
@@ -36,9 +36,8 @@ impl ClippyProjectInfo {
 }
 
 pub fn setup_rustc_src(rustc_path: &str) {
-    let rustc_source_dir = match check_and_get_rustc_dir(rustc_path) {
-        Ok(path) => path,
-        Err(_) => return,
+    let Ok(rustc_source_dir) = check_and_get_rustc_dir(rustc_path) else {
+        return
     };
 
     for project in CLIPPY_PROJECTS {
@@ -172,14 +171,10 @@ pub fn remove_rustc_src() {
 }
 
 fn remove_rustc_src_from_project(project: &ClippyProjectInfo) -> bool {
-    let mut cargo_content = if let Ok(content) = read_project_file(project.cargo_file) {
-        content
-    } else {
+    let Ok(mut cargo_content) = read_project_file(project.cargo_file) else {
         return false;
     };
-    let section_start = if let Some(section_start) = cargo_content.find(RUSTC_PATH_SECTION) {
-        section_start
-    } else {
+    let Some(section_start) = cargo_content.find(RUSTC_PATH_SECTION) else {
         println!(
             "info: dependencies could not be found in `{}` for {}, skipping file",
             project.cargo_file, project.name
@@ -187,9 +182,7 @@ fn remove_rustc_src_from_project(project: &ClippyProjectInfo) -> bool {
         return true;
     };
 
-    let end_point = if let Some(end_point) = cargo_content.find(DEPENDENCIES_SECTION) {
-        end_point
-    } else {
+    let Some(end_point) = cargo_content.find(DEPENDENCIES_SECTION) else {
         eprintln!(
             "error: the end of the rustc dependencies section could not be found in `{}`",
             project.cargo_file
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 0eb443167ec..e690bc369cd 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -128,7 +128,7 @@ fn generate_lint_files(
     for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) {
         let content = gen_lint_group_list(&lint_group, lints.iter());
         process_file(
-            &format!("clippy_lints/src/lib.register_{lint_group}.rs"),
+            format!("clippy_lints/src/lib.register_{lint_group}.rs"),
             update_mode,
             &content,
         );
@@ -869,13 +869,11 @@ fn clippy_lints_src_files() -> impl Iterator<Item = (PathBuf, DirEntry)> {
 macro_rules! match_tokens {
     ($iter:ident, $($token:ident $({$($fields:tt)*})? $(($capture:ident))?)*) => {
          {
-            $($(let $capture =)? if let Some(LintDeclSearchResult {
+            $(#[allow(clippy::redundant_pattern)] let Some(LintDeclSearchResult {
                     token_kind: TokenKind::$token $({$($fields)*})?,
-                    content: _x,
+                    content: $($capture @)? _,
                     ..
-            }) = $iter.next() {
-                _x
-            } else {
+            }) = $iter.next() else {
                 continue;
             };)*
             #[allow(clippy::unused_unit)]
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 2a15cbc7a3c..08164c0b654 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
+use clippy_utils::eq_expr_value;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{eq_expr_value, get_trait_def_id, paths};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -483,7 +483,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
 
 fn implements_ord<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
-    get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]))
+    cx.tcx
+        .get_diagnostic_item(sym::Ord)
+        .map_or(false, |id| implements_trait(cx, ty, id, &[]))
 }
 
 struct NotSimplificationVisitor<'a, 'tcx> {
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index 792183ac408..36daceabe0b 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -1,5 +1,12 @@
-use clippy_utils::{diagnostics::span_lint_and_help, is_default_equivalent, path_def_id};
-use rustc_hir::{Expr, ExprKind, QPath};
+use clippy_utils::{
+    diagnostics::span_lint_and_sugg, get_parent_node, is_default_equivalent, macros::macro_backtrace, match_path,
+    path_def_id, paths, ty::expr_sig,
+};
+use rustc_errors::Applicability;
+use rustc_hir::{
+    intravisit::{walk_ty, Visitor},
+    Block, Expr, ExprKind, Local, Node, QPath, TyKind,
+};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -15,12 +22,6 @@ declare_clippy_lint! {
     /// Second, `Box::default()` can be faster
     /// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box).
     ///
-    /// ### Known problems
-    /// The lint may miss some cases (e.g. Box::new(String::from(""))).
-    /// On the other hand, it will trigger on cases where the `default`
-    /// code comes from a macro that does something different based on
-    /// e.g. target operating system.
-    ///
     /// ### Example
     /// ```rust
     /// let x: Box<String> = Box::new(Default::default());
@@ -41,21 +42,88 @@ impl LateLintPass<'_> for BoxDefault {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let ExprKind::Call(box_new, [arg]) = expr.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_new.kind
-            && let ExprKind::Call(..) = arg.kind
+            && let ExprKind::Call(arg_path, ..) = arg.kind
             && !in_external_macro(cx.sess(), expr.span)
-            && expr.span.eq_ctxt(arg.span)
+            && (expr.span.eq_ctxt(arg.span) || is_vec_expn(cx, arg))
             && seg.ident.name == sym::new
-            && path_def_id(cx, ty) == cx.tcx.lang_items().owned_box()
+            && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box())
             && is_default_equivalent(cx, arg)
         {
-            span_lint_and_help(
+            let arg_ty = cx.typeck_results().expr_ty(arg);
+            span_lint_and_sugg(
                 cx,
                 BOX_DEFAULT,
                 expr.span,
                 "`Box::new(_)` of default value",
-                None,
-                "use `Box::default()` instead",
+                "try",
+                if is_plain_default(arg_path) || given_type(cx, expr) {
+                    "Box::default()".into()
+                } else {
+                    format!("Box::<{arg_ty}>::default()")
+                },
+                Applicability::MachineApplicable
             );
         }
     }
 }
+
+fn is_plain_default(arg_path: &Expr<'_>) -> bool {
+    // we need to match the actual path so we don't match e.g. "u8::default"
+    if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind {
+        // avoid generic parameters
+        match_path(path, &paths::DEFAULT_TRAIT_METHOD) && path.segments.iter().all(|seg| seg.args.is_none())
+    } else {
+        false
+    }
+}
+
+fn is_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    macro_backtrace(expr.span)
+        .next()
+        .map_or(false, |call| cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id))
+}
+
+#[derive(Default)]
+struct InferVisitor(bool);
+
+impl<'tcx> Visitor<'tcx> for InferVisitor {
+    fn visit_ty(&mut self, t: &rustc_hir::Ty<'_>) {
+        self.0 |= matches!(t.kind, TyKind::Infer | TyKind::OpaqueDef(..) | TyKind::TraitObject(..));
+        if !self.0 {
+            walk_ty(self, t);
+        }
+    }
+}
+
+fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    match get_parent_node(cx.tcx, expr.hir_id) {
+        Some(Node::Local(Local { ty: Some(ty), .. })) => {
+            let mut v = InferVisitor::default();
+            v.visit_ty(ty);
+            !v.0
+        },
+        Some(
+            Node::Expr(Expr {
+                kind: ExprKind::Call(path, args),
+                ..
+            }) | Node::Block(Block {
+                expr:
+                    Some(Expr {
+                        kind: ExprKind::Call(path, args),
+                        ..
+                    }),
+                ..
+            }),
+        ) => {
+            if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) &&
+                let Some(sig) = expr_sig(cx, path) &&
+                let Some(input) = sig.input(index)
+            {
+                input.no_bound_vars().is_some()
+            } else {
+                false
+            }
+        },
+        _ => false,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
new file mode 100644
index 00000000000..9409f4844f5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
@@ -0,0 +1,38 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_opt;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::{
+    mir::Mutability,
+    ty::{self, Ty, TypeAndMut},
+};
+
+use super::AS_PTR_CAST_MUT;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) {
+    if let ty::RawPtr(ptrty @ TypeAndMut { mutbl: Mutability::Mut, .. }) = cast_to.kind()
+        && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) =
+            cx.typeck_results().node_type(cast_expr.hir_id).kind()
+        && let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind
+        && method_name.ident.name == rustc_span::sym::as_ptr
+        && let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id)
+        && let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did)
+        && let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next()
+        && let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind()
+        && let Some(recv) = snippet_opt(cx, receiver.span)
+    {
+        // `as_mut_ptr` might not exist
+        let applicability = Applicability::MaybeIncorrect;
+
+        span_lint_and_sugg(
+            cx,
+            AS_PTR_CAST_MUT,
+            expr.span,
+            &format!("casting the result of `as_ptr` to *{ptrty}"),
+            "replace with",
+            format!("{recv}.as_mut_ptr()"),
+            applicability
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
new file mode 100644
index 00000000000..322dc41b3a1
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs
@@ -0,0 +1,28 @@
+use super::CAST_NAN_TO_INT;
+
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_note;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, from_ty: Ty<'_>, to_ty: Ty<'_>) {
+    if from_ty.is_floating_point() && to_ty.is_integral() && is_known_nan(cx, cast_expr) {
+        span_lint_and_note(
+            cx,
+            CAST_NAN_TO_INT,
+            expr.span,
+            &format!("casting a known NaN to {to_ty}"),
+            None,
+            "this always evaluates to 0",
+        );
+    }
+}
+
+fn is_known_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+    match constant(cx, cx.typeck_results(), e) {
+        Some((Constant::F64(n), _)) => n.is_nan(),
+        Some((Constant::F32(n), _)) => n.is_nan(),
+        _ => false,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index cc5d346b954..b72c4c772f1 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -1,8 +1,10 @@
+mod as_ptr_cast_mut;
 mod as_underscore;
 mod borrow_as_ptr;
 mod cast_abs_to_unsigned;
 mod cast_enum_constructor;
 mod cast_lossless;
+mod cast_nan_to_int;
 mod cast_possible_truncation;
 mod cast_possible_wrap;
 mod cast_precision_loss;
@@ -569,6 +571,7 @@ declare_clippy_lint! {
     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
@@ -596,6 +599,54 @@ declare_clippy_lint! {
     "casting a slice created from a pointer and length to a slice pointer"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer
+    ///
+    /// ### Why is this bad?
+    /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior
+    /// mutability is used, making it unlikely that having it as a mutable pointer is correct.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let string = String::with_capacity(1);
+    /// let ptr = string.as_ptr() as *mut u8;
+    /// unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let mut string = String::with_capacity(1);
+    /// let ptr = string.as_mut_ptr();
+    /// unsafe { ptr.write(4) };
+    /// ```
+    #[clippy::version = "1.66.0"]
+    pub AS_PTR_CAST_MUT,
+    nursery,
+    "casting the result of the `&self`-taking `as_ptr` to a mutabe pointer"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for a known NaN float being cast to an integer
+    ///
+    /// ### Why is this bad?
+    /// NaNs are cast into zero, so one could simply use this and make the
+    /// code more readable. The lint could also hint at a programmer error.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let _: (0.0_f32 / 0.0) as u64;
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// let _: = 0_u64;
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub CAST_NAN_TO_INT,
+    suspicious,
+    "casting a known floating-point NaN into an integer"
+}
+
 pub struct Casts {
     msrv: Option<RustcVersion>,
 }
@@ -627,7 +678,9 @@ impl_lint_pass!(Casts => [
     CAST_ABS_TO_UNSIGNED,
     AS_UNDERSCORE,
     BORROW_AS_PTR,
-    CAST_SLICE_FROM_RAW_PARTS
+    CAST_SLICE_FROM_RAW_PARTS,
+    AS_PTR_CAST_MUT,
+    CAST_NAN_TO_INT,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -653,6 +706,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
                 return;
             }
             cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, self.msrv);
+            as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
             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);
@@ -664,6 +718,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
                     cast_precision_loss::check(cx, expr, cast_from, cast_to);
                     cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
                     cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
+                    cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
                 }
                 cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
                 cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 21ed7f4844c..c8596987e4d 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -59,9 +59,6 @@ pub(super) fn check<'tcx>(
                 lint_unnecessary_cast(cx, expr, literal_str, cast_from, cast_to);
                 return false;
             },
-            LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) => {
-                return false;
-            },
             LitKind::Int(_, LitIntType::Signed(_) | LitIntType::Unsigned(_))
             | LitKind::Float(_, LitFloatType::Suffixed(_))
                 if cast_from.kind() == cast_to.kind() =>
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index a05b41eb3ab..0fe973b49a3 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -1,9 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_trait_def_id, if_sequence, in_constant, is_else_clause, paths, SpanlessEq};
+use clippy_utils::{if_sequence, in_constant, is_else_clause, SpanlessEq};
 use rustc_hir::{BinOpKind, 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
@@ -106,7 +107,10 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
 
                 // Check that the type being compared implements `core::cmp::Ord`
                 let ty = cx.typeck_results().expr_ty(lhs1);
-                let is_ord = get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[]));
+                let is_ord = cx
+                    .tcx
+                    .get_diagnostic_item(sym::Ord)
+                    .map_or(false, |id| implements_trait(cx, ty, id, &[]));
 
                 if !is_ord {
                     return;
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 3ed9cd36a22..03460689e19 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::numeric_literal;
 use clippy_utils::source::snippet_opt;
+use clippy_utils::{get_parent_node, numeric_literal};
 use if_chain::if_chain;
 use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::{
     intravisit::{walk_expr, walk_stmt, Visitor},
-    Body, Expr, ExprKind, HirId, Lit, Stmt, StmtKind,
+    Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::{
@@ -55,22 +55,31 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]);
 
 impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback {
     fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
-        let mut visitor = NumericFallbackVisitor::new(cx);
+        let is_parent_const = if let Some(Node::Item(item)) = get_parent_node(cx.tcx, body.id().hir_id) {
+            matches!(item.kind, ItemKind::Const(..))
+        } else {
+            false
+        };
+        let mut visitor = NumericFallbackVisitor::new(cx, is_parent_const);
         visitor.visit_body(body);
     }
 }
 
 struct NumericFallbackVisitor<'a, 'tcx> {
     /// Stack manages type bound of exprs. The top element holds current expr type.
-    ty_bounds: Vec<TyBound<'tcx>>,
+    ty_bounds: Vec<ExplicitTyBound>,
 
     cx: &'a LateContext<'tcx>,
 }
 
 impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
-    fn new(cx: &'a LateContext<'tcx>) -> Self {
+    fn new(cx: &'a LateContext<'tcx>, is_parent_const: bool) -> Self {
         Self {
-            ty_bounds: vec![TyBound::Nothing],
+            ty_bounds: vec![if is_parent_const {
+                ExplicitTyBound(true)
+            } else {
+                ExplicitTyBound(false)
+            }],
             cx,
         }
     }
@@ -79,10 +88,9 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
     fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) {
         if_chain! {
                 if !in_external_macro(self.cx.sess(), lit.span);
-                if let Some(ty_bound) = self.ty_bounds.last();
+                if matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false)));
                 if matches!(lit.node,
                             LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed));
-                if !ty_bound.is_numeric();
                 then {
                     let (suffix, is_float) = match lit_ty.kind() {
                         ty::Int(IntTy::I32) => ("i32", false),
@@ -123,7 +131,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                 if let Some(fn_sig) = fn_sig_opt(self.cx, func.hir_id) {
                     for (expr, bound) in iter::zip(*args, fn_sig.skip_binder().inputs()) {
                         // Push found arg type, then visit arg.
-                        self.ty_bounds.push(TyBound::Ty(*bound));
+                        self.ty_bounds.push((*bound).into());
                         self.visit_expr(expr);
                         self.ty_bounds.pop();
                     }
@@ -135,7 +143,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                 if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
                     let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
                     for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) {
-                        self.ty_bounds.push(TyBound::Ty(*bound));
+                        self.ty_bounds.push((*bound).into());
                         self.visit_expr(expr);
                         self.ty_bounds.pop();
                     }
@@ -169,7 +177,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
 
                         // Visit base with no bound.
                         if let Some(base) = base {
-                            self.ty_bounds.push(TyBound::Nothing);
+                            self.ty_bounds.push(ExplicitTyBound(false));
                             self.visit_expr(base);
                             self.ty_bounds.pop();
                         }
@@ -192,15 +200,10 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
 
     fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
         match stmt.kind {
-            StmtKind::Local(local) => {
-                if local.ty.is_some() {
-                    self.ty_bounds.push(TyBound::Any);
-                } else {
-                    self.ty_bounds.push(TyBound::Nothing);
-                }
-            },
+            // we cannot check the exact type since it's a hir::Ty which does not implement `is_numeric`
+            StmtKind::Local(local) => self.ty_bounds.push(ExplicitTyBound(local.ty.is_some())),
 
-            _ => self.ty_bounds.push(TyBound::Nothing),
+            _ => self.ty_bounds.push(ExplicitTyBound(false)),
         }
 
         walk_stmt(self, stmt);
@@ -218,28 +221,18 @@ fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'
     }
 }
 
+/// Wrapper around a `bool` to make the meaning of the value clearer
 #[derive(Debug, Clone, Copy)]
-enum TyBound<'tcx> {
-    Any,
-    Ty(Ty<'tcx>),
-    Nothing,
-}
+struct ExplicitTyBound(pub bool);
 
-impl<'tcx> TyBound<'tcx> {
-    fn is_numeric(self) -> bool {
-        match self {
-            TyBound::Any => true,
-            TyBound::Ty(t) => t.is_numeric(),
-            TyBound::Nothing => false,
-        }
+impl<'tcx> From<Ty<'tcx>> for ExplicitTyBound {
+    fn from(v: Ty<'tcx>) -> Self {
+        Self(v.is_numeric())
     }
 }
 
-impl<'tcx> From<Option<Ty<'tcx>>> for TyBound<'tcx> {
+impl<'tcx> From<Option<Ty<'tcx>>> for ExplicitTyBound {
     fn from(v: Option<Ty<'tcx>>) -> Self {
-        match v {
-            Some(t) => TyBound::Ty(t),
-            None => TyBound::Nothing,
-        }
+        Self(v.map_or(false, Ty::is_numeric))
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 02a16f765b7..a95d9f5390d 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
+use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
 use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res};
@@ -11,13 +12,16 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{
-    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,
+    self as hir,
+    def_id::{DefId, LocalDefId},
+    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::mir::{Rvalue, StatementKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{
     self, Binder, BoundVariableKind, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind,
@@ -141,7 +145,7 @@ declare_clippy_lint! {
     "dereferencing when the compiler would automatically dereference"
 }
 
-impl_lint_pass!(Dereferencing => [
+impl_lint_pass!(Dereferencing<'_> => [
     EXPLICIT_DEREF_METHODS,
     NEEDLESS_BORROW,
     REF_BINDING_TO_REFERENCE,
@@ -149,7 +153,7 @@ impl_lint_pass!(Dereferencing => [
 ]);
 
 #[derive(Default)]
-pub struct Dereferencing {
+pub struct Dereferencing<'tcx> {
     state: Option<(State, StateData)>,
 
     // While parsing a `deref` method call in ufcs form, the path to the function is itself an
@@ -170,11 +174,16 @@ pub struct Dereferencing {
     /// e.g. `m!(x) | Foo::Bar(ref x)`
     ref_locals: FxIndexMap<HirId, Option<RefPat>>,
 
+    /// Stack of (body owner, `PossibleBorrowerMap`) pairs. Used by
+    /// `needless_borrow_impl_arg_position` to determine when a borrowed expression can instead
+    /// be moved.
+    possible_borrowers: Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
+
     // `IntoIterator` for arrays requires Rust 1.53.
     msrv: Option<RustcVersion>,
 }
 
-impl Dereferencing {
+impl<'tcx> Dereferencing<'tcx> {
     #[must_use]
     pub fn new(msrv: Option<RustcVersion>) -> Self {
         Self {
@@ -244,7 +253,7 @@ struct RefPat {
     hir_id: HirId,
 }
 
-impl<'tcx> LateLintPass<'tcx> for Dereferencing {
+impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
     #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // Skip path expressions from deref calls. e.g. `Deref::deref(e)`
@@ -278,7 +287,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, self.msrv);
+                let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, self.msrv);
                 match kind {
                     RefOp::Deref => {
                         if let Position::FieldAccess {
@@ -550,6 +559,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
     }
 
     fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
+        if self.possible_borrowers.last().map_or(false, |&(local_def_id, _)| {
+            local_def_id == cx.tcx.hir().body_owner_def_id(body.id())
+        }) {
+            self.possible_borrowers.pop();
+        }
+
         if Some(body.id()) == self.current_body {
             for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) {
                 let replacements = pat.replacements;
@@ -682,6 +697,7 @@ impl Position {
 #[expect(clippy::too_many_lines)]
 fn walk_parents<'tcx>(
     cx: &LateContext<'tcx>,
+    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
     e: &'tcx Expr<'_>,
     msrv: Option<RustcVersion>,
 ) -> (Position, &'tcx [Adjustment<'tcx>]) {
@@ -796,7 +812,16 @@ fn walk_parents<'tcx>(
                             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)
+                                    needless_borrow_impl_arg_position(
+                                        cx,
+                                        possible_borrowers,
+                                        parent,
+                                        i,
+                                        *param_ty,
+                                        e,
+                                        precedence,
+                                        msrv,
+                                    )
                                 } else {
                                     ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
                                         .position_for_arg()
@@ -843,7 +868,16 @@ fn walk_parents<'tcx>(
                     args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
                         let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1];
                         if let ty::Param(param_ty) = ty.kind() {
-                            needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv)
+                            needless_borrow_impl_arg_position(
+                                cx,
+                                possible_borrowers,
+                                parent,
+                                i + 1,
+                                *param_ty,
+                                e,
+                                precedence,
+                                msrv,
+                            )
                         } else {
                             ty_auto_deref_stability(
                                 cx,
@@ -1017,8 +1051,10 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
 // 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.
+#[expect(clippy::too_many_arguments)]
 fn needless_borrow_impl_arg_position<'tcx>(
     cx: &LateContext<'tcx>,
+    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
     parent: &Expr<'tcx>,
     arg_index: usize,
     param_ty: ParamTy,
@@ -1081,10 +1117,13 @@ fn needless_borrow_impl_arg_position<'tcx>(
     // 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 mut check_reference_and_referent = |reference, referent| {
         let referent_ty = cx.typeck_results().expr_ty(referent);
 
-        if !is_copy(cx, referent_ty) {
+        if !is_copy(cx, referent_ty)
+            && (referent_ty.has_significant_drop(cx.tcx, cx.param_env)
+                || !referent_used_exactly_once(cx, possible_borrowers, reference))
+        {
             return false;
         }
 
@@ -1125,7 +1164,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
 
     let mut needless_borrow = false;
     while let ExprKind::AddrOf(_, _, referent) = expr.kind {
-        if !check_referent(referent) {
+        if !check_reference_and_referent(expr, referent) {
             break;
         }
         expr = referent;
@@ -1153,6 +1192,36 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
         })
 }
 
+fn referent_used_exactly_once<'tcx>(
+    cx: &LateContext<'tcx>,
+    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
+    reference: &Expr<'tcx>,
+) -> bool {
+    let mir = enclosing_mir(cx.tcx, reference.hir_id);
+    if let Some(local) = expr_local(cx.tcx, reference)
+        && let [location] = *local_assignments(mir, local).as_slice()
+        && let Some(statement) = mir.basic_blocks[location.block].statements.get(location.statement_index)
+        && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
+        && !place.has_deref()
+    {
+        let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
+        if possible_borrowers
+            .last()
+            .map_or(true, |&(local_def_id, _)| local_def_id != body_owner_local_def_id)
+        {
+            possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
+        }
+        let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
+        // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
+        // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
+        // itself. See the comment in that method for an explanation as to why.
+        possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
+            && used_exactly_once(mir, place.local).unwrap_or(false)
+    } 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`.
@@ -1437,8 +1506,8 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
     }
 }
 
-impl Dereferencing {
-    fn check_local_usage<'tcx>(&mut self, cx: &LateContext<'tcx>, e: &Expr<'tcx>, local: HirId) {
+impl<'tcx> Dereferencing<'tcx> {
+    fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &Expr<'tcx>, local: HirId) {
         if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
             if let Some(pat) = outer_pat {
                 // Check for auto-deref
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 3fac93dcc90..fad984d05ca 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -339,10 +339,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
         Some(id) if trait_ref.trait_def_id() == Some(id) => id,
         _ => return,
     };
-    let copy_id = match cx.tcx.lang_items().copy_trait() {
-        Some(id) => id,
-        None => return,
-    };
+    let Some(copy_id) = cx.tcx.lang_items().copy_trait() else { return };
     let (ty_adt, ty_subs) = match *ty.kind() {
         // Unions can't derive clone.
         ty::Adt(adt, subs) if !adt.is_union() => (adt, subs),
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index 1a381f92c03..6ac85606d9c 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -94,9 +94,8 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
         } else {
             path_def_id(cx, expr)
         };
-        let def_id = match uncalled_path.or_else(|| fn_def_id(cx, expr)) {
-            Some(def_id) => def_id,
-            None => return,
+        let Some(def_id) = uncalled_path.or_else(|| fn_def_id(cx, expr)) else {
+            return
         };
         let conf = match self.disallowed.get(&def_id) {
             Some(&index) => &self.conf_disallowed[index],
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 9c834cf0144..b44e6243588 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -65,28 +65,24 @@ declare_lint_pass!(HashMapPass => [MAP_ENTRY]);
 impl<'tcx> LateLintPass<'tcx> for HashMapPass {
     #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let (cond_expr, then_expr, else_expr) = match higher::If::hir(expr) {
-            Some(higher::If { cond, then, r#else }) => (cond, then, r#else),
-            _ => return,
+        let Some(higher::If { cond: cond_expr, then: then_expr, r#else: else_expr }) = higher::If::hir(expr) else {
+            return
         };
 
-        let (map_ty, contains_expr) = match try_parse_contains(cx, cond_expr) {
-            Some(x) => x,
-            None => return,
+        let Some((map_ty, contains_expr)) = try_parse_contains(cx, cond_expr) else {
+            return
         };
 
-        let then_search = match find_insert_calls(cx, &contains_expr, then_expr) {
-            Some(x) => x,
-            None => return,
+        let Some(then_search) = find_insert_calls(cx, &contains_expr, then_expr) else {
+            return
         };
 
         let mut app = Applicability::MachineApplicable;
         let map_str = snippet_with_context(cx, contains_expr.map.span, contains_expr.call_ctxt, "..", &mut app).0;
         let key_str = snippet_with_context(cx, contains_expr.key.span, contains_expr.call_ctxt, "..", &mut app).0;
         let sugg = if let Some(else_expr) = else_expr {
-            let else_search = match find_insert_calls(cx, &contains_expr, else_expr) {
-                Some(search) => search,
-                None => return,
+            let Some(else_search) = find_insert_calls(cx, &contains_expr, else_expr) else {
+                return;
             };
 
             if then_search.edits.is_empty() && else_search.edits.is_empty() {
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 3732410e71e..7b9786d7e57 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -213,9 +213,8 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tc
     if !closure_ty.has_late_bound_regions() {
         return true;
     }
-    let substs = match closure_ty.kind() {
-        ty::Closure(_, substs) => substs,
-        _ => return false,
+    let ty::Closure(_, substs) = closure_ty.kind() else {
+        return false;
     };
     let closure_sig = cx.tcx.signature_unclosure(substs.as_closure().sig(), Unsafety::Normal);
     cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig)
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 99bef62f814..32073536b45 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -1,8 +1,10 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::macros::FormatParamKind::{Implicit, Named, Numbered, Starred};
-use clippy_utils::macros::{is_format_macro, FormatArgsExpn, FormatParam, FormatParamUsage};
+use clippy_utils::macros::{
+    is_format_macro, is_panic, root_macro_call, Count, FormatArg, FormatArgsExpn, FormatParam, FormatParamUsage,
+};
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::implements_trait;
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs};
 use if_chain::if_chain;
 use itertools::Itertools;
@@ -13,6 +15,8 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_middle::ty::Ty;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::DefId;
+use rustc_span::edition::Edition::Edition2021;
 use rustc_span::{sym, ExpnData, ExpnKind, Span, Symbol};
 
 declare_clippy_lint! {
@@ -111,11 +115,47 @@ declare_clippy_lint! {
     /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
     #[clippy::version = "1.65.0"]
     pub UNINLINED_FORMAT_ARGS,
-    pedantic,
+    style,
     "using non-inlined variables in `format!` calls"
 }
 
-impl_lint_pass!(FormatArgs => [FORMAT_IN_FORMAT_ARGS, UNINLINED_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS]);
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects [formatting parameters] that have no effect on the output of
+    /// `format!()`, `println!()` or similar macros.
+    ///
+    /// ### Why is this bad?
+    /// Shorter format specifiers are easier to read, it may also indicate that
+    /// an expected formatting operation such as adding padding isn't happening.
+    ///
+    /// ### Example
+    /// ```rust
+    /// println!("{:.}", 1.0);
+    ///
+    /// println!("not padded: {:5}", format_args!("..."));
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// println!("{}", 1.0);
+    ///
+    /// println!("not padded: {}", format_args!("..."));
+    /// // OR
+    /// println!("padded: {:5}", format!("..."));
+    /// ```
+    ///
+    /// [formatting parameters]: https://doc.rust-lang.org/std/fmt/index.html#formatting-parameters
+    #[clippy::version = "1.66.0"]
+    pub UNUSED_FORMAT_SPECS,
+    complexity,
+    "use of a format specifier that has no effect"
+}
+
+impl_lint_pass!(FormatArgs => [
+    FORMAT_IN_FORMAT_ARGS,
+    TO_STRING_IN_FORMAT_ARGS,
+    UNINLINED_FORMAT_ARGS,
+    UNUSED_FORMAT_SPECS,
+]);
 
 pub struct FormatArgs {
     msrv: Option<RustcVersion>,
@@ -130,27 +170,26 @@ impl FormatArgs {
 
 impl<'tcx> LateLintPass<'tcx> for FormatArgs {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if_chain! {
-            if let Some(format_args) = FormatArgsExpn::parse(cx, expr);
-            let expr_expn_data = expr.span.ctxt().outer_expn_data();
-            let outermost_expn_data = outermost_expn_data(expr_expn_data);
-            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;
-            then {
-                for arg in &format_args.args {
-                    if !arg.format.is_default() {
-                        continue;
-                    }
-                    if is_aliased(&format_args, arg.param.value.hir_id) {
-                        continue;
-                    }
-                    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);
+        if let Some(format_args) = FormatArgsExpn::parse(cx, expr)
+            && let expr_expn_data = expr.span.ctxt().outer_expn_data()
+            && let outermost_expn_data = outermost_expn_data(expr_expn_data)
+            && let Some(macro_def_id) = outermost_expn_data.macro_def_id
+            && is_format_macro(cx, macro_def_id)
+            && let ExpnKind::Macro(_, name) = outermost_expn_data.kind
+        {
+            for arg in &format_args.args {
+                check_unused_format_specifier(cx, arg);
+                if !arg.format.is_default() {
+                    continue;
                 }
-                if meets_msrv(self.msrv, msrvs::FORMAT_ARGS_CAPTURE) {
-                    check_uninlined_args(cx, &format_args, outermost_expn_data.call_site);
+                if is_aliased(&format_args, arg.param.value.hir_id) {
+                    continue;
                 }
+                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);
+            }
+            if meets_msrv(self.msrv, msrvs::FORMAT_ARGS_CAPTURE) {
+                check_uninlined_args(cx, &format_args, outermost_expn_data.call_site, macro_def_id);
             }
         }
     }
@@ -158,10 +197,84 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs {
     extract_msrv_attr!(LateContext);
 }
 
-fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_site: Span) {
+fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) {
+    let param_ty = cx.typeck_results().expr_ty(arg.param.value).peel_refs();
+
+    if let Count::Implied(Some(mut span)) = arg.format.precision
+        && !span.is_empty()
+    {
+        span_lint_and_then(
+            cx,
+            UNUSED_FORMAT_SPECS,
+            span,
+            "empty precision specifier has no effect",
+            |diag| {
+                if param_ty.is_floating_point() {
+                    diag.note("a precision specifier is not required to format floats");
+                }
+
+                if arg.format.is_default() {
+                    // If there's no other specifiers remove the `:` too
+                    span = arg.format_span();
+                }
+
+                diag.span_suggestion_verbose(span, "remove the `.`", "", Applicability::MachineApplicable);
+            },
+        );
+    }
+
+    if is_type_diagnostic_item(cx, param_ty, sym::Arguments) && !arg.format.is_default_for_trait() {
+        span_lint_and_then(
+            cx,
+            UNUSED_FORMAT_SPECS,
+            arg.span,
+            "format specifiers have no effect on `format_args!()`",
+            |diag| {
+                let mut suggest_format = |spec, span| {
+                    let message = format!("for the {spec} to apply consider using `format!()`");
+
+                    if let Some(mac_call) = root_macro_call(arg.param.value.span)
+                        && cx.tcx.is_diagnostic_item(sym::format_args_macro, mac_call.def_id)
+                        && arg.span.eq_ctxt(mac_call.span)
+                    {
+                        diag.span_suggestion(
+                            cx.sess().source_map().span_until_char(mac_call.span, '!'),
+                            message,
+                            "format",
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else if let Some(span) = span {
+                        diag.span_help(span, message);
+                    }
+                };
+
+                if !arg.format.width.is_implied() {
+                    suggest_format("width", arg.format.width.span());
+                }
+
+                if !arg.format.precision.is_implied() {
+                    suggest_format("precision", arg.format.precision.span());
+                }
+
+                diag.span_suggestion_verbose(
+                    arg.format_span(),
+                    "if the current behavior is intentional, remove the format specifiers",
+                    "",
+                    Applicability::MaybeIncorrect,
+                );
+            },
+        );
+    }
+}
+
+fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_site: Span, def_id: DefId) {
     if args.format_string.span.from_expansion() {
         return;
     }
+    if call_site.edition() < Edition2021 && is_panic(cx, def_id) {
+        // panic! before 2021 edition considers a single string argument as non-format
+        return;
+    }
 
     let mut fixes = Vec::new();
     // If any of the arguments are referenced by an index number,
@@ -248,7 +361,7 @@ fn check_format_in_format_args(
 fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
     if_chain! {
         if !value.span.from_expansion();
-        if let ExprKind::MethodCall(_, receiver, [], _) = value.kind;
+        if let ExprKind::MethodCall(_, receiver, [], to_string_span) = value.kind;
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
         if is_diag_trait_item(cx, method_def_id, sym::ToString);
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
@@ -264,7 +377,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex
                 span_lint_and_sugg(
                     cx,
                     TO_STRING_IN_FORMAT_ARGS,
-                    value.span.with_lo(receiver.span.hi()),
+                    to_string_span.with_lo(receiver.span.hi()),
                     &format!(
                         "`to_string` applied to a type that implements `Display` in `{name}!` args"
                     ),
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 5d25c1d0634..95eda4ea882 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -1,11 +1,19 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{meets_msrv, msrvs};
-use if_chain::if_chain;
-use rustc_hir as hir;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::span_is_local;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{meets_msrv, msrvs, path_def_id};
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::{walk_path, Visitor};
+use rustc_hir::{
+    GenericArg, GenericArgs, HirId, Impl, ImplItemKind, ImplItemRef, Item, ItemKind, PatKind, Path, PathSegment, Ty,
+    TyKind,
+};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{kw, sym};
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -54,28 +62,152 @@ impl FromOverInto {
 impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
 
 impl<'tcx> LateLintPass<'tcx> for FromOverInto {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
-        if !meets_msrv(self.msrv, msrvs::RE_REBALANCING_COHERENCE) {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        if !meets_msrv(self.msrv, msrvs::RE_REBALANCING_COHERENCE) || !span_is_local(item.span) {
             return;
         }
 
-        if_chain! {
-            if let hir::ItemKind::Impl{ .. } = &item.kind;
-            if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.def_id);
-            if cx.tcx.is_diagnostic_item(sym::Into, impl_trait_ref.def_id);
-
-            then {
-                span_lint_and_help(
-                    cx,
-                    FROM_OVER_INTO,
-                    cx.tcx.sess.source_map().guess_head_span(item.span),
-                    "an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true",
-                    None,
-                    &format!("consider to implement `From<{}>` instead", impl_trait_ref.self_ty()),
-                );
-            }
+        if let ItemKind::Impl(Impl {
+            of_trait: Some(hir_trait_ref),
+            self_ty,
+            items: [impl_item_ref],
+            ..
+        }) = item.kind
+            && let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
+            // `impl Into<target_ty> for self_ty`
+            && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
+            && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.def_id)
+            && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
+        {
+            span_lint_and_then(
+                cx,
+                FROM_OVER_INTO,
+                cx.tcx.sess.source_map().guess_head_span(item.span),
+                "an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true",
+                |diag| {
+                    // If the target type is likely foreign mention the orphan rules as it's a common source of confusion
+                    if path_def_id(cx, target_ty.peel_refs()).map_or(true, |id| !id.is_local()) {
+                        diag.help(
+                            "`impl From<Local> for Foreign` is allowed by the orphan rules, for more information see\n\
+                            https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence"
+                        );
+                    }
+
+                    let message = format!("replace the `Into` implentation with `From<{}>`", middle_trait_ref.self_ty());
+                    if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) {
+                        diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable);
+                    } else {
+                        diag.help(message);
+                    }
+                },
+            );
         }
     }
 
     extract_msrv_attr!(LateContext);
 }
+
+/// Finds the occurences of `Self` and `self`
+struct SelfFinder<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    /// Occurences of `Self`
+    upper: Vec<Span>,
+    /// Occurences of `self`
+    lower: Vec<Span>,
+    /// If any of the `self`/`Self` usages were from an expansion, or the body contained a binding
+    /// already named `val`
+    invalid: bool,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> {
+    type NestedFilter = OnlyBodies;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
+    }
+
+    fn visit_path(&mut self, path: &'tcx Path<'tcx>, _id: HirId) {
+        for segment in path.segments {
+            match segment.ident.name {
+                kw::SelfLower => self.lower.push(segment.ident.span),
+                kw::SelfUpper => self.upper.push(segment.ident.span),
+                _ => continue,
+            }
+        }
+
+        self.invalid |= path.span.from_expansion();
+        if !self.invalid {
+            walk_path(self, path);
+        }
+    }
+
+    fn visit_name(&mut self, name: Symbol) {
+        if name == sym::val {
+            self.invalid = true;
+        }
+    }
+}
+
+fn convert_to_from(
+    cx: &LateContext<'_>,
+    into_trait_seg: &PathSegment<'_>,
+    target_ty: &Ty<'_>,
+    self_ty: &Ty<'_>,
+    impl_item_ref: &ImplItemRef,
+) -> Option<Vec<(Span, String)>> {
+    let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
+    let ImplItemKind::Fn(ref sig, body_id) = impl_item.kind else { return None };
+    let body = cx.tcx.hir().body(body_id);
+    let [input] = body.params else { return None };
+    let PatKind::Binding(.., self_ident, None) = input.pat.kind else { return None };
+
+    let from = snippet_opt(cx, self_ty.span)?;
+    let into = snippet_opt(cx, target_ty.span)?;
+
+    let mut suggestions = vec![
+        // impl Into<T> for U  ->  impl From<T> for U
+        //      ~~~~                    ~~~~
+        (into_trait_seg.ident.span, String::from("From")),
+        // impl Into<T> for U  ->  impl Into<U> for U
+        //           ~                       ~
+        (target_ty.span, from.clone()),
+        // impl Into<T> for U  ->  impl Into<T> for T
+        //                  ~                       ~
+        (self_ty.span, into),
+        // fn into(self) -> T  ->  fn from(self) -> T
+        //    ~~~~                    ~~~~
+        (impl_item.ident.span, String::from("from")),
+        // fn into([mut] self) -> T  ->  fn into([mut] v: T) -> T
+        //               ~~~~                          ~~~~
+        (self_ident.span, format!("val: {from}")),
+        // fn into(self) -> T  ->  fn into(self) -> Self
+        //                  ~                       ~~~~
+        (sig.decl.output.span(), String::from("Self")),
+    ];
+
+    let mut finder = SelfFinder {
+        cx,
+        upper: Vec::new(),
+        lower: Vec::new(),
+        invalid: false,
+    };
+    finder.visit_expr(body.value);
+
+    if finder.invalid {
+        return None;
+    }
+
+    // don't try to replace e.g. `Self::default()` with `&[T]::default()`
+    if !finder.upper.is_empty() && !matches!(self_ty.kind, TyKind::Path(_)) {
+        return None;
+    }
+
+    for span in finder.upper {
+        suggestions.push((span, from.clone()));
+    }
+    for span in finder.lower {
+        suggestions.push((span, String::from("val")));
+    }
+
+    Some(suggestions)
+}
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index d263804f32c..3064b6c9d22 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -7,14 +7,14 @@ use rustc_middle::{
     lint::in_external_macro,
     ty::{self, Ty},
 };
-use rustc_span::{sym, Span};
+use rustc_span::{sym, Span, Symbol};
 
 use clippy_utils::attrs::is_proc_macro;
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::is_must_use_ty;
 use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{match_def_path, return_ty, trait_ref_of_method};
+use clippy_utils::{return_ty, trait_ref_of_method};
 
 use core::ops::ControlFlow;
 
@@ -181,7 +181,7 @@ fn is_mutable_pat(cx: &LateContext<'_>, pat: &hir::Pat<'_>, tys: &mut DefIdSet)
     }
 }
 
-static KNOWN_WRAPPER_TYS: &[&[&str]] = &[&["alloc", "rc", "Rc"], &["std", "sync", "Arc"]];
+static KNOWN_WRAPPER_TYS: &[Symbol] = &[sym::Rc, sym::Arc];
 
 fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &mut DefIdSet) -> bool {
     match *ty.kind() {
@@ -189,7 +189,9 @@ fn is_mutable_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, tys: &m
         ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
         ty::Adt(adt, substs) => {
             tys.insert(adt.did()) && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
-                || KNOWN_WRAPPER_TYS.iter().any(|path| match_def_path(cx, adt.did(), path))
+                || KNOWN_WRAPPER_TYS
+                    .iter()
+                    .any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
                     && substs.types().any(|ty| is_mutable_ty(cx, ty, span, tys))
         },
         ty::Tuple(substs) => substs.iter().any(|ty| is_mutable_ty(cx, ty, span, tys)),
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
index f83f8b40f94..bd473ac7e51 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
@@ -22,9 +22,8 @@ pub(super) fn check_fn(
         return;
     }
 
-    let code_snippet = match snippet_opt(cx, body.value.span) {
-        Some(s) => s,
-        _ => return,
+    let Some(code_snippet) = snippet_opt(cx, body.value.span) else {
+        return
     };
     let mut line_count: u64 = 0;
     let mut in_comment = false;
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index 48edbf6ae57..29d59c26d92 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -35,7 +35,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.44.0"]
     pub IMPLICIT_SATURATING_SUB,
-    pedantic,
+    style,
     "Perform saturating subtraction instead of implicitly checking lower bound of data type"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index 36e03e50a8e..0ef77e03de9 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -145,9 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidUpcastComparisons {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let ExprKind::Binary(ref cmp, lhs, rhs) = expr.kind {
             let normalized = comparisons::normalize_comparison(cmp.node, lhs, rhs);
-            let (rel, normalized_lhs, normalized_rhs) = if let Some(val) = normalized {
-                val
-            } else {
+            let Some((rel, normalized_lhs, normalized_rhs)) = normalized else {
                 return;
             };
 
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index eb13d0869c0..8ed7e4bb196 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -124,9 +124,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
             let ty = cx.tcx.type_of(item.def_id);
-            let (adt, subst) = match ty.kind() {
-                Adt(adt, subst) => (adt, subst),
-                _ => panic!("already checked whether this is an enum"),
+            let Adt(adt, subst) = ty.kind() else {
+                panic!("already checked whether this is an enum")
             };
             if adt.variants().len() <= 1 {
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 176787497eb..b7798b1c1d7 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::{is_must_use_ty, match_type};
+use clippy_utils::ty::{is_must_use_ty, is_type_diagnostic_item, match_type};
 use clippy_utils::{is_must_use_func_call, paths};
 use if_chain::if_chain;
 use rustc_hir::{Local, PatKind};
@@ -7,6 +7,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -99,10 +100,9 @@ declare_clippy_lint! {
 
 declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]);
 
-const SYNC_GUARD_PATHS: [&[&str]; 6] = [
-    &paths::MUTEX_GUARD,
-    &paths::RWLOCK_READ_GUARD,
-    &paths::RWLOCK_WRITE_GUARD,
+const SYNC_GUARD_SYMS: [Symbol; 3] = [sym::MutexGuard, sym::RwLockReadGuard, sym::RwLockWriteGuard];
+
+const SYNC_GUARD_PATHS: [&[&str]; 3] = [
     &paths::PARKING_LOT_MUTEX_GUARD,
     &paths::PARKING_LOT_RWLOCK_READ_GUARD,
     &paths::PARKING_LOT_RWLOCK_WRITE_GUARD,
@@ -121,7 +121,10 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                 let init_ty = cx.typeck_results().expr_ty(init);
                 let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
                     GenericArgKind::Type(inner_ty) => {
-                        SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
+                        SYNC_GUARD_SYMS
+                            .iter()
+                            .any(|&sym| is_type_diagnostic_item(cx, inner_ty, sym))
+                            || SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
                     },
 
                     GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
@@ -134,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                         "non-binding let on a synchronization lock",
                         None,
                         "consider using an underscore-prefixed named \
-                            binding or dropping explicitly with `std::mem::drop`"
+                            binding or dropping explicitly with `std::mem::drop`",
                     );
                 } else if init_ty.needs_drop(cx.tcx, cx.param_env) {
                     span_lint_and_help(
@@ -144,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                         "non-binding `let` on a type that implements `Drop`",
                         None,
                         "consider using an underscore-prefixed named \
-                            binding or dropping explicitly with `std::mem::drop`"
+                            binding or dropping explicitly with `std::mem::drop`",
                     );
                 } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
                     span_lint_and_help(
@@ -153,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                         local.span,
                         "non-binding let on an expression with `#[must_use]` type",
                         None,
-                        "consider explicitly using expression value"
+                        "consider explicitly using expression value",
                     );
                 } else if is_must_use_func_call(cx, init) {
                     span_lint_and_help(
@@ -162,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                         local.span,
                         "non-binding let on a result of a `#[must_use]` function",
                         None,
-                        "consider explicitly using function result"
+                        "consider explicitly using function result",
                     );
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
index fe1f0b56646..f5ad52ba189 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
@@ -25,6 +25,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(casts::CAST_ABS_TO_UNSIGNED),
     LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
     LintId::of(casts::CAST_ENUM_TRUNCATION),
+    LintId::of(casts::CAST_NAN_TO_INT),
     LintId::of(casts::CAST_REF_TO_MUT),
     LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
     LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
@@ -71,6 +72,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(format::USELESS_FORMAT),
     LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
     LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
+    LintId::of(format_args::UNINLINED_FORMAT_ARGS),
+    LintId::of(format_args::UNUSED_FORMAT_SPECS),
     LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
     LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
     LintId::of(formatting::POSSIBLE_MISSING_COMMA),
@@ -87,6 +90,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(functions::TOO_MANY_ARGUMENTS),
     LintId::of(if_let_mutex::IF_LET_MUTEX),
     LintId::of(implicit_saturating_add::IMPLICIT_SATURATING_ADD),
+    LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
     LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
     LintId::of(infinite_iter::INFINITE_ITER),
     LintId::of(inherent_to_string::INHERENT_TO_STRING),
@@ -136,6 +140,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(match_result_ok::MATCH_RESULT_OK),
     LintId::of(matches::COLLAPSIBLE_MATCH),
     LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
+    LintId::of(matches::MANUAL_FILTER),
     LintId::of(matches::MANUAL_MAP),
     LintId::of(matches::MANUAL_UNWRAP_OR),
     LintId::of(matches::MATCH_AS_REF),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
index a58d066fa6b..8be9dc4baf1 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
@@ -13,6 +13,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(double_parens::DOUBLE_PARENS),
     LintId::of(explicit_write::EXPLICIT_WRITE),
     LintId::of(format::USELESS_FORMAT),
+    LintId::of(format_args::UNUSED_FORMAT_SPECS),
     LintId::of(functions::TOO_MANY_ARGUMENTS),
     LintId::of(int_plus_one::INT_PLUS_ONE),
     LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
@@ -27,6 +28,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(manual_strip::MANUAL_STRIP),
     LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
     LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
+    LintId::of(matches::MANUAL_FILTER),
     LintId::of(matches::MANUAL_UNWRAP_OR),
     LintId::of(matches::MATCH_AS_REF),
     LintId::of(matches::MATCH_SINGLE_BINDING),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_internal.rs b/src/tools/clippy/clippy_lints/src/lib.register_internal.rs
index 71dfdab369b..40c94c6e8d3 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_internal.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_internal.rs
@@ -3,20 +3,20 @@
 // Manual edits will be overwritten.
 
 store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
-    LintId::of(utils::internal_lints::CLIPPY_LINTS_INTERNAL),
-    LintId::of(utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS),
-    LintId::of(utils::internal_lints::COMPILER_LINT_FUNCTIONS),
-    LintId::of(utils::internal_lints::DEFAULT_DEPRECATION_REASON),
-    LintId::of(utils::internal_lints::DEFAULT_LINT),
-    LintId::of(utils::internal_lints::IF_CHAIN_STYLE),
-    LintId::of(utils::internal_lints::INTERNING_DEFINED_SYMBOL),
-    LintId::of(utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE),
-    LintId::of(utils::internal_lints::INVALID_PATHS),
-    LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
-    LintId::of(utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE),
-    LintId::of(utils::internal_lints::MISSING_MSRV_ATTR_IMPL),
-    LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
-    LintId::of(utils::internal_lints::PRODUCE_ICE),
-    LintId::of(utils::internal_lints::UNNECESSARY_DEF_PATH),
-    LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
+    LintId::of(utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL),
+    LintId::of(utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS),
+    LintId::of(utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS),
+    LintId::of(utils::internal_lints::if_chain_style::IF_CHAIN_STYLE),
+    LintId::of(utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL),
+    LintId::of(utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR),
+    LintId::of(utils::internal_lints::invalid_paths::INVALID_PATHS),
+    LintId::of(utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON),
+    LintId::of(utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT),
+    LintId::of(utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE),
+    LintId::of(utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS),
+    LintId::of(utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE),
+    LintId::of(utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL),
+    LintId::of(utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA),
+    LintId::of(utils::internal_lints::produce_ice::PRODUCE_ICE),
+    LintId::of(utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH),
 ])
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
index 306cb6a61c9..800e3a87671 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
@@ -4,37 +4,37 @@
 
 store.register_lints(&[
     #[cfg(feature = "internal")]
-    utils::internal_lints::CLIPPY_LINTS_INTERNAL,
+    utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL,
     #[cfg(feature = "internal")]
-    utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
+    utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS,
     #[cfg(feature = "internal")]
-    utils::internal_lints::COMPILER_LINT_FUNCTIONS,
+    utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS,
     #[cfg(feature = "internal")]
-    utils::internal_lints::DEFAULT_DEPRECATION_REASON,
+    utils::internal_lints::if_chain_style::IF_CHAIN_STYLE,
     #[cfg(feature = "internal")]
-    utils::internal_lints::DEFAULT_LINT,
+    utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL,
     #[cfg(feature = "internal")]
-    utils::internal_lints::IF_CHAIN_STYLE,
+    utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR,
     #[cfg(feature = "internal")]
-    utils::internal_lints::INTERNING_DEFINED_SYMBOL,
+    utils::internal_lints::invalid_paths::INVALID_PATHS,
     #[cfg(feature = "internal")]
-    utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE,
+    utils::internal_lints::lint_without_lint_pass::DEFAULT_DEPRECATION_REASON,
     #[cfg(feature = "internal")]
-    utils::internal_lints::INVALID_PATHS,
+    utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT,
     #[cfg(feature = "internal")]
-    utils::internal_lints::LINT_WITHOUT_LINT_PASS,
+    utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE,
     #[cfg(feature = "internal")]
-    utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE,
+    utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS,
     #[cfg(feature = "internal")]
-    utils::internal_lints::MISSING_MSRV_ATTR_IMPL,
+    utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE,
     #[cfg(feature = "internal")]
-    utils::internal_lints::OUTER_EXPN_EXPN_DATA,
+    utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL,
     #[cfg(feature = "internal")]
-    utils::internal_lints::PRODUCE_ICE,
+    utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA,
     #[cfg(feature = "internal")]
-    utils::internal_lints::UNNECESSARY_DEF_PATH,
+    utils::internal_lints::produce_ice::PRODUCE_ICE,
     #[cfg(feature = "internal")]
-    utils::internal_lints::UNNECESSARY_SYMBOL_STR,
+    utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH,
     almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE,
     approx_const::APPROX_CONSTANT,
     as_conversions::AS_CONVERSIONS,
@@ -66,12 +66,14 @@ store.register_lints(&[
     cargo::NEGATIVE_FEATURE_NAMES,
     cargo::REDUNDANT_FEATURE_NAMES,
     cargo::WILDCARD_DEPENDENCIES,
+    casts::AS_PTR_CAST_MUT,
     casts::AS_UNDERSCORE,
     casts::BORROW_AS_PTR,
     casts::CAST_ABS_TO_UNSIGNED,
     casts::CAST_ENUM_CONSTRUCTOR,
     casts::CAST_ENUM_TRUNCATION,
     casts::CAST_LOSSLESS,
+    casts::CAST_NAN_TO_INT,
     casts::CAST_POSSIBLE_TRUNCATION,
     casts::CAST_POSSIBLE_WRAP,
     casts::CAST_PRECISION_LOSS,
@@ -162,6 +164,7 @@ store.register_lints(&[
     format_args::FORMAT_IN_FORMAT_ARGS,
     format_args::TO_STRING_IN_FORMAT_ARGS,
     format_args::UNINLINED_FORMAT_ARGS,
+    format_args::UNUSED_FORMAT_SPECS,
     format_impl::PRINT_IN_FORMAT_IMPL,
     format_impl::RECURSIVE_FORMAT_IMPL,
     format_push_string::FORMAT_PUSH_STRING,
@@ -258,6 +261,7 @@ store.register_lints(&[
     match_result_ok::MATCH_RESULT_OK,
     matches::COLLAPSIBLE_MATCH,
     matches::INFALLIBLE_DESTRUCTURING_MATCH,
+    matches::MANUAL_FILTER,
     matches::MANUAL_MAP,
     matches::MANUAL_UNWRAP_OR,
     matches::MATCH_AS_REF,
@@ -403,6 +407,7 @@ store.register_lints(&[
     missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
     missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
     missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS,
+    missing_trait_methods::MISSING_TRAIT_METHODS,
     mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION,
     mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION,
     module_style::MOD_MODULE_FILES,
@@ -475,6 +480,7 @@ store.register_lints(&[
     panic_unimplemented::TODO,
     panic_unimplemented::UNIMPLEMENTED,
     panic_unimplemented::UNREACHABLE,
+    partial_pub_fields::PARTIAL_PUB_FIELDS,
     partialeq_ne_impl::PARTIALEQ_NE_IMPL,
     partialeq_to_none::PARTIALEQ_TO_NONE,
     pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
index e0b4639af53..65616d28d8f 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
@@ -4,6 +4,7 @@
 
 store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
     LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
+    LintId::of(casts::AS_PTR_CAST_MUT),
     LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
     LintId::of(copies::BRANCHES_SHARING_CODE),
     LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
index bc2f0beb358..060d3bdc7c6 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
@@ -29,12 +29,10 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
     LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
     LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
-    LintId::of(format_args::UNINLINED_FORMAT_ARGS),
     LintId::of(functions::MUST_USE_CANDIDATE),
     LintId::of(functions::TOO_MANY_LINES),
     LintId::of(if_not_else::IF_NOT_ELSE),
     LintId::of(implicit_hasher::IMPLICIT_HASHER),
-    LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
     LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
     LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
     LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
index 6eb9b3d3b9b..f62d57af5b4 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
@@ -47,6 +47,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
     LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
     LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
+    LintId::of(missing_trait_methods::MISSING_TRAIT_METHODS),
     LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION),
     LintId::of(module_style::MOD_MODULE_FILES),
     LintId::of(module_style::SELF_NAMED_MODULE_FILES),
@@ -61,6 +62,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(panic_unimplemented::TODO),
     LintId::of(panic_unimplemented::UNIMPLEMENTED),
     LintId::of(panic_unimplemented::UNREACHABLE),
+    LintId::of(partial_pub_fields::PARTIAL_PUB_FIELDS),
     LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
     LintId::of(pub_use::PUB_USE),
     LintId::of(redundant_slicing::DEREF_BY_SLICING),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_style.rs b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
index 8e1390167dc..6894d69e928 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
@@ -25,12 +25,14 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(enum_variants::MODULE_INCEPTION),
     LintId::of(eta_reduction::REDUNDANT_CLOSURE),
     LintId::of(float_literal::EXCESSIVE_PRECISION),
+    LintId::of(format_args::UNINLINED_FORMAT_ARGS),
     LintId::of(from_over_into::FROM_OVER_INTO),
     LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
     LintId::of(functions::DOUBLE_MUST_USE),
     LintId::of(functions::MUST_USE_UNIT),
     LintId::of(functions::RESULT_UNIT_ERR),
     LintId::of(implicit_saturating_add::IMPLICIT_SATURATING_ADD),
+    LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
     LintId::of(inherent_to_string::INHERENT_TO_STRING),
     LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
     LintId::of(len_zero::COMPARISON_TO_EMPTY),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
index d6d95c95c85..b70c4bb73e5 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
+++ b/src/tools/clippy/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_NAN_TO_INT),
     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),
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 89ffca8128a..1307096b28d 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -39,7 +39,6 @@ extern crate rustc_infer;
 extern crate rustc_lexer;
 extern crate rustc_lint;
 extern crate rustc_middle;
-extern crate rustc_mir_dataflow;
 extern crate rustc_parse;
 extern crate rustc_session;
 extern crate rustc_span;
@@ -291,6 +290,7 @@ mod missing_const_for_fn;
 mod missing_doc;
 mod missing_enforced_import_rename;
 mod missing_inline;
+mod missing_trait_methods;
 mod mixed_read_write_in_expression;
 mod module_style;
 mod multi_assignments;
@@ -326,6 +326,7 @@ mod option_if_let_else;
 mod overflow_check_conditional;
 mod panic_in_result_fn;
 mod panic_unimplemented;
+mod partial_pub_fields;
 mod partialeq_ne_impl;
 mod partialeq_to_none;
 mod pass_by_ref_or_value;
@@ -419,7 +420,7 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se
 
     let msrv = conf.msrv.as_ref().and_then(|s| {
         parse_msrv(s, None, None).or_else(|| {
-            sess.err(&format!(
+            sess.err(format!(
                 "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
             ));
             None
@@ -435,7 +436,7 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> {
         .and_then(|v| parse_msrv(&v, None, None));
     let clippy_msrv = conf.msrv.as_ref().and_then(|s| {
         parse_msrv(s, None, None).or_else(|| {
-            sess.err(&format!(
+            sess.err(format!(
                 "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
             ));
             None
@@ -446,7 +447,7 @@ fn read_msrv(conf: &Conf, sess: &Session) -> Option<RustcVersion> {
         if let Some(clippy_msrv) = clippy_msrv {
             // if both files have an msrv, let's compare them and emit a warning if they differ
             if clippy_msrv != cargo_msrv {
-                sess.warn(&format!(
+                sess.warn(format!(
                     "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
                 ));
             }
@@ -475,7 +476,7 @@ pub fn read_conf(sess: &Session) -> Conf {
     let TryConf { conf, errors, warnings } = utils::conf::read(&file_name);
     // all conf errors are non-fatal, we just use the default conf in case of error
     for error in errors {
-        sess.err(&format!(
+        sess.err(format!(
             "error reading Clippy's configuration file `{}`: {}",
             file_name.display(),
             format_error(error)
@@ -483,7 +484,7 @@ pub fn read_conf(sess: &Session) -> Conf {
     }
 
     for warning in warnings {
-        sess.struct_warn(&format!(
+        sess.struct_warn(format!(
             "error reading Clippy's configuration file `{}`: {}",
             file_name.display(),
             format_error(warning)
@@ -530,17 +531,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     // all the internal lints
     #[cfg(feature = "internal")]
     {
-        store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal));
-        store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce));
-        store.register_late_pass(|_| Box::new(utils::internal_lints::CollapsibleCalls));
-        store.register_late_pass(|_| Box::new(utils::internal_lints::CompilerLintFunctions::new()));
-        store.register_late_pass(|_| Box::new(utils::internal_lints::IfChainStyle));
-        store.register_late_pass(|_| Box::new(utils::internal_lints::InvalidPaths));
-        store.register_late_pass(|_| Box::<utils::internal_lints::InterningDefinedSymbol>::default());
-        store.register_late_pass(|_| Box::<utils::internal_lints::LintWithoutLintPass>::default());
-        store.register_late_pass(|_| Box::new(utils::internal_lints::UnnecessaryDefPath));
-        store.register_late_pass(|_| Box::new(utils::internal_lints::OuterExpnDataPass));
-        store.register_late_pass(|_| Box::new(utils::internal_lints::MsrvAttrImpl));
+        store.register_early_pass(|| Box::new(utils::internal_lints::clippy_lints_internal::ClippyLintsInternal));
+        store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls));
+        store.register_late_pass(|_| {
+            Box::new(utils::internal_lints::compiler_lint_functions::CompilerLintFunctions::new())
+        });
+        store.register_late_pass(|_| Box::new(utils::internal_lints::if_chain_style::IfChainStyle));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths));
+        store.register_late_pass(|_| {
+            Box::<utils::internal_lints::interning_defined_symbol::InterningDefinedSymbol>::default()
+        });
+        store.register_late_pass(|_| {
+            Box::<utils::internal_lints::lint_without_lint_pass::LintWithoutLintPass>::default()
+        });
+        store.register_late_pass(|_| Box::<utils::internal_lints::unnecessary_def_path::UnnecessaryDefPath>::default());
+        store.register_late_pass(|_| Box::new(utils::internal_lints::outer_expn_data_pass::OuterExpnDataPass));
+        store.register_late_pass(|_| Box::new(utils::internal_lints::msrv_attr_impl::MsrvAttrImpl));
     }
 
     let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone();
@@ -910,6 +917,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(bool_to_int_with_if::BoolToIntWithIf));
     store.register_late_pass(|_| Box::new(box_default::BoxDefault));
     store.register_late_pass(|_| Box::new(implicit_saturating_add::ImplicitSaturatingAdd));
+    store.register_early_pass(|| Box::new(partial_pub_fields::PartialPubFields));
+    store.register_late_pass(|_| Box::new(missing_trait_methods::MissingTraitMethods));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 00cfc6d49f1..27ba27202bf 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::has_iter_method;
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{contains_name, higher, is_integer_const, match_trait_method, paths, sugg, SpanlessEq};
+use clippy_utils::{contains_name, higher, is_integer_const, sugg, SpanlessEq};
 use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -263,7 +263,8 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
                 match res {
                     Res::Local(hir_id) => {
                         let parent_def_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
-                        let extent = self.cx
+                        let extent = self
+                            .cx
                             .tcx
                             .region_scope_tree(parent_def_id)
                             .var_scope(hir_id.local_id)
@@ -274,11 +275,12 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
                                 (Some(extent), self.cx.typeck_results().node_type(seqexpr.hir_id)),
                             );
                         } else {
-                            self.indexed_indirectly.insert(seqvar.segments[0].ident.name, Some(extent));
+                            self.indexed_indirectly
+                                .insert(seqvar.segments[0].ident.name, Some(extent));
                         }
-                        return false;  // no need to walk further *on the variable*
-                    }
-                    Res::Def(DefKind::Static (_)| DefKind::Const, ..) => {
+                        return false; // no need to walk further *on the variable*
+                    },
+                    Res::Def(DefKind::Static(_) | DefKind::Const, ..) => {
                         if index_used_directly {
                             self.indexed_directly.insert(
                                 seqvar.segments[0].ident.name,
@@ -287,8 +289,8 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
                         } else {
                             self.indexed_indirectly.insert(seqvar.segments[0].ident.name, None);
                         }
-                        return false;  // no need to walk further *on the variable*
-                    }
+                        return false; // no need to walk further *on the variable*
+                    },
                     _ => (),
                 }
             }
@@ -302,17 +304,26 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
         if_chain! {
             // a range index op
             if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind;
-            if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX))
-                || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT));
+            if let Some(trait_id) = self
+                .cx
+                .typeck_results()
+                .type_dependent_def_id(expr.hir_id)
+                .and_then(|def_id| self.cx.tcx.trait_of_item(def_id));
+            if (meth.ident.name == sym::index && self.cx.tcx.lang_items().index_trait() == Some(trait_id))
+                || (meth.ident.name == sym::index_mut && self.cx.tcx.lang_items().index_mut_trait() == Some(trait_id));
             if !self.check(args_1, args_0, expr);
-            then { return }
+            then {
+                return;
+            }
         }
 
         if_chain! {
             // an index op
             if let ExprKind::Index(seqexpr, idx) = expr.kind;
             if !self.check(idx, seqexpr, expr);
-            then { return }
+            then {
+                return;
+            }
         }
 
         if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index 153f97e4e66..55989f8a446 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -331,9 +331,8 @@ fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &
     }
 
     if let Some(e) = get_enclosing_loop_or_multi_call_closure(cx, loop_expr) {
-        let local_id = match iter_expr.path {
-            Res::Local(id) => id,
-            _ => return true,
+        let Res::Local(local_id) = iter_expr.path else {
+            return true
         };
         let mut v = NestedLoopVisitor {
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 9a0a26c0991..090f9f8ff73 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -1,6 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::match_function_call;
-use clippy_utils::paths::FUTURE_FROM_GENERATOR;
+use clippy_utils::match_function_call_with_def_id;
 use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -140,9 +139,9 @@ fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'t
         if args.bindings.len() == 1;
         let binding = &args.bindings[0];
         if binding.ident.name == sym::Output;
-        if let TypeBindingKind::Equality{term: Term::Ty(output)} = binding.kind;
+        if let TypeBindingKind::Equality { term: Term::Ty(output) } = binding.kind;
         then {
-            return Some(output)
+            return Some(output);
         }
     }
 
@@ -175,9 +174,16 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName])
 fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
     if_chain! {
         if let Some(block_expr) = block.expr;
-        if let Some(args) = match_function_call(cx, block_expr, &FUTURE_FROM_GENERATOR);
+        if let Some(args) = cx
+            .tcx
+            .lang_items()
+            .from_generator_fn()
+            .and_then(|def_id| match_function_call_with_def_id(cx, block_expr, def_id));
         if args.len() == 1;
-        if let Expr{kind: ExprKind::Closure(&Closure { body, .. }), ..} = args[0];
+        if let Expr {
+            kind: ExprKind::Closure(&Closure { body, .. }),
+            ..
+        } = args[0];
         let closure_body = cx.tcx.hir().body(body);
         if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block));
         then {
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index ece4df95505..02dc8755dd6 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -12,9 +12,9 @@ use std::ops::Deref;
 
 use clippy_utils::{
     diagnostics::{span_lint_and_then, span_lint_hir_and_then},
-    eq_expr_value, get_trait_def_id,
+    eq_expr_value,
     higher::If,
-    is_diag_trait_item, is_trait_method, meets_msrv, msrvs, path_res, path_to_local_id, paths, peel_blocks,
+    is_diag_trait_item, is_trait_method, meets_msrv, msrvs, path_res, path_to_local_id, peel_blocks,
     peel_blocks_with_stmt,
     sugg::Sugg,
     ty::implements_trait,
@@ -190,7 +190,11 @@ impl TypeClampability {
     fn is_clampable<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<TypeClampability> {
         if ty.is_floating_point() {
             Some(TypeClampability::Float)
-        } else if get_trait_def_id(cx, &paths::ORD).map_or(false, |id| implements_trait(cx, ty, id, &[])) {
+        } else if cx
+            .tcx
+            .get_diagnostic_item(sym::Ord)
+            .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+        {
             Some(TypeClampability::Ord)
         } else {
             None
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index fd14d868df3..33a052c41a3 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::IfLetOrMatch;
+use clippy_utils::source::snippet;
 use clippy_utils::visitors::is_local_used;
 use clippy_utils::{
     is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt, peel_ref_operators, SpanlessEq,
@@ -63,7 +64,8 @@ fn check_arm<'tcx>(
         if !pat_contains_or(inner_then_pat);
         // the binding must come from the pattern of the containing match arm
         // ..<local>.. => match <local> { .. }
-        if let Some(binding_span) = find_pat_binding(outer_pat, binding_id);
+        if let (Some(binding_span), is_innermost_parent_pat_struct)
+            = find_pat_binding_and_is_innermost_parent_pat_struct(outer_pat, binding_id);
         // the "else" branches must be equal
         if match (outer_else_body, inner_else_body) {
             (None, None) => true,
@@ -88,6 +90,13 @@ fn check_arm<'tcx>(
                 if matches!(inner, IfLetOrMatch::Match(..)) { "match" } else { "if let" },
                 if outer_is_match { "match" } else { "if let" },
             );
+            // collapsing patterns need an explicit field name in struct pattern matching
+            // ex: Struct {x: Some(1)}
+            let replace_msg = if is_innermost_parent_pat_struct {
+                format!(", prefixed by {}:", snippet(cx, binding_span, "their field name"))
+            } else {
+                String::new()
+            };
             span_lint_and_then(
                 cx,
                 COLLAPSIBLE_MATCH,
@@ -96,7 +105,7 @@ fn check_arm<'tcx>(
                 |diag| {
                     let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]);
                     help_span.push_span_label(binding_span, "replace this binding");
-                    help_span.push_span_label(inner_then_pat.span, "with this pattern");
+                    help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}"));
                     diag.span_help(help_span, "the outer pattern can be modified to include the inner pattern");
                 },
             );
@@ -117,8 +126,9 @@ fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     }
 }
 
-fn find_pat_binding(pat: &Pat<'_>, hir_id: HirId) -> Option<Span> {
+fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: HirId) -> (Option<Span>, bool) {
     let mut span = None;
+    let mut is_innermost_parent_pat_struct = false;
     pat.walk_short(|p| match &p.kind {
         // ignore OR patterns
         PatKind::Or(_) => false,
@@ -129,9 +139,12 @@ fn find_pat_binding(pat: &Pat<'_>, hir_id: HirId) -> Option<Span> {
             }
             !found
         },
-        _ => true,
+        _ => {
+            is_innermost_parent_pat_struct = matches!(p.kind, PatKind::Struct(..));
+            true
+        },
     });
-    span
+    (span, is_innermost_parent_pat_struct)
 }
 
 fn pat_contains_or(pat: &Pat<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
new file mode 100644
index 00000000000..66ba1f6f9c5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
@@ -0,0 +1,153 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::contains_unsafe_block;
+use clippy_utils::{is_res_lang_ctor, path_res, path_to_local_id};
+
+use rustc_hir::LangItem::OptionSome;
+use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::{sym, SyntaxContext};
+
+use super::manual_utils::{check_with, SomeExpr};
+use super::MANUAL_FILTER;
+
+// Function called on the <expr> of `[&+]Some((ref | ref mut) x) => <expr>`
+// Need to check if it's of the form `<expr>=if <cond> {<then_expr>} else {<else_expr>}`
+// AND that only one `then/else_expr` resolves to `Some(x)` while the other resolves to `None`
+// return the `cond` expression if so.
+fn get_cond_expr<'tcx>(
+    cx: &LateContext<'tcx>,
+    pat: &Pat<'_>,
+    expr: &'tcx Expr<'_>,
+    ctxt: SyntaxContext,
+) -> Option<SomeExpr<'tcx>> {
+    if_chain! {
+        if let Some(block_expr) = peels_blocks_incl_unsafe_opt(expr);
+        if let ExprKind::If(cond, then_expr, Some(else_expr)) = block_expr.kind;
+        if let PatKind::Binding(_,target, ..) = pat.kind;
+        if let (then_visitor, else_visitor)
+            = (is_some_expr(cx, target, ctxt, then_expr),
+                is_some_expr(cx, target, ctxt, else_expr));
+        if then_visitor != else_visitor; // check that one expr resolves to `Some(x)`, the other to `None`
+        then {
+            return Some(SomeExpr {
+                    expr: peels_blocks_incl_unsafe(cond.peel_drop_temps()),
+                    needs_unsafe_block: contains_unsafe_block(cx, expr),
+                    needs_negated: !then_visitor // if the `then_expr` resolves to `None`, need to negate the cond
+                })
+            }
+    };
+    None
+}
+
+fn peels_blocks_incl_unsafe_opt<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
+    // we don't want to use `peel_blocks` here because we don't care if the block is unsafe, it's
+    // checked by `contains_unsafe_block`
+    if let ExprKind::Block(block, None) = expr.kind {
+        if block.stmts.is_empty() {
+            return block.expr;
+        }
+    };
+    None
+}
+
+fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> {
+    peels_blocks_incl_unsafe_opt(expr).unwrap_or(expr)
+}
+
+// function called for each <expr> expression:
+// Some(x) => if <cond> {
+//    <expr>
+// } else {
+//    <expr>
+// }
+// Returns true if <expr> resolves to `Some(x)`, `false` otherwise
+fn is_some_expr<'tcx>(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &'tcx Expr<'_>) -> bool {
+    if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
+        // there can be not statements in the block as they would be removed when switching to `.filter`
+        if let ExprKind::Call(callee, [arg]) = inner_expr.kind {
+            return ctxt == expr.span.ctxt()
+                && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome)
+                && path_to_local_id(arg, target);
+        }
+    };
+    false
+}
+
+// given the closure: `|<pattern>| <expr>`
+// returns `|&<pattern>| <expr>`
+fn add_ampersand_if_copy(body_str: String, has_copy_trait: bool) -> String {
+    if has_copy_trait {
+        let mut with_ampersand = body_str;
+        with_ampersand.insert(1, '&');
+        with_ampersand
+    } else {
+        body_str
+    }
+}
+
+pub(super) fn check_match<'tcx>(
+    cx: &LateContext<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    arms: &'tcx [Arm<'_>],
+    expr: &'tcx Expr<'_>,
+) {
+    let ty = cx.typeck_results().expr_ty(expr);
+    if is_type_diagnostic_item(cx, ty, sym::Option)
+    && let [first_arm, second_arm] = arms
+    && first_arm.guard.is_none()
+    && second_arm.guard.is_none()
+         {
+            check(cx, expr, scrutinee, first_arm.pat, first_arm.body, Some(second_arm.pat), second_arm.body);
+        }
+}
+
+pub(super) fn check_if_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    let_pat: &'tcx Pat<'_>,
+    let_expr: &'tcx Expr<'_>,
+    then_expr: &'tcx Expr<'_>,
+    else_expr: &'tcx Expr<'_>,
+) {
+    check(cx, expr, let_expr, let_pat, then_expr, None, else_expr);
+}
+
+fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    scrutinee: &'tcx Expr<'_>,
+    then_pat: &'tcx Pat<'_>,
+    then_body: &'tcx Expr<'_>,
+    else_pat: Option<&'tcx Pat<'_>>,
+    else_body: &'tcx Expr<'_>,
+) {
+    if let Some(sugg_info) = check_with(
+        cx,
+        expr,
+        scrutinee,
+        then_pat,
+        then_body,
+        else_pat,
+        else_body,
+        get_cond_expr,
+    ) {
+        let body_str = add_ampersand_if_copy(sugg_info.body_str, sugg_info.scrutinee_impl_copy);
+        span_lint_and_sugg(
+            cx,
+            MANUAL_FILTER,
+            expr.span,
+            "manual implementation of `Option::filter`",
+            "try this",
+            if sugg_info.needs_brackets {
+                format!(
+                    "{{ {}{}.filter({body_str}) }}",
+                    sugg_info.scrutinee_str, sugg_info.as_ref_str
+                )
+            } else {
+                format!("{}{}.filter({body_str})", sugg_info.scrutinee_str, sugg_info.as_ref_str)
+            },
+            sugg_info.app,
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
index 76f5e1c941c..aaba239677f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs
@@ -1,22 +1,13 @@
-use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF};
+use super::manual_utils::{check_with, SomeExpr};
+use super::MANUAL_MAP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
-use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
-use clippy_utils::{
-    can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id,
-    peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
-};
-use rustc_ast::util::parser::PREC_POSTFIX;
-use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionNone, OptionSome};
-use rustc_hir::{
-    def::Res, Arm, BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path,
-    QPath, UnsafeSource,
-};
-use rustc_lint::LateContext;
-use rustc_span::{sym, SyntaxContext};
 
-use super::MANUAL_MAP;
+use clippy_utils::{is_res_lang_ctor, path_res};
+
+use rustc_hir::LangItem::OptionSome;
+use rustc_hir::{Arm, Block, BlockCheckMode, Expr, ExprKind, Pat, UnsafeSource};
+use rustc_lint::LateContext;
+use rustc_span::SyntaxContext;
 
 pub(super) fn check_match<'tcx>(
     cx: &LateContext<'tcx>,
@@ -43,7 +34,6 @@ pub(super) fn check_if_let<'tcx>(
     check(cx, expr, let_expr, let_pat, then_expr, None, else_expr);
 }
 
-#[expect(clippy::too_many_lines)]
 fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
@@ -53,254 +43,74 @@ fn check<'tcx>(
     else_pat: Option<&'tcx Pat<'_>>,
     else_body: &'tcx Expr<'_>,
 ) {
-    let (scrutinee_ty, ty_ref_count, ty_mutability) =
-        peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee));
-    if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::Option)
-        && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Option))
-    {
-        return;
-    }
-
-    let expr_ctxt = expr.span.ctxt();
-    let (some_expr, some_pat, pat_ref_count, is_wild_none) = match (
-        try_parse_pattern(cx, then_pat, expr_ctxt),
-        else_pat.map_or(Some(OptionPat::Wild), |p| try_parse_pattern(cx, p, expr_ctxt)),
+    if let Some(sugg_info) = check_with(
+        cx,
+        expr,
+        scrutinee,
+        then_pat,
+        then_body,
+        else_pat,
+        else_body,
+        get_some_expr,
     ) {
-        (Some(OptionPat::Wild), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => {
-            (else_body, pattern, ref_count, true)
-        },
-        (Some(OptionPat::None), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => {
-            (else_body, pattern, ref_count, false)
-        },
-        (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::Wild)) if is_none_expr(cx, else_body) => {
-            (then_body, pattern, ref_count, true)
-        },
-        (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::None)) if is_none_expr(cx, else_body) => {
-            (then_body, pattern, ref_count, false)
-        },
-        _ => return,
-    };
-
-    // Top level or patterns aren't allowed in closures.
-    if matches!(some_pat.kind, PatKind::Or(_)) {
-        return;
-    }
-
-    let some_expr = match get_some_expr(cx, some_expr, false, expr_ctxt) {
-        Some(expr) => expr,
-        None => return,
-    };
-
-    // These two lints will go back and forth with each other.
-    if cx.typeck_results().expr_ty(some_expr.expr) == cx.tcx.types.unit
-        && !is_lint_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id)
-    {
-        return;
-    }
-
-    // `map` won't perform any adjustments.
-    if !cx.typeck_results().expr_adjustments(some_expr.expr).is_empty() {
-        return;
-    }
-
-    // Determine which binding mode to use.
-    let explicit_ref = some_pat.contains_explicit_ref_binding();
-    let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then_some(ty_mutability));
-
-    let as_ref_str = match binding_ref {
-        Some(Mutability::Mut) => ".as_mut()",
-        Some(Mutability::Not) => ".as_ref()",
-        None => "",
-    };
-
-    match can_move_expr_to_closure(cx, some_expr.expr) {
-        Some(captures) => {
-            // 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.
-            if let Some(binding_ref_mutability) = binding_ref {
-                let e = peel_hir_expr_while(scrutinee, |e| match e.kind {
-                    ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e),
-                    _ => None,
-                });
-                if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind {
-                    match captures.get(l) {
-                        Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return,
-                        Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => {
-                            return;
-                        },
-                        Some(CaptureKind::Ref(Mutability::Not)) | None => (),
-                    }
-                }
-            }
-        },
-        None => return,
-    };
-
-    let mut app = Applicability::MachineApplicable;
-
-    // Remove address-of expressions from the scrutinee. Either `as_ref` will be called, or
-    // it's being passed by value.
-    let scrutinee = peel_hir_expr_refs(scrutinee).0;
-    let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
-    let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX {
-        format!("({scrutinee_str})")
-    } else {
-        scrutinee_str.into()
-    };
-
-    let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
-        if_chain! {
-            if !some_expr.needs_unsafe_block;
-            if let Some(func) = can_pass_as_func(cx, id, some_expr.expr);
-            if func.span.ctxt() == some_expr.expr.span.ctxt();
-            then {
-                snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
+        span_lint_and_sugg(
+            cx,
+            MANUAL_MAP,
+            expr.span,
+            "manual implementation of `Option::map`",
+            "try this",
+            if sugg_info.needs_brackets {
+                format!(
+                    "{{ {}{}.map({}) }}",
+                    sugg_info.scrutinee_str, sugg_info.as_ref_str, sugg_info.body_str
+                )
             } else {
-                if path_to_local_id(some_expr.expr, id)
-                    && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
-                    && binding_ref.is_some()
-                {
-                    return;
-                }
-
-                // `ref` and `ref mut` annotations were handled earlier.
-                let annotation = if matches!(annotation, BindingAnnotation::MUT) {
-                    "mut "
-                } else {
-                    ""
-                };
-                let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0;
-                if some_expr.needs_unsafe_block {
-                    format!("|{annotation}{some_binding}| unsafe {{ {expr_snip} }}")
-                } else {
-                    format!("|{annotation}{some_binding}| {expr_snip}")
-                }
-            }
-        }
-    } else if !is_wild_none && explicit_ref.is_none() {
-        // TODO: handle explicit reference annotations.
-        let pat_snip = snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0;
-        let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0;
-        if some_expr.needs_unsafe_block {
-            format!("|{pat_snip}| unsafe {{ {expr_snip} }}")
-        } else {
-            format!("|{pat_snip}| {expr_snip}")
-        }
-    } else {
-        // Refutable bindings and mixed reference annotations can't be handled by `map`.
-        return;
-    };
-
-    span_lint_and_sugg(
-        cx,
-        MANUAL_MAP,
-        expr.span,
-        "manual implementation of `Option::map`",
-        "try this",
-        if else_pat.is_none() && is_else_clause(cx.tcx, expr) {
-            format!("{{ {scrutinee_str}{as_ref_str}.map({body_str}) }}")
-        } else {
-            format!("{scrutinee_str}{as_ref_str}.map({body_str})")
-        },
-        app,
-    );
-}
-
-// Checks whether the expression could be passed as a function, or whether a closure is needed.
-// Returns the function to be passed to `map` if it exists.
-fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
-    match expr.kind {
-        ExprKind::Call(func, [arg])
-            if path_to_local_id(arg, binding)
-                && cx.typeck_results().expr_adjustments(arg).is_empty()
-                && !type_is_unsafe_function(cx, cx.typeck_results().expr_ty(func).peel_refs()) =>
-        {
-            Some(func)
-        },
-        _ => None,
-    }
-}
-
-enum OptionPat<'a> {
-    Wild,
-    None,
-    Some {
-        // The pattern contained in the `Some` tuple.
-        pattern: &'a Pat<'a>,
-        // The number of references before the `Some` tuple.
-        // e.g. `&&Some(_)` has a ref count of 2.
-        ref_count: usize,
-    },
-}
-
-struct SomeExpr<'tcx> {
-    expr: &'tcx Expr<'tcx>,
-    needs_unsafe_block: bool,
-}
-
-// Try to parse into a recognized `Option` pattern.
-// i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
-fn try_parse_pattern<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
-    fn f<'tcx>(
-        cx: &LateContext<'tcx>,
-        pat: &'tcx Pat<'_>,
-        ref_count: usize,
-        ctxt: SyntaxContext,
-    ) -> Option<OptionPat<'tcx>> {
-        match pat.kind {
-            PatKind::Wild => Some(OptionPat::Wild),
-            PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
-            PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone) => {
-                Some(OptionPat::None)
-            },
-            PatKind::TupleStruct(ref qpath, [pattern], _)
-                if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionSome) && pat.span.ctxt() == ctxt =>
-            {
-                Some(OptionPat::Some { pattern, ref_count })
+                format!(
+                    "{}{}.map({})",
+                    sugg_info.scrutinee_str, sugg_info.as_ref_str, sugg_info.body_str
+                )
             },
-            _ => None,
-        }
+            sugg_info.app,
+        );
     }
-    f(cx, pat, 0, ctxt)
 }
 
 // Checks for an expression wrapped by the `Some` constructor. Returns the contained expression.
 fn get_some_expr<'tcx>(
     cx: &LateContext<'tcx>,
+    _: &'tcx Pat<'_>,
     expr: &'tcx Expr<'_>,
-    needs_unsafe_block: bool,
     ctxt: SyntaxContext,
 ) -> Option<SomeExpr<'tcx>> {
-    // TODO: Allow more complex expressions.
-    match expr.kind {
-        ExprKind::Call(callee, [arg])
-            if ctxt == expr.span.ctxt() && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome) =>
-        {
-            Some(SomeExpr {
-                expr: arg,
-                needs_unsafe_block,
-            })
-        },
-        ExprKind::Block(
-            Block {
-                stmts: [],
-                expr: Some(expr),
-                rules,
-                ..
+    fn get_some_expr_internal<'tcx>(
+        cx: &LateContext<'tcx>,
+        expr: &'tcx Expr<'_>,
+        needs_unsafe_block: bool,
+        ctxt: SyntaxContext,
+    ) -> Option<SomeExpr<'tcx>> {
+        // TODO: Allow more complex expressions.
+        match expr.kind {
+            ExprKind::Call(callee, [arg])
+                if ctxt == expr.span.ctxt() && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome) =>
+            {
+                Some(SomeExpr::new_no_negated(arg, needs_unsafe_block))
             },
-            _,
-        ) => get_some_expr(
-            cx,
-            expr,
-            needs_unsafe_block || *rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
-            ctxt,
-        ),
-        _ => None,
+            ExprKind::Block(
+                Block {
+                    stmts: [],
+                    expr: Some(expr),
+                    rules,
+                    ..
+                },
+                _,
+            ) => get_some_expr_internal(
+                cx,
+                expr,
+                needs_unsafe_block || *rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+                ctxt,
+            ),
+            _ => None,
+        }
     }
-}
-
-// Checks for the `None` value.
-fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    is_res_lang_ctor(cx, path_res(cx, peel_blocks(expr)), OptionNone)
+    get_some_expr_internal(cx, expr, false, ctxt)
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
new file mode 100644
index 00000000000..5b7644a5383
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -0,0 +1,277 @@
+use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF};
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
+use clippy_utils::{
+    can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, path_to_local_id,
+    peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, sugg::Sugg, CaptureKind,
+};
+use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::{OptionNone, OptionSome};
+use rustc_hir::{def::Res, BindingAnnotation, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath};
+use rustc_lint::LateContext;
+use rustc_span::{sym, SyntaxContext};
+
+#[expect(clippy::too_many_arguments)]
+#[expect(clippy::too_many_lines)]
+pub(super) fn check_with<'tcx, F>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    scrutinee: &'tcx Expr<'_>,
+    then_pat: &'tcx Pat<'_>,
+    then_body: &'tcx Expr<'_>,
+    else_pat: Option<&'tcx Pat<'_>>,
+    else_body: &'tcx Expr<'_>,
+    get_some_expr_fn: F,
+) -> Option<SuggInfo<'tcx>>
+where
+    F: Fn(&LateContext<'tcx>, &'tcx Pat<'_>, &'tcx Expr<'_>, SyntaxContext) -> Option<SomeExpr<'tcx>>,
+{
+    let (scrutinee_ty, ty_ref_count, ty_mutability) =
+        peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee));
+    if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::Option)
+        && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Option))
+    {
+        return None;
+    }
+
+    let expr_ctxt = expr.span.ctxt();
+    let (some_expr, some_pat, pat_ref_count, is_wild_none) = match (
+        try_parse_pattern(cx, then_pat, expr_ctxt),
+        else_pat.map_or(Some(OptionPat::Wild), |p| try_parse_pattern(cx, p, expr_ctxt)),
+    ) {
+        (Some(OptionPat::Wild), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => {
+            (else_body, pattern, ref_count, true)
+        },
+        (Some(OptionPat::None), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => {
+            (else_body, pattern, ref_count, false)
+        },
+        (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::Wild)) if is_none_expr(cx, else_body) => {
+            (then_body, pattern, ref_count, true)
+        },
+        (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::None)) if is_none_expr(cx, else_body) => {
+            (then_body, pattern, ref_count, false)
+        },
+        _ => return None,
+    };
+
+    // Top level or patterns aren't allowed in closures.
+    if matches!(some_pat.kind, PatKind::Or(_)) {
+        return None;
+    }
+
+    let Some(some_expr) = get_some_expr_fn(cx, some_pat, some_expr, expr_ctxt) else {
+        return None;
+    };
+
+    // These two lints will go back and forth with each other.
+    if cx.typeck_results().expr_ty(some_expr.expr) == cx.tcx.types.unit
+        && !is_lint_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id)
+    {
+        return None;
+    }
+
+    // `map` won't perform any adjustments.
+    if !cx.typeck_results().expr_adjustments(some_expr.expr).is_empty() {
+        return None;
+    }
+
+    // Determine which binding mode to use.
+    let explicit_ref = some_pat.contains_explicit_ref_binding();
+    let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then_some(ty_mutability));
+
+    let as_ref_str = match binding_ref {
+        Some(Mutability::Mut) => ".as_mut()",
+        Some(Mutability::Not) => ".as_ref()",
+        None => "",
+    };
+
+    match can_move_expr_to_closure(cx, some_expr.expr) {
+        Some(captures) => {
+            // 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.
+            if let Some(binding_ref_mutability) = binding_ref {
+                let e = peel_hir_expr_while(scrutinee, |e| match e.kind {
+                    ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e),
+                    _ => None,
+                });
+                if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind {
+                    match captures.get(l) {
+                        Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None,
+                        Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => {
+                            return None;
+                        },
+                        Some(CaptureKind::Ref(Mutability::Not)) | None => (),
+                    }
+                }
+            }
+        },
+        None => return None,
+    };
+
+    let mut app = Applicability::MachineApplicable;
+
+    // Remove address-of expressions from the scrutinee. Either `as_ref` will be called, or
+    // it's being passed by value.
+    let scrutinee = peel_hir_expr_refs(scrutinee).0;
+    let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
+    let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX {
+        format!("({scrutinee_str})")
+    } else {
+        scrutinee_str.into()
+    };
+
+    let closure_expr_snip = some_expr.to_snippet_with_context(cx, expr_ctxt, &mut app);
+    let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
+        if_chain! {
+            if !some_expr.needs_unsafe_block;
+            if let Some(func) = can_pass_as_func(cx, id, some_expr.expr);
+            if func.span.ctxt() == some_expr.expr.span.ctxt();
+            then {
+                snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
+            } else {
+                if path_to_local_id(some_expr.expr, id)
+                    && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
+                    && binding_ref.is_some()
+                {
+                    return None;
+                }
+
+                // `ref` and `ref mut` annotations were handled earlier.
+                let annotation = if matches!(annotation, BindingAnnotation::MUT) {
+                    "mut "
+                } else {
+                    ""
+                };
+
+                if some_expr.needs_unsafe_block {
+                    format!("|{annotation}{some_binding}| unsafe {{ {closure_expr_snip} }}")
+                } else {
+                    format!("|{annotation}{some_binding}| {closure_expr_snip}")
+                }
+            }
+        }
+    } else if !is_wild_none && explicit_ref.is_none() {
+        // TODO: handle explicit reference annotations.
+        let pat_snip = snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0;
+        if some_expr.needs_unsafe_block {
+            format!("|{pat_snip}| unsafe {{ {closure_expr_snip} }}")
+        } else {
+            format!("|{pat_snip}| {closure_expr_snip}")
+        }
+    } else {
+        // Refutable bindings and mixed reference annotations can't be handled by `map`.
+        return None;
+    };
+
+    // relies on the fact that Option<T>: Copy where T: copy
+    let scrutinee_impl_copy = is_copy(cx, scrutinee_ty);
+
+    Some(SuggInfo {
+        needs_brackets: else_pat.is_none() && is_else_clause(cx.tcx, expr),
+        scrutinee_impl_copy,
+        scrutinee_str,
+        as_ref_str,
+        body_str,
+        app,
+    })
+}
+
+pub struct SuggInfo<'a> {
+    pub needs_brackets: bool,
+    pub scrutinee_impl_copy: bool,
+    pub scrutinee_str: String,
+    pub as_ref_str: &'a str,
+    pub body_str: String,
+    pub app: Applicability,
+}
+
+// Checks whether the expression could be passed as a function, or whether a closure is needed.
+// Returns the function to be passed to `map` if it exists.
+fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+    match expr.kind {
+        ExprKind::Call(func, [arg])
+            if path_to_local_id(arg, binding)
+                && cx.typeck_results().expr_adjustments(arg).is_empty()
+                && !type_is_unsafe_function(cx, cx.typeck_results().expr_ty(func).peel_refs()) =>
+        {
+            Some(func)
+        },
+        _ => None,
+    }
+}
+
+#[derive(Debug)]
+pub(super) enum OptionPat<'a> {
+    Wild,
+    None,
+    Some {
+        // The pattern contained in the `Some` tuple.
+        pattern: &'a Pat<'a>,
+        // The number of references before the `Some` tuple.
+        // e.g. `&&Some(_)` has a ref count of 2.
+        ref_count: usize,
+    },
+}
+
+pub(super) struct SomeExpr<'tcx> {
+    pub expr: &'tcx Expr<'tcx>,
+    pub needs_unsafe_block: bool,
+    pub needs_negated: bool, // for `manual_filter` lint
+}
+
+impl<'tcx> SomeExpr<'tcx> {
+    pub fn new_no_negated(expr: &'tcx Expr<'tcx>, needs_unsafe_block: bool) -> Self {
+        Self {
+            expr,
+            needs_unsafe_block,
+            needs_negated: false,
+        }
+    }
+
+    pub fn to_snippet_with_context(
+        &self,
+        cx: &LateContext<'tcx>,
+        ctxt: SyntaxContext,
+        app: &mut Applicability,
+    ) -> Sugg<'tcx> {
+        let sugg = Sugg::hir_with_context(cx, self.expr, ctxt, "..", app);
+        if self.needs_negated { !sugg } else { sugg }
+    }
+}
+
+// Try to parse into a recognized `Option` pattern.
+// i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
+pub(super) fn try_parse_pattern<'tcx>(
+    cx: &LateContext<'tcx>,
+    pat: &'tcx Pat<'_>,
+    ctxt: SyntaxContext,
+) -> Option<OptionPat<'tcx>> {
+    fn f<'tcx>(
+        cx: &LateContext<'tcx>,
+        pat: &'tcx Pat<'_>,
+        ref_count: usize,
+        ctxt: SyntaxContext,
+    ) -> Option<OptionPat<'tcx>> {
+        match pat.kind {
+            PatKind::Wild => Some(OptionPat::Wild),
+            PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
+            PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone) => {
+                Some(OptionPat::None)
+            },
+            PatKind::TupleStruct(ref qpath, [pattern], _)
+                if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionSome) && pat.span.ctxt() == ctxt =>
+            {
+                Some(OptionPat::Some { pattern, ref_count })
+            },
+            _ => None,
+        }
+    }
+    f(cx, pat, 0, ctxt)
+}
+
+// Checks for the `None` value.
+fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    is_res_lang_ctor(cx, path_res(cx, peel_blocks(expr)), OptionNone)
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 37049f83577..168c1e4d2e6 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -221,7 +221,6 @@ fn iter_matching_struct_fields<'a>(
 
 #[expect(clippy::similar_names)]
 impl<'a> NormalizedPat<'a> {
-    #[expect(clippy::too_many_lines)]
     fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self {
         match pat.kind {
             PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,
@@ -235,9 +234,8 @@ impl<'a> NormalizedPat<'a> {
                 Self::Struct(cx.qpath_res(path, pat.hir_id).opt_def_id(), fields)
             },
             PatKind::TupleStruct(ref path, pats, wild_idx) => {
-                let adt = match cx.typeck_results().pat_ty(pat).ty_adt_def() {
-                    Some(x) => x,
-                    None => return Self::Wild,
+                let Some(adt) = cx.typeck_results().pat_ty(pat).ty_adt_def() else {
+                    return Self::Wild
                 };
                 let (var_id, variant) = if adt.is_enum() {
                     match cx.qpath_res(path, pat.hir_id).opt_def_id() {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
index 68682cedf1d..1bf8d4e96ad 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
@@ -58,6 +58,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
                         &snippet_body,
                         &mut applicability,
                         Some(span),
+                        true,
                     );
 
                     span_lint_and_sugg(
@@ -90,6 +91,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
                         &snippet_body,
                         &mut applicability,
                         None,
+                        true,
                     );
                     (expr.span, sugg)
                 },
@@ -107,10 +109,14 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
         },
         PatKind::Wild => {
             if ex.can_have_side_effects() {
-                let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0));
-                let sugg = format!(
-                    "{};\n{indent}{snippet_body}",
-                    snippet_with_applicability(cx, ex.span, "..", &mut applicability)
+                let sugg = sugg_with_curlies(
+                    cx,
+                    (ex, expr),
+                    (bind_names, matched_vars),
+                    &snippet_body,
+                    &mut applicability,
+                    None,
+                    false,
                 );
 
                 span_lint_and_sugg(
@@ -169,6 +175,7 @@ fn sugg_with_curlies<'a>(
     snippet_body: &str,
     applicability: &mut Applicability,
     assignment: Option<Span>,
+    needs_var_binding: bool,
 ) -> String {
     let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
 
@@ -200,9 +207,15 @@ fn sugg_with_curlies<'a>(
         s
     });
 
-    format!(
-        "{cbrace_start}let {} = {};\n{indent}{assignment_str}{snippet_body}{cbrace_end}",
-        snippet_with_applicability(cx, bind_names, "..", applicability),
-        snippet_with_applicability(cx, matched_vars, "..", applicability)
-    )
+    let scrutinee = if needs_var_binding {
+        format!(
+            "let {} = {}",
+            snippet_with_applicability(cx, bind_names, "..", applicability),
+            snippet_with_applicability(cx, matched_vars, "..", applicability)
+        )
+    } else {
+        snippet_with_applicability(cx, matched_vars, "..", applicability).to_string()
+    };
+
+    format!("{cbrace_start}{scrutinee};\n{indent}{assignment_str}{snippet_body}{cbrace_end}")
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index e6b183fc05f..7d8171ead89 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -1,7 +1,9 @@
 mod collapsible_match;
 mod infallible_destructuring_match;
+mod manual_filter;
 mod manual_map;
 mod manual_unwrap_or;
+mod manual_utils;
 mod match_as_ref;
 mod match_bool;
 mod match_like_matches;
@@ -898,6 +900,34 @@ declare_clippy_lint! {
     "reimplementation of `map`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usages of `match` which could be implemented using `filter`
+    ///
+    /// ### Why is this bad?
+    /// Using the `filter` method is clearer and more concise.
+    ///
+    /// ### Example
+    /// ```rust
+    /// match Some(0) {
+    ///     Some(x) => if x % 2 == 0 {
+    ///                     Some(x)
+    ///                } else {
+    ///                     None
+    ///                 },
+    ///     None => None,
+    /// };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// Some(0).filter(|&x| x % 2 == 0);
+    /// ```
+    #[clippy::version = "1.66.0"]
+    pub MANUAL_FILTER,
+    complexity,
+    "reimplentation of `filter`"
+}
+
 #[derive(Default)]
 pub struct Matches {
     msrv: Option<RustcVersion>,
@@ -939,6 +969,7 @@ impl_lint_pass!(Matches => [
     SIGNIFICANT_DROP_IN_SCRUTINEE,
     TRY_ERR,
     MANUAL_MAP,
+    MANUAL_FILTER,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Matches {
@@ -988,6 +1019,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                     if !in_constant(cx, expr.hir_id) {
                         manual_unwrap_or::check(cx, expr, ex, arms);
                         manual_map::check_match(cx, expr, ex, arms);
+                        manual_filter::check_match(cx, ex, arms, expr);
                     }
 
                     if self.infallible_destructuring_match_linted {
@@ -1014,6 +1046,14 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                     }
                     if !in_constant(cx, expr.hir_id) {
                         manual_map::check_if_let(cx, expr, if_let.let_pat, if_let.let_expr, if_let.if_then, else_expr);
+                        manual_filter::check_if_let(
+                            cx,
+                            expr,
+                            if_let.let_pat,
+                            if_let.let_expr,
+                            if_let.if_then,
+                            else_expr,
+                        );
                     }
                 }
                 redundant_pattern_match::check_if_let(
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index d496107ffd6..e5a15b2e1a1 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -1,14 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{expr_block, snippet};
-use clippy_utils::ty::{implements_trait, match_type, peel_mid_ty_refs};
-use clippy_utils::{
-    is_lint_allowed, is_unit_expr, is_wild, paths, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs,
-};
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs};
+use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs};
 use core::cmp::max;
 use rustc_errors::Applicability;
 use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
+use rustc_span::sym;
 
 use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
 
@@ -156,10 +155,10 @@ fn pat_in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'a>, pat: &Pat<'_>) ->
 /// Returns `true` if the given type is an enum we know won't be expanded in the future
 fn in_candidate_enum<'a>(cx: &LateContext<'a>, ty: Ty<'_>) -> bool {
     // list of candidate `Enum`s we know will never get any more members
-    let candidates = [&paths::COW, &paths::OPTION, &paths::RESULT];
+    let candidates = [sym::Cow, sym::Option, sym::Result];
 
     for candidate_ty in candidates {
-        if match_type(cx, ty, candidate_ty) {
+        if is_type_diagnostic_item(cx, ty, candidate_ty) {
             return true;
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
index be56b63506a..8adf9e37059 100644
--- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
@@ -42,9 +42,8 @@ pub(super) fn check(
 
 fn ty_has_iter_method(cx: &LateContext<'_>, self_ref_ty: Ty<'_>) -> Option<(Symbol, &'static str)> {
     has_iter_method(cx, self_ref_ty).map(|ty_name| {
-        let mutbl = match self_ref_ty.kind() {
-            ty::Ref(_, _, mutbl) => mutbl,
-            _ => unreachable!(),
+        let ty::Ref(_, _, mutbl) = self_ref_ty.kind() else {
+            unreachable!()
         };
         let method_name = match mutbl {
             hir::Mutability::Not => "iter",
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
index ec694cf6882..b80541b8647 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -21,11 +21,7 @@ pub fn check(
         return;
     }
 
-    let mm = if let Some(mm) = is_min_or_max(cx, unwrap_arg) {
-        mm
-    } else {
-        return;
-    };
+    let Some(mm) = is_min_or_max(cx, unwrap_arg) else { return };
 
     if ty.is_signed() {
         use self::{
@@ -33,9 +29,7 @@ pub fn check(
             Sign::{Neg, Pos},
         };
 
-        let sign = if let Some(sign) = lit_sign(arith_rhs) {
-            sign
-        } else {
+        let Some(sign) = lit_sign(arith_rhs) else {
             return;
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index cfcf9596c50..fb92779be2a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -102,9 +102,7 @@ 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, 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 clippy_utils::{contains_return, is_trait_method, iter_input_pats, meets_msrv, msrvs, return_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -3372,7 +3370,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             then {
                 let first_arg_span = first_arg_ty.span;
                 let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
-                let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder();
+                let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id())
+                    .self_ty()
+                    .skip_binder();
                 wrong_self_convention::check(
                     cx,
                     item.ident.name.as_str(),
@@ -3380,7 +3380,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                     first_arg_ty,
                     first_arg_span,
                     false,
-                    true
+                    true,
                 );
             }
         }
@@ -3389,7 +3389,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             if item.ident.name == sym::new;
             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();
+            let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id())
+                .self_ty()
+                .skip_binder();
             if !ret_ty.contains(self_ty);
 
             then {
@@ -3846,14 +3848,13 @@ impl SelfKind {
                 return m == mutability && t == parent_ty;
             }
 
-            let trait_path = match mutability {
-                hir::Mutability::Not => &paths::ASREF_TRAIT,
-                hir::Mutability::Mut => &paths::ASMUT_TRAIT,
+            let trait_sym = match mutability {
+                hir::Mutability::Not => sym::AsRef,
+                hir::Mutability::Mut => sym::AsMut,
             };
 
-            let trait_def_id = match get_trait_def_id(cx, trait_path) {
-                Some(did) => did,
-                None => return false,
+            let Some(trait_def_id) = cx.tcx.get_diagnostic_item(trait_sym) else {
+                return false
             };
             implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index 6fb92d1c663..742483e6b2e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -32,8 +32,7 @@ pub(super) fn check<'tcx>(
         return;
     }
 
-    let deref_aliases: [&[&str]; 9] = [
-        &paths::DEREF_TRAIT_METHOD,
+    let deref_aliases: [&[&str]; 8] = [
         &paths::DEREF_MUT_TRAIT_METHOD,
         &paths::CSTRING_AS_C_STR,
         &paths::OS_STRING_AS_OS_STR,
@@ -45,12 +44,14 @@ pub(super) fn check<'tcx>(
     ];
 
     let is_deref = match map_arg.kind {
-        hir::ExprKind::Path(ref expr_qpath) => cx
-            .qpath_res(expr_qpath, map_arg.hir_id)
-            .opt_def_id()
-            .map_or(false, |fun_def_id| {
-                deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
-            }),
+        hir::ExprKind::Path(ref expr_qpath) => {
+            cx.qpath_res(expr_qpath, map_arg.hir_id)
+                .opt_def_id()
+                .map_or(false, |fun_def_id| {
+                    cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id)
+                        || deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
+                })
+        },
         hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
             let closure_body = cx.tcx.hir().body(body);
             let closure_expr = peel_blocks(closure_body.value);
@@ -68,7 +69,8 @@ pub(super) fn check<'tcx>(
                         if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
                         then {
                             let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
-                            deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
+                            cx.tcx.is_diagnostic_item(sym::deref_method, method_did)
+                                || deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
                         } else {
                             false
                         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 6a35024d036..991d3dd538b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -1,14 +1,14 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
 use clippy_utils::source::{snippet, snippet_with_macro_callsite};
-use clippy_utils::ty::{implements_trait, match_type};
-use clippy_utils::{contains_return, is_trait_item, last_path_segment, paths};
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::{contains_return, is_trait_item, last_path_segment};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::source_map::Span;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::{kw, sym, Symbol};
 use std::borrow::Cow;
 
 use super::OR_FUN_CALL;
@@ -88,11 +88,11 @@ pub(super) fn check<'tcx>(
         fun_span: Option<Span>,
     ) {
         // (path, fn_has_argument, methods, suffix)
-        const KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [
-            (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"),
-            (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"),
-            (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
-            (&paths::RESULT, true, &["or", "unwrap_or"], "else"),
+        const KNOW_TYPES: [(Symbol, bool, &[&str], &str); 4] = [
+            (sym::BTreeEntry, false, &["or_insert"], "with"),
+            (sym::HashMapEntry, false, &["or_insert"], "with"),
+            (sym::Option, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"),
+            (sym::Result, true, &["or", "unwrap_or"], "else"),
         ];
 
         if_chain! {
@@ -104,7 +104,7 @@ pub(super) fn check<'tcx>(
             let self_ty = cx.typeck_results().expr_ty(self_expr);
 
             if let Some(&(_, fn_has_arguments, poss, suffix)) =
-                KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0));
+                KNOW_TYPES.iter().find(|&&i| is_type_diagnostic_item(cx, self_ty, i.0));
 
             if poss.contains(&name);
 
@@ -121,10 +121,9 @@ pub(super) fn check<'tcx>(
                             macro_expanded_snipped = snippet(cx, snippet_span, "..");
                             match macro_expanded_snipped.strip_prefix("$crate::vec::") {
                                 Some(stripped) => Cow::from(stripped),
-                                None => macro_expanded_snipped
+                                None => macro_expanded_snipped,
                             }
-                        }
-                        else {
+                        } else {
                             not_macro_argument_snippet
                         }
                     };
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index ae3594bd36c..1acac59144c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -289,9 +289,7 @@ fn parse_iter_usage<'tcx>(
 ) -> Option<IterUsage> {
     let (kind, span) = match iter.next() {
         Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
-            let (name, args) = if let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind {
-                (name, args)
-            } else {
+            let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind else {
                 return None;
             };
             let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 5cf88bfc888..3566fe9a0bb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -363,7 +363,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                 && let output_ty = return_ty(cx, item.hir_id())
                 && let local_def_id = cx.tcx.hir().local_def_id(item.hir_id())
                 && Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
-                    let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.hir_id());
+                    let fn_ctxt = FnCtxt::new(inherited, cx.param_env, item.hir_id());
                     fn_ctxt.can_coerce(ty, output_ty)
                 }) {
                     if has_lifetime(output_ty) && has_lifetime(ty) {
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
index 62c6ca32d31..27e7f8505eb 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
@@ -6,9 +6,7 @@ use rustc_lint::EarlyContext;
 use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX};
 
 pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
-    let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
-        val
-    } else {
+    let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else {
         return; // It's useless so shouldn't lint.
     };
     // Do not lint when literal is unsuffixed.
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs b/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
index 80e24213100..263ee1e945a 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
@@ -5,9 +5,7 @@ use rustc_lint::EarlyContext;
 use super::MIXED_CASE_HEX_LITERALS;
 
 pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, suffix: &str, lit_snip: &str) {
-    let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
-        val
-    } else {
+    let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else {
         return; // It's useless so shouldn't lint.
     };
     if maybe_last_sep_idx <= 2 {
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs b/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs
index 4963bba82f2..9ead43ea4a4 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs
@@ -6,6 +6,7 @@ use rustc_lint::EarlyContext;
 use super::ZERO_PREFIXED_LITERAL;
 
 pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str) {
+    let trimmed_lit_snip = lit_snip.trim_start_matches(|c| c == '_' || c == '0');
     span_lint_and_then(
         cx,
         ZERO_PREFIXED_LITERAL,
@@ -15,15 +16,18 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str) {
             diag.span_suggestion(
                 lit.span,
                 "if you mean to use a decimal constant, remove the `0` to avoid confusion",
-                lit_snip.trim_start_matches(|c| c == '_' || c == '0').to_string(),
-                Applicability::MaybeIncorrect,
-            );
-            diag.span_suggestion(
-                lit.span,
-                "if you mean to use an octal constant, use `0o`",
-                format!("0o{}", lit_snip.trim_start_matches(|c| c == '_' || c == '0')),
+                trimmed_lit_snip.to_string(),
                 Applicability::MaybeIncorrect,
             );
+            // do not advise to use octal form if the literal cannot be expressed in base 8.
+            if !lit_snip.contains(|c| c == '8' || c == '9') {
+                diag.span_suggestion(
+                    lit.span,
+                    "if you mean to use an octal constant, use `0o`",
+                    format!("0o{trimmed_lit_snip}"),
+                    Applicability::MaybeIncorrect,
+                );
+            }
         },
     );
 }
diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
index 6dd76a6531e..9de4b56b77b 100644
--- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
+++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
@@ -70,9 +70,8 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch {
 
                 // find the type that the Impl is for
                 // only lint on struct/enum/union for now
-                let defid = match path.res {
-                    Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, defid) => defid,
-                    _ => return,
+                let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, defid) = path.res else {
+                    return
                 };
 
                 // get the names of the generic parameters in the type
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
new file mode 100644
index 00000000000..68af8a672f6
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -0,0 +1,98 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_lint_allowed;
+use clippy_utils::macros::span_is_local;
+use rustc_hir::def_id::DefIdMap;
+use rustc_hir::{Impl, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::AssocItem;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks if a provided method is used implicitly by a trait
+    /// implementation. A usage example would be a wrapper where every method
+    /// should perform some operation before delegating to the inner type's
+    /// implemenation.
+    ///
+    /// This lint should typically be enabled on a specific trait `impl` item
+    /// rather than globally.
+    ///
+    /// ### Why is this bad?
+    /// Indicates that a method is missing.
+    ///
+    /// ### Example
+    /// ```rust
+    /// trait Trait {
+    ///     fn required();
+    ///
+    ///     fn provided() {}
+    /// }
+    ///
+    /// # struct Type;
+    /// #[warn(clippy::missing_trait_methods)]
+    /// impl Trait for Type {
+    ///     fn required() { /* ... */ }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// trait Trait {
+    ///     fn required();
+    ///
+    ///     fn provided() {}
+    /// }
+    ///
+    /// # struct Type;
+    /// #[warn(clippy::missing_trait_methods)]
+    /// impl Trait for Type {
+    ///     fn required() { /* ... */ }
+    ///
+    ///     fn provided() { /* ... */ }
+    /// }
+    /// ```
+    #[clippy::version = "1.66.0"]
+    pub MISSING_TRAIT_METHODS,
+    restriction,
+    "trait implementation uses default provided method"
+}
+declare_lint_pass!(MissingTraitMethods => [MISSING_TRAIT_METHODS]);
+
+impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if !is_lint_allowed(cx, MISSING_TRAIT_METHODS, item.hir_id())
+            && span_is_local(item.span)
+            && let ItemKind::Impl(Impl {
+                items,
+                of_trait: Some(trait_ref),
+                ..
+            }) = item.kind
+            && let Some(trait_id) = trait_ref.trait_def_id()
+        {
+            let mut provided: DefIdMap<&AssocItem> = cx
+                .tcx
+                .provided_trait_methods(trait_id)
+                .map(|assoc| (assoc.def_id, assoc))
+                .collect();
+
+            for impl_item in *items {
+                if let Some(def_id) = impl_item.trait_item_def_id {
+                    provided.remove(&def_id);
+                }
+            }
+
+            for assoc in provided.values() {
+                let source_map = cx.tcx.sess.source_map();
+                let definition_span = source_map.guess_head_span(cx.tcx.def_span(assoc.def_id));
+
+                span_lint_and_help(
+                    cx,
+                    MISSING_TRAIT_METHODS,
+                    source_map.guess_head_span(item.span),
+                    &format!("missing trait method provided by default: `{}`", assoc.name),
+                    Some(definition_span),
+                    "implement the method",
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index a2419c277e9..6752976348f 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -190,10 +190,7 @@ fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
         if parent_id == cur_id {
             break;
         }
-        let parent_node = match map.find(parent_id) {
-            Some(parent) => parent,
-            None => break,
-        };
+        let Some(parent_node) = map.find(parent_id) else { break };
 
         let stop_early = match parent_node {
             Node::Expr(expr) => check_expr(vis, expr),
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 3233d87c073..c3b633fd6a0 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -49,9 +49,8 @@ declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]);
 
 impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        let expr = match stmt.kind {
-            StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr,
-            _ => return,
+        let (StmtKind::Expr(expr) | StmtKind::Semi(expr)) = stmt.kind else {
+             return
         };
 
         if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
index a7e0e35787c..5c2b96f5b2c 100644
--- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{self, get_trait_def_id, paths};
 use if_chain::if_chain;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 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::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -47,18 +47,16 @@ declare_lint_pass!(NoNegCompOpForPartialOrd => [NEG_CMP_OP_ON_PARTIAL_ORD]);
 impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
-
             if !in_external_macro(cx.sess(), expr.span);
             if let ExprKind::Unary(UnOp::Not, inner) = expr.kind;
             if let ExprKind::Binary(ref op, left, _) = inner.kind;
             if let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node;
 
             then {
-
                 let ty = cx.typeck_results().expr_ty(left);
 
                 let implements_ord = {
-                    if let Some(id) = get_trait_def_id(cx, &paths::ORD) {
+                    if let Some(id) = cx.tcx.get_diagnostic_item(sym::Ord) {
                         implements_trait(cx, ty, id, &[])
                     } else {
                         return;
@@ -81,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
                         "the use of negated comparison operators on partially ordered \
                         types produces code that is hard to read and refactor, please \
                         consider using the `partial_cmp` method instead, to make it \
-                        clear that the two values could be incomparable"
+                        clear that the two values could be incomparable",
                     );
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 2c839d029c6..a6742824bc5 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -357,9 +357,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
             }
 
             // Make sure it is a const item.
-            let item_def_id = match cx.qpath_res(qpath, expr.hir_id) {
-                Res::Def(DefKind::Const | DefKind::AssocConst, did) => did,
-                _ => return,
+            let Res::Def(DefKind::Const | DefKind::AssocConst, item_def_id) = cx.qpath_res(qpath, expr.hir_id) else {
+                return
             };
 
             // Climb up to resolve any field access and explicit referencing.
diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
index 1a765b14892..2ecb0487484 100644
--- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
@@ -55,9 +55,8 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
                     if let ExprKind::Lit(_) = param.kind;
 
                     then {
-                        let snip = match snippet_opt(cx, param.span) {
-                            Some(s) => s,
-                            _ => return,
+                        let Some(snip) = snippet_opt(cx, param.span) else {
+                            return
                         };
 
                         if !snip.starts_with("0o") {
@@ -72,16 +71,10 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
                     if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
                     if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE);
                     if let ExprKind::Lit(_) = param.kind;
-
+                    if let Some(snip) = snippet_opt(cx, param.span);
+                    if !snip.starts_with("0o");
                     then {
-                        let snip = match snippet_opt(cx, param.span) {
-                            Some(s) => s,
-                            _ => return,
-                        };
-
-                        if !snip.starts_with("0o") {
-                            show_error(cx, param);
-                        }
+                        show_error(cx, param);
                     }
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
index 0ca0befc135..6c909e5ed73 100644
--- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
+++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
@@ -266,7 +266,7 @@ impl<'de> Deserialize<'de> for MacroMatcher {
                         .iter()
                         .find(|b| b.0 == brace)
                         .map(|(o, c)| ((*o).to_owned(), (*c).to_owned()))
-                        .ok_or_else(|| de::Error::custom(&format!("expected one of `(`, `{{`, `[` found `{brace}`")))?,
+                        .ok_or_else(|| de::Error::custom(format!("expected one of `(`, `{{`, `[` found `{brace}`")))?,
                 })
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index c9c777f1bd8..24aeb82a37f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{match_any_def_paths, path_def_id, paths};
+use clippy_utils::{match_def_path, path_def_id, paths};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 use rustc_lint::LateContext;
@@ -49,13 +49,15 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
             (arg, arg.span)
         },
         ExprKind::Call(path, [arg])
-            if path_def_id(cx, path)
-                .and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM]))
-                .map_or(false, |idx| match idx {
-                    0 => true,
-                    1 => !is_copy(cx, typeck.expr_ty(expr)),
-                    _ => false,
-                }) =>
+            if path_def_id(cx, path).map_or(false, |id| {
+                if match_def_path(cx, id, &paths::FROM_STR_METHOD) {
+                    true
+                } else if cx.tcx.lang_items().from_fn() == Some(id) {
+                    !is_copy(cx, typeck.expr_ty(expr))
+                } else {
+                    false
+                }
+            }) =>
         {
             (arg, arg.span)
         },
diff --git a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
new file mode 100644
index 00000000000..f60d9d65b12
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
@@ -0,0 +1,81 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_ast::ast::{Item, ItemKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks whether partial fields of a struct are public.
+    ///
+    /// Either make all fields of a type public, or make none of them public
+    ///
+    /// ### Why is this bad?
+    /// Most types should either be:
+    /// * Abstract data types: complex objects with opaque implementation which guard
+    /// interior invariants and expose intentionally limited API to the outside world.
+    /// * Data: relatively simple objects which group a bunch of related attributes together.
+    ///
+    /// ### Example
+    /// ```rust
+    /// pub struct Color {
+    ///     pub r: u8,
+    ///     pub g: u8,
+    ///     b: u8,
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// pub struct Color {
+    ///     pub r: u8,
+    ///     pub g: u8,
+    ///     pub b: u8,
+    /// }
+    /// ```
+    #[clippy::version = "1.66.0"]
+    pub PARTIAL_PUB_FIELDS,
+    restriction,
+    "partial fields of a struct are public"
+}
+declare_lint_pass!(PartialPubFields => [PARTIAL_PUB_FIELDS]);
+
+impl EarlyLintPass for PartialPubFields {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        let ItemKind::Struct(ref st, _) = item.kind else {
+            return;
+        };
+
+        let mut fields = st.fields().iter();
+        let Some(first_field) = fields.next() else {
+            // Empty struct.
+            return;
+        };
+        let all_pub = first_field.vis.kind.is_pub();
+        let all_priv = !all_pub;
+
+        let msg = "mixed usage of pub and non-pub fields";
+
+        for field in fields {
+            if all_priv && field.vis.kind.is_pub() {
+                span_lint_and_help(
+                    cx,
+                    PARTIAL_PUB_FIELDS,
+                    field.vis.span,
+                    msg,
+                    None,
+                    "consider using private field here",
+                );
+                return;
+            } else if all_pub && !field.vis.kind.is_pub() {
+                span_lint_and_help(
+                    cx,
+                    PARTIAL_PUB_FIELDS,
+                    field.vis.span,
+                    msg,
+                    None,
+                    "consider using public field here",
+                );
+                return;
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index d296a150b46..40db315bf27 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -15,13 +15,17 @@ use rustc_hir::{
     ImplItemKind, ItemKind, Lifetime, LifetimeName, Mutability, Node, Param, ParamName, PatKind, QPath, TraitFn,
     TraitItem, TraitItemKind, TyKind, Unsafety,
 };
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::{Obligation, ObligationCause};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Binder, ExistentialPredicate, List, PredicateKind, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use std::fmt;
 use std::iter;
 
@@ -384,6 +388,17 @@ enum DerefTy<'tcx> {
     Slice(Option<Span>, Ty<'tcx>),
 }
 impl<'tcx> DerefTy<'tcx> {
+    fn ty(&self, cx: &LateContext<'tcx>) -> Ty<'tcx> {
+        match *self {
+            Self::Str => cx.tcx.types.str_,
+            Self::Path => cx.tcx.mk_adt(
+                cx.tcx.adt_def(cx.tcx.get_diagnostic_item(sym::Path).unwrap()),
+                List::empty(),
+            ),
+            Self::Slice(_, ty) => cx.tcx.mk_slice(ty),
+        }
+    }
+
     fn argless_str(&self) -> &'static str {
         match *self {
             Self::Str => "str",
@@ -552,9 +567,8 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
             }
 
             // Check if this is local we care about
-            let args_idx = match path_to_local(e).and_then(|id| self.bindings.get(&id)) {
-                Some(&i) => i,
-                None => return walk_expr(self, e),
+            let Some(&args_idx) = path_to_local(e).and_then(|id| self.bindings.get(&id)) else {
+                return walk_expr(self, e);
             };
             let args = &self.args[args_idx];
             let result = &mut self.results[args_idx];
@@ -582,6 +596,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
                         let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
                         if expr_sig(self.cx, f).and_then(|sig| sig.input(i)).map_or(true, |ty| {
                             match *ty.skip_binder().peel_refs().kind() {
+                                ty::Dynamic(preds, _, _) => !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds),
                                 ty::Param(_) => true,
                                 ty::Adt(def, _) => def.did() == args.ty_did,
                                 _ => false,
@@ -609,14 +624,15 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
                             }
                         }
 
-                        let id = if let Some(x) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) {
-                            x
-                        } else {
+                        let Some(id) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) else {
                             set_skip_flag();
                             return;
                         };
 
                         match *self.cx.tcx.fn_sig(id).skip_binder().inputs()[i].peel_refs().kind() {
+                            ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => {
+                                set_skip_flag();
+                            },
                             ty::Param(_) => {
                                 set_skip_flag();
                             },
@@ -668,6 +684,30 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
     v.results
 }
 
+fn matches_preds<'tcx>(
+    cx: &LateContext<'tcx>,
+    ty: Ty<'tcx>,
+    preds: &'tcx [Binder<'tcx, ExistentialPredicate<'tcx>>],
+) -> bool {
+    let infcx = cx.tcx.infer_ctxt().build();
+    preds.iter().all(|&p| match cx.tcx.erase_late_bound_regions(p) {
+        ExistentialPredicate::Trait(p) => infcx
+            .type_implements_trait(p.def_id, ty, p.substs, cx.param_env)
+            .must_apply_modulo_regions(),
+        ExistentialPredicate::Projection(p) => infcx.predicate_must_hold_modulo_regions(&Obligation::new(
+            ObligationCause::dummy(),
+            cx.param_env,
+            cx.tcx.mk_predicate(Binder::bind_with_vars(
+                PredicateKind::Projection(p.with_self_ty(cx.tcx, ty)),
+                List::empty(),
+            )),
+        )),
+        ExistentialPredicate::AutoTrait(p) => infcx
+            .type_implements_trait(p, ty, List::empty(), cx.param_env)
+            .must_apply_modulo_regions(),
+    })
+}
+
 fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
     if let TyKind::Rptr(lt, ref m) = ty.kind {
         Some((lt, m.mutbl, ty.span))
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index b0a5d1a6758..72dda67c72b 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -49,15 +49,13 @@ declare_lint_pass!(PtrOffsetWithCast => [PTR_OFFSET_WITH_CAST]);
 impl<'tcx> LateLintPass<'tcx> for PtrOffsetWithCast {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // Check if the expressions is a ptr.offset or ptr.wrapping_offset method call
-        let (receiver_expr, arg_expr, method) = match expr_as_ptr_offset_call(cx, expr) {
-            Some(call_arg) => call_arg,
-            None => return,
+        let Some((receiver_expr, arg_expr, method)) = expr_as_ptr_offset_call(cx, expr) else {
+            return
         };
 
         // Check if the argument to the method call is a cast from usize
-        let cast_lhs_expr = match expr_as_cast_from_usize(cx, arg_expr) {
-            Some(cast_lhs_expr) => cast_lhs_expr,
-            None => return,
+        let Some(cast_lhs_expr) = expr_as_cast_from_usize(cx, arg_expr) else {
+            return
         };
 
         let msg = format!("use of `{method}` with a `usize` casted to an `isize`");
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 9fd86331ec7..aedbe08e3e4 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -1,25 +1,18 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
+use clippy_utils::mir::{visit_local_usage, LocalUsage, PossibleBorrowerMap};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{has_drop, is_copy, is_type_diagnostic_item, walk_ptrs_ty_depth};
 use clippy_utils::{fn_has_unsatisfiable_preds, match_def_path, paths};
 use if_chain::if_chain;
-use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{def_id, Body, FnDecl, HirId};
-use rustc_index::bit_set::{BitSet, HybridBitSet};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::mir::{
-    self, traversal,
-    visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _},
-    Mutability,
-};
-use rustc_middle::ty::{self, visit::TypeVisitor, Ty};
-use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis, ResultsCursor};
+use rustc_middle::mir;
+use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::{BytePos, Span};
 use rustc_span::sym;
-use std::ops::ControlFlow;
 
 macro_rules! unwrap_or_continue {
     ($x:expr) => {
@@ -89,21 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
 
         let mir = cx.tcx.optimized_mir(def_id.to_def_id());
 
-        let possible_origin = {
-            let mut vis = PossibleOriginVisitor::new(mir);
-            vis.visit_body(mir);
-            vis.into_map(cx)
-        };
-        let maybe_storage_live_result = MaybeStorageLive
-            .into_engine(cx.tcx, mir)
-            .pass_name("redundant_clone")
-            .iterate_to_fixpoint()
-            .into_results_cursor(mir);
-        let mut possible_borrower = {
-            let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
-            vis.visit_body(mir);
-            vis.into_map(cx, maybe_storage_live_result)
-        };
+        let mut possible_borrower = PossibleBorrowerMap::new(cx, mir);
 
         for (bb, bbdata) in mir.basic_blocks.iter_enumerated() {
             let terminator = bbdata.terminator();
@@ -374,403 +353,40 @@ struct CloneUsage {
     /// Whether the clone value is mutated.
     clone_consumed_or_mutated: bool,
 }
-fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, bb: mir::BasicBlock) -> CloneUsage {
-    struct V {
-        cloned: mir::Local,
-        clone: mir::Local,
-        result: CloneUsage,
-    }
-    impl<'tcx> mir::visit::Visitor<'tcx> for V {
-        fn visit_basic_block_data(&mut self, block: mir::BasicBlock, data: &mir::BasicBlockData<'tcx>) {
-            let statements = &data.statements;
-            for (statement_index, statement) in statements.iter().enumerate() {
-                self.visit_statement(statement, mir::Location { block, statement_index });
-            }
-
-            self.visit_terminator(
-                data.terminator(),
-                mir::Location {
-                    block,
-                    statement_index: statements.len(),
-                },
-            );
-        }
-
-        fn visit_place(&mut self, place: &mir::Place<'tcx>, ctx: PlaceContext, loc: mir::Location) {
-            let local = place.local;
-
-            if local == self.cloned
-                && !matches!(
-                    ctx,
-                    PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_)
-                )
-            {
-                self.result.cloned_used = true;
-                self.result.cloned_consume_or_mutate_loc = self.result.cloned_consume_or_mutate_loc.or_else(|| {
-                    matches!(
-                        ctx,
-                        PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)
-                            | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
-                    )
-                    .then(|| loc)
-                });
-            } else if local == self.clone {
-                match ctx {
-                    PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)
-                    | PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
-                        self.result.clone_consumed_or_mutated = true;
-                    },
-                    _ => {},
-                }
-            }
-        }
-    }
-
-    let init = CloneUsage {
-        cloned_used: false,
-        cloned_consume_or_mutate_loc: None,
-        // Consider non-temporary clones consumed.
-        // TODO: Actually check for mutation of non-temporaries.
-        clone_consumed_or_mutated: mir.local_kind(clone) != mir::LocalKind::Temp,
-    };
-    traversal::ReversePostorder::new(mir, bb)
-        .skip(1)
-        .fold(init, |usage, (tbb, tdata)| {
-            // Short-circuit
-            if (usage.cloned_used && usage.clone_consumed_or_mutated) ||
-                // Give up on loops
-                tdata.terminator().successors().any(|s| s == bb)
-            {
-                return CloneUsage {
-                    cloned_used: true,
-                    clone_consumed_or_mutated: true,
-                    ..usage
-                };
-            }
-
-            let mut v = V {
-                cloned,
-                clone,
-                result: usage,
-            };
-            v.visit_basic_block_data(tbb, tdata);
-            v.result
-        })
-}
-
-/// Determines liveness of each local purely based on `StorageLive`/`Dead`.
-#[derive(Copy, Clone)]
-struct MaybeStorageLive;
-
-impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
-    type Domain = BitSet<mir::Local>;
-    const NAME: &'static str = "maybe_storage_live";
-
-    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
-        // bottom = dead
-        BitSet::new_empty(body.local_decls.len())
-    }
-
-    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
-        for arg in body.args_iter() {
-            state.insert(arg);
-        }
-    }
-}
-
-impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
-    type Idx = mir::Local;
-
-    fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
-        match stmt.kind {
-            mir::StatementKind::StorageLive(l) => trans.gen(l),
-            mir::StatementKind::StorageDead(l) => trans.kill(l),
-            _ => (),
-        }
-    }
-
-    fn terminator_effect(
-        &self,
-        _trans: &mut impl GenKill<Self::Idx>,
-        _terminator: &mir::Terminator<'tcx>,
-        _loc: mir::Location,
-    ) {
-    }
-
-    fn call_return_effect(
-        &self,
-        _trans: &mut impl GenKill<Self::Idx>,
-        _block: mir::BasicBlock,
-        _return_places: CallReturnPlaces<'_, 'tcx>,
-    ) {
-        // Nothing to do when a call returns successfully
-    }
-}
-
-/// Collects the possible borrowers of each local.
-/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
-/// possible borrowers of `a`.
-struct PossibleBorrowerVisitor<'a, 'tcx> {
-    possible_borrower: TransitiveRelation,
-    body: &'a mir::Body<'tcx>,
-    cx: &'a LateContext<'tcx>,
-    possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
-}
-
-impl<'a, 'tcx> PossibleBorrowerVisitor<'a, 'tcx> {
-    fn new(
-        cx: &'a LateContext<'tcx>,
-        body: &'a mir::Body<'tcx>,
-        possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
-    ) -> Self {
-        Self {
-            possible_borrower: TransitiveRelation::default(),
-            cx,
-            body,
-            possible_origin,
-        }
-    }
-
-    fn into_map(
-        self,
-        cx: &LateContext<'tcx>,
-        maybe_live: ResultsCursor<'tcx, 'tcx, MaybeStorageLive>,
-    ) -> PossibleBorrowerMap<'a, 'tcx> {
-        let mut map = FxHashMap::default();
-        for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
-            if is_copy(cx, self.body.local_decls[row].ty) {
-                continue;
-            }
-
-            let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
-            borrowers.remove(mir::Local::from_usize(0));
-            if !borrowers.is_empty() {
-                map.insert(row, borrowers);
-            }
-        }
-
-        let bs = BitSet::new_empty(self.body.local_decls.len());
-        PossibleBorrowerMap {
-            map,
-            maybe_live,
-            bitset: (bs.clone(), bs),
-        }
-    }
-}
-
-impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
-    fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
-        let lhs = place.local;
-        match rvalue {
-            mir::Rvalue::Ref(_, _, borrowed) => {
-                self.possible_borrower.add(borrowed.local, lhs);
-            },
-            other => {
-                if ContainsRegion
-                    .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
-                    .is_continue()
-                {
-                    return;
-                }
-                rvalue_locals(other, |rhs| {
-                    if lhs != rhs {
-                        self.possible_borrower.add(rhs, lhs);
-                    }
-                });
-            },
-        }
-    }
-
-    fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) {
-        if let mir::TerminatorKind::Call {
-            args,
-            destination: mir::Place { local: dest, .. },
-            ..
-        } = &terminator.kind
-        {
-            // TODO add doc
-            // If the call returns something with lifetimes,
-            // let's conservatively assume the returned value contains lifetime of all the arguments.
-            // For example, given `let y: Foo<'a> = foo(x)`, `y` is considered to be a possible borrower of `x`.
-
-            let mut immutable_borrowers = vec![];
-            let mut mutable_borrowers = vec![];
-
-            for op in args {
-                match op {
-                    mir::Operand::Copy(p) | mir::Operand::Move(p) => {
-                        if let ty::Ref(_, _, Mutability::Mut) = self.body.local_decls[p.local].ty.kind() {
-                            mutable_borrowers.push(p.local);
-                        } else {
-                            immutable_borrowers.push(p.local);
-                        }
-                    },
-                    mir::Operand::Constant(..) => (),
-                }
-            }
-
-            let mut mutable_variables: Vec<mir::Local> = mutable_borrowers
-                .iter()
-                .filter_map(|r| self.possible_origin.get(r))
-                .flat_map(HybridBitSet::iter)
-                .collect();
-
-            if ContainsRegion.visit_ty(self.body.local_decls[*dest].ty).is_break() {
-                mutable_variables.push(*dest);
-            }
-
-            for y in mutable_variables {
-                for x in &immutable_borrowers {
-                    self.possible_borrower.add(*x, y);
-                }
-                for x in &mutable_borrowers {
-                    self.possible_borrower.add(*x, y);
-                }
-            }
-        }
-    }
-}
-
-/// Collect possible borrowed for every `&mut` local.
-/// For example, `_1 = &mut _2` generate _1: {_2,...}
-/// Known Problems: not sure all borrowed are tracked
-struct PossibleOriginVisitor<'a, 'tcx> {
-    possible_origin: TransitiveRelation,
-    body: &'a mir::Body<'tcx>,
-}
-
-impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> {
-    fn new(body: &'a mir::Body<'tcx>) -> Self {
-        Self {
-            possible_origin: TransitiveRelation::default(),
-            body,
-        }
-    }
-
-    fn into_map(self, cx: &LateContext<'tcx>) -> FxHashMap<mir::Local, HybridBitSet<mir::Local>> {
-        let mut map = FxHashMap::default();
-        for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
-            if is_copy(cx, self.body.local_decls[row].ty) {
-                continue;
-            }
-
-            let mut borrowers = self.possible_origin.reachable_from(row, self.body.local_decls.len());
-            borrowers.remove(mir::Local::from_usize(0));
-            if !borrowers.is_empty() {
-                map.insert(row, borrowers);
-            }
-        }
-        map
-    }
-}
-
-impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> {
-    fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
-        let lhs = place.local;
-        match rvalue {
-            // Only consider `&mut`, which can modify origin place
-            mir::Rvalue::Ref(_, rustc_middle::mir::BorrowKind::Mut { .. }, borrowed) |
-            // _2: &mut _;
-            // _3 = move _2
-            mir::Rvalue::Use(mir::Operand::Move(borrowed))  |
-            // _3 = move _2 as &mut _;
-            mir::Rvalue::Cast(_, mir::Operand::Move(borrowed), _)
-                => {
-                self.possible_origin.add(lhs, borrowed.local);
-            },
-            _ => {},
-        }
-    }
-}
-
-struct ContainsRegion;
-
-impl TypeVisitor<'_> for ContainsRegion {
-    type BreakTy = ();
-
-    fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<Self::BreakTy> {
-        ControlFlow::BREAK
-    }
-}
-
-fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
-    use rustc_middle::mir::Rvalue::{Aggregate, BinaryOp, Cast, CheckedBinaryOp, Repeat, UnaryOp, Use};
-
-    let mut visit_op = |op: &mir::Operand<'_>| match op {
-        mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local),
-        mir::Operand::Constant(..) => (),
-    };
 
-    match rvalue {
-        Use(op) | Repeat(op, _) | Cast(_, op, _) | UnaryOp(_, op) => visit_op(op),
-        Aggregate(_, ops) => ops.iter().for_each(visit_op),
-        BinaryOp(_, box (lhs, rhs)) | CheckedBinaryOp(_, box (lhs, rhs)) => {
-            visit_op(lhs);
-            visit_op(rhs);
+fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>, bb: mir::BasicBlock) -> CloneUsage {
+    if let Some((
+        LocalUsage {
+            local_use_locs: cloned_use_locs,
+            local_consume_or_mutate_locs: cloned_consume_or_mutate_locs,
         },
-        _ => (),
-    }
-}
-
-/// Result of `PossibleBorrowerVisitor`.
-struct PossibleBorrowerMap<'a, 'tcx> {
-    /// Mapping `Local -> its possible borrowers`
-    map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
-    maybe_live: ResultsCursor<'a, 'tcx, MaybeStorageLive>,
-    // Caches to avoid allocation of `BitSet` on every query
-    bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
-}
-
-impl PossibleBorrowerMap<'_, '_> {
-    /// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
-    fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
-        self.maybe_live.seek_after_primary_effect(at);
-
-        self.bitset.0.clear();
-        let maybe_live = &mut self.maybe_live;
-        if let Some(bitset) = self.map.get(&borrowed) {
-            for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) {
-                self.bitset.0.insert(b);
-            }
-        } else {
-            return false;
-        }
-
-        self.bitset.1.clear();
-        for b in borrowers {
-            self.bitset.1.insert(*b);
+        LocalUsage {
+            local_use_locs: _,
+            local_consume_or_mutate_locs: clone_consume_or_mutate_locs,
+        },
+    )) = visit_local_usage(
+        &[cloned, clone],
+        mir,
+        mir::Location {
+            block: bb,
+            statement_index: mir.basic_blocks[bb].statements.len(),
+        },
+    )
+    .map(|mut vec| (vec.remove(0), vec.remove(0)))
+    {
+        CloneUsage {
+            cloned_used: !cloned_use_locs.is_empty(),
+            cloned_consume_or_mutate_loc: cloned_consume_or_mutate_locs.first().copied(),
+            // Consider non-temporary clones consumed.
+            // TODO: Actually check for mutation of non-temporaries.
+            clone_consumed_or_mutated: mir.local_kind(clone) != mir::LocalKind::Temp
+                || !clone_consume_or_mutate_locs.is_empty(),
         }
-
-        self.bitset.0 == self.bitset.1
-    }
-
-    fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
-        self.maybe_live.seek_after_primary_effect(at);
-        self.maybe_live.contains(local)
-    }
-}
-
-#[derive(Default)]
-struct TransitiveRelation {
-    relations: FxHashMap<mir::Local, Vec<mir::Local>>,
-}
-impl TransitiveRelation {
-    fn add(&mut self, a: mir::Local, b: mir::Local) {
-        self.relations.entry(a).or_default().push(b);
-    }
-
-    fn reachable_from(&self, a: mir::Local, domain_size: usize) -> HybridBitSet<mir::Local> {
-        let mut seen = HybridBitSet::new_empty(domain_size);
-        let mut stack = vec![a];
-        while let Some(u) = stack.pop() {
-            if let Some(edges) = self.relations.get(&u) {
-                for &v in edges {
-                    if seen.insert(v) {
-                        stack.push(v);
-                    }
-                }
-            }
+    } else {
+        CloneUsage {
+            cloned_used: true,
+            cloned_consume_or_mutate_loc: None,
+            clone_consumed_or_mutated: true,
         }
-        seen
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
index 42514f861be..f21b3ea6c3b 100644
--- a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs
@@ -52,7 +52,8 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef {
                 GenericArg::Type(inner_ty) => Some(inner_ty),
                 _ => None,
             });
-            if let TyKind::Rptr(_, _) = inner_ty.kind;
+            if let TyKind::Rptr(_, ref inner_mut_ty) = inner_ty.kind;
+            if inner_mut_ty.mutbl == Mutability::Not;
 
             then {
                 span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 5dcdab5b8ab..87f966ced0d 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -106,10 +106,7 @@ impl_lint_pass!(Shadow => [SHADOW_SAME, SHADOW_REUSE, SHADOW_UNRELATED]);
 
 impl<'tcx> LateLintPass<'tcx> for Shadow {
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
-        let (id, ident) = match pat.kind {
-            PatKind::Binding(_, hir_id, ident, _) => (hir_id, ident),
-            _ => return,
-        };
+        let PatKind::Binding(_, id, ident, _) = pat.kind else { return };
 
         if pat.span.desugaring_kind().is_some() {
             return;
diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
index 70d166c4854..2f190e594a8 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
@@ -6,11 +6,7 @@ use rustc_span::DUMMY_SP;
 
 // check if the component types of the transmuted collection and the result have different ABI,
 // size or alignment
-pub(super) fn is_layout_incompatible<'tcx>(
-    cx: &LateContext<'tcx>,
-    from: Ty<'tcx>,
-    to: Ty<'tcx>,
-) -> bool {
+pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool {
     if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from)
         && let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to)
         && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from))
@@ -33,9 +29,7 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
 ) -> bool {
-    use CastKind::{
-        AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast,
-    };
+    use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
     matches!(
         check_cast(cx, e, from_ty, to_ty),
         Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast)
@@ -46,20 +40,18 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>(
 /// the cast. In certain cases, including some invalid casts from array references
 /// to pointers, this may cause additional errors to be emitted and/or ICE error
 /// messages. This function will panic if that occurs.
-fn check_cast<'tcx>(
-    cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
-    from_ty: Ty<'tcx>,
-    to_ty: Ty<'tcx>,
-) -> Option<CastKind> {
+fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option<CastKind> {
     let hir_id = e.hir_id;
     let local_def_id = hir_id.owner.def_id;
 
     Inherited::build(cx.tcx, local_def_id).enter(|inherited| {
-        let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id);
+        let fn_ctxt = FnCtxt::new(inherited, cx.param_env, hir_id);
 
         // If we already have errors, we can't be sure we can pointer cast.
-        assert!(!fn_ctxt.errors_reported_since_creation(), "Newly created FnCtxt contained errors");
+        assert!(
+            !fn_ctxt.errors_reported_since_creation(),
+            "Newly created FnCtxt contained errors"
+        );
 
         if let Ok(check) = cast::CastCheck::new(
             &fn_ctxt, e, from_ty, to_ty,
diff --git a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
index 6b9de64e24c..fa567b9b2d2 100644
--- a/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
+++ b/src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
@@ -9,6 +9,7 @@ use rustc_span::symbol::sym;
 use super::RC_BUFFER;
 
 pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
+    let app = Applicability::Unspecified;
     if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
         if let Some(alternate) = match_buffer_type(cx, qpath) {
             span_lint_and_sugg(
@@ -18,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                 "usage of `Rc<T>` when T is a buffer type",
                 "try",
                 format!("Rc<{alternate}>"),
-                Applicability::MachineApplicable,
+                app,
             );
         } else {
             let Some(ty) = qpath_generic_tys(qpath).next() else { return false };
@@ -26,15 +27,12 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
             if !cx.tcx.is_diagnostic_item(sym::Vec, id) {
                 return false;
             }
-            let qpath = match &ty.kind {
-                TyKind::Path(qpath) => qpath,
-                _ => return false,
-            };
+            let TyKind::Path(qpath) = &ty.kind else { return false };
             let inner_span = match qpath_generic_tys(qpath).next() {
                 Some(ty) => ty.span,
                 None => return false,
             };
-            let mut applicability = Applicability::MachineApplicable;
+            let mut applicability = app;
             span_lint_and_sugg(
                 cx,
                 RC_BUFFER,
@@ -45,7 +43,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                     "Rc<[{}]>",
                     snippet_with_applicability(cx, inner_span, "..", &mut applicability)
                 ),
-                Applicability::MachineApplicable,
+                app,
             );
             return true;
         }
@@ -58,22 +56,19 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                 "usage of `Arc<T>` when T is a buffer type",
                 "try",
                 format!("Arc<{alternate}>"),
-                Applicability::MachineApplicable,
+                app,
             );
         } else if let Some(ty) = qpath_generic_tys(qpath).next() {
             let Some(id) = path_def_id(cx, ty) else { return false };
             if !cx.tcx.is_diagnostic_item(sym::Vec, id) {
                 return false;
             }
-            let qpath = match &ty.kind {
-                TyKind::Path(qpath) => qpath,
-                _ => return false,
-            };
+            let TyKind::Path(qpath) = &ty.kind else { return false };
             let inner_span = match qpath_generic_tys(qpath).next() {
                 Some(ty) => ty.span,
                 None => return false,
             };
-            let mut applicability = Applicability::MachineApplicable;
+            let mut applicability = app;
             span_lint_and_sugg(
                 cx,
                 RC_BUFFER,
@@ -84,7 +79,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                     "Arc<[{}]>",
                     snippet_with_applicability(cx, inner_span, "..", &mut applicability)
                 ),
-                Applicability::MachineApplicable,
+                app,
             );
             return true;
         }
diff --git a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
index ecb67200539..7883353e3fe 100644
--- a/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
+++ b/src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
@@ -10,6 +10,7 @@ use rustc_span::symbol::sym;
 use super::{utils, REDUNDANT_ALLOCATION};
 
 pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
+    let mut applicability = Applicability::MaybeIncorrect;
     let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() {
         "Box"
     } else if cx.tcx.is_diagnostic_item(sym::Rc, def_id) {
@@ -21,7 +22,6 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
     };
 
     if let Some(span) = utils::match_borrows_parameter(cx, qpath) {
-        let mut applicability = Applicability::MaybeIncorrect;
         let generic_snippet = snippet_with_applicability(cx, span, "..", &mut applicability);
         span_lint_and_then(
             cx,
@@ -47,9 +47,8 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
         _ => return false,
     };
 
-    let inner_qpath = match &ty.kind {
-        TyKind::Path(inner_qpath) => inner_qpath,
-        _ => return false,
+    let TyKind::Path(inner_qpath) = &ty.kind else {
+        return false
     };
     let inner_span = match qpath_generic_tys(inner_qpath).next() {
         Some(ty) => {
@@ -64,7 +63,6 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
         None => return false,
     };
     if inner_sym == outer_sym {
-        let mut applicability = Applicability::MaybeIncorrect;
         let generic_snippet = snippet_with_applicability(cx, inner_span, "..", &mut applicability);
         span_lint_and_then(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index 57aff5367dd..1307288623f 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::{get_trait_def_id, paths};
 use if_chain::if_chain;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Closure, Expr, ExprKind, StmtKind};
@@ -7,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::{GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{BytePos, Span};
+use rustc_span::{sym, BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -80,7 +79,7 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
         let fn_sig = cx.tcx.fn_sig(def_id);
         let generics = cx.tcx.predicates_of(def_id);
         let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait());
-        let ord_preds = get_trait_predicates_for_trait_id(cx, generics, get_trait_def_id(cx, &paths::ORD));
+        let ord_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.get_diagnostic_item(sym::Ord));
         let partial_ord_preds =
             get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().partial_ord_trait());
         // Trying to call erase_late_bound_regions on fn_sig.inputs() gives the following error
@@ -99,11 +98,15 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
                         if trait_pred.self_ty() == inp;
                         if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
                         then {
-                            if ord_preds.iter().any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty()) {
+                            if ord_preds
+                                .iter()
+                                .any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty())
+                            {
                                 args_to_check.push((i, "Ord".to_string()));
-                            } else if partial_ord_preds.iter().any(|pord| {
-                                pord.self_ty() == return_ty_pred.term.ty().unwrap()
-                            }) {
+                            } else if partial_ord_preds
+                                .iter()
+                                .any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap())
+                            {
                                 args_to_check.push((i, "PartialOrd".to_string()));
                             }
                         }
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index fb73c386640..b305dae7608 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -163,9 +163,8 @@ fn unnest_or_patterns(pat: &mut P<Pat>) -> bool {
             noop_visit_pat(p, self);
 
             // Don't have an or-pattern? Just quit early on.
-            let alternatives = match &mut p.kind {
-                Or(ps) => ps,
-                _ => return,
+            let Or(alternatives) = &mut p.kind else {
+                return
             };
 
             // Collapse or-patterns directly nested in or-patterns.
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 8bcdff66331..92053cec59f 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -47,9 +47,8 @@ declare_lint_pass!(UnusedIoAmount => [UNUSED_IO_AMOUNT]);
 
 impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
     fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
-        let expr = match s.kind {
-            hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr) => expr,
-            _ => return,
+        let (hir::StmtKind::Semi(expr) | hir::StmtKind::Expr(expr)) = s.kind else {
+            return
         };
 
         match expr.kind {
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index a82643a59f9..1f69db1cbca 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -55,9 +55,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
 
         match e.kind {
             ExprKind::Match(_, arms, MatchSource::TryDesugar) => {
-                let e = match arms[0].body.kind {
-                    ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e)) => e,
-                    _ => return,
+                let (ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e))) = arms[0].body.kind else {
+                     return
                 };
                 if let ExprKind::Call(_, [arg, ..]) = e.kind {
                     self.try_desugar_arm.push(arg.hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index e069de8cb5c..0c052d86eda 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -12,6 +12,7 @@ use rustc_hir::{
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::{Ident, Symbol};
+use std::cell::Cell;
 use std::fmt::{Display, Formatter, Write as _};
 
 declare_clippy_lint! {
@@ -37,15 +38,13 @@ declare_clippy_lint! {
     ///
     /// ```rust,ignore
     /// // ./tests/ui/new_lint.stdout
-    /// if_chain! {
-    ///     if let ExprKind::If(ref cond, ref then, None) = item.kind,
-    ///     if let ExprKind::Binary(BinOp::Eq, ref left, ref right) = cond.kind,
-    ///     if let ExprKind::Path(ref path) = left.kind,
-    ///     if let ExprKind::Lit(ref lit) = right.kind,
-    ///     if let LitKind::Int(42, _) = lit.node,
-    ///     then {
-    ///         // report your lint here
-    ///     }
+    /// if ExprKind::If(ref cond, ref then, None) = item.kind
+    ///     && let ExprKind::Binary(BinOp::Eq, ref left, ref right) = cond.kind
+    ///     && let ExprKind::Path(ref path) = left.kind
+    ///     && let ExprKind::Lit(ref lit) = right.kind
+    ///     && let LitKind::Int(42, _) = lit.node
+    /// {
+    ///     // report your lint here
     /// }
     /// ```
     pub LINT_AUTHOR,
@@ -91,15 +90,16 @@ macro_rules! field {
     };
 }
 
-fn prelude() {
-    println!("if_chain! {{");
-}
-
-fn done() {
-    println!("    then {{");
-    println!("        // report your lint here");
-    println!("    }}");
-    println!("}}");
+/// Print a condition of a let chain, `chain!(self, "let Some(x) = y")` will print
+/// `if let Some(x) = y` on the first call and `    && let Some(x) = y` thereafter
+macro_rules! chain {
+    ($self:ident, $($t:tt)*) => {
+        if $self.first.take() {
+            println!("if {}", format_args!($($t)*));
+        } else {
+            println!("    && {}", format_args!($($t)*));
+        }
+    }
 }
 
 impl<'tcx> LateLintPass<'tcx> for Author {
@@ -149,9 +149,10 @@ fn check_item(cx: &LateContext<'_>, hir_id: HirId) {
 
 fn check_node(cx: &LateContext<'_>, hir_id: HirId, f: impl Fn(&PrintVisitor<'_, '_>)) {
     if has_attr(cx, hir_id) {
-        prelude();
         f(&PrintVisitor::new(cx));
-        done();
+        println!("{{");
+        println!("    // report your lint here");
+        println!("}}");
     }
 }
 
@@ -195,7 +196,9 @@ struct PrintVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     /// Fields are the current index that needs to be appended to pattern
     /// binding names
-    ids: std::cell::Cell<FxHashMap<&'static str, u32>>,
+    ids: Cell<FxHashMap<&'static str, u32>>,
+    /// Currently at the first condition in the if chain
+    first: Cell<bool>,
 }
 
 #[allow(clippy::unused_self)]
@@ -203,7 +206,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
     fn new(cx: &'a LateContext<'tcx>) -> Self {
         Self {
             cx,
-            ids: std::cell::Cell::default(),
+            ids: Cell::default(),
+            first: Cell::new(true),
         }
     }
 
@@ -226,10 +230,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
     fn option<T: Copy>(&self, option: &Binding<Option<T>>, name: &'static str, f: impl Fn(&Binding<T>)) {
         match option.value {
-            None => out!("if {option}.is_none();"),
+            None => chain!(self, "{option}.is_none()"),
             Some(value) => {
                 let value = &self.bind(name, value);
-                out!("if let Some({value}) = {option};");
+                chain!(self, "let Some({value}) = {option}");
                 f(value);
             },
         }
@@ -237,9 +241,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
     fn slice<T>(&self, slice: &Binding<&[T]>, f: impl Fn(&Binding<&T>)) {
         if slice.value.is_empty() {
-            out!("if {slice}.is_empty();");
+            chain!(self, "{slice}.is_empty()");
         } else {
-            out!("if {slice}.len() == {};", slice.value.len());
+            chain!(self, "{slice}.len() == {}", slice.value.len());
             for (i, value) in slice.value.iter().enumerate() {
                 let name = format!("{slice}[{i}]");
                 f(&Binding { name, value });
@@ -254,23 +258,23 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
     }
 
     fn ident(&self, ident: &Binding<Ident>) {
-        out!("if {ident}.as_str() == {:?};", ident.value.as_str());
+        chain!(self, "{ident}.as_str() == {:?}", ident.value.as_str());
     }
 
     fn symbol(&self, symbol: &Binding<Symbol>) {
-        out!("if {symbol}.as_str() == {:?};", symbol.value.as_str());
+        chain!(self, "{symbol}.as_str() == {:?}", symbol.value.as_str());
     }
 
     fn qpath(&self, qpath: &Binding<&QPath<'_>>) {
         if let QPath::LangItem(lang_item, ..) = *qpath.value {
-            out!("if matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _));");
+            chain!(self, "matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))");
         } else {
-            out!("if match_qpath({qpath}, &[{}]);", path_to_string(qpath.value));
+            chain!(self, "match_qpath({qpath}, &[{}])", path_to_string(qpath.value));
         }
     }
 
     fn lit(&self, lit: &Binding<&Lit>) {
-        let kind = |kind| out!("if let LitKind::{kind} = {lit}.node;");
+        let kind = |kind| chain!(self, "let LitKind::{kind} = {lit}.node");
         macro_rules! kind {
             ($($t:tt)*) => (kind(format_args!($($t)*)));
         }
@@ -298,7 +302,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             LitKind::ByteStr(ref vec) => {
                 bind!(self, vec);
                 kind!("ByteStr(ref {vec})");
-                out!("if let [{:?}] = **{vec};", vec.value);
+                chain!(self, "let [{:?}] = **{vec}", vec.value);
             },
             LitKind::Str(s, _) => {
                 bind!(self, s);
@@ -311,15 +315,15 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
     fn arm(&self, arm: &Binding<&hir::Arm<'_>>) {
         self.pat(field!(arm.pat));
         match arm.value.guard {
-            None => out!("if {arm}.guard.is_none();"),
+            None => chain!(self, "{arm}.guard.is_none()"),
             Some(hir::Guard::If(expr)) => {
                 bind!(self, expr);
-                out!("if let Some(Guard::If({expr})) = {arm}.guard;");
+                chain!(self, "let Some(Guard::If({expr})) = {arm}.guard");
                 self.expr(expr);
             },
             Some(hir::Guard::IfLet(let_expr)) => {
                 bind!(self, let_expr);
-                out!("if let Some(Guard::IfLet({let_expr}) = {arm}.guard;");
+                chain!(self, "let Some(Guard::IfLet({let_expr}) = {arm}.guard");
                 self.pat(field!(let_expr.pat));
                 self.expr(field!(let_expr.init));
             },
@@ -331,9 +335,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
     fn expr(&self, expr: &Binding<&hir::Expr<'_>>) {
         if let Some(higher::While { condition, body }) = higher::While::hir(expr.value) {
             bind!(self, condition, body);
-            out!(
-                "if let Some(higher::While {{ condition: {condition}, body: {body} }}) \
-                = higher::While::hir({expr});"
+            chain!(
+                self,
+                "let Some(higher::While {{ condition: {condition}, body: {body} }}) \
+                = higher::While::hir({expr})"
             );
             self.expr(condition);
             self.expr(body);
@@ -347,9 +352,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
         }) = higher::WhileLet::hir(expr.value)
         {
             bind!(self, let_pat, let_expr, if_then);
-            out!(
-                "if let Some(higher::WhileLet {{ let_pat: {let_pat}, let_expr: {let_expr}, if_then: {if_then} }}) \
-                = higher::WhileLet::hir({expr});"
+            chain!(
+                self,
+                "let Some(higher::WhileLet {{ let_pat: {let_pat}, let_expr: {let_expr}, if_then: {if_then} }}) \
+                = higher::WhileLet::hir({expr})"
             );
             self.pat(let_pat);
             self.expr(let_expr);
@@ -359,9 +365,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
         if let Some(higher::ForLoop { pat, arg, body, .. }) = higher::ForLoop::hir(expr.value) {
             bind!(self, pat, arg, body);
-            out!(
-                "if let Some(higher::ForLoop {{ pat: {pat}, arg: {arg}, body: {body}, .. }}) \
-                = higher::ForLoop::hir({expr});"
+            chain!(
+                self,
+                "let Some(higher::ForLoop {{ pat: {pat}, arg: {arg}, body: {body}, .. }}) \
+                = higher::ForLoop::hir({expr})"
             );
             self.pat(pat);
             self.expr(arg);
@@ -369,7 +376,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             return;
         }
 
-        let kind = |kind| out!("if let ExprKind::{kind} = {expr}.kind;");
+        let kind = |kind| chain!(self, "let ExprKind::{kind} = {expr}.kind");
         macro_rules! kind {
             ($($t:tt)*) => (kind(format_args!($($t)*)));
         }
@@ -383,7 +390,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 // if it's a path
                 if let Some(TyKind::Path(ref qpath)) = let_expr.value.ty.as_ref().map(|ty| &ty.kind) {
                     bind!(self, qpath);
-                    out!("if let TyKind::Path(ref {qpath}) = {let_expr}.ty.kind;");
+                    chain!(self, "let TyKind::Path(ref {qpath}) = {let_expr}.ty.kind");
                     self.qpath(qpath);
                 }
                 self.expr(field!(let_expr.init));
@@ -419,7 +426,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             ExprKind::Binary(op, left, right) => {
                 bind!(self, op, left, right);
                 kind!("Binary({op}, {left}, {right})");
-                out!("if BinOpKind::{:?} == {op}.node;", op.value.node);
+                chain!(self, "BinOpKind::{:?} == {op}.node", op.value.node);
                 self.expr(left);
                 self.expr(right);
             },
@@ -438,7 +445,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("Cast({expr}, {cast_ty})");
                 if let TyKind::Path(ref qpath) = cast_ty.value.kind {
                     bind!(self, qpath);
-                    out!("if let TyKind::Path(ref {qpath}) = {cast_ty}.kind;");
+                    chain!(self, "let TyKind::Path(ref {qpath}) = {cast_ty}.kind");
                     self.qpath(qpath);
                 }
                 self.expr(expr);
@@ -485,7 +492,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
                 bind!(self, fn_decl, body_id);
                 kind!("Closure(CaptureBy::{capture_clause:?}, {fn_decl}, {body_id}, _, {movability})");
-                out!("if let {ret_ty} = {fn_decl}.output;");
+                chain!(self, "let {ret_ty} = {fn_decl}.output");
                 self.body(body_id);
             },
             ExprKind::Yield(sub, source) => {
@@ -509,7 +516,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
             ExprKind::AssignOp(op, target, value) => {
                 bind!(self, op, target, value);
                 kind!("AssignOp({op}, {target}, {value})");
-                out!("if BinOpKind::{:?} == {op}.node;", op.value.node);
+                chain!(self, "BinOpKind::{:?} == {op}.node", op.value.node);
                 self.expr(target);
                 self.expr(value);
             },
@@ -573,10 +580,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("Repeat({value}, {length})");
                 self.expr(value);
                 match length.value {
-                    ArrayLen::Infer(..) => out!("if let ArrayLen::Infer(..) = length;"),
+                    ArrayLen::Infer(..) => chain!(self, "let ArrayLen::Infer(..) = length"),
                     ArrayLen::Body(anon_const) => {
                         bind!(self, anon_const);
-                        out!("if let ArrayLen::Body({anon_const}) = {length};");
+                        chain!(self, "let ArrayLen::Body({anon_const}) = {length}");
                         self.body(field!(anon_const.body));
                     },
                 }
@@ -600,12 +607,12 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
     fn body(&self, body_id: &Binding<hir::BodyId>) {
         let expr = self.cx.tcx.hir().body(body_id.value).value;
         bind!(self, expr);
-        out!("let {expr} = &cx.tcx.hir().body({body_id}).value;");
+        chain!(self, "{expr} = &cx.tcx.hir().body({body_id}).value");
         self.expr(expr);
     }
 
     fn pat(&self, pat: &Binding<&hir::Pat<'_>>) {
-        let kind = |kind| out!("if let PatKind::{kind} = {pat}.kind;");
+        let kind = |kind| chain!(self, "let PatKind::{kind} = {pat}.kind");
         macro_rules! kind {
             ($($t:tt)*) => (kind(format_args!($($t)*)));
         }
@@ -688,7 +695,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
     }
 
     fn stmt(&self, stmt: &Binding<&hir::Stmt<'_>>) {
-        let kind = |kind| out!("if let StmtKind::{kind} = {stmt}.kind;");
+        let kind = |kind| chain!(self, "let StmtKind::{kind} = {stmt}.kind");
         macro_rules! kind {
             ($($t:tt)*) => (kind(format_args!($($t)*)));
         }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index 85bcbc7ad23..71f6c9909dd 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -1,1566 +1,12 @@
-use crate::utils::internal_lints::metadata_collector::is_deprecated_lint;
-use clippy_utils::consts::{constant_simple, Constant};
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::macros::root_macro_call_first_node;
-use clippy_utils::source::{snippet, snippet_with_applicability};
-use clippy_utils::ty::match_type;
-use clippy_utils::{
-    def_path_res, higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_any_def_paths,
-    match_def_path, method_calls, paths, peel_blocks_with_stmt, peel_hir_expr_refs, SpanlessEq,
-};
-use if_chain::if_chain;
-use rustc_ast as ast;
-use rustc_ast::ast::{Crate, ItemKind, LitKind, ModKind, NodeId};
-use rustc_ast::visit::FnKind;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Namespace, Res};
-use rustc_hir::def_id::DefId;
-use rustc_hir::hir_id::CRATE_HIR_ID;
-use rustc_hir::intravisit::Visitor;
-use rustc_hir::{
-    BinOpKind, Block, Closure, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind,
-    TyKind, UnOp,
-};
-use rustc_hir_analysis::hir_ty_to_ty;
-use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::nested_filter;
-use rustc_middle::mir::interpret::{Allocation, ConstValue, GlobalAlloc};
-use rustc_middle::ty::{
-    self, fast_reject::SimplifiedTypeGen, subst::GenericArgKind, AssocKind, DefIdTree, FloatTy, Ty,
-};
-use rustc_semver::RustcVersion;
-use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::Spanned;
-use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::{sym, BytePos, Span};
-
-use std::borrow::{Borrow, Cow};
-use std::str;
-
-#[cfg(feature = "internal")]
+pub mod clippy_lints_internal;
+pub mod collapsible_calls;
+pub mod compiler_lint_functions;
+pub mod if_chain_style;
+pub mod interning_defined_symbol;
+pub mod invalid_paths;
+pub mod lint_without_lint_pass;
 pub mod metadata_collector;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for various things we like to keep tidy in clippy.
-    ///
-    /// ### Why is this bad?
-    /// We like to pretend we're an example of tidy code.
-    ///
-    /// ### Example
-    /// Wrong ordering of the util::paths constants.
-    pub CLIPPY_LINTS_INTERNAL,
-    internal,
-    "various things that will negatively affect your clippy experience"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Ensures every lint is associated to a `LintPass`.
-    ///
-    /// ### Why is this bad?
-    /// The compiler only knows lints via a `LintPass`. Without
-    /// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not
-    /// know the name of the lint.
-    ///
-    /// ### Known problems
-    /// Only checks for lints associated using the
-    /// `declare_lint_pass!`, `impl_lint_pass!`, and `lint_array!` macros.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// declare_lint! { pub LINT_1, ... }
-    /// declare_lint! { pub LINT_2, ... }
-    /// declare_lint! { pub FORGOTTEN_LINT, ... }
-    /// // ...
-    /// declare_lint_pass!(Pass => [LINT_1, LINT_2]);
-    /// // missing FORGOTTEN_LINT
-    /// ```
-    pub LINT_WITHOUT_LINT_PASS,
-    internal,
-    "declaring a lint without associating it in a LintPass"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
-    /// variant of the function.
-    ///
-    /// ### Why is this bad?
-    /// The `utils::*` variants also add a link to the Clippy documentation to the
-    /// warning/error messages.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// cx.span_lint(LINT_NAME, "message");
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// utils::span_lint(cx, LINT_NAME, "message");
-    /// ```
-    pub COMPILER_LINT_FUNCTIONS,
-    internal,
-    "usage of the lint functions of the compiler instead of the utils::* variant"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for calls to `cx.outer().expn_data()` and suggests to use
-    /// the `cx.outer_expn_data()`
-    ///
-    /// ### Why is this bad?
-    /// `cx.outer_expn_data()` is faster and more concise.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// expr.span.ctxt().outer().expn_data()
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// expr.span.ctxt().outer_expn_data()
-    /// ```
-    pub OUTER_EXPN_EXPN_DATA,
-    internal,
-    "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Not an actual lint. This lint is only meant for testing our customized internal compiler
-    /// error message by calling `panic`.
-    ///
-    /// ### Why is this bad?
-    /// ICE in large quantities can damage your teeth
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// 🍦🍦🍦🍦🍦
-    /// ```
-    pub PRODUCE_ICE,
-    internal,
-    "this message should not appear anywhere as we ICE before and don't emit the lint"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for cases of an auto-generated lint without an updated description,
-    /// i.e. `default lint description`.
-    ///
-    /// ### Why is this bad?
-    /// Indicates that the lint is not finished.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// declare_lint! { pub COOL_LINT, nursery, "default lint description" }
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" }
-    /// ```
-    pub DEFAULT_LINT,
-    internal,
-    "found 'default lint description' in a lint declaration"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Lints `span_lint_and_then` function calls, where the
-    /// closure argument has only one statement and that statement is a method
-    /// call to `span_suggestion`, `span_help`, `span_note` (using the same
-    /// span), `help` or `note`.
-    ///
-    /// These usages of `span_lint_and_then` should be replaced with one of the
-    /// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or
-    /// `span_lint_and_note`.
-    ///
-    /// ### Why is this bad?
-    /// Using the wrapper `span_lint_and_*` functions, is more
-    /// convenient, readable and less error prone.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
-    ///     diag.span_suggestion(
-    ///         expr.span,
-    ///         help_msg,
-    ///         sugg.to_string(),
-    ///         Applicability::MachineApplicable,
-    ///     );
-    /// });
-    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
-    ///     diag.span_help(expr.span, help_msg);
-    /// });
-    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
-    ///     diag.help(help_msg);
-    /// });
-    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
-    ///     diag.span_note(expr.span, note_msg);
-    /// });
-    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
-    ///     diag.note(note_msg);
-    /// });
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// span_lint_and_sugg(
-    ///     cx,
-    ///     TEST_LINT,
-    ///     expr.span,
-    ///     lint_msg,
-    ///     help_msg,
-    ///     sugg.to_string(),
-    ///     Applicability::MachineApplicable,
-    /// );
-    /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg);
-    /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg);
-    /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg);
-    /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg);
-    /// ```
-    pub COLLAPSIBLE_SPAN_LINT_CALLS,
-    internal,
-    "found collapsible `span_lint_and_then` calls"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for usages of def paths when a diagnostic item or a `LangItem` could be used.
-    ///
-    /// ### Why is this bad?
-    /// The path for an item is subject to change and is less efficient to look up than a
-    /// diagnostic item or a `LangItem`.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// utils::match_type(cx, ty, &paths::VEC)
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// utils::is_type_diagnostic_item(cx, ty, sym::Vec)
-    /// ```
-    pub UNNECESSARY_DEF_PATH,
-    internal,
-    "using a def path when a diagnostic item or a `LangItem` is available"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks the paths module for invalid paths.
-    ///
-    /// ### Why is this bad?
-    /// It indicates a bug in the code.
-    ///
-    /// ### Example
-    /// None.
-    pub INVALID_PATHS,
-    internal,
-    "invalid path"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for interning symbols that have already been pre-interned and defined as constants.
-    ///
-    /// ### Why is this bad?
-    /// It's faster and easier to use the symbol constant.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// let _ = sym!(f32);
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// let _ = sym::f32;
-    /// ```
-    pub INTERNING_DEFINED_SYMBOL,
-    internal,
-    "interning a symbol that is pre-interned and defined as a constant"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for unnecessary conversion from Symbol to a string.
-    ///
-    /// ### Why is this bad?
-    /// It's faster use symbols directly instead of strings.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// symbol.as_str() == "clippy";
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// symbol == sym::clippy;
-    /// ```
-    pub UNNECESSARY_SYMBOL_STR,
-    internal,
-    "unnecessary conversion between Symbol and string"
-}
-
-declare_clippy_lint! {
-    /// Finds unidiomatic usage of `if_chain!`
-    pub IF_CHAIN_STYLE,
-    internal,
-    "non-idiomatic `if_chain!` usage"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for invalid `clippy::version` attributes.
-    ///
-    /// Valid values are:
-    /// * "pre 1.29.0"
-    /// * any valid semantic version
-    pub INVALID_CLIPPY_VERSION_ATTRIBUTE,
-    internal,
-    "found an invalid `clippy::version` attribute"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for declared clippy lints without the `clippy::version` attribute.
-    ///
-    pub MISSING_CLIPPY_VERSION_ATTRIBUTE,
-    internal,
-    "found clippy lint without `clippy::version` attribute"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Check that the `extract_msrv_attr!` macro is used, when a lint has a MSRV.
-    ///
-    pub MISSING_MSRV_ATTR_IMPL,
-    internal,
-    "checking if all necessary steps were taken when adding a MSRV to a lint"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for cases of an auto-generated deprecated lint without an updated reason,
-    /// i.e. `"default deprecation note"`.
-    ///
-    /// ### Why is this bad?
-    /// Indicates that the documentation is incomplete.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// declare_deprecated_lint! {
-    ///     /// ### What it does
-    ///     /// Nothing. This lint has been deprecated.
-    ///     ///
-    ///     /// ### Deprecation reason
-    ///     /// TODO
-    ///     #[clippy::version = "1.63.0"]
-    ///     pub COOL_LINT,
-    ///     "default deprecation note"
-    /// }
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// declare_deprecated_lint! {
-    ///     /// ### What it does
-    ///     /// Nothing. This lint has been deprecated.
-    ///     ///
-    ///     /// ### Deprecation reason
-    ///     /// This lint has been replaced by `cooler_lint`
-    ///     #[clippy::version = "1.63.0"]
-    ///     pub COOL_LINT,
-    ///     "this lint has been replaced by `cooler_lint`"
-    /// }
-    /// ```
-    pub DEFAULT_DEPRECATION_REASON,
-    internal,
-    "found 'default deprecation note' in a deprecated lint declaration"
-}
-
-declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
-
-impl EarlyLintPass for ClippyLintsInternal {
-    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
-        if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") {
-            if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind {
-                if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") {
-                    if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = paths.kind {
-                        let mut last_name: Option<&str> = None;
-                        for item in items {
-                            let name = item.ident.as_str();
-                            if let Some(last_name) = last_name {
-                                if *last_name > *name {
-                                    span_lint(
-                                        cx,
-                                        CLIPPY_LINTS_INTERNAL,
-                                        item.span,
-                                        "this constant should be before the previous constant due to lexical \
-                                         ordering",
-                                    );
-                                }
-                            }
-                            last_name = Some(name);
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
-#[derive(Clone, Debug, Default)]
-pub struct LintWithoutLintPass {
-    declared_lints: FxHashMap<Symbol, Span>,
-    registered_lints: FxHashSet<Symbol>,
-}
-
-impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE, DEFAULT_DEPRECATION_REASON]);
-
-impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id())
-            || is_lint_allowed(cx, DEFAULT_DEPRECATION_REASON, item.hir_id())
-        {
-            return;
-        }
-
-        if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind {
-            let is_lint_ref_ty = is_lint_ref_type(cx, ty);
-            if is_deprecated_lint(cx, ty) || is_lint_ref_ty {
-                check_invalid_clippy_version_attribute(cx, item);
-
-                let expr = &cx.tcx.hir().body(body_id).value;
-                let fields;
-                if is_lint_ref_ty {
-                    if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind
-                        && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind {
-                            fields = struct_fields;
-                    } else {
-                        return;
-                    }
-                } else if let ExprKind::Struct(_, struct_fields, _) = expr.kind {
-                    fields = struct_fields;
-                } else {
-                    return;
-                }
-
-                let field = fields
-                    .iter()
-                    .find(|f| f.ident.as_str() == "desc")
-                    .expect("lints must have a description field");
-
-                if let ExprKind::Lit(Spanned {
-                    node: LitKind::Str(ref sym, _),
-                    ..
-                }) = field.expr.kind
-                {
-                    let sym_str = sym.as_str();
-                    if is_lint_ref_ty {
-                        if sym_str == "default lint description" {
-                            span_lint(
-                                cx,
-                                DEFAULT_LINT,
-                                item.span,
-                                &format!("the lint `{}` has the default lint description", item.ident.name),
-                            );
-                        }
-
-                        self.declared_lints.insert(item.ident.name, item.span);
-                    } else if sym_str == "default deprecation note" {
-                        span_lint(
-                            cx,
-                            DEFAULT_DEPRECATION_REASON,
-                            item.span,
-                            &format!("the lint `{}` has the default deprecation reason", item.ident.name),
-                        );
-                    }
-                }
-            }
-        } else if let Some(macro_call) = root_macro_call_first_node(cx, item) {
-            if !matches!(
-                cx.tcx.item_name(macro_call.def_id).as_str(),
-                "impl_lint_pass" | "declare_lint_pass"
-            ) {
-                return;
-            }
-            if let hir::ItemKind::Impl(hir::Impl {
-                of_trait: None,
-                items: impl_item_refs,
-                ..
-            }) = item.kind
-            {
-                let mut collector = LintCollector {
-                    output: &mut self.registered_lints,
-                    cx,
-                };
-                let body_id = cx.tcx.hir().body_owned_by(
-                    cx.tcx.hir().local_def_id(
-                        impl_item_refs
-                            .iter()
-                            .find(|iiref| iiref.ident.as_str() == "get_lints")
-                            .expect("LintPass needs to implement get_lints")
-                            .id
-                            .hir_id(),
-                    ),
-                );
-                collector.visit_expr(cx.tcx.hir().body(body_id).value);
-            }
-        }
-    }
-
-    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
-        if is_lint_allowed(cx, LINT_WITHOUT_LINT_PASS, CRATE_HIR_ID) {
-            return;
-        }
-
-        for (lint_name, &lint_span) in &self.declared_lints {
-            // When using the `declare_tool_lint!` macro, the original `lint_span`'s
-            // file points to "<rustc macros>".
-            // `compiletest-rs` thinks that's an error in a different file and
-            // just ignores it. This causes the test in compile-fail/lint_pass
-            // not able to capture the error.
-            // Therefore, we need to climb the macro expansion tree and find the
-            // actual span that invoked `declare_tool_lint!`:
-            let lint_span = lint_span.ctxt().outer_expn_data().call_site;
-
-            if !self.registered_lints.contains(lint_name) {
-                span_lint(
-                    cx,
-                    LINT_WITHOUT_LINT_PASS,
-                    lint_span,
-                    &format!("the lint `{lint_name}` is not added to any `LintPass`"),
-                );
-            }
-        }
-    }
-}
-
-fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &hir::Ty<'_>) -> bool {
-    if let TyKind::Rptr(
-        _,
-        MutTy {
-            ty: inner,
-            mutbl: Mutability::Not,
-        },
-    ) = ty.kind
-    {
-        if let TyKind::Path(ref path) = inner.kind {
-            if let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) {
-                return match_def_path(cx, def_id, &paths::LINT);
-            }
-        }
-    }
-
-    false
-}
-
-fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) {
-    if let Some(value) = extract_clippy_version_value(cx, item) {
-        // The `sym!` macro doesn't work as it only expects a single token.
-        // It's better to keep it this way and have a direct `Symbol::intern` call here.
-        if value == Symbol::intern("pre 1.29.0") {
-            return;
-        }
-
-        if RustcVersion::parse(value.as_str()).is_err() {
-            span_lint_and_help(
-                cx,
-                INVALID_CLIPPY_VERSION_ATTRIBUTE,
-                item.span,
-                "this item has an invalid `clippy::version` attribute",
-                None,
-                "please use a valid semantic version, see `doc/adding_lints.md`",
-            );
-        }
-    } else {
-        span_lint_and_help(
-            cx,
-            MISSING_CLIPPY_VERSION_ATTRIBUTE,
-            item.span,
-            "this lint is missing the `clippy::version` attribute or version value",
-            None,
-            "please use a `clippy::version` attribute, see `doc/adding_lints.md`",
-        );
-    }
-}
-
-/// This function extracts the version value of a `clippy::version` attribute if the given value has
-/// one
-fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option<Symbol> {
-    let attrs = cx.tcx.hir().attrs(item.hir_id());
-    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.item.path.segments[..];
-            if tool_name.ident.name == sym::clippy;
-            if attr_name.ident.name == sym::version;
-            if let Some(version) = attr.value_str();
-            then {
-                Some(version)
-            } else {
-                None
-            }
-        }
-    })
-}
-
-struct LintCollector<'a, 'tcx> {
-    output: &'a mut FxHashSet<Symbol>,
-    cx: &'a LateContext<'tcx>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
-    type NestedFilter = nested_filter::All;
-
-    fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
-        if path.segments.len() == 1 {
-            self.output.insert(path.segments[0].ident.name);
-        }
-    }
-
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.cx.tcx.hir()
-    }
-}
-
-#[derive(Clone, Default)]
-pub struct CompilerLintFunctions {
-    map: FxHashMap<&'static str, &'static str>,
-}
-
-impl CompilerLintFunctions {
-    #[must_use]
-    pub fn new() -> Self {
-        let mut map = FxHashMap::default();
-        map.insert("span_lint", "utils::span_lint");
-        map.insert("struct_span_lint", "utils::span_lint");
-        map.insert("lint", "utils::span_lint");
-        map.insert("span_lint_note", "utils::span_lint_and_note");
-        map.insert("span_lint_help", "utils::span_lint_and_help");
-        Self { map }
-    }
-}
-
-impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]);
-
-impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) {
-            return;
-        }
-
-        if_chain! {
-            if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind;
-            let fn_name = path.ident;
-            if let Some(sugg) = self.map.get(fn_name.as_str());
-            let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
-            if match_type(cx, ty, &paths::EARLY_CONTEXT)
-                || match_type(cx, ty, &paths::LATE_CONTEXT);
-            then {
-                span_lint_and_help(
-                    cx,
-                    COMPILER_LINT_FUNCTIONS,
-                    path.ident.span,
-                    "usage of a compiler lint function",
-                    None,
-                    &format!("please use the Clippy variant of this function: `{sugg}`"),
-                );
-            }
-        }
-    }
-}
-
-declare_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]);
-
-impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if is_lint_allowed(cx, OUTER_EXPN_EXPN_DATA, expr.hir_id) {
-            return;
-        }
-
-        let (method_names, arg_lists, spans) = method_calls(expr, 2);
-        let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect();
-        if_chain! {
-            if let ["expn_data", "outer_expn"] = method_names.as_slice();
-            let (self_arg, args)= arg_lists[1];
-            if args.is_empty();
-            let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
-            if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
-            then {
-                span_lint_and_sugg(
-                    cx,
-                    OUTER_EXPN_EXPN_DATA,
-                    spans[1].with_hi(expr.span.hi()),
-                    "usage of `outer_expn().expn_data()`",
-                    "try",
-                    "outer_expn_data()".to_string(),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-    }
-}
-
-declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);
-
-impl EarlyLintPass for ProduceIce {
-    fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
-        assert!(!is_trigger_fn(fn_kind), "Would you like some help with that?");
-    }
-}
-
-fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
-    match fn_kind {
-        FnKind::Fn(_, ident, ..) => ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy",
-        FnKind::Closure(..) => false,
-    }
-}
-
-declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]);
-
-impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        if is_lint_allowed(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.hir_id) {
-            return;
-        }
-
-        if_chain! {
-            if let ExprKind::Call(func, and_then_args) = expr.kind;
-            if is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]);
-            if and_then_args.len() == 5;
-            if let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind;
-            let body = cx.tcx.hir().body(body);
-            let only_expr = peel_blocks_with_stmt(body.value);
-            if let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind;
-            if let ExprKind::Path(..) = recv.kind;
-            then {
-                let and_then_snippets = get_and_then_snippets(cx, and_then_args);
-                let mut sle = SpanlessEq::new(cx).deny_side_effects();
-                match ps.ident.as_str() {
-                    "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
-                        suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args));
-                    },
-                    "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
-                        let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
-                        suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
-                    },
-                    "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
-                        let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
-                        suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
-                    },
-                    "help" => {
-                        let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
-                        suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
-                    }
-                    "note" => {
-                        let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
-                        suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
-                    }
-                    _  => (),
-                }
-            }
-        }
-    }
-}
-
-struct AndThenSnippets<'a> {
-    cx: Cow<'a, str>,
-    lint: Cow<'a, str>,
-    span: Cow<'a, str>,
-    msg: Cow<'a, str>,
-}
-
-fn get_and_then_snippets<'a, 'hir>(cx: &LateContext<'_>, and_then_snippets: &'hir [Expr<'hir>]) -> AndThenSnippets<'a> {
-    let cx_snippet = snippet(cx, and_then_snippets[0].span, "cx");
-    let lint_snippet = snippet(cx, and_then_snippets[1].span, "..");
-    let span_snippet = snippet(cx, and_then_snippets[2].span, "span");
-    let msg_snippet = snippet(cx, and_then_snippets[3].span, r#""...""#);
-
-    AndThenSnippets {
-        cx: cx_snippet,
-        lint: lint_snippet,
-        span: span_snippet,
-        msg: msg_snippet,
-    }
-}
-
-struct SpanSuggestionSnippets<'a> {
-    help: Cow<'a, str>,
-    sugg: Cow<'a, str>,
-    applicability: Cow<'a, str>,
-}
-
-fn span_suggestion_snippets<'a, 'hir>(
-    cx: &LateContext<'_>,
-    span_call_args: &'hir [Expr<'hir>],
-) -> SpanSuggestionSnippets<'a> {
-    let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
-    let sugg_snippet = snippet(cx, span_call_args[2].span, "..");
-    let applicability_snippet = snippet(cx, span_call_args[3].span, "Applicability::MachineApplicable");
-
-    SpanSuggestionSnippets {
-        help: help_snippet,
-        sugg: sugg_snippet,
-        applicability: applicability_snippet,
-    }
-}
-
-fn suggest_suggestion(
-    cx: &LateContext<'_>,
-    expr: &Expr<'_>,
-    and_then_snippets: &AndThenSnippets<'_>,
-    span_suggestion_snippets: &SpanSuggestionSnippets<'_>,
-) {
-    span_lint_and_sugg(
-        cx,
-        COLLAPSIBLE_SPAN_LINT_CALLS,
-        expr.span,
-        "this call is collapsible",
-        "collapse into",
-        format!(
-            "span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})",
-            and_then_snippets.cx,
-            and_then_snippets.lint,
-            and_then_snippets.span,
-            and_then_snippets.msg,
-            span_suggestion_snippets.help,
-            span_suggestion_snippets.sugg,
-            span_suggestion_snippets.applicability
-        ),
-        Applicability::MachineApplicable,
-    );
-}
-
-fn suggest_help(
-    cx: &LateContext<'_>,
-    expr: &Expr<'_>,
-    and_then_snippets: &AndThenSnippets<'_>,
-    help: &str,
-    with_span: bool,
-) {
-    let option_span = if with_span {
-        format!("Some({})", and_then_snippets.span)
-    } else {
-        "None".to_string()
-    };
-
-    span_lint_and_sugg(
-        cx,
-        COLLAPSIBLE_SPAN_LINT_CALLS,
-        expr.span,
-        "this call is collapsible",
-        "collapse into",
-        format!(
-            "span_lint_and_help({}, {}, {}, {}, {}, {help})",
-            and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg, &option_span,
-        ),
-        Applicability::MachineApplicable,
-    );
-}
-
-fn suggest_note(
-    cx: &LateContext<'_>,
-    expr: &Expr<'_>,
-    and_then_snippets: &AndThenSnippets<'_>,
-    note: &str,
-    with_span: bool,
-) {
-    let note_span = if with_span {
-        format!("Some({})", and_then_snippets.span)
-    } else {
-        "None".to_string()
-    };
-
-    span_lint_and_sugg(
-        cx,
-        COLLAPSIBLE_SPAN_LINT_CALLS,
-        expr.span,
-        "this call is collapsible",
-        "collapse into",
-        format!(
-            "span_lint_and_note({}, {}, {}, {}, {note_span}, {note})",
-            and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg,
-        ),
-        Applicability::MachineApplicable,
-    );
-}
-
-declare_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]);
-
-#[allow(clippy::too_many_lines)]
-impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        enum Item {
-            LangItem(Symbol),
-            DiagnosticItem(Symbol),
-        }
-        static PATHS: &[&[&str]] = &[
-            &["clippy_utils", "match_def_path"],
-            &["clippy_utils", "match_trait_method"],
-            &["clippy_utils", "ty", "match_type"],
-            &["clippy_utils", "is_expr_path_def_path"],
-        ];
-
-        if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) {
-            return;
-        }
-
-        if_chain! {
-            if let ExprKind::Call(func, [cx_arg, def_arg, args@..]) = expr.kind;
-            if let ExprKind::Path(path) = &func.kind;
-            if let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id();
-            if let Some(which_path) = match_any_def_paths(cx, id, PATHS);
-            let item_arg = if which_path == 4 { &args[1] } else { &args[0] };
-            // Extract the path to the matched type
-            if let Some(segments) = path_to_matched_type(cx, item_arg);
-            let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
-            if let Some(def_id) = def_path_res(cx, &segments[..], None).opt_def_id();
-            then {
-                // def_path_res will match field names before anything else, but for this we want to match
-                // inherent functions first.
-                let def_id = if cx.tcx.def_kind(def_id) == DefKind::Field {
-                    let method_name = *segments.last().unwrap();
-                    cx.tcx.def_key(def_id).parent
-                        .and_then(|parent_idx|
-                            cx.tcx.inherent_impls(DefId { index: parent_idx, krate: def_id.krate }).iter()
-                                .find_map(|impl_id| cx.tcx.associated_items(*impl_id)
-                                    .find_by_name_and_kind(
-                                        cx.tcx,
-                                        Ident::from_str(method_name),
-                                        AssocKind::Fn,
-                                        *impl_id,
-                                    )
-                                )
-                        )
-                        .map_or(def_id, |item| item.def_id)
-                } else {
-                    def_id
-                };
-
-                // Check if the target item is a diagnostic item or LangItem.
-                let (msg, item) = if let Some(item_name)
-                    = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id)
-                {
-                    (
-                        "use of a def path to a diagnostic item",
-                        Item::DiagnosticItem(*item_name),
-                    )
-                } else if let Some(lang_item) = cx.tcx.lang_items().items().iter().position(|id| *id == Some(def_id)) {
-                    let lang_items = def_path_res(cx, &["rustc_hir", "lang_items", "LangItem"], Some(Namespace::TypeNS)).def_id();
-                    let item_name = cx.tcx.adt_def(lang_items).variants().iter().nth(lang_item).unwrap().name;
-                    (
-                        "use of a def path to a `LangItem`",
-                        Item::LangItem(item_name),
-                    )
-                } else {
-                    return;
-                };
-
-                let has_ctor = match cx.tcx.def_kind(def_id) {
-                    DefKind::Struct => {
-                        let variant = cx.tcx.adt_def(def_id).non_enum_variant();
-                        variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
-                    }
-                    DefKind::Variant => {
-                        let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id);
-                        variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
-                    }
-                    _ => false,
-                };
-
-                let mut app = Applicability::MachineApplicable;
-                let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app);
-                let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app);
-                let (sugg, with_note) = match (which_path, item) {
-                    // match_def_path
-                    (0, Item::DiagnosticItem(item)) =>
-                        (format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"), has_ctor),
-                    (0, Item::LangItem(item)) => (
-                        format!("{cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some({def_snip})"),
-                        has_ctor
-                    ),
-                    // match_trait_method
-                    (1, Item::DiagnosticItem(item)) =>
-                        (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false),
-                    // match_type
-                    (2, Item::DiagnosticItem(item)) =>
-                        (format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), false),
-                    (2, Item::LangItem(item)) =>
-                        (format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"), false),
-                    // is_expr_path_def_path
-                    (3, Item::DiagnosticItem(item)) if has_ctor => (
-                        format!(
-                            "is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",
-                        ),
-                        false,
-                    ),
-                    (3, Item::LangItem(item)) if has_ctor => (
-                        format!(
-                            "is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",
-                        ),
-                        false,
-                    ),
-                    (3, Item::DiagnosticItem(item)) =>
-                        (format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), false),
-                    (3, Item::LangItem(item)) => (
-                        format!(
-                            "path_res({cx_snip}, {def_snip}).opt_def_id()\
-                                .map_or(false, |id| {cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some(id))",
-                        ),
-                        false,
-                    ),
-                    _ => return,
-                };
-
-                span_lint_and_then(
-                    cx,
-                    UNNECESSARY_DEF_PATH,
-                    expr.span,
-                    msg,
-                    |diag| {
-                        diag.span_suggestion(expr.span, "try", sugg, app);
-                        if with_note {
-                            diag.help(
-                                "if this `DefId` came from a constructor expression or pattern then the \
-                                    parent `DefId` should be used instead"
-                            );
-                        }
-                    },
-                );
-            }
-        }
-    }
-}
-
-fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<String>> {
-    match peel_hir_expr_refs(expr).0.kind {
-        ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
-            Res::Local(hir_id) => {
-                let parent_id = cx.tcx.hir().get_parent_node(hir_id);
-                if let Some(Node::Local(Local { init: Some(init), .. })) = cx.tcx.hir().find(parent_id) {
-                    path_to_matched_type(cx, init)
-                } else {
-                    None
-                }
-            },
-            Res::Def(DefKind::Static(_), def_id) => read_mir_alloc_def_path(
-                cx,
-                cx.tcx.eval_static_initializer(def_id).ok()?.inner(),
-                cx.tcx.type_of(def_id),
-            ),
-            Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? {
-                ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => {
-                    read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id))
-                },
-                _ => None,
-            },
-            _ => None,
-        },
-        ExprKind::Array(exprs) => exprs
-            .iter()
-            .map(|expr| {
-                if let ExprKind::Lit(lit) = &expr.kind {
-                    if let LitKind::Str(sym, _) = lit.node {
-                        return Some((*sym.as_str()).to_owned());
-                    }
-                }
-
-                None
-            })
-            .collect(),
-        _ => None,
-    }
-}
-
-fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option<Vec<String>> {
-    let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() {
-        let &alloc = alloc.provenance().values().next()?;
-        if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
-            (alloc.inner(), ty)
-        } else {
-            return None;
-        }
-    } else {
-        (alloc, ty)
-    };
-
-    if let ty::Array(ty, _) | ty::Slice(ty) = *ty.kind()
-        && let ty::Ref(_, ty, Mutability::Not) = *ty.kind()
-        && ty.is_str()
-    {
-        alloc
-            .provenance()
-            .values()
-            .map(|&alloc| {
-                if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
-                    let alloc = alloc.inner();
-                    str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()))
-                        .ok().map(ToOwned::to_owned)
-                } else {
-                    None
-                }
-            })
-            .collect()
-    } else {
-        None
-    }
-}
-
-// This is not a complete resolver for paths. It works on all the paths currently used in the paths
-// module.  That's all it does and all it needs to do.
-pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
-    if def_path_res(cx, path, None) != Res::Err {
-        return true;
-    }
-
-    // Some implementations can't be found by `path_to_res`, particularly inherent
-    // implementations of native types. Check lang items.
-    let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect();
-    let lang_items = cx.tcx.lang_items();
-    // This list isn't complete, but good enough for our current list of paths.
-    let incoherent_impls = [
-        SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F32),
-        SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F64),
-        SimplifiedTypeGen::SliceSimplifiedType,
-        SimplifiedTypeGen::StrSimplifiedType,
-    ]
-    .iter()
-    .flat_map(|&ty| cx.tcx.incoherent_impls(ty));
-    for item_def_id in lang_items.items().iter().flatten().chain(incoherent_impls) {
-        let lang_item_path = cx.get_def_path(*item_def_id);
-        if path_syms.starts_with(&lang_item_path) {
-            if let [item] = &path_syms[lang_item_path.len()..] {
-                if matches!(
-                    cx.tcx.def_kind(*item_def_id),
-                    DefKind::Mod | DefKind::Enum | DefKind::Trait
-                ) {
-                    for child in cx.tcx.module_children(*item_def_id) {
-                        if child.ident.name == *item {
-                            return true;
-                        }
-                    }
-                } else {
-                    for child in cx.tcx.associated_item_def_ids(*item_def_id) {
-                        if cx.tcx.item_name(*child) == *item {
-                            return true;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    false
-}
-
-declare_lint_pass!(InvalidPaths => [INVALID_PATHS]);
-
-impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        let local_def_id = &cx.tcx.parent_module(item.hir_id());
-        let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
-        if_chain! {
-            if mod_name.as_str() == "paths";
-            if let hir::ItemKind::Const(ty, body_id) = item.kind;
-            let ty = hir_ty_to_ty(cx.tcx, ty);
-            if let ty::Array(el_ty, _) = &ty.kind();
-            if let ty::Ref(_, el_ty, _) = &el_ty.kind();
-            if el_ty.is_str();
-            let body = cx.tcx.hir().body(body_id);
-            let typeck_results = cx.tcx.typeck_body(body_id);
-            if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value);
-            let path: Vec<&str> = path.iter().map(|x| {
-                    if let Constant::Str(s) = x {
-                        s.as_str()
-                    } else {
-                        // We checked the type of the constant above
-                        unreachable!()
-                    }
-                }).collect();
-            if !check_path(cx, &path[..]);
-            then {
-                span_lint(cx, INVALID_PATHS, item.span, "invalid path");
-            }
-        }
-    }
-}
-
-#[derive(Default)]
-pub struct InterningDefinedSymbol {
-    // Maps the symbol value to the constant DefId.
-    symbol_map: FxHashMap<u32, DefId>,
-}
-
-impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]);
-
-impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
-    fn check_crate(&mut self, cx: &LateContext<'_>) {
-        if !self.symbol_map.is_empty() {
-            return;
-        }
-
-        for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
-            if let Some(def_id) = def_path_res(cx, module, None).opt_def_id() {
-                for item in cx.tcx.module_children(def_id).iter() {
-                    if_chain! {
-                        if let Res::Def(DefKind::Const, item_def_id) = item.res;
-                        let ty = cx.tcx.type_of(item_def_id);
-                        if match_type(cx, ty, &paths::SYMBOL);
-                        if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
-                        if let Ok(value) = value.to_u32();
-                        then {
-                            self.symbol_map.insert(value, item_def_id);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let ExprKind::Call(func, [arg]) = &expr.kind;
-            if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind();
-            if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN);
-            if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg);
-            let value = Symbol::intern(&arg).as_u32();
-            if let Some(&def_id) = self.symbol_map.get(&value);
-            then {
-                span_lint_and_sugg(
-                    cx,
-                    INTERNING_DEFINED_SYMBOL,
-                    is_expn_of(expr.span, "sym").unwrap_or(expr.span),
-                    "interning a defined symbol",
-                    "try",
-                    cx.tcx.def_path_str(def_id),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-        if let ExprKind::Binary(op, left, right) = expr.kind {
-            if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) {
-                let data = [
-                    (left, self.symbol_str_expr(left, cx)),
-                    (right, self.symbol_str_expr(right, cx)),
-                ];
-                match data {
-                    // both operands are a symbol string
-                    [(_, Some(left)), (_, Some(right))] => {
-                        span_lint_and_sugg(
-                            cx,
-                            UNNECESSARY_SYMBOL_STR,
-                            expr.span,
-                            "unnecessary `Symbol` to string conversion",
-                            "try",
-                            format!(
-                                "{} {} {}",
-                                left.as_symbol_snippet(cx),
-                                op.node.as_str(),
-                                right.as_symbol_snippet(cx),
-                            ),
-                            Applicability::MachineApplicable,
-                        );
-                    },
-                    // one of the operands is a symbol string
-                    [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => {
-                        // creating an owned string for comparison
-                        if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) {
-                            span_lint_and_sugg(
-                                cx,
-                                UNNECESSARY_SYMBOL_STR,
-                                expr.span,
-                                "unnecessary string allocation",
-                                "try",
-                                format!("{}.as_str()", symbol.as_symbol_snippet(cx)),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                    },
-                    // nothing found
-                    [(_, None), (_, None)] => {},
-                }
-            }
-        }
-    }
-}
-
-impl InterningDefinedSymbol {
-    fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
-        static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD];
-        static SYMBOL_STR_PATHS: &[&[&str]] = &[
-            &paths::SYMBOL_AS_STR,
-            &paths::SYMBOL_TO_IDENT_STRING,
-            &paths::TO_STRING_METHOD,
-        ];
-        let call = if_chain! {
-            if let ExprKind::AddrOf(_, _, e) = expr.kind;
-            if let ExprKind::Unary(UnOp::Deref, e) = e.kind;
-            then { e } else { expr }
-        };
-        if_chain! {
-            // is a method call
-            if let ExprKind::MethodCall(_, item, [], _) = call.kind;
-            if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id);
-            let ty = cx.typeck_results().expr_ty(item);
-            // ...on either an Ident or a Symbol
-            if let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) {
-                Some(false)
-            } else if match_type(cx, ty, &paths::IDENT) {
-                Some(true)
-            } else {
-                None
-            };
-            // ...which converts it to a string
-            let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS };
-            if let Some(path) = paths.iter().find(|path| match_def_path(cx, did, path));
-            then {
-                let is_to_owned = path.last().unwrap().ends_with("string");
-                return Some(SymbolStrExpr::Expr {
-                    item,
-                    is_ident,
-                    is_to_owned,
-                });
-            }
-        }
-        // is a string constant
-        if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) {
-            let value = Symbol::intern(&s).as_u32();
-            // ...which matches a symbol constant
-            if let Some(&def_id) = self.symbol_map.get(&value) {
-                return Some(SymbolStrExpr::Const(def_id));
-            }
-        }
-        None
-    }
-}
-
-enum SymbolStrExpr<'tcx> {
-    /// a string constant with a corresponding symbol constant
-    Const(DefId),
-    /// a "symbol to string" expression like `symbol.as_str()`
-    Expr {
-        /// part that evaluates to `Symbol` or `Ident`
-        item: &'tcx Expr<'tcx>,
-        is_ident: bool,
-        /// whether an owned `String` is created like `to_ident_string()`
-        is_to_owned: bool,
-    },
-}
-
-impl<'tcx> SymbolStrExpr<'tcx> {
-    /// Returns a snippet that evaluates to a `Symbol` and is const if possible
-    fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> {
-        match *self {
-            Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(),
-            Self::Expr { item, is_ident, .. } => {
-                let mut snip = snippet(cx, item.span.source_callsite(), "..");
-                if is_ident {
-                    // get `Ident.name`
-                    snip.to_mut().push_str(".name");
-                }
-                snip
-            },
-        }
-    }
-}
-
-declare_lint_pass!(IfChainStyle => [IF_CHAIN_STYLE]);
-
-impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
-    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
-        let (local, after, if_chain_span) = if_chain! {
-            if let [Stmt { kind: StmtKind::Local(local), .. }, after @ ..] = block.stmts;
-            if let Some(if_chain_span) = is_expn_of(block.span, "if_chain");
-            then { (local, after, if_chain_span) } else { return }
-        };
-        if is_first_if_chain_expr(cx, block.hir_id, if_chain_span) {
-            span_lint(
-                cx,
-                IF_CHAIN_STYLE,
-                if_chain_local_span(cx, local, if_chain_span),
-                "`let` expression should be above the `if_chain!`",
-            );
-        } else if local.span.ctxt() == block.span.ctxt() && is_if_chain_then(after, block.expr, if_chain_span) {
-            span_lint(
-                cx,
-                IF_CHAIN_STYLE,
-                if_chain_local_span(cx, local, if_chain_span),
-                "`let` expression should be inside `then { .. }`",
-            );
-        }
-    }
-
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
-        let (cond, then, els) = if let Some(higher::IfOrIfLet { cond, r#else, then }) = higher::IfOrIfLet::hir(expr) {
-            (cond, then, r#else.is_some())
-        } else {
-            return;
-        };
-        let then_block = match then.kind {
-            ExprKind::Block(block, _) => block,
-            _ => return,
-        };
-        let if_chain_span = is_expn_of(expr.span, "if_chain");
-        if !els {
-            check_nested_if_chains(cx, expr, then_block, if_chain_span);
-        }
-        let if_chain_span = match if_chain_span {
-            None => return,
-            Some(span) => span,
-        };
-        // check for `if a && b;`
-        if_chain! {
-            if let ExprKind::Binary(op, _, _) = cond.kind;
-            if op.node == BinOpKind::And;
-            if cx.sess().source_map().is_multiline(cond.span);
-            then {
-                span_lint(cx, IF_CHAIN_STYLE, cond.span, "`if a && b;` should be `if a; if b;`");
-            }
-        }
-        if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
-            && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
-        {
-            span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
-        }
-    }
-}
-
-fn check_nested_if_chains(
-    cx: &LateContext<'_>,
-    if_expr: &Expr<'_>,
-    then_block: &Block<'_>,
-    if_chain_span: Option<Span>,
-) {
-    #[rustfmt::skip]
-    let (head, tail) = match *then_block {
-        Block { stmts, expr: Some(tail), .. } => (stmts, tail),
-        Block {
-            stmts: &[
-                ref head @ ..,
-                Stmt { kind: StmtKind::Expr(tail) | StmtKind::Semi(tail), .. }
-            ],
-            ..
-        } => (head, tail),
-        _ => return,
-    };
-    if_chain! {
-        if let Some(higher::IfOrIfLet { r#else: None, .. }) = higher::IfOrIfLet::hir(tail);
-        let sm = cx.sess().source_map();
-        if head
-            .iter()
-            .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span));
-        if if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr);
-        then {} else { return }
-    }
-    let (span, msg) = match (if_chain_span, is_expn_of(tail.span, "if_chain")) {
-        (None, Some(_)) => (if_expr.span, "this `if` can be part of the inner `if_chain!`"),
-        (Some(_), None) => (tail.span, "this `if` can be part of the outer `if_chain!`"),
-        (Some(a), Some(b)) if a != b => (b, "this `if_chain!` can be merged with the outer `if_chain!`"),
-        _ => return,
-    };
-    span_lint_and_then(cx, IF_CHAIN_STYLE, span, msg, |diag| {
-        let (span, msg) = match head {
-            [] => return,
-            [stmt] => (stmt.span, "this `let` statement can also be in the `if_chain!`"),
-            [a, .., b] => (
-                a.span.to(b.span),
-                "these `let` statements can also be in the `if_chain!`",
-            ),
-        };
-        diag.span_help(span, msg);
-    });
-}
-
-fn is_first_if_chain_expr(cx: &LateContext<'_>, hir_id: HirId, if_chain_span: Span) -> bool {
-    cx.tcx
-        .hir()
-        .parent_iter(hir_id)
-        .find(|(_, node)| {
-            #[rustfmt::skip]
-            !matches!(node, Node::Expr(Expr { kind: ExprKind::Block(..), .. }) | Node::Stmt(_))
-        })
-        .map_or(false, |(id, _)| {
-            is_expn_of(cx.tcx.hir().span(id), "if_chain") != Some(if_chain_span)
-        })
-}
-
-/// Checks a trailing slice of statements and expression of a `Block` to see if they are part
-/// of the `then {..}` portion of an `if_chain!`
-fn is_if_chain_then(stmts: &[Stmt<'_>], expr: Option<&Expr<'_>>, if_chain_span: Span) -> bool {
-    let span = if let [stmt, ..] = stmts {
-        stmt.span
-    } else if let Some(expr) = expr {
-        expr.span
-    } else {
-        // empty `then {}`
-        return true;
-    };
-    is_expn_of(span, "if_chain").map_or(true, |span| span != if_chain_span)
-}
-
-/// Creates a `Span` for `let x = ..;` in an `if_chain!` call.
-fn if_chain_local_span(cx: &LateContext<'_>, local: &Local<'_>, if_chain_span: Span) -> Span {
-    let mut span = local.pat.span;
-    if let Some(init) = local.init {
-        span = span.to(init.span);
-    }
-    span.adjust(if_chain_span.ctxt().outer_expn());
-    let sm = cx.sess().source_map();
-    let span = sm.span_extend_to_prev_str(span, "let", false, true).unwrap_or(span);
-    let span = sm.span_extend_to_next_char(span, ';', false);
-    Span::new(
-        span.lo() - BytePos(3),
-        span.hi() + BytePos(1),
-        span.ctxt(),
-        span.parent(),
-    )
-}
-
-declare_lint_pass!(MsrvAttrImpl => [MISSING_MSRV_ATTR_IMPL]);
-
-impl LateLintPass<'_> for MsrvAttrImpl {
-    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        if_chain! {
-            if let hir::ItemKind::Impl(hir::Impl {
-                of_trait: Some(lint_pass_trait_ref),
-                self_ty,
-                items,
-                ..
-            }) = &item.kind;
-            if let Some(lint_pass_trait_def_id) = lint_pass_trait_ref.trait_def_id();
-            let is_late_pass = match_def_path(cx, lint_pass_trait_def_id, &paths::LATE_LINT_PASS);
-            if is_late_pass || match_def_path(cx, lint_pass_trait_def_id, &paths::EARLY_LINT_PASS);
-            let self_ty = hir_ty_to_ty(cx.tcx, self_ty);
-            if let ty::Adt(self_ty_def, _) = self_ty.kind();
-            if self_ty_def.is_struct();
-            if self_ty_def.all_fields().any(|f| {
-                cx.tcx
-                    .type_of(f.did)
-                    .walk()
-                    .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
-                    .any(|t| match_type(cx, t.expect_ty(), &paths::RUSTC_VERSION))
-            });
-            if !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs));
-            then {
-                let context = if is_late_pass { "LateContext" } else { "EarlyContext" };
-                let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" };
-                let span = cx.sess().source_map().span_through_char(item.span, '{');
-                span_lint_and_sugg(
-                    cx,
-                    MISSING_MSRV_ATTR_IMPL,
-                    span,
-                    &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"),
-                    &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"),
-                    format!("{}\n    extract_msrv_attr!({context});", snippet(cx, span, "..")),
-                    Applicability::MachineApplicable,
-                );
-            }
-        }
-    }
-}
+pub mod msrv_attr_impl;
+pub mod outer_expn_data_pass;
+pub mod produce_ice;
+pub mod unnecessary_def_path;
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs
new file mode 100644
index 00000000000..da9514dd15e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs
@@ -0,0 +1,49 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::ast::{Crate, ItemKind, ModKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for various things we like to keep tidy in clippy.
+    ///
+    /// ### Why is this bad?
+    /// We like to pretend we're an example of tidy code.
+    ///
+    /// ### Example
+    /// Wrong ordering of the util::paths constants.
+    pub CLIPPY_LINTS_INTERNAL,
+    internal,
+    "various things that will negatively affect your clippy experience"
+}
+
+declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
+
+impl EarlyLintPass for ClippyLintsInternal {
+    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
+        if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") {
+            if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind {
+                if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") {
+                    if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = paths.kind {
+                        let mut last_name: Option<&str> = None;
+                        for item in items {
+                            let name = item.ident.as_str();
+                            if let Some(last_name) = last_name {
+                                if *last_name > *name {
+                                    span_lint(
+                                        cx,
+                                        CLIPPY_LINTS_INTERNAL,
+                                        item.span,
+                                        "this constant should be before the previous constant due to lexical \
+                                         ordering",
+                                    );
+                                }
+                            }
+                            last_name = Some(name);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
new file mode 100644
index 00000000000..d7666b77f6e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
@@ -0,0 +1,245 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::{is_expr_path_def_path, is_lint_allowed, peel_blocks_with_stmt, SpanlessEq};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::{Closure, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+use std::borrow::{Borrow, Cow};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Lints `span_lint_and_then` function calls, where the
+    /// closure argument has only one statement and that statement is a method
+    /// call to `span_suggestion`, `span_help`, `span_note` (using the same
+    /// span), `help` or `note`.
+    ///
+    /// These usages of `span_lint_and_then` should be replaced with one of the
+    /// wrapper functions `span_lint_and_sugg`, span_lint_and_help`, or
+    /// `span_lint_and_note`.
+    ///
+    /// ### Why is this bad?
+    /// Using the wrapper `span_lint_and_*` functions, is more
+    /// convenient, readable and less error prone.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
+    ///     diag.span_suggestion(
+    ///         expr.span,
+    ///         help_msg,
+    ///         sugg.to_string(),
+    ///         Applicability::MachineApplicable,
+    ///     );
+    /// });
+    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
+    ///     diag.span_help(expr.span, help_msg);
+    /// });
+    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
+    ///     diag.help(help_msg);
+    /// });
+    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
+    ///     diag.span_note(expr.span, note_msg);
+    /// });
+    /// span_lint_and_then(cx, TEST_LINT, expr.span, lint_msg, |diag| {
+    ///     diag.note(note_msg);
+    /// });
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// span_lint_and_sugg(
+    ///     cx,
+    ///     TEST_LINT,
+    ///     expr.span,
+    ///     lint_msg,
+    ///     help_msg,
+    ///     sugg.to_string(),
+    ///     Applicability::MachineApplicable,
+    /// );
+    /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), help_msg);
+    /// span_lint_and_help(cx, TEST_LINT, expr.span, lint_msg, None, help_msg);
+    /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg);
+    /// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg);
+    /// ```
+    pub COLLAPSIBLE_SPAN_LINT_CALLS,
+    internal,
+    "found collapsible `span_lint_and_then` calls"
+}
+
+declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]);
+
+impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if is_lint_allowed(cx, COLLAPSIBLE_SPAN_LINT_CALLS, expr.hir_id) {
+            return;
+        }
+
+        if_chain! {
+            if let ExprKind::Call(func, and_then_args) = expr.kind;
+            if is_expr_path_def_path(cx, func, &["clippy_utils", "diagnostics", "span_lint_and_then"]);
+            if and_then_args.len() == 5;
+            if let ExprKind::Closure(&Closure { body, .. }) = &and_then_args[4].kind;
+            let body = cx.tcx.hir().body(body);
+            let only_expr = peel_blocks_with_stmt(body.value);
+            if let ExprKind::MethodCall(ps, recv, span_call_args, _) = &only_expr.kind;
+            if let ExprKind::Path(..) = recv.kind;
+            then {
+                let and_then_snippets = get_and_then_snippets(cx, and_then_args);
+                let mut sle = SpanlessEq::new(cx).deny_side_effects();
+                match ps.ident.as_str() {
+                    "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+                        suggest_suggestion(
+                            cx,
+                            expr,
+                            &and_then_snippets,
+                            &span_suggestion_snippets(cx, span_call_args),
+                        );
+                    },
+                    "span_help" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+                        let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+                        suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), true);
+                    },
+                    "span_note" if sle.eq_expr(&and_then_args[2], &span_call_args[0]) => {
+                        let note_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+                        suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), true);
+                    },
+                    "help" => {
+                        let help_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
+                        suggest_help(cx, expr, &and_then_snippets, help_snippet.borrow(), false);
+                    },
+                    "note" => {
+                        let note_snippet = snippet(cx, span_call_args[0].span, r#""...""#);
+                        suggest_note(cx, expr, &and_then_snippets, note_snippet.borrow(), false);
+                    },
+                    _ => (),
+                }
+            }
+        }
+    }
+}
+
+struct AndThenSnippets<'a> {
+    cx: Cow<'a, str>,
+    lint: Cow<'a, str>,
+    span: Cow<'a, str>,
+    msg: Cow<'a, str>,
+}
+
+fn get_and_then_snippets<'a, 'hir>(cx: &LateContext<'_>, and_then_snippets: &'hir [Expr<'hir>]) -> AndThenSnippets<'a> {
+    let cx_snippet = snippet(cx, and_then_snippets[0].span, "cx");
+    let lint_snippet = snippet(cx, and_then_snippets[1].span, "..");
+    let span_snippet = snippet(cx, and_then_snippets[2].span, "span");
+    let msg_snippet = snippet(cx, and_then_snippets[3].span, r#""...""#);
+
+    AndThenSnippets {
+        cx: cx_snippet,
+        lint: lint_snippet,
+        span: span_snippet,
+        msg: msg_snippet,
+    }
+}
+
+struct SpanSuggestionSnippets<'a> {
+    help: Cow<'a, str>,
+    sugg: Cow<'a, str>,
+    applicability: Cow<'a, str>,
+}
+
+fn span_suggestion_snippets<'a, 'hir>(
+    cx: &LateContext<'_>,
+    span_call_args: &'hir [Expr<'hir>],
+) -> SpanSuggestionSnippets<'a> {
+    let help_snippet = snippet(cx, span_call_args[1].span, r#""...""#);
+    let sugg_snippet = snippet(cx, span_call_args[2].span, "..");
+    let applicability_snippet = snippet(cx, span_call_args[3].span, "Applicability::MachineApplicable");
+
+    SpanSuggestionSnippets {
+        help: help_snippet,
+        sugg: sugg_snippet,
+        applicability: applicability_snippet,
+    }
+}
+
+fn suggest_suggestion(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    and_then_snippets: &AndThenSnippets<'_>,
+    span_suggestion_snippets: &SpanSuggestionSnippets<'_>,
+) {
+    span_lint_and_sugg(
+        cx,
+        COLLAPSIBLE_SPAN_LINT_CALLS,
+        expr.span,
+        "this call is collapsible",
+        "collapse into",
+        format!(
+            "span_lint_and_sugg({}, {}, {}, {}, {}, {}, {})",
+            and_then_snippets.cx,
+            and_then_snippets.lint,
+            and_then_snippets.span,
+            and_then_snippets.msg,
+            span_suggestion_snippets.help,
+            span_suggestion_snippets.sugg,
+            span_suggestion_snippets.applicability
+        ),
+        Applicability::MachineApplicable,
+    );
+}
+
+fn suggest_help(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    and_then_snippets: &AndThenSnippets<'_>,
+    help: &str,
+    with_span: bool,
+) {
+    let option_span = if with_span {
+        format!("Some({})", and_then_snippets.span)
+    } else {
+        "None".to_string()
+    };
+
+    span_lint_and_sugg(
+        cx,
+        COLLAPSIBLE_SPAN_LINT_CALLS,
+        expr.span,
+        "this call is collapsible",
+        "collapse into",
+        format!(
+            "span_lint_and_help({}, {}, {}, {}, {}, {help})",
+            and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg, &option_span,
+        ),
+        Applicability::MachineApplicable,
+    );
+}
+
+fn suggest_note(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    and_then_snippets: &AndThenSnippets<'_>,
+    note: &str,
+    with_span: bool,
+) {
+    let note_span = if with_span {
+        format!("Some({})", and_then_snippets.span)
+    } else {
+        "None".to_string()
+    };
+
+    span_lint_and_sugg(
+        cx,
+        COLLAPSIBLE_SPAN_LINT_CALLS,
+        expr.span,
+        "this call is collapsible",
+        "collapse into",
+        format!(
+            "span_lint_and_note({}, {}, {}, {}, {note_span}, {note})",
+            and_then_snippets.cx, and_then_snippets.lint, and_then_snippets.span, and_then_snippets.msg,
+        ),
+        Applicability::MachineApplicable,
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
new file mode 100644
index 00000000000..cacd05262a2
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
@@ -0,0 +1,77 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::match_type;
+use clippy_utils::{is_lint_allowed, paths};
+use if_chain::if_chain;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
+    /// variant of the function.
+    ///
+    /// ### Why is this bad?
+    /// The `utils::*` variants also add a link to the Clippy documentation to the
+    /// warning/error messages.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// cx.span_lint(LINT_NAME, "message");
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// utils::span_lint(cx, LINT_NAME, "message");
+    /// ```
+    pub COMPILER_LINT_FUNCTIONS,
+    internal,
+    "usage of the lint functions of the compiler instead of the utils::* variant"
+}
+
+impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]);
+
+#[derive(Clone, Default)]
+pub struct CompilerLintFunctions {
+    map: FxHashMap<&'static str, &'static str>,
+}
+
+impl CompilerLintFunctions {
+    #[must_use]
+    pub fn new() -> Self {
+        let mut map = FxHashMap::default();
+        map.insert("span_lint", "utils::span_lint");
+        map.insert("struct_span_lint", "utils::span_lint");
+        map.insert("lint", "utils::span_lint");
+        map.insert("span_lint_note", "utils::span_lint_and_note");
+        map.insert("span_lint_help", "utils::span_lint_and_help");
+        Self { map }
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) {
+            return;
+        }
+
+        if_chain! {
+            if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind;
+            let fn_name = path.ident;
+            if let Some(sugg) = self.map.get(fn_name.as_str());
+            let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
+            if match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT);
+            then {
+                span_lint_and_help(
+                    cx,
+                    COMPILER_LINT_FUNCTIONS,
+                    path.ident.span,
+                    "usage of a compiler lint function",
+                    None,
+                    &format!("please use the Clippy variant of this function: `{sugg}`"),
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
new file mode 100644
index 00000000000..883a5c08e5c
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
@@ -0,0 +1,164 @@
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::{higher, is_else_clause, is_expn_of};
+use if_chain::if_chain;
+use rustc_hir as hir;
+use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Local, Node, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{BytePos, Span};
+
+declare_clippy_lint! {
+    /// Finds unidiomatic usage of `if_chain!`
+    pub IF_CHAIN_STYLE,
+    internal,
+    "non-idiomatic `if_chain!` usage"
+}
+
+declare_lint_pass!(IfChainStyle => [IF_CHAIN_STYLE]);
+
+impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
+        let (local, after, if_chain_span) = if_chain! {
+            if let [Stmt { kind: StmtKind::Local(local), .. }, after @ ..] = block.stmts;
+            if let Some(if_chain_span) = is_expn_of(block.span, "if_chain");
+            then { (local, after, if_chain_span) } else { return }
+        };
+        if is_first_if_chain_expr(cx, block.hir_id, if_chain_span) {
+            span_lint(
+                cx,
+                IF_CHAIN_STYLE,
+                if_chain_local_span(cx, local, if_chain_span),
+                "`let` expression should be above the `if_chain!`",
+            );
+        } else if local.span.ctxt() == block.span.ctxt() && is_if_chain_then(after, block.expr, if_chain_span) {
+            span_lint(
+                cx,
+                IF_CHAIN_STYLE,
+                if_chain_local_span(cx, local, if_chain_span),
+                "`let` expression should be inside `then { .. }`",
+            );
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        let (cond, then, els) = if let Some(higher::IfOrIfLet { cond, r#else, then }) = higher::IfOrIfLet::hir(expr) {
+            (cond, then, r#else.is_some())
+        } else {
+            return;
+        };
+        let ExprKind::Block(then_block, _) = then.kind else { return };
+        let if_chain_span = is_expn_of(expr.span, "if_chain");
+        if !els {
+            check_nested_if_chains(cx, expr, then_block, if_chain_span);
+        }
+        let Some(if_chain_span) = if_chain_span else { return };
+        // check for `if a && b;`
+        if_chain! {
+            if let ExprKind::Binary(op, _, _) = cond.kind;
+            if op.node == BinOpKind::And;
+            if cx.sess().source_map().is_multiline(cond.span);
+            then {
+                span_lint(cx, IF_CHAIN_STYLE, cond.span, "`if a && b;` should be `if a; if b;`");
+            }
+        }
+        if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
+            && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
+        {
+            span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
+        }
+    }
+}
+
+fn check_nested_if_chains(
+    cx: &LateContext<'_>,
+    if_expr: &Expr<'_>,
+    then_block: &Block<'_>,
+    if_chain_span: Option<Span>,
+) {
+    #[rustfmt::skip]
+    let (head, tail) = match *then_block {
+        Block { stmts, expr: Some(tail), .. } => (stmts, tail),
+        Block {
+            stmts: &[
+                ref head @ ..,
+                Stmt { kind: StmtKind::Expr(tail) | StmtKind::Semi(tail), .. }
+            ],
+            ..
+        } => (head, tail),
+        _ => return,
+    };
+    if_chain! {
+        if let Some(higher::IfOrIfLet { r#else: None, .. }) = higher::IfOrIfLet::hir(tail);
+        let sm = cx.sess().source_map();
+        if head
+            .iter()
+            .all(|stmt| matches!(stmt.kind, StmtKind::Local(..)) && !sm.is_multiline(stmt.span));
+        if if_chain_span.is_some() || !is_else_clause(cx.tcx, if_expr);
+        then {
+        } else {
+            return;
+        }
+    }
+    let (span, msg) = match (if_chain_span, is_expn_of(tail.span, "if_chain")) {
+        (None, Some(_)) => (if_expr.span, "this `if` can be part of the inner `if_chain!`"),
+        (Some(_), None) => (tail.span, "this `if` can be part of the outer `if_chain!`"),
+        (Some(a), Some(b)) if a != b => (b, "this `if_chain!` can be merged with the outer `if_chain!`"),
+        _ => return,
+    };
+    span_lint_and_then(cx, IF_CHAIN_STYLE, span, msg, |diag| {
+        let (span, msg) = match head {
+            [] => return,
+            [stmt] => (stmt.span, "this `let` statement can also be in the `if_chain!`"),
+            [a, .., b] => (
+                a.span.to(b.span),
+                "these `let` statements can also be in the `if_chain!`",
+            ),
+        };
+        diag.span_help(span, msg);
+    });
+}
+
+fn is_first_if_chain_expr(cx: &LateContext<'_>, hir_id: HirId, if_chain_span: Span) -> bool {
+    cx.tcx
+        .hir()
+        .parent_iter(hir_id)
+        .find(|(_, node)| {
+            #[rustfmt::skip]
+            !matches!(node, Node::Expr(Expr { kind: ExprKind::Block(..), .. }) | Node::Stmt(_))
+        })
+        .map_or(false, |(id, _)| {
+            is_expn_of(cx.tcx.hir().span(id), "if_chain") != Some(if_chain_span)
+        })
+}
+
+/// Checks a trailing slice of statements and expression of a `Block` to see if they are part
+/// of the `then {..}` portion of an `if_chain!`
+fn is_if_chain_then(stmts: &[Stmt<'_>], expr: Option<&Expr<'_>>, if_chain_span: Span) -> bool {
+    let span = if let [stmt, ..] = stmts {
+        stmt.span
+    } else if let Some(expr) = expr {
+        expr.span
+    } else {
+        // empty `then {}`
+        return true;
+    };
+    is_expn_of(span, "if_chain").map_or(true, |span| span != if_chain_span)
+}
+
+/// Creates a `Span` for `let x = ..;` in an `if_chain!` call.
+fn if_chain_local_span(cx: &LateContext<'_>, local: &Local<'_>, if_chain_span: Span) -> Span {
+    let mut span = local.pat.span;
+    if let Some(init) = local.init {
+        span = span.to(init.span);
+    }
+    span.adjust(if_chain_span.ctxt().outer_expn());
+    let sm = cx.sess().source_map();
+    let span = sm.span_extend_to_prev_str(span, "let", false, true).unwrap_or(span);
+    let span = sm.span_extend_to_next_char(span, ';', false);
+    Span::new(
+        span.lo() - BytePos(3),
+        span.hi() + BytePos(1),
+        span.ctxt(),
+        span.parent(),
+    )
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
new file mode 100644
index 00000000000..096b601572b
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -0,0 +1,239 @@
+use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::match_type;
+use clippy_utils::{def_path_res, is_expn_of, match_def_path, paths};
+use if_chain::if_chain;
+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::{BinOpKind, Expr, ExprKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::mir::interpret::ConstValue;
+use rustc_middle::ty::{self};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::Symbol;
+
+use std::borrow::Cow;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for interning symbols that have already been pre-interned and defined as constants.
+    ///
+    /// ### Why is this bad?
+    /// It's faster and easier to use the symbol constant.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let _ = sym!(f32);
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// let _ = sym::f32;
+    /// ```
+    pub INTERNING_DEFINED_SYMBOL,
+    internal,
+    "interning a symbol that is pre-interned and defined as a constant"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for unnecessary conversion from Symbol to a string.
+    ///
+    /// ### Why is this bad?
+    /// It's faster use symbols directly instead of strings.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// symbol.as_str() == "clippy";
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// symbol == sym::clippy;
+    /// ```
+    pub UNNECESSARY_SYMBOL_STR,
+    internal,
+    "unnecessary conversion between Symbol and string"
+}
+
+#[derive(Default)]
+pub struct InterningDefinedSymbol {
+    // Maps the symbol value to the constant DefId.
+    symbol_map: FxHashMap<u32, DefId>,
+}
+
+impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]);
+
+impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
+    fn check_crate(&mut self, cx: &LateContext<'_>) {
+        if !self.symbol_map.is_empty() {
+            return;
+        }
+
+        for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
+            if let Some(def_id) = def_path_res(cx, module, None).opt_def_id() {
+                for item in cx.tcx.module_children(def_id).iter() {
+                    if_chain! {
+                        if let Res::Def(DefKind::Const, item_def_id) = item.res;
+                        let ty = cx.tcx.type_of(item_def_id);
+                        if match_type(cx, ty, &paths::SYMBOL);
+                        if let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id);
+                        if let Ok(value) = value.to_u32();
+                        then {
+                            self.symbol_map.insert(value, item_def_id);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if_chain! {
+            if let ExprKind::Call(func, [arg]) = &expr.kind;
+            if let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind();
+            if match_def_path(cx, *def_id, &paths::SYMBOL_INTERN);
+            if let Some(Constant::Str(arg)) = constant_simple(cx, cx.typeck_results(), arg);
+            let value = Symbol::intern(&arg).as_u32();
+            if let Some(&def_id) = self.symbol_map.get(&value);
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    INTERNING_DEFINED_SYMBOL,
+                    is_expn_of(expr.span, "sym").unwrap_or(expr.span),
+                    "interning a defined symbol",
+                    "try",
+                    cx.tcx.def_path_str(def_id),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+        if let ExprKind::Binary(op, left, right) = expr.kind {
+            if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) {
+                let data = [
+                    (left, self.symbol_str_expr(left, cx)),
+                    (right, self.symbol_str_expr(right, cx)),
+                ];
+                match data {
+                    // both operands are a symbol string
+                    [(_, Some(left)), (_, Some(right))] => {
+                        span_lint_and_sugg(
+                            cx,
+                            UNNECESSARY_SYMBOL_STR,
+                            expr.span,
+                            "unnecessary `Symbol` to string conversion",
+                            "try",
+                            format!(
+                                "{} {} {}",
+                                left.as_symbol_snippet(cx),
+                                op.node.as_str(),
+                                right.as_symbol_snippet(cx),
+                            ),
+                            Applicability::MachineApplicable,
+                        );
+                    },
+                    // one of the operands is a symbol string
+                    [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => {
+                        // creating an owned string for comparison
+                        if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) {
+                            span_lint_and_sugg(
+                                cx,
+                                UNNECESSARY_SYMBOL_STR,
+                                expr.span,
+                                "unnecessary string allocation",
+                                "try",
+                                format!("{}.as_str()", symbol.as_symbol_snippet(cx)),
+                                Applicability::MachineApplicable,
+                            );
+                        }
+                    },
+                    // nothing found
+                    [(_, None), (_, None)] => {},
+                }
+            }
+        }
+    }
+}
+
+impl InterningDefinedSymbol {
+    fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
+        static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD];
+        static SYMBOL_STR_PATHS: &[&[&str]] = &[
+            &paths::SYMBOL_AS_STR,
+            &paths::SYMBOL_TO_IDENT_STRING,
+            &paths::TO_STRING_METHOD,
+        ];
+        let call = if_chain! {
+            if let ExprKind::AddrOf(_, _, e) = expr.kind;
+            if let ExprKind::Unary(UnOp::Deref, e) = e.kind;
+            then { e } else { expr }
+        };
+        if_chain! {
+            // is a method call
+            if let ExprKind::MethodCall(_, item, [], _) = call.kind;
+            if let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id);
+            let ty = cx.typeck_results().expr_ty(item);
+            // ...on either an Ident or a Symbol
+            if let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) {
+                Some(false)
+            } else if match_type(cx, ty, &paths::IDENT) {
+                Some(true)
+            } else {
+                None
+            };
+            // ...which converts it to a string
+            let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS };
+            if let Some(path) = paths.iter().find(|path| match_def_path(cx, did, path));
+            then {
+                let is_to_owned = path.last().unwrap().ends_with("string");
+                return Some(SymbolStrExpr::Expr {
+                    item,
+                    is_ident,
+                    is_to_owned,
+                });
+            }
+        }
+        // is a string constant
+        if let Some(Constant::Str(s)) = constant_simple(cx, cx.typeck_results(), expr) {
+            let value = Symbol::intern(&s).as_u32();
+            // ...which matches a symbol constant
+            if let Some(&def_id) = self.symbol_map.get(&value) {
+                return Some(SymbolStrExpr::Const(def_id));
+            }
+        }
+        None
+    }
+}
+
+enum SymbolStrExpr<'tcx> {
+    /// a string constant with a corresponding symbol constant
+    Const(DefId),
+    /// a "symbol to string" expression like `symbol.as_str()`
+    Expr {
+        /// part that evaluates to `Symbol` or `Ident`
+        item: &'tcx Expr<'tcx>,
+        is_ident: bool,
+        /// whether an owned `String` is created like `to_ident_string()`
+        is_to_owned: bool,
+    },
+}
+
+impl<'tcx> SymbolStrExpr<'tcx> {
+    /// Returns a snippet that evaluates to a `Symbol` and is const if possible
+    fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> {
+        match *self {
+            Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(),
+            Self::Expr { item, is_ident, .. } => {
+                let mut snip = snippet(cx, item.span.source_callsite(), "..");
+                if is_ident {
+                    // get `Ident.name`
+                    snip.to_mut().push_str(".name");
+                }
+                snip
+            },
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
new file mode 100644
index 00000000000..25532dd4e26
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -0,0 +1,108 @@
+use clippy_utils::consts::{constant_simple, Constant};
+use clippy_utils::def_path_res;
+use clippy_utils::diagnostics::span_lint;
+use if_chain::if_chain;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::Item;
+use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, FloatTy};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::Symbol;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks the paths module for invalid paths.
+    ///
+    /// ### Why is this bad?
+    /// It indicates a bug in the code.
+    ///
+    /// ### Example
+    /// None.
+    pub INVALID_PATHS,
+    internal,
+    "invalid path"
+}
+
+declare_lint_pass!(InvalidPaths => [INVALID_PATHS]);
+
+impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        let local_def_id = &cx.tcx.parent_module(item.hir_id());
+        let mod_name = &cx.tcx.item_name(local_def_id.to_def_id());
+        if_chain! {
+            if mod_name.as_str() == "paths";
+            if let hir::ItemKind::Const(ty, body_id) = item.kind;
+            let ty = hir_ty_to_ty(cx.tcx, ty);
+            if let ty::Array(el_ty, _) = &ty.kind();
+            if let ty::Ref(_, el_ty, _) = &el_ty.kind();
+            if el_ty.is_str();
+            let body = cx.tcx.hir().body(body_id);
+            let typeck_results = cx.tcx.typeck_body(body_id);
+            if let Some(Constant::Vec(path)) = constant_simple(cx, typeck_results, body.value);
+            let path: Vec<&str> = path
+                .iter()
+                .map(|x| {
+                    if let Constant::Str(s) = x {
+                        s.as_str()
+                    } else {
+                        // We checked the type of the constant above
+                        unreachable!()
+                    }
+                })
+                .collect();
+            if !check_path(cx, &path[..]);
+            then {
+                span_lint(cx, INVALID_PATHS, item.span, "invalid path");
+            }
+        }
+    }
+}
+
+// This is not a complete resolver for paths. It works on all the paths currently used in the paths
+// module.  That's all it does and all it needs to do.
+pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
+    if def_path_res(cx, path, None) != Res::Err {
+        return true;
+    }
+
+    // Some implementations can't be found by `path_to_res`, particularly inherent
+    // implementations of native types. Check lang items.
+    let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect();
+    let lang_items = cx.tcx.lang_items();
+    // This list isn't complete, but good enough for our current list of paths.
+    let incoherent_impls = [
+        SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F32),
+        SimplifiedTypeGen::FloatSimplifiedType(FloatTy::F64),
+        SimplifiedTypeGen::SliceSimplifiedType,
+        SimplifiedTypeGen::StrSimplifiedType,
+    ]
+    .iter()
+    .flat_map(|&ty| cx.tcx.incoherent_impls(ty));
+    for item_def_id in lang_items.items().iter().flatten().chain(incoherent_impls) {
+        let lang_item_path = cx.get_def_path(*item_def_id);
+        if path_syms.starts_with(&lang_item_path) {
+            if let [item] = &path_syms[lang_item_path.len()..] {
+                if matches!(
+                    cx.tcx.def_kind(*item_def_id),
+                    DefKind::Mod | DefKind::Enum | DefKind::Trait
+                ) {
+                    for child in cx.tcx.module_children(*item_def_id) {
+                        if child.ident.name == *item {
+                            return true;
+                        }
+                    }
+                } else {
+                    for child in cx.tcx.associated_item_def_ids(*item_def_id) {
+                        if cx.tcx.item_name(*child) == *item {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    false
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
new file mode 100644
index 00000000000..0dac64376b0
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
@@ -0,0 +1,342 @@
+use crate::utils::internal_lints::metadata_collector::is_deprecated_lint;
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::{is_lint_allowed, match_def_path, paths};
+use if_chain::if_chain;
+use rustc_ast as ast;
+use rustc_ast::ast::LitKind;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::hir_id::CRATE_HIR_ID;
+use rustc_hir::intravisit::Visitor;
+use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::nested_filter;
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::source_map::Spanned;
+use rustc_span::symbol::Symbol;
+use rustc_span::{sym, Span};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Ensures every lint is associated to a `LintPass`.
+    ///
+    /// ### Why is this bad?
+    /// The compiler only knows lints via a `LintPass`. Without
+    /// putting a lint to a `LintPass::get_lints()`'s return, the compiler will not
+    /// know the name of the lint.
+    ///
+    /// ### Known problems
+    /// Only checks for lints associated using the
+    /// `declare_lint_pass!`, `impl_lint_pass!`, and `lint_array!` macros.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// declare_lint! { pub LINT_1, ... }
+    /// declare_lint! { pub LINT_2, ... }
+    /// declare_lint! { pub FORGOTTEN_LINT, ... }
+    /// // ...
+    /// declare_lint_pass!(Pass => [LINT_1, LINT_2]);
+    /// // missing FORGOTTEN_LINT
+    /// ```
+    pub LINT_WITHOUT_LINT_PASS,
+    internal,
+    "declaring a lint without associating it in a LintPass"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for cases of an auto-generated lint without an updated description,
+    /// i.e. `default lint description`.
+    ///
+    /// ### Why is this bad?
+    /// Indicates that the lint is not finished.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// declare_lint! { pub COOL_LINT, nursery, "default lint description" }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" }
+    /// ```
+    pub DEFAULT_LINT,
+    internal,
+    "found 'default lint description' in a lint declaration"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for invalid `clippy::version` attributes.
+    ///
+    /// Valid values are:
+    /// * "pre 1.29.0"
+    /// * any valid semantic version
+    pub INVALID_CLIPPY_VERSION_ATTRIBUTE,
+    internal,
+    "found an invalid `clippy::version` attribute"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for declared clippy lints without the `clippy::version` attribute.
+    ///
+    pub MISSING_CLIPPY_VERSION_ATTRIBUTE,
+    internal,
+    "found clippy lint without `clippy::version` attribute"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for cases of an auto-generated deprecated lint without an updated reason,
+    /// i.e. `"default deprecation note"`.
+    ///
+    /// ### Why is this bad?
+    /// Indicates that the documentation is incomplete.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// declare_deprecated_lint! {
+    ///     /// ### What it does
+    ///     /// Nothing. This lint has been deprecated.
+    ///     ///
+    ///     /// ### Deprecation reason
+    ///     /// TODO
+    ///     #[clippy::version = "1.63.0"]
+    ///     pub COOL_LINT,
+    ///     "default deprecation note"
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// declare_deprecated_lint! {
+    ///     /// ### What it does
+    ///     /// Nothing. This lint has been deprecated.
+    ///     ///
+    ///     /// ### Deprecation reason
+    ///     /// This lint has been replaced by `cooler_lint`
+    ///     #[clippy::version = "1.63.0"]
+    ///     pub COOL_LINT,
+    ///     "this lint has been replaced by `cooler_lint`"
+    /// }
+    /// ```
+    pub DEFAULT_DEPRECATION_REASON,
+    internal,
+    "found 'default deprecation note' in a deprecated lint declaration"
+}
+
+#[derive(Clone, Debug, Default)]
+pub struct LintWithoutLintPass {
+    declared_lints: FxHashMap<Symbol, Span>,
+    registered_lints: FxHashSet<Symbol>,
+}
+
+impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS, INVALID_CLIPPY_VERSION_ATTRIBUTE, MISSING_CLIPPY_VERSION_ATTRIBUTE, DEFAULT_DEPRECATION_REASON]);
+
+impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id())
+            || is_lint_allowed(cx, DEFAULT_DEPRECATION_REASON, item.hir_id())
+        {
+            return;
+        }
+
+        if let hir::ItemKind::Static(ty, Mutability::Not, body_id) = item.kind {
+            let is_lint_ref_ty = is_lint_ref_type(cx, ty);
+            if is_deprecated_lint(cx, ty) || is_lint_ref_ty {
+                check_invalid_clippy_version_attribute(cx, item);
+
+                let expr = &cx.tcx.hir().body(body_id).value;
+                let fields;
+                if is_lint_ref_ty {
+                    if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind
+                        && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind {
+                            fields = struct_fields;
+                    } else {
+                        return;
+                    }
+                } else if let ExprKind::Struct(_, struct_fields, _) = expr.kind {
+                    fields = struct_fields;
+                } else {
+                    return;
+                }
+
+                let field = fields
+                    .iter()
+                    .find(|f| f.ident.as_str() == "desc")
+                    .expect("lints must have a description field");
+
+                if let ExprKind::Lit(Spanned {
+                    node: LitKind::Str(ref sym, _),
+                    ..
+                }) = field.expr.kind
+                {
+                    let sym_str = sym.as_str();
+                    if is_lint_ref_ty {
+                        if sym_str == "default lint description" {
+                            span_lint(
+                                cx,
+                                DEFAULT_LINT,
+                                item.span,
+                                &format!("the lint `{}` has the default lint description", item.ident.name),
+                            );
+                        }
+
+                        self.declared_lints.insert(item.ident.name, item.span);
+                    } else if sym_str == "default deprecation note" {
+                        span_lint(
+                            cx,
+                            DEFAULT_DEPRECATION_REASON,
+                            item.span,
+                            &format!("the lint `{}` has the default deprecation reason", item.ident.name),
+                        );
+                    }
+                }
+            }
+        } else if let Some(macro_call) = root_macro_call_first_node(cx, item) {
+            if !matches!(
+                cx.tcx.item_name(macro_call.def_id).as_str(),
+                "impl_lint_pass" | "declare_lint_pass"
+            ) {
+                return;
+            }
+            if let hir::ItemKind::Impl(hir::Impl {
+                of_trait: None,
+                items: impl_item_refs,
+                ..
+            }) = item.kind
+            {
+                let mut collector = LintCollector {
+                    output: &mut self.registered_lints,
+                    cx,
+                };
+                let body_id = cx.tcx.hir().body_owned_by(
+                    cx.tcx.hir().local_def_id(
+                        impl_item_refs
+                            .iter()
+                            .find(|iiref| iiref.ident.as_str() == "get_lints")
+                            .expect("LintPass needs to implement get_lints")
+                            .id
+                            .hir_id(),
+                    ),
+                );
+                collector.visit_expr(cx.tcx.hir().body(body_id).value);
+            }
+        }
+    }
+
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        if is_lint_allowed(cx, LINT_WITHOUT_LINT_PASS, CRATE_HIR_ID) {
+            return;
+        }
+
+        for (lint_name, &lint_span) in &self.declared_lints {
+            // When using the `declare_tool_lint!` macro, the original `lint_span`'s
+            // file points to "<rustc macros>".
+            // `compiletest-rs` thinks that's an error in a different file and
+            // just ignores it. This causes the test in compile-fail/lint_pass
+            // not able to capture the error.
+            // Therefore, we need to climb the macro expansion tree and find the
+            // actual span that invoked `declare_tool_lint!`:
+            let lint_span = lint_span.ctxt().outer_expn_data().call_site;
+
+            if !self.registered_lints.contains(lint_name) {
+                span_lint(
+                    cx,
+                    LINT_WITHOUT_LINT_PASS,
+                    lint_span,
+                    &format!("the lint `{lint_name}` is not added to any `LintPass`"),
+                );
+            }
+        }
+    }
+}
+
+pub(super) fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &hir::Ty<'_>) -> bool {
+    if let TyKind::Rptr(
+        _,
+        MutTy {
+            ty: inner,
+            mutbl: Mutability::Not,
+        },
+    ) = ty.kind
+    {
+        if let TyKind::Path(ref path) = inner.kind {
+            if let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) {
+                return match_def_path(cx, def_id, &paths::LINT);
+            }
+        }
+    }
+
+    false
+}
+
+fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'_>) {
+    if let Some(value) = extract_clippy_version_value(cx, item) {
+        // The `sym!` macro doesn't work as it only expects a single token.
+        // It's better to keep it this way and have a direct `Symbol::intern` call here.
+        if value == Symbol::intern("pre 1.29.0") {
+            return;
+        }
+
+        if RustcVersion::parse(value.as_str()).is_err() {
+            span_lint_and_help(
+                cx,
+                INVALID_CLIPPY_VERSION_ATTRIBUTE,
+                item.span,
+                "this item has an invalid `clippy::version` attribute",
+                None,
+                "please use a valid semantic version, see `doc/adding_lints.md`",
+            );
+        }
+    } else {
+        span_lint_and_help(
+            cx,
+            MISSING_CLIPPY_VERSION_ATTRIBUTE,
+            item.span,
+            "this lint is missing the `clippy::version` attribute or version value",
+            None,
+            "please use a `clippy::version` attribute, see `doc/adding_lints.md`",
+        );
+    }
+}
+
+/// This function extracts the version value of a `clippy::version` attribute if the given value has
+/// one
+pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option<Symbol> {
+    let attrs = cx.tcx.hir().attrs(item.hir_id());
+    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.item.path.segments[..];
+            if tool_name.ident.name == sym::clippy;
+            if attr_name.ident.name == sym::version;
+            if let Some(version) = attr.value_str();
+            then { Some(version) } else { None }
+        }
+    })
+}
+
+struct LintCollector<'a, 'tcx> {
+    output: &'a mut FxHashSet<Symbol>,
+    cx: &'a LateContext<'tcx>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
+    type NestedFilter = nested_filter::All;
+
+    fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
+        if path.segments.len() == 1 {
+            self.output.insert(path.segments[0].ident.name);
+        }
+    }
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index c84191bb010..d06a616e4b3 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -8,7 +8,7 @@
 //! a simple mistake)
 
 use crate::renamed_lints::RENAMED_LINTS;
-use crate::utils::internal_lints::{extract_clippy_version_value, is_lint_ref_type};
+use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type};
 
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
@@ -532,7 +532,11 @@ fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
 
             // Extract lints
             doc_comment.make_ascii_lowercase();
-            let lints: Vec<String> = doc_comment.split_off(DOC_START.len()).split(", ").map(str::to_string).collect();
+            let lints: Vec<String> = doc_comment
+                .split_off(DOC_START.len())
+                .split(", ")
+                .map(str::to_string)
+                .collect();
 
             // Format documentation correctly
             // split off leading `.` from lint name list and indent for correct formatting
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
new file mode 100644
index 00000000000..1e994e3f2b1
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
@@ -0,0 +1,63 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::match_type;
+use clippy_utils::{match_def_path, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::ty::{self, subst::GenericArgKind};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Check that the `extract_msrv_attr!` macro is used, when a lint has a MSRV.
+    ///
+    pub MISSING_MSRV_ATTR_IMPL,
+    internal,
+    "checking if all necessary steps were taken when adding a MSRV to a lint"
+}
+
+declare_lint_pass!(MsrvAttrImpl => [MISSING_MSRV_ATTR_IMPL]);
+
+impl LateLintPass<'_> for MsrvAttrImpl {
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
+        if_chain! {
+            if let hir::ItemKind::Impl(hir::Impl {
+                of_trait: Some(lint_pass_trait_ref),
+                self_ty,
+                items,
+                ..
+            }) = &item.kind;
+            if let Some(lint_pass_trait_def_id) = lint_pass_trait_ref.trait_def_id();
+            let is_late_pass = match_def_path(cx, lint_pass_trait_def_id, &paths::LATE_LINT_PASS);
+            if is_late_pass || match_def_path(cx, lint_pass_trait_def_id, &paths::EARLY_LINT_PASS);
+            let self_ty = hir_ty_to_ty(cx.tcx, self_ty);
+            if let ty::Adt(self_ty_def, _) = self_ty.kind();
+            if self_ty_def.is_struct();
+            if self_ty_def.all_fields().any(|f| {
+                cx.tcx
+                    .type_of(f.did)
+                    .walk()
+                    .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_)))
+                    .any(|t| match_type(cx, t.expect_ty(), &paths::RUSTC_VERSION))
+            });
+            if !items.iter().any(|item| item.ident.name == sym!(enter_lint_attrs));
+            then {
+                let context = if is_late_pass { "LateContext" } else { "EarlyContext" };
+                let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" };
+                let span = cx.sess().source_map().span_through_char(item.span, '{');
+                span_lint_and_sugg(
+                    cx,
+                    MISSING_MSRV_ATTR_IMPL,
+                    span,
+                    &format!("`extract_msrv_attr!` macro missing from `{lint_pass}` implementation"),
+                    &format!("add `extract_msrv_attr!({context})` to the `{lint_pass}` implementation"),
+                    format!("{}\n    extract_msrv_attr!({context});", snippet(cx, span, "..")),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs
new file mode 100644
index 00000000000..2b13fad8066
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs
@@ -0,0 +1,62 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::match_type;
+use clippy_utils::{is_lint_allowed, method_calls, paths};
+use if_chain::if_chain;
+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::symbol::Symbol;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `cx.outer().expn_data()` and suggests to use
+    /// the `cx.outer_expn_data()`
+    ///
+    /// ### Why is this bad?
+    /// `cx.outer_expn_data()` is faster and more concise.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// expr.span.ctxt().outer().expn_data()
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// expr.span.ctxt().outer_expn_data()
+    /// ```
+    pub OUTER_EXPN_EXPN_DATA,
+    internal,
+    "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
+}
+
+declare_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]);
+
+impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if is_lint_allowed(cx, OUTER_EXPN_EXPN_DATA, expr.hir_id) {
+            return;
+        }
+
+        let (method_names, arg_lists, spans) = method_calls(expr, 2);
+        let method_names: Vec<&str> = method_names.iter().map(Symbol::as_str).collect();
+        if_chain! {
+            if let ["expn_data", "outer_expn"] = method_names.as_slice();
+            let (self_arg, args) = arg_lists[1];
+            if args.is_empty();
+            let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
+            if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT);
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    OUTER_EXPN_EXPN_DATA,
+                    spans[1].with_hi(expr.span.hi()),
+                    "usage of `outer_expn().expn_data()`",
+                    "try",
+                    "outer_expn_data()".to_string(),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs
new file mode 100644
index 00000000000..5899b94e16b
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs
@@ -0,0 +1,37 @@
+use rustc_ast::ast::NodeId;
+use rustc_ast::visit::FnKind;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Not an actual lint. This lint is only meant for testing our customized internal compiler
+    /// error message by calling `panic`.
+    ///
+    /// ### Why is this bad?
+    /// ICE in large quantities can damage your teeth
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// 🍦🍦🍦🍦🍦
+    /// ```
+    pub PRODUCE_ICE,
+    internal,
+    "this message should not appear anywhere as we ICE before and don't emit the lint"
+}
+
+declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);
+
+impl EarlyLintPass for ProduceIce {
+    fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
+        assert!(!is_trigger_fn(fn_kind), "Would you like some help with that?");
+    }
+}
+
+fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
+    match fn_kind {
+        FnKind::Fn(_, ident, ..) => ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy",
+        FnKind::Closure(..) => false,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
new file mode 100644
index 00000000000..4cf76f53625
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -0,0 +1,343 @@
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{def_path_res, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Namespace, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{Expr, ExprKind, Local, Mutability, Node};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::mir::interpret::{Allocation, ConstValue, GlobalAlloc};
+use rustc_middle::ty::{self, AssocKind, DefIdTree, Ty};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::Span;
+
+use std::str;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usages of def paths when a diagnostic item or a `LangItem` could be used.
+    ///
+    /// ### Why is this bad?
+    /// The path for an item is subject to change and is less efficient to look up than a
+    /// diagnostic item or a `LangItem`.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// utils::match_type(cx, ty, &paths::VEC)
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// utils::is_type_diagnostic_item(cx, ty, sym::Vec)
+    /// ```
+    pub UNNECESSARY_DEF_PATH,
+    internal,
+    "using a def path when a diagnostic item or a `LangItem` is available"
+}
+
+impl_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]);
+
+#[derive(Default)]
+pub struct UnnecessaryDefPath {
+    array_def_ids: FxHashSet<(DefId, Span)>,
+    linted_def_ids: FxHashSet<DefId>,
+}
+
+impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) {
+            return;
+        }
+
+        match expr.kind {
+            ExprKind::Call(func, args) => self.check_call(cx, func, args, expr.span),
+            ExprKind::Array(elements) => self.check_array(cx, elements, expr.span),
+            _ => {},
+        }
+    }
+
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        for &(def_id, span) in &self.array_def_ids {
+            if self.linted_def_ids.contains(&def_id) {
+                continue;
+            }
+
+            let (msg, sugg) = if let Some(sym) = cx.tcx.get_diagnostic_name(def_id) {
+                ("diagnostic item", format!("sym::{sym}"))
+            } else if let Some(sym) = get_lang_item_name(cx, def_id) {
+                ("language item", format!("LangItem::{sym}"))
+            } else {
+                continue;
+            };
+
+            span_lint_and_help(
+                cx,
+                UNNECESSARY_DEF_PATH,
+                span,
+                &format!("hardcoded path to a {msg}"),
+                None,
+                &format!("convert all references to use `{sugg}`"),
+            );
+        }
+    }
+}
+
+impl UnnecessaryDefPath {
+    #[allow(clippy::too_many_lines)]
+    fn check_call(&mut self, cx: &LateContext<'_>, func: &Expr<'_>, args: &[Expr<'_>], span: Span) {
+        enum Item {
+            LangItem(Symbol),
+            DiagnosticItem(Symbol),
+        }
+        static PATHS: &[&[&str]] = &[
+            &["clippy_utils", "match_def_path"],
+            &["clippy_utils", "match_trait_method"],
+            &["clippy_utils", "ty", "match_type"],
+            &["clippy_utils", "is_expr_path_def_path"],
+        ];
+
+        if_chain! {
+            if let [cx_arg, def_arg, args @ ..] = args;
+            if let ExprKind::Path(path) = &func.kind;
+            if let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id();
+            if let Some(which_path) = match_any_def_paths(cx, id, PATHS);
+            let item_arg = if which_path == 4 { &args[1] } else { &args[0] };
+            // Extract the path to the matched type
+            if let Some(segments) = path_to_matched_type(cx, item_arg);
+            let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
+            if let Some(def_id) = inherent_def_path_res(cx, &segments[..]);
+            then {
+                // Check if the target item is a diagnostic item or LangItem.
+                #[rustfmt::skip]
+                let (msg, item) = if let Some(item_name)
+                    = cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id)
+                {
+                    (
+                        "use of a def path to a diagnostic item",
+                        Item::DiagnosticItem(*item_name),
+                    )
+                } else if let Some(item_name) = get_lang_item_name(cx, def_id) {
+                    (
+                        "use of a def path to a `LangItem`",
+                        Item::LangItem(item_name),
+                    )
+                } else {
+                    return;
+                };
+
+                let has_ctor = match cx.tcx.def_kind(def_id) {
+                    DefKind::Struct => {
+                        let variant = cx.tcx.adt_def(def_id).non_enum_variant();
+                        variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
+                    },
+                    DefKind::Variant => {
+                        let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id);
+                        variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
+                    },
+                    _ => false,
+                };
+
+                let mut app = Applicability::MachineApplicable;
+                let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app);
+                let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app);
+                let (sugg, with_note) = match (which_path, item) {
+                    // match_def_path
+                    (0, Item::DiagnosticItem(item)) => (
+                        format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"),
+                        has_ctor,
+                    ),
+                    (0, Item::LangItem(item)) => (
+                        format!("{cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some({def_snip})"),
+                        has_ctor,
+                    ),
+                    // match_trait_method
+                    (1, Item::DiagnosticItem(item)) => {
+                        (format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false)
+                    },
+                    // match_type
+                    (2, Item::DiagnosticItem(item)) => (
+                        format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"),
+                        false,
+                    ),
+                    (2, Item::LangItem(item)) => (
+                        format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"),
+                        false,
+                    ),
+                    // is_expr_path_def_path
+                    (3, Item::DiagnosticItem(item)) if has_ctor => (
+                        format!("is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",),
+                        false,
+                    ),
+                    (3, Item::LangItem(item)) if has_ctor => (
+                        format!("is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",),
+                        false,
+                    ),
+                    (3, Item::DiagnosticItem(item)) => (
+                        format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"),
+                        false,
+                    ),
+                    (3, Item::LangItem(item)) => (
+                        format!(
+                            "path_res({cx_snip}, {def_snip}).opt_def_id()\
+                                .map_or(false, |id| {cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some(id))",
+                        ),
+                        false,
+                    ),
+                    _ => return,
+                };
+
+                span_lint_and_then(cx, UNNECESSARY_DEF_PATH, span, msg, |diag| {
+                    diag.span_suggestion(span, "try", sugg, app);
+                    if with_note {
+                        diag.help(
+                            "if this `DefId` came from a constructor expression or pattern then the \
+                                    parent `DefId` should be used instead",
+                        );
+                    }
+                });
+
+                self.linted_def_ids.insert(def_id);
+            }
+        }
+    }
+
+    fn check_array(&mut self, cx: &LateContext<'_>, elements: &[Expr<'_>], span: Span) {
+        let Some(path) = path_from_array(elements) else { return };
+
+        if let Some(def_id) = inherent_def_path_res(cx, &path.iter().map(AsRef::as_ref).collect::<Vec<_>>()) {
+            self.array_def_ids.insert((def_id, span));
+        }
+    }
+}
+
+fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<String>> {
+    match peel_hir_expr_refs(expr).0.kind {
+        ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
+            Res::Local(hir_id) => {
+                let parent_id = cx.tcx.hir().get_parent_node(hir_id);
+                if let Some(Node::Local(Local { init: Some(init), .. })) = cx.tcx.hir().find(parent_id) {
+                    path_to_matched_type(cx, init)
+                } else {
+                    None
+                }
+            },
+            Res::Def(DefKind::Static(_), def_id) => read_mir_alloc_def_path(
+                cx,
+                cx.tcx.eval_static_initializer(def_id).ok()?.inner(),
+                cx.tcx.type_of(def_id),
+            ),
+            Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? {
+                ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => {
+                    read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id))
+                },
+                _ => None,
+            },
+            _ => None,
+        },
+        ExprKind::Array(exprs) => path_from_array(exprs),
+        _ => None,
+    }
+}
+
+fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option<Vec<String>> {
+    let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() {
+        let &alloc = alloc.provenance().values().next()?;
+        if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
+            (alloc.inner(), ty)
+        } else {
+            return None;
+        }
+    } else {
+        (alloc, ty)
+    };
+
+    if let ty::Array(ty, _) | ty::Slice(ty) = *ty.kind()
+        && let ty::Ref(_, ty, Mutability::Not) = *ty.kind()
+        && ty.is_str()
+    {
+        alloc
+            .provenance()
+            .values()
+            .map(|&alloc| {
+                if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
+                    let alloc = alloc.inner();
+                    str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()))
+                        .ok().map(ToOwned::to_owned)
+                } else {
+                    None
+                }
+            })
+            .collect()
+    } else {
+        None
+    }
+}
+
+fn path_from_array(exprs: &[Expr<'_>]) -> Option<Vec<String>> {
+    exprs
+        .iter()
+        .map(|expr| {
+            if let ExprKind::Lit(lit) = &expr.kind {
+                if let LitKind::Str(sym, _) = lit.node {
+                    return Some((*sym.as_str()).to_owned());
+                }
+            }
+
+            None
+        })
+        .collect()
+}
+
+// def_path_res will match field names before anything else, but for this we want to match
+// inherent functions first.
+fn inherent_def_path_res(cx: &LateContext<'_>, segments: &[&str]) -> Option<DefId> {
+    def_path_res(cx, segments, None).opt_def_id().map(|def_id| {
+        if cx.tcx.def_kind(def_id) == DefKind::Field {
+            let method_name = *segments.last().unwrap();
+            cx.tcx
+                .def_key(def_id)
+                .parent
+                .and_then(|parent_idx| {
+                    cx.tcx
+                        .inherent_impls(DefId {
+                            index: parent_idx,
+                            krate: def_id.krate,
+                        })
+                        .iter()
+                        .find_map(|impl_id| {
+                            cx.tcx.associated_items(*impl_id).find_by_name_and_kind(
+                                cx.tcx,
+                                Ident::from_str(method_name),
+                                AssocKind::Fn,
+                                *impl_id,
+                            )
+                        })
+                })
+                .map_or(def_id, |item| item.def_id)
+        } else {
+            def_id
+        }
+    })
+}
+
+fn get_lang_item_name(cx: &LateContext<'_>, def_id: DefId) -> Option<Symbol> {
+    if let Some(lang_item) = cx.tcx.lang_items().items().iter().position(|id| *id == Some(def_id)) {
+        let lang_items = def_path_res(cx, &["rustc_hir", "lang_items", "LangItem"], Some(Namespace::TypeNS)).def_id();
+        let item_name = cx
+            .tcx
+            .adt_def(lang_items)
+            .variants()
+            .iter()
+            .nth(lang_item)
+            .unwrap()
+            .name;
+        Some(item_name)
+    } else {
+        None
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index d9b22664fd2..cd8575c90e8 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -136,7 +136,7 @@ pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'s
                     .emit();
             },
             ast::AttrStyle::Outer => {
-                sess.span_err(attr.span, &format!("`{name}` cannot be an outer attribute"));
+                sess.span_err(attr.span, format!("`{name}` cannot be an outer attribute"));
             },
         }
     }
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index fa6766f7cfe..07e4ef6a2fe 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -136,17 +136,49 @@ impl Constant {
             (&Self::F64(l), &Self::F64(r)) => l.partial_cmp(&r),
             (&Self::F32(l), &Self::F32(r)) => l.partial_cmp(&r),
             (&Self::Bool(ref l), &Self::Bool(ref r)) => Some(l.cmp(r)),
-            (&Self::Tuple(ref l), &Self::Tuple(ref r)) | (&Self::Vec(ref l), &Self::Vec(ref r)) => iter::zip(l, r)
-                .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri))
-                .find(|r| r.map_or(true, |o| o != Ordering::Equal))
-                .unwrap_or_else(|| Some(l.len().cmp(&r.len()))),
+            (&Self::Tuple(ref l), &Self::Tuple(ref r)) if l.len() == r.len() => match *cmp_type.kind() {
+                ty::Tuple(tys) if tys.len() == l.len() => l
+                    .iter()
+                    .zip(r)
+                    .zip(tys)
+                    .map(|((li, ri), cmp_type)| Self::partial_cmp(tcx, cmp_type, li, ri))
+                    .find(|r| r.map_or(true, |o| o != Ordering::Equal))
+                    .unwrap_or_else(|| Some(l.len().cmp(&r.len()))),
+                _ => None,
+            },
+            (&Self::Vec(ref l), &Self::Vec(ref r)) => {
+                let cmp_type = match *cmp_type.kind() {
+                    ty::Array(ty, _) | ty::Slice(ty) => ty,
+                    _ => return None,
+                };
+                iter::zip(l, r)
+                    .map(|(li, ri)| Self::partial_cmp(tcx, cmp_type, li, ri))
+                    .find(|r| r.map_or(true, |o| o != Ordering::Equal))
+                    .unwrap_or_else(|| Some(l.len().cmp(&r.len())))
+            },
             (&Self::Repeat(ref lv, ref ls), &Self::Repeat(ref rv, ref rs)) => {
-                match Self::partial_cmp(tcx, cmp_type, lv, rv) {
+                match Self::partial_cmp(
+                    tcx,
+                    match *cmp_type.kind() {
+                        ty::Array(ty, _) => ty,
+                        _ => return None,
+                    },
+                    lv,
+                    rv,
+                ) {
                     Some(Equal) => Some(ls.cmp(rs)),
                     x => x,
                 }
             },
-            (&Self::Ref(ref lb), &Self::Ref(ref rb)) => Self::partial_cmp(tcx, cmp_type, lb, rb),
+            (&Self::Ref(ref lb), &Self::Ref(ref rb)) => Self::partial_cmp(
+                tcx,
+                match *cmp_type.kind() {
+                    ty::Ref(_, ty, _) => ty,
+                    _ => return None,
+                },
+                lb,
+                rb,
+            ),
             // TODO: are there any useful inter-type orderings?
             _ => None,
         }
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 8724a4cd651..95b3e651e2b 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -120,7 +120,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                             .expr_ty(e)
                             .has_significant_drop(self.cx.tcx, self.cx.param_env)
                         {
-                            self.eagerness = Lazy;
+                            self.eagerness = ForceNoChange;
                             return;
                         }
                     },
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 7e42fcc6569..052db3f3a03 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -25,10 +25,12 @@ extern crate rustc_data_structures;
 extern crate rustc_errors;
 extern crate rustc_hir;
 extern crate rustc_hir_typeck;
+extern crate rustc_index;
 extern crate rustc_infer;
 extern crate rustc_lexer;
 extern crate rustc_lint;
 extern crate rustc_middle;
+extern crate rustc_mir_dataflow;
 extern crate rustc_parse_format;
 extern crate rustc_session;
 extern crate rustc_span;
@@ -48,6 +50,7 @@ pub mod eager_or_lazy;
 pub mod higher;
 mod hir_utils;
 pub mod macros;
+pub mod mir;
 pub mod msrvs;
 pub mod numeric_literal;
 pub mod paths;
@@ -122,7 +125,7 @@ pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Opt
         return Some(version);
     } else if let Some(sess) = sess {
         if let Some(span) = span {
-            sess.span_err(span, &format!("`{msrv}` is not a valid Rust version"));
+            sess.span_err(span, format!("`{msrv}` is not a valid Rust version"));
         }
     }
     None
@@ -815,13 +818,37 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
                 false
             }
         },
-        ExprKind::Call(repl_func, _) => is_default_equivalent_call(cx, repl_func),
+        ExprKind::Call(repl_func, []) => is_default_equivalent_call(cx, repl_func),
+        ExprKind::Call(from_func, [ref arg]) => is_default_equivalent_from(cx, from_func, arg),
         ExprKind::Path(qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, e.hir_id), OptionNone),
         ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
         _ => false,
     }
 }
 
+fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &Expr<'_>) -> bool {
+    if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = from_func.kind &&
+        seg.ident.name == sym::from
+    {
+        match arg.kind {
+            ExprKind::Lit(hir::Lit {
+                node: LitKind::Str(ref sym, _),
+                ..
+            }) => return sym.is_empty() && is_path_diagnostic_item(cx, ty, sym::String),
+            ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
+            ExprKind::Repeat(_, ArrayLen::Body(len)) => {
+                if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind &&
+                    let LitKind::Int(v, _) = const_lit.node
+                {
+                        return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
+                }
+            }
+            _ => (),
+        }
+    }
+    false
+}
+
 /// Checks if the top level expression can be moved into a closure as is.
 /// Currently checks for:
 /// * Break/Continue outside the given loop HIR ids.
@@ -1739,6 +1766,7 @@ pub fn any_parent_is_automatically_derived(tcx: TyCtxt<'_>, node: HirId) -> bool
 /// ```rust,ignore
 /// if let Some(args) = match_function_call(cx, cmp_max_call, &paths::CMP_MAX);
 /// ```
+/// This function is deprecated. Use [`match_function_call_with_def_id`].
 pub fn match_function_call<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
@@ -1756,6 +1784,22 @@ pub fn match_function_call<'tcx>(
     None
 }
 
+pub fn match_function_call_with_def_id<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    fun_def_id: DefId,
+) -> Option<&'tcx [Expr<'tcx>]> {
+    if_chain! {
+        if let ExprKind::Call(fun, args) = expr.kind;
+        if let ExprKind::Path(ref qpath) = fun.kind;
+        if cx.qpath_res(qpath, fun.hir_id).opt_def_id() == Some(fun_def_id);
+        then {
+            return Some(args);
+        }
+    };
+    None
+}
+
 /// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
 /// any.
 ///
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index 5a63c290a31..9a682fbe604 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -627,7 +627,7 @@ pub enum Count<'tcx> {
     /// `FormatParamKind::Numbered`.
     Param(FormatParam<'tcx>),
     /// Not specified.
-    Implied,
+    Implied(Option<Span>),
 }
 
 impl<'tcx> Count<'tcx> {
@@ -638,8 +638,10 @@ impl<'tcx> Count<'tcx> {
         inner: Option<rpf::InnerSpan>,
         values: &FormatArgsValues<'tcx>,
     ) -> Option<Self> {
+        let span = inner.map(|inner| span_from_inner(values.format_string_span, inner));
+
         Some(match count {
-            rpf::Count::CountIs(val) => Self::Is(val, span_from_inner(values.format_string_span, inner?)),
+            rpf::Count::CountIs(val) => Self::Is(val, span?),
             rpf::Count::CountIsName(name, _) => Self::Param(FormatParam::new(
                 FormatParamKind::Named(Symbol::intern(name)),
                 usage,
@@ -661,12 +663,12 @@ impl<'tcx> Count<'tcx> {
                 inner?,
                 values,
             )?),
-            rpf::Count::CountImplied => Self::Implied,
+            rpf::Count::CountImplied => Self::Implied(span),
         })
     }
 
     pub fn is_implied(self) -> bool {
-        matches!(self, Count::Implied)
+        matches!(self, Count::Implied(_))
     }
 
     pub fn param(self) -> Option<FormatParam<'tcx>> {
@@ -675,6 +677,14 @@ impl<'tcx> Count<'tcx> {
             _ => None,
         }
     }
+
+    pub fn span(self) -> Option<Span> {
+        match self {
+            Count::Is(_, span) => Some(span),
+            Count::Param(param) => Some(param.span),
+            Count::Implied(span) => span,
+        }
+    }
 }
 
 /// Specification for the formatting of an argument in the format string. See
@@ -738,8 +748,13 @@ impl<'tcx> FormatSpec<'tcx> {
     /// Returns true if this format spec is unchanged from the default. e.g. returns true for `{}`,
     /// `{foo}` and `{2}`, but false for `{:?}`, `{foo:5}` and `{3:.5}`
     pub fn is_default(&self) -> bool {
-        self.r#trait == sym::Display
-            && self.width.is_implied()
+        self.r#trait == sym::Display && self.is_default_for_trait()
+    }
+
+    /// Has no other formatting specifiers than setting the format trait. returns true for `{}`,
+    /// `{foo}`, `{:?}`, but false for `{foo:5}`, `{3:.5?}`
+    pub fn is_default_for_trait(&self) -> bool {
+        self.width.is_implied()
             && self.precision.is_implied()
             && self.align == Alignment::AlignUnknown
             && self.flags == 0
@@ -757,6 +772,22 @@ pub struct FormatArg<'tcx> {
     pub span: Span,
 }
 
+impl<'tcx> FormatArg<'tcx> {
+    /// Span of the `:` and format specifiers
+    ///
+    /// ```ignore
+    /// format!("{:.}"), format!("{foo:.}")
+    ///           ^^                  ^^
+    /// ```
+    pub fn format_span(&self) -> Span {
+        let base = self.span.data();
+
+        // `base.hi` is `{...}|`, subtract 1 byte (the length of '}') so that it points before the closing
+        // brace `{...|}`
+        Span::new(self.param.span.hi(), base.hi - BytePos(1), base.ctxt, base.parent)
+    }
+}
+
 /// A parsed `format_args!` expansion.
 #[derive(Debug)]
 pub struct FormatArgsExpn<'tcx> {
diff --git a/src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs b/src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs
new file mode 100644
index 00000000000..d262b335d99
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/mir/maybe_storage_live.rs
@@ -0,0 +1,52 @@
+use rustc_index::bit_set::BitSet;
+use rustc_middle::mir;
+use rustc_mir_dataflow::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis};
+
+/// Determines liveness of each local purely based on `StorageLive`/`Dead`.
+#[derive(Copy, Clone)]
+pub(super) struct MaybeStorageLive;
+
+impl<'tcx> AnalysisDomain<'tcx> for MaybeStorageLive {
+    type Domain = BitSet<mir::Local>;
+    const NAME: &'static str = "maybe_storage_live";
+
+    fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+        // bottom = dead
+        BitSet::new_empty(body.local_decls.len())
+    }
+
+    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) {
+        for arg in body.args_iter() {
+            state.insert(arg);
+        }
+    }
+}
+
+impl<'tcx> GenKillAnalysis<'tcx> for MaybeStorageLive {
+    type Idx = mir::Local;
+
+    fn statement_effect(&self, trans: &mut impl GenKill<Self::Idx>, stmt: &mir::Statement<'tcx>, _: mir::Location) {
+        match stmt.kind {
+            mir::StatementKind::StorageLive(l) => trans.gen(l),
+            mir::StatementKind::StorageDead(l) => trans.kill(l),
+            _ => (),
+        }
+    }
+
+    fn terminator_effect(
+        &self,
+        _trans: &mut impl GenKill<Self::Idx>,
+        _terminator: &mir::Terminator<'tcx>,
+        _loc: mir::Location,
+    ) {
+    }
+
+    fn call_return_effect(
+        &self,
+        _trans: &mut impl GenKill<Self::Idx>,
+        _block: mir::BasicBlock,
+        _return_places: CallReturnPlaces<'_, 'tcx>,
+    ) {
+        // Nothing to do when a call returns successfully
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/mir/mod.rs b/src/tools/clippy/clippy_utils/src/mir/mod.rs
new file mode 100644
index 00000000000..818e603f665
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/mir/mod.rs
@@ -0,0 +1,164 @@
+use rustc_hir::{Expr, HirId};
+use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
+use rustc_middle::mir::{
+    traversal, Body, InlineAsmOperand, Local, Location, Place, StatementKind, TerminatorKind, START_BLOCK,
+};
+use rustc_middle::ty::TyCtxt;
+
+mod maybe_storage_live;
+
+mod possible_borrower;
+pub use possible_borrower::PossibleBorrowerMap;
+
+mod possible_origin;
+
+mod transitive_relation;
+
+#[derive(Clone, Debug, Default)]
+pub struct LocalUsage {
+    /// The locations where the local is used, if any.
+    pub local_use_locs: Vec<Location>,
+    /// The locations where the local is consumed or mutated, if any.
+    pub local_consume_or_mutate_locs: Vec<Location>,
+}
+
+pub fn visit_local_usage(locals: &[Local], mir: &Body<'_>, location: Location) -> Option<Vec<LocalUsage>> {
+    let init = vec![
+        LocalUsage {
+            local_use_locs: Vec::new(),
+            local_consume_or_mutate_locs: Vec::new(),
+        };
+        locals.len()
+    ];
+
+    traversal::ReversePostorder::new(mir, location.block).try_fold(init, |usage, (tbb, tdata)| {
+        // Give up on loops
+        if tdata.terminator().successors().any(|s| s == location.block) {
+            return None;
+        }
+
+        let mut v = V {
+            locals,
+            location,
+            results: usage,
+        };
+        v.visit_basic_block_data(tbb, tdata);
+        Some(v.results)
+    })
+}
+
+struct V<'a> {
+    locals: &'a [Local],
+    location: Location,
+    results: Vec<LocalUsage>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for V<'a> {
+    fn visit_place(&mut self, place: &Place<'tcx>, ctx: PlaceContext, loc: Location) {
+        if loc.block == self.location.block && loc.statement_index <= self.location.statement_index {
+            return;
+        }
+
+        let local = place.local;
+
+        for (i, self_local) in self.locals.iter().enumerate() {
+            if local == *self_local {
+                if !matches!(
+                    ctx,
+                    PlaceContext::MutatingUse(MutatingUseContext::Drop) | PlaceContext::NonUse(_)
+                ) {
+                    self.results[i].local_use_locs.push(loc);
+                }
+                if matches!(
+                    ctx,
+                    PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)
+                        | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
+                ) {
+                    self.results[i].local_consume_or_mutate_locs.push(loc);
+                }
+            }
+        }
+    }
+}
+
+/// Convenience wrapper around `visit_local_usage`.
+pub fn used_exactly_once(mir: &rustc_middle::mir::Body<'_>, local: rustc_middle::mir::Local) -> Option<bool> {
+    visit_local_usage(
+        &[local],
+        mir,
+        Location {
+            block: START_BLOCK,
+            statement_index: 0,
+        },
+    )
+    .map(|mut vec| {
+        let LocalUsage { local_use_locs, .. } = vec.remove(0);
+        local_use_locs
+            .into_iter()
+            .filter(|location| !is_local_assignment(mir, local, *location))
+            .count()
+            == 1
+    })
+}
+
+/// Returns the `mir::Body` containing the node associated with `hir_id`.
+#[allow(clippy::module_name_repetitions)]
+pub fn enclosing_mir(tcx: TyCtxt<'_>, hir_id: HirId) -> &Body<'_> {
+    let body_owner_local_def_id = tcx.hir().enclosing_body_owner(hir_id);
+    tcx.optimized_mir(body_owner_local_def_id.to_def_id())
+}
+
+/// Tries to determine the `Local` corresponding to `expr`, if any.
+/// This function is expensive and should be used sparingly.
+pub fn expr_local(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> Option<Local> {
+    let mir = enclosing_mir(tcx, expr.hir_id);
+    mir.local_decls.iter_enumerated().find_map(|(local, local_decl)| {
+        if local_decl.source_info.span == expr.span {
+            Some(local)
+        } else {
+            None
+        }
+    })
+}
+
+/// Returns a vector of `mir::Location` where `local` is assigned.
+pub fn local_assignments(mir: &Body<'_>, local: Local) -> Vec<Location> {
+    let mut locations = Vec::new();
+    for (block, data) in mir.basic_blocks.iter_enumerated() {
+        for statement_index in 0..=data.statements.len() {
+            let location = Location { block, statement_index };
+            if is_local_assignment(mir, local, location) {
+                locations.push(location);
+            }
+        }
+    }
+    locations
+}
+
+// `is_local_assignment` is based on `is_place_assignment`:
+// https://github.com/rust-lang/rust/blob/b7413511dc85ec01ef4b91785f86614589ac6103/compiler/rustc_middle/src/mir/visit.rs#L1350
+fn is_local_assignment(mir: &Body<'_>, local: Local, location: Location) -> bool {
+    let Location { block, statement_index } = location;
+    let basic_block = &mir.basic_blocks[block];
+    if statement_index < basic_block.statements.len() {
+        let statement = &basic_block.statements[statement_index];
+        if let StatementKind::Assign(box (place, _)) = statement.kind {
+            place.as_local() == Some(local)
+        } else {
+            false
+        }
+    } else {
+        let terminator = basic_block.terminator();
+        match &terminator.kind {
+            TerminatorKind::Call { destination, .. } => destination.as_local() == Some(local),
+            TerminatorKind::InlineAsm { operands, .. } => operands.iter().any(|operand| {
+                if let InlineAsmOperand::Out { place: Some(place), .. } = operand {
+                    place.as_local() == Some(local)
+                } else {
+                    false
+                }
+            }),
+            _ => false,
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
new file mode 100644
index 00000000000..25717bf3d2f
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -0,0 +1,241 @@
+use super::{
+    maybe_storage_live::MaybeStorageLive, possible_origin::PossibleOriginVisitor,
+    transitive_relation::TransitiveRelation,
+};
+use crate::ty::is_copy;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_index::bit_set::{BitSet, HybridBitSet};
+use rustc_lint::LateContext;
+use rustc_middle::mir::{self, visit::Visitor as _, Mutability};
+use rustc_middle::ty::{self, visit::TypeVisitor};
+use rustc_mir_dataflow::{Analysis, ResultsCursor};
+use std::ops::ControlFlow;
+
+/// Collects the possible borrowers of each local.
+/// For example, `b = &a; c = &a;` will make `b` and (transitively) `c`
+/// possible borrowers of `a`.
+#[allow(clippy::module_name_repetitions)]
+struct PossibleBorrowerVisitor<'a, 'b, 'tcx> {
+    possible_borrower: TransitiveRelation,
+    body: &'b mir::Body<'tcx>,
+    cx: &'a LateContext<'tcx>,
+    possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
+}
+
+impl<'a, 'b, 'tcx> PossibleBorrowerVisitor<'a, 'b, 'tcx> {
+    fn new(
+        cx: &'a LateContext<'tcx>,
+        body: &'b mir::Body<'tcx>,
+        possible_origin: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
+    ) -> Self {
+        Self {
+            possible_borrower: TransitiveRelation::default(),
+            cx,
+            body,
+            possible_origin,
+        }
+    }
+
+    fn into_map(
+        self,
+        cx: &'a LateContext<'tcx>,
+        maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
+    ) -> PossibleBorrowerMap<'b, 'tcx> {
+        let mut map = FxHashMap::default();
+        for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
+            if is_copy(cx, self.body.local_decls[row].ty) {
+                continue;
+            }
+
+            let mut borrowers = self.possible_borrower.reachable_from(row, self.body.local_decls.len());
+            borrowers.remove(mir::Local::from_usize(0));
+            if !borrowers.is_empty() {
+                map.insert(row, borrowers);
+            }
+        }
+
+        let bs = BitSet::new_empty(self.body.local_decls.len());
+        PossibleBorrowerMap {
+            map,
+            maybe_live,
+            bitset: (bs.clone(), bs),
+        }
+    }
+}
+
+impl<'a, 'b, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'b, 'tcx> {
+    fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
+        let lhs = place.local;
+        match rvalue {
+            mir::Rvalue::Ref(_, _, borrowed) => {
+                self.possible_borrower.add(borrowed.local, lhs);
+            },
+            other => {
+                if ContainsRegion
+                    .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
+                    .is_continue()
+                {
+                    return;
+                }
+                rvalue_locals(other, |rhs| {
+                    if lhs != rhs {
+                        self.possible_borrower.add(rhs, lhs);
+                    }
+                });
+            },
+        }
+    }
+
+    fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Location) {
+        if let mir::TerminatorKind::Call {
+            args,
+            destination: mir::Place { local: dest, .. },
+            ..
+        } = &terminator.kind
+        {
+            // TODO add doc
+            // If the call returns something with lifetimes,
+            // let's conservatively assume the returned value contains lifetime of all the arguments.
+            // For example, given `let y: Foo<'a> = foo(x)`, `y` is considered to be a possible borrower of `x`.
+
+            let mut immutable_borrowers = vec![];
+            let mut mutable_borrowers = vec![];
+
+            for op in args {
+                match op {
+                    mir::Operand::Copy(p) | mir::Operand::Move(p) => {
+                        if let ty::Ref(_, _, Mutability::Mut) = self.body.local_decls[p.local].ty.kind() {
+                            mutable_borrowers.push(p.local);
+                        } else {
+                            immutable_borrowers.push(p.local);
+                        }
+                    },
+                    mir::Operand::Constant(..) => (),
+                }
+            }
+
+            let mut mutable_variables: Vec<mir::Local> = mutable_borrowers
+                .iter()
+                .filter_map(|r| self.possible_origin.get(r))
+                .flat_map(HybridBitSet::iter)
+                .collect();
+
+            if ContainsRegion.visit_ty(self.body.local_decls[*dest].ty).is_break() {
+                mutable_variables.push(*dest);
+            }
+
+            for y in mutable_variables {
+                for x in &immutable_borrowers {
+                    self.possible_borrower.add(*x, y);
+                }
+                for x in &mutable_borrowers {
+                    self.possible_borrower.add(*x, y);
+                }
+            }
+        }
+    }
+}
+
+struct ContainsRegion;
+
+impl TypeVisitor<'_> for ContainsRegion {
+    type BreakTy = ();
+
+    fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<Self::BreakTy> {
+        ControlFlow::BREAK
+    }
+}
+
+fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
+    use rustc_middle::mir::Rvalue::{Aggregate, BinaryOp, Cast, CheckedBinaryOp, Repeat, UnaryOp, Use};
+
+    let mut visit_op = |op: &mir::Operand<'_>| match op {
+        mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local),
+        mir::Operand::Constant(..) => (),
+    };
+
+    match rvalue {
+        Use(op) | Repeat(op, _) | Cast(_, op, _) | UnaryOp(_, op) => visit_op(op),
+        Aggregate(_, ops) => ops.iter().for_each(visit_op),
+        BinaryOp(_, box (lhs, rhs)) | CheckedBinaryOp(_, box (lhs, rhs)) => {
+            visit_op(lhs);
+            visit_op(rhs);
+        },
+        _ => (),
+    }
+}
+
+/// Result of `PossibleBorrowerVisitor`.
+#[allow(clippy::module_name_repetitions)]
+pub struct PossibleBorrowerMap<'b, 'tcx> {
+    /// Mapping `Local -> its possible borrowers`
+    pub map: FxHashMap<mir::Local, HybridBitSet<mir::Local>>,
+    maybe_live: ResultsCursor<'b, 'tcx, MaybeStorageLive>,
+    // Caches to avoid allocation of `BitSet` on every query
+    pub bitset: (BitSet<mir::Local>, BitSet<mir::Local>),
+}
+
+impl<'a, 'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
+    pub fn new(cx: &'a LateContext<'tcx>, mir: &'b mir::Body<'tcx>) -> Self {
+        let possible_origin = {
+            let mut vis = PossibleOriginVisitor::new(mir);
+            vis.visit_body(mir);
+            vis.into_map(cx)
+        };
+        let maybe_storage_live_result = MaybeStorageLive
+            .into_engine(cx.tcx, mir)
+            .pass_name("redundant_clone")
+            .iterate_to_fixpoint()
+            .into_results_cursor(mir);
+        let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
+        vis.visit_body(mir);
+        vis.into_map(cx, maybe_storage_live_result)
+    }
+
+    /// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
+    pub fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
+        self.bounded_borrowers(borrowers, borrowers, borrowed, at)
+    }
+
+    /// Returns true if the set of borrowers of `borrowed` living at `at` includes at least `below`
+    /// but no more than `above`.
+    pub fn bounded_borrowers(
+        &mut self,
+        below: &[mir::Local],
+        above: &[mir::Local],
+        borrowed: mir::Local,
+        at: mir::Location,
+    ) -> bool {
+        self.maybe_live.seek_after_primary_effect(at);
+
+        self.bitset.0.clear();
+        let maybe_live = &mut self.maybe_live;
+        if let Some(bitset) = self.map.get(&borrowed) {
+            for b in bitset.iter().filter(move |b| maybe_live.contains(*b)) {
+                self.bitset.0.insert(b);
+            }
+        } else {
+            return false;
+        }
+
+        self.bitset.1.clear();
+        for b in below {
+            self.bitset.1.insert(*b);
+        }
+
+        if !self.bitset.0.superset(&self.bitset.1) {
+            return false;
+        }
+
+        for b in above {
+            self.bitset.0.remove(*b);
+        }
+
+        self.bitset.0.is_empty()
+    }
+
+    pub fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
+        self.maybe_live.seek_after_primary_effect(at);
+        self.maybe_live.contains(local)
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
new file mode 100644
index 00000000000..8e7513d740a
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
@@ -0,0 +1,59 @@
+use super::transitive_relation::TransitiveRelation;
+use crate::ty::is_copy;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_index::bit_set::HybridBitSet;
+use rustc_lint::LateContext;
+use rustc_middle::mir;
+
+/// Collect possible borrowed for every `&mut` local.
+/// For example, `_1 = &mut _2` generate _1: {_2,...}
+/// Known Problems: not sure all borrowed are tracked
+#[allow(clippy::module_name_repetitions)]
+pub(super) struct PossibleOriginVisitor<'a, 'tcx> {
+    possible_origin: TransitiveRelation,
+    body: &'a mir::Body<'tcx>,
+}
+
+impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> {
+    pub fn new(body: &'a mir::Body<'tcx>) -> Self {
+        Self {
+            possible_origin: TransitiveRelation::default(),
+            body,
+        }
+    }
+
+    pub fn into_map(self, cx: &LateContext<'tcx>) -> FxHashMap<mir::Local, HybridBitSet<mir::Local>> {
+        let mut map = FxHashMap::default();
+        for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
+            if is_copy(cx, self.body.local_decls[row].ty) {
+                continue;
+            }
+
+            let mut borrowers = self.possible_origin.reachable_from(row, self.body.local_decls.len());
+            borrowers.remove(mir::Local::from_usize(0));
+            if !borrowers.is_empty() {
+                map.insert(row, borrowers);
+            }
+        }
+        map
+    }
+}
+
+impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> {
+    fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
+        let lhs = place.local;
+        match rvalue {
+            // Only consider `&mut`, which can modify origin place
+            mir::Rvalue::Ref(_, rustc_middle::mir::BorrowKind::Mut { .. }, borrowed) |
+            // _2: &mut _;
+            // _3 = move _2
+            mir::Rvalue::Use(mir::Operand::Move(borrowed))  |
+            // _3 = move _2 as &mut _;
+            mir::Rvalue::Cast(_, mir::Operand::Move(borrowed), _)
+                => {
+                self.possible_origin.add(lhs, borrowed.local);
+            },
+            _ => {},
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs b/src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs
new file mode 100644
index 00000000000..7fe2960739f
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/mir/transitive_relation.rs
@@ -0,0 +1,29 @@
+use rustc_data_structures::fx::FxHashMap;
+use rustc_index::bit_set::HybridBitSet;
+use rustc_middle::mir;
+
+#[derive(Default)]
+pub(super) struct TransitiveRelation {
+    relations: FxHashMap<mir::Local, Vec<mir::Local>>,
+}
+
+impl TransitiveRelation {
+    pub fn add(&mut self, a: mir::Local, b: mir::Local) {
+        self.relations.entry(a).or_default().push(b);
+    }
+
+    pub fn reachable_from(&self, a: mir::Local, domain_size: usize) -> HybridBitSet<mir::Local> {
+        let mut seen = HybridBitSet::new_empty(domain_size);
+        let mut stack = vec![a];
+        while let Some(u) = stack.pop() {
+            if let Some(edges) = self.relations.get(&u) {
+                for &v in edges {
+                    if seen.insert(v) {
+                        stack.push(v);
+                    }
+                }
+            }
+        }
+        seen
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
index 80098d9766c..c5dcd7b31f5 100644
--- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs
+++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
@@ -69,12 +69,13 @@ impl<'a> NumericLiteral<'a> {
 
     #[must_use]
     pub fn new(lit: &'a str, suffix: Option<&'a str>, float: bool) -> Self {
+        let unsigned_lit = lit.trim_start_matches('-');
         // Determine delimiter for radix prefix, if present, and radix.
-        let radix = if lit.starts_with("0x") {
+        let radix = if unsigned_lit.starts_with("0x") {
             Radix::Hexadecimal
-        } else if lit.starts_with("0b") {
+        } else if unsigned_lit.starts_with("0b") {
             Radix::Binary
-        } else if lit.starts_with("0o") {
+        } else if unsigned_lit.starts_with("0o") {
             Radix::Octal
         } else {
             Radix::Decimal
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 13938645fc3..bc851473430 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -16,25 +16,17 @@ pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
 #[cfg(feature = "internal")]
 pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"];
 pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
-pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
-pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
 pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
-pub const BTREEMAP_ENTRY: [&str; 6] = ["alloc", "collections", "btree", "map", "entry", "Entry"];
 pub const BTREEMAP_INSERT: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "insert"];
 pub const BTREESET_ITER: [&str; 6] = ["alloc", "collections", "btree", "set", "BTreeSet", "iter"];
 pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"];
-pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"];
 pub const CORE_ITER_COLLECT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "collect"];
 pub const CORE_ITER_CLONED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "cloned"];
 pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "copied"];
 pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
-pub const CORE_ITER_INTO_ITER: [&str; 6] = ["core", "iter", "traits", "collect", "IntoIterator", "into_iter"];
 pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"];
 pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
 pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
-/// Preferably use the diagnostic item `sym::deref_method` where possible
-pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
-pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
 #[cfg(feature = "internal")]
 pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
 #[cfg(feature = "internal")]
@@ -42,30 +34,22 @@ pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"]
 pub const EXIT: [&str; 3] = ["std", "process", "exit"];
 pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
 pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
-pub const FILE: [&str; 3] = ["std", "fs", "File"];
-pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
-pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
 pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
 pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"];
-pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
 #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"];
 #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"];
 pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"];
-pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
 pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"];
 pub const HASHSET_ITER: [&str; 6] = ["std", "collections", "hash", "set", "HashSet", "iter"];
 #[cfg(feature = "internal")]
 pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
 #[cfg(feature = "internal")]
 pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
-pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
-pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
 pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
 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"];
 pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
 #[cfg(feature = "internal")]
 pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
@@ -76,13 +60,7 @@ pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"];
 #[cfg(feature = "internal")]
 pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
 pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"];
-pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"];
 pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
-/// Preferably use the diagnostic item `sym::Option` where possible
-pub const OPTION: [&str; 3] = ["core", "option", "Option"];
-pub const OPTION_NONE: [&str; 4] = ["core", "option", "Option", "None"];
-pub const OPTION_SOME: [&str; 4] = ["core", "option", "Option", "Some"];
-pub const ORD: [&str; 3] = ["core", "cmp", "Ord"];
 pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
 pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
 pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"];
@@ -95,8 +73,6 @@ 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"];
 pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
-pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
-pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
 pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
 pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
 pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
@@ -119,26 +95,14 @@ pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
 pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
 pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"];
 pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const REGEX_BYTES_SET_NEW: [&str; 5] = ["regex", "re_set", "bytes", "RegexSet", "new"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const REGEX_NEW: [&str; 4] = ["regex", "re_unicode", "Regex", "new"];
-#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const REGEX_SET_NEW: [&str; 5] = ["regex", "re_set", "unicode", "RegexSet", "new"];
-/// Preferably use the diagnostic item `sym::Result` where possible
-pub const RESULT: [&str; 3] = ["core", "result", "Result"];
-pub const RESULT_ERR: [&str; 4] = ["core", "result", "Result", "Err"];
-pub const RESULT_OK: [&str; 4] = ["core", "result", "Result", "Ok"];
 #[cfg(feature = "internal")]
 pub const RUSTC_VERSION: [&str; 2] = ["rustc_semver", "RustcVersion"];
-pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGuard"];
-pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"];
 pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
 pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
 pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 5089987ef72..aad7da61a8a 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -1,7 +1,9 @@
 //! Contains utility functions to generate suggestions.
 #![deny(clippy::missing_docs_in_private_items)]
 
-use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite};
+use crate::source::{
+    snippet, snippet_opt, snippet_with_applicability, snippet_with_context, snippet_with_macro_callsite,
+};
 use crate::ty::expr_sig;
 use crate::{get_parent_expr_for_hir, higher};
 use rustc_ast::util::parser::AssocOp;
@@ -110,7 +112,7 @@ impl<'a> Sugg<'a> {
         if expr.span.ctxt() == ctxt {
             Self::hir_from_snippet(expr, |span| snippet(cx, span, default))
         } else {
-            let snip = snippet_with_applicability(cx, expr.span, default, applicability);
+            let (snip, _) = snippet_with_context(cx, expr.span, ctxt, default, applicability);
             Sugg::NonParen(snip)
         }
     }
@@ -1052,12 +1054,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
 
     fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
 
-    fn fake_read(
-        &mut self,
-        _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
-        _: FakeReadCause,
-        _: HirId,
-    ) {}
+    fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
 }
 
 #[cfg(test)]
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index b344db634f6..b8824024e6c 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -73,8 +73,7 @@ impl LintcheckConfig {
         let sources_toml = env::var("LINTCHECK_TOML").unwrap_or_else(|_| {
             clap_config
                 .get_one::<String>("crates-toml")
-                .map(|s| &**s)
-                .unwrap_or("lintcheck/lintcheck_crates.toml")
+                .map_or("lintcheck/lintcheck_crates.toml", |s| &**s)
                 .into()
         });
 
@@ -97,7 +96,7 @@ impl LintcheckConfig {
             Some(&0) => {
                 // automatic choice
                 // Rayon seems to return thread count so half that for core count
-                (rayon::current_num_threads() / 2) as usize
+                rayon::current_num_threads() / 2
             },
             Some(&threads) => threads,
             // no -j passed, use a single thread
diff --git a/src/tools/clippy/lintcheck/src/driver.rs b/src/tools/clippy/lintcheck/src/driver.rs
index 63221bab32d..47724a2fedb 100644
--- a/src/tools/clippy/lintcheck/src/driver.rs
+++ b/src/tools/clippy/lintcheck/src/driver.rs
@@ -5,7 +5,7 @@ use std::net::TcpStream;
 use std::process::{self, Command, Stdio};
 use std::{env, mem};
 
-/// 1. Sends [DriverInfo] to the [crate::recursive::LintcheckServer] running on `addr`
+/// 1. Sends [`DriverInfo`] to the [`crate::recursive::LintcheckServer`] running on `addr`
 /// 2. Receives [bool] from the server, if `false` returns `None`
 /// 3. Otherwise sends the stderr of running `clippy-driver` to the server
 fn run_clippy(addr: &str) -> Option<i32> {
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index cc2b3e1acec..54c1b80c42d 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -116,12 +116,13 @@ impl ClippyWarning {
 
         let span = diag.spans.into_iter().find(|span| span.is_primary)?;
 
-        let file = match Path::new(&span.file_name).strip_prefix(env!("CARGO_HOME")) {
-            Ok(stripped) => format!("$CARGO_HOME/{}", stripped.display()),
-            Err(_) => format!(
+        let file = if let Ok(stripped) = Path::new(&span.file_name).strip_prefix(env!("CARGO_HOME")) {
+            format!("$CARGO_HOME/{}", stripped.display())
+        } else {
+            format!(
                 "target/lintcheck/sources/{}-{}/{}",
                 crate_name, crate_version, span.file_name
-            ),
+            )
         };
 
         Some(Self {
@@ -144,16 +145,17 @@ impl ClippyWarning {
             }
 
             let mut output = String::from("| ");
-            let _ = write!(output, "[`{}`]({}#L{})", file_with_pos, file, self.line);
+            let _ = write!(output, "[`{file_with_pos}`]({file}#L{})", self.line);
             let _ = write!(output, r#" | `{:<50}` | "{}" |"#, self.lint_type, self.message);
             output.push('\n');
             output
         } else {
-            format!("{} {} \"{}\"\n", file_with_pos, self.lint_type, self.message)
+            format!("{file_with_pos} {} \"{}\"\n", self.lint_type, self.message)
         }
     }
 }
 
+#[allow(clippy::result_large_err)]
 fn get(path: &str) -> Result<ureq::Response, ureq::Error> {
     const MAX_RETRIES: u8 = 4;
     let mut retries = 0;
@@ -161,11 +163,11 @@ fn get(path: &str) -> Result<ureq::Response, ureq::Error> {
         match ureq::get(path).call() {
             Ok(res) => return Ok(res),
             Err(e) if retries >= MAX_RETRIES => return Err(e),
-            Err(ureq::Error::Transport(e)) => eprintln!("Error: {}", e),
+            Err(ureq::Error::Transport(e)) => eprintln!("Error: {e}"),
             Err(e) => return Err(e),
         }
-        eprintln!("retrying in {} seconds...", retries);
-        thread::sleep(Duration::from_secs(retries as u64));
+        eprintln!("retrying in {retries} seconds...");
+        thread::sleep(Duration::from_secs(u64::from(retries)));
         retries += 1;
     }
 }
@@ -181,11 +183,11 @@ impl CrateSource {
                 let krate_download_dir = PathBuf::from(LINTCHECK_DOWNLOADS);
 
                 // url to download the crate from crates.io
-                let url = format!("https://crates.io/api/v1/crates/{}/{}/download", name, version);
-                println!("Downloading and extracting {} {} from {}", name, version, url);
+                let url = format!("https://crates.io/api/v1/crates/{name}/{version}/download");
+                println!("Downloading and extracting {name} {version} from {url}");
                 create_dirs(&krate_download_dir, &extract_dir);
 
-                let krate_file_path = krate_download_dir.join(format!("{}-{}.crate.tar.gz", name, version));
+                let krate_file_path = krate_download_dir.join(format!("{name}-{version}.crate.tar.gz"));
                 // don't download/extract if we already have done so
                 if !krate_file_path.is_file() {
                     // create a file path to download and write the crate data into
@@ -205,7 +207,7 @@ impl CrateSource {
                 Crate {
                     version: version.clone(),
                     name: name.clone(),
-                    path: extract_dir.join(format!("{}-{}/", name, version)),
+                    path: extract_dir.join(format!("{name}-{version}/")),
                     options: options.clone(),
                 }
             },
@@ -218,12 +220,12 @@ impl CrateSource {
                 let repo_path = {
                     let mut repo_path = PathBuf::from(LINTCHECK_SOURCES);
                     // add a -git suffix in case we have the same crate from crates.io and a git repo
-                    repo_path.push(format!("{}-git", name));
+                    repo_path.push(format!("{name}-git"));
                     repo_path
                 };
                 // clone the repo if we have not done so
                 if !repo_path.is_dir() {
-                    println!("Cloning {} and checking out {}", url, commit);
+                    println!("Cloning {url} and checking out {commit}");
                     if !Command::new("git")
                         .arg("clone")
                         .arg(url)
@@ -232,7 +234,7 @@ impl CrateSource {
                         .expect("Failed to clone git repo!")
                         .success()
                     {
-                        eprintln!("Failed to clone {} into {}", url, repo_path.display())
+                        eprintln!("Failed to clone {url} into {}", repo_path.display());
                     }
                 }
                 // check out the commit/branch/whatever
@@ -245,7 +247,7 @@ impl CrateSource {
                     .expect("Failed to check out commit")
                     .success()
                 {
-                    eprintln!("Failed to checkout {} of repo at {}", commit, repo_path.display())
+                    eprintln!("Failed to checkout {commit} of repo at {}", repo_path.display());
                 }
 
                 Crate {
@@ -256,22 +258,22 @@ impl CrateSource {
                 }
             },
             CrateSource::Path { name, path, options } => {
+                fn is_cache_dir(entry: &DirEntry) -> bool {
+                    std::fs::read(entry.path().join("CACHEDIR.TAG"))
+                        .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55"))
+                        .unwrap_or(false)
+                }
+
                 // copy path into the dest_crate_root but skip directories that contain a CACHEDIR.TAG file.
                 // The target/ directory contains a CACHEDIR.TAG file so it is the most commonly skipped directory
                 // as a result of this filter.
                 let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name);
                 if dest_crate_root.exists() {
-                    println!("Deleting existing directory at {:?}", dest_crate_root);
+                    println!("Deleting existing directory at {dest_crate_root:?}");
                     std::fs::remove_dir_all(&dest_crate_root).unwrap();
                 }
 
-                println!("Copying {:?} to {:?}", path, dest_crate_root);
-
-                fn is_cache_dir(entry: &DirEntry) -> bool {
-                    std::fs::read(entry.path().join("CACHEDIR.TAG"))
-                        .map(|x| x.starts_with(b"Signature: 8a477f597d28d172789f06886806bc55"))
-                        .unwrap_or(false)
-                }
+                println!("Copying {path:?} to {dest_crate_root:?}");
 
                 for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) {
                     let entry = entry.unwrap();
@@ -301,6 +303,7 @@ impl CrateSource {
 impl Crate {
     /// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy
     /// issued
+    #[allow(clippy::too_many_arguments)]
     fn run_clippy_lints(
         &self,
         cargo_clippy_path: &Path,
@@ -345,14 +348,14 @@ impl Crate {
                 clippy_args.push(opt);
             }
         } else {
-            clippy_args.extend(&["-Wclippy::pedantic", "-Wclippy::cargo"])
+            clippy_args.extend(["-Wclippy::pedantic", "-Wclippy::cargo"]);
         }
 
         if lint_filter.is_empty() {
             clippy_args.push("--cap-lints=warn");
         } else {
             clippy_args.push("--cap-lints=allow");
-            clippy_args.extend(lint_filter.iter().map(|filter| filter.as_str()))
+            clippy_args.extend(lint_filter.iter().map(std::string::String::as_str));
         }
 
         if let Some(server) = server {
@@ -389,10 +392,7 @@ impl Crate {
 
         let all_output = Command::new(&cargo_clippy_path)
             // use the looping index to create individual target dirs
-            .env(
-                "CARGO_TARGET_DIR",
-                shared_target_dir.join(format!("_{:?}", thread_index)),
-            )
+            .env("CARGO_TARGET_DIR", shared_target_dir.join(format!("_{thread_index:?}")))
             .args(&cargo_clippy_args)
             .current_dir(&self.path)
             .output()
@@ -422,8 +422,8 @@ impl Crate {
             {
                 let subcrate = &stderr[63..];
                 println!(
-                    "ERROR: failed to apply some suggetion to {} / to (sub)crate {}",
-                    self.name, subcrate
+                    "ERROR: failed to apply some suggetion to {} / to (sub)crate {subcrate}",
+                    self.name
                 );
             }
             // fast path, we don't need the warnings anyway
@@ -457,20 +457,16 @@ fn build_clippy() {
 /// Read a `lintcheck_crates.toml` file
 fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) {
     let toml_content: String =
-        std::fs::read_to_string(&toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
+        std::fs::read_to_string(toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
     let crate_list: SourceList =
-        toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{}", toml_path.display(), e));
+        toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{e}", toml_path.display()));
     // parse the hashmap of the toml file into a list of crates
-    let tomlcrates: Vec<TomlCrate> = crate_list
-        .crates
-        .into_iter()
-        .map(|(_cratename, tomlcrate)| tomlcrate)
-        .collect();
+    let tomlcrates: Vec<TomlCrate> = crate_list.crates.into_values().collect();
 
     // flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate =>
     // multiple Cratesources)
     let mut crate_sources = Vec::new();
-    tomlcrates.into_iter().for_each(|tk| {
+    for tk in tomlcrates {
         if let Some(ref path) = tk.path {
             crate_sources.push(CrateSource::Path {
                 name: tk.name.clone(),
@@ -479,13 +475,13 @@ fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) {
             });
         } else if let Some(ref versions) = tk.versions {
             // if we have multiple versions, save each one
-            versions.iter().for_each(|ver| {
+            for ver in versions.iter() {
                 crate_sources.push(CrateSource::CratesIo {
                     name: tk.name.clone(),
                     version: ver.to_string(),
                     options: tk.options.clone(),
                 });
-            })
+            }
         } else if tk.git_url.is_some() && tk.git_hash.is_some() {
             // otherwise, we should have a git source
             crate_sources.push(CrateSource::Git {
@@ -502,16 +498,19 @@ fn read_crates(toml_path: &Path) -> (Vec<CrateSource>, RecursiveOptions) {
         if tk.versions.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some())
             || tk.git_hash.is_some() != tk.git_url.is_some()
         {
-            eprintln!("tomlkrate: {:?}", tk);
-            if tk.git_hash.is_some() != tk.git_url.is_some() {
-                panic!("Error: Encountered TomlCrate with only one of git_hash and git_url!");
-            }
-            if tk.path.is_some() && (tk.git_hash.is_some() || tk.versions.is_some()) {
-                panic!("Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields");
-            }
+            eprintln!("tomlkrate: {tk:?}");
+            assert_eq!(
+                tk.git_hash.is_some(),
+                tk.git_url.is_some(),
+                "Error: Encountered TomlCrate with only one of git_hash and git_url!"
+            );
+            assert!(
+                tk.path.is_none() || (tk.git_hash.is_none() && tk.versions.is_none()),
+                "Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields"
+            );
             unreachable!("Failed to translate TomlCrate into CrateSource!");
         }
-    });
+    }
     // sort the crates
     crate_sources.sort();
 
@@ -530,13 +529,13 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String,
     let mut stats: Vec<(&&String, &usize)> = counter.iter().map(|(lint, count)| (lint, count)).collect();
     // sort by "000{count} {clippy::lintname}"
     // to not have a lint with 200 and 2 warnings take the same spot
-    stats.sort_by_key(|(lint, count)| format!("{:0>4}, {}", count, lint));
+    stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}"));
 
     let mut header = String::from("| lint                                               | count |\n");
     header.push_str("| -------------------------------------------------- | ----- |\n");
     let stats_string = stats
         .iter()
-        .map(|(lint, count)| format!("| {:<50} |  {:>4} |\n", lint, count))
+        .map(|(lint, count)| format!("| {lint:<50} |  {count:>4} |\n"))
         .fold(header, |mut table, line| {
             table.push_str(&line);
             table
@@ -573,6 +572,7 @@ fn lintcheck_needs_rerun(lintcheck_logs_path: &Path, paths: [&Path; 2]) -> bool
     logs_modified < clippy_modified
 }
 
+#[allow(clippy::too_many_lines)]
 fn main() {
     // We're being executed as a `RUSTC_WRAPPER` as part of `--recursive`
     if let Ok(addr) = env::var("LINTCHECK_SERVER") {
@@ -602,10 +602,10 @@ fn main() {
     ) {
         let shared_target_dir = "target/lintcheck/shared_target_dir";
         // if we get an Err here, the shared target dir probably does simply not exist
-        if let Ok(metadata) = std::fs::metadata(&shared_target_dir) {
+        if let Ok(metadata) = std::fs::metadata(shared_target_dir) {
             if metadata.is_dir() {
                 println!("Clippy is newer than lint check logs, clearing lintcheck shared target dir...");
-                std::fs::remove_dir_all(&shared_target_dir)
+                std::fs::remove_dir_all(shared_target_dir)
                     .expect("failed to remove target/lintcheck/shared_target_dir");
             }
         }
@@ -678,7 +678,7 @@ fn main() {
         .unwrap();
 
     let server = config.recursive.then(|| {
-        let _ = fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive");
+        fs::remove_dir_all("target/lintcheck/shared_target_dir/recursive").unwrap_or_default();
 
         LintcheckServer::spawn(recursive_options)
     });
@@ -734,8 +734,8 @@ fn main() {
     }
     write!(text, "{}", all_msgs.join("")).unwrap();
     text.push_str("\n\n### ICEs:\n");
-    for (cratename, msg) in ices.iter() {
-        let _ = write!(text, "{}: '{}'", cratename, msg);
+    for (cratename, msg) in &ices {
+        let _ = write!(text, "{cratename}: '{msg}'");
     }
 
     println!("Writing logs to {}", config.lintcheck_results_path.display());
@@ -779,7 +779,7 @@ fn read_stats_from_file(file_path: &Path) -> HashMap<String, usize> {
 fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, usize>, lint_filter: &Vec<String>) {
     let same_in_both_hashmaps = old_stats
         .iter()
-        .filter(|(old_key, old_val)| new_stats.get::<&String>(&old_key) == Some(old_val))
+        .filter(|(old_key, old_val)| new_stats.get::<&String>(old_key) == Some(old_val))
         .map(|(k, v)| (k.to_string(), *v))
         .collect::<Vec<(String, usize)>>();
 
@@ -787,37 +787,37 @@ fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, us
     let mut new_stats_deduped = new_stats;
 
     // remove duplicates from both hashmaps
-    same_in_both_hashmaps.iter().for_each(|(k, v)| {
+    for (k, v) in &same_in_both_hashmaps {
         assert!(old_stats_deduped.remove(k) == Some(*v));
         assert!(new_stats_deduped.remove(k) == Some(*v));
-    });
+    }
 
     println!("\nStats:");
 
     // list all new counts  (key is in new stats but not in old stats)
     new_stats_deduped
         .iter()
-        .filter(|(new_key, _)| old_stats_deduped.get::<str>(&new_key).is_none())
+        .filter(|(new_key, _)| old_stats_deduped.get::<str>(new_key).is_none())
         .for_each(|(new_key, new_value)| {
-            println!("{} 0 => {}", new_key, new_value);
+            println!("{new_key} 0 => {new_value}");
         });
 
     // list all changed counts (key is in both maps but value differs)
     new_stats_deduped
         .iter()
-        .filter(|(new_key, _new_val)| old_stats_deduped.get::<str>(&new_key).is_some())
+        .filter(|(new_key, _new_val)| old_stats_deduped.get::<str>(new_key).is_some())
         .for_each(|(new_key, new_val)| {
-            let old_val = old_stats_deduped.get::<str>(&new_key).unwrap();
-            println!("{} {} => {}", new_key, old_val, new_val);
+            let old_val = old_stats_deduped.get::<str>(new_key).unwrap();
+            println!("{new_key} {old_val} => {new_val}");
         });
 
     // list all gone counts (key is in old status but not in new stats)
     old_stats_deduped
         .iter()
-        .filter(|(old_key, _)| new_stats_deduped.get::<&String>(&old_key).is_none())
+        .filter(|(old_key, _)| new_stats_deduped.get::<&String>(old_key).is_none())
         .filter(|(old_key, _)| lint_filter.is_empty() || lint_filter.contains(old_key))
         .for_each(|(old_key, old_value)| {
-            println!("{} {} => 0", old_key, old_value);
+            println!("{old_key} {old_value} => 0");
         });
 }
 
@@ -828,19 +828,21 @@ fn print_stats(old_stats: HashMap<String, usize>, new_stats: HashMap<&String, us
 /// This function panics if creating one of the dirs fails.
 fn create_dirs(krate_download_dir: &Path, extract_dir: &Path) {
     std::fs::create_dir("target/lintcheck/").unwrap_or_else(|err| {
-        if err.kind() != ErrorKind::AlreadyExists {
-            panic!("cannot create lintcheck target dir");
-        }
+        assert_eq!(
+            err.kind(),
+            ErrorKind::AlreadyExists,
+            "cannot create lintcheck target dir"
+        );
     });
-    std::fs::create_dir(&krate_download_dir).unwrap_or_else(|err| {
-        if err.kind() != ErrorKind::AlreadyExists {
-            panic!("cannot create crate download dir");
-        }
+    std::fs::create_dir(krate_download_dir).unwrap_or_else(|err| {
+        assert_eq!(err.kind(), ErrorKind::AlreadyExists, "cannot create crate download dir");
     });
-    std::fs::create_dir(&extract_dir).unwrap_or_else(|err| {
-        if err.kind() != ErrorKind::AlreadyExists {
-            panic!("cannot create crate extraction dir");
-        }
+    std::fs::create_dir(extract_dir).unwrap_or_else(|err| {
+        assert_eq!(
+            err.kind(),
+            ErrorKind::AlreadyExists,
+            "cannot create crate extraction dir"
+        );
     });
 }
 
@@ -863,7 +865,7 @@ fn lintcheck_test() {
         "lintcheck/test_sources.toml",
     ];
     let status = std::process::Command::new("cargo")
-        .args(&args)
+        .args(args)
         .current_dir("..") // repo root
         .status();
     //.output();
diff --git a/src/tools/clippy/lintcheck/src/recursive.rs b/src/tools/clippy/lintcheck/src/recursive.rs
index 67dcfc2b199..49072e65192 100644
--- a/src/tools/clippy/lintcheck/src/recursive.rs
+++ b/src/tools/clippy/lintcheck/src/recursive.rs
@@ -1,7 +1,7 @@
 //! In `--recursive` mode we set the `lintcheck` binary as the `RUSTC_WRAPPER` of `cargo check`,
-//! this allows [crate::driver] to be run for every dependency. The driver connects to
-//! [LintcheckServer] to ask if it should be skipped, and if not sends the stderr of running clippy
-//! on the crate to the server
+//! this allows [`crate::driver`] to be run for every dependency. The driver connects to
+//! [`LintcheckServer`] to ask if it should be skipped, and if not sends the stderr of running
+//! clippy on the crate to the server
 
 use crate::ClippyWarning;
 use crate::RecursiveOptions;
@@ -109,8 +109,8 @@ impl LintcheckServer {
 
         Self {
             local_addr,
-            sender,
             receiver,
+            sender,
         }
     }
 
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 49b13cb54e7..748d8a31716 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-10-06"
+channel = "nightly-2022-10-20"
 components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/docs.rs b/src/tools/clippy/src/docs.rs
index bd27bc7938f..c033ad294a3 100644
--- a/src/tools/clippy/src/docs.rs
+++ b/src/tools/clippy/src/docs.rs
@@ -28,6 +28,7 @@ docs! {
     "approx_constant",
     "arithmetic_side_effects",
     "as_conversions",
+    "as_ptr_cast_mut",
     "as_underscore",
     "assertions_on_constants",
     "assertions_on_result_states",
@@ -60,6 +61,7 @@ docs! {
     "cast_enum_constructor",
     "cast_enum_truncation",
     "cast_lossless",
+    "cast_nan_to_int",
     "cast_possible_truncation",
     "cast_possible_wrap",
     "cast_precision_loss",
@@ -257,6 +259,7 @@ docs! {
     "manual_async_fn",
     "manual_bits",
     "manual_clamp",
+    "manual_filter",
     "manual_filter_map",
     "manual_find",
     "manual_find_map",
@@ -313,6 +316,7 @@ docs! {
     "missing_panics_doc",
     "missing_safety_doc",
     "missing_spin_loop",
+    "missing_trait_methods",
     "mistyped_literal_suffixes",
     "mixed_case_hex_literals",
     "mixed_read_write_in_expression",
@@ -391,6 +395,7 @@ docs! {
     "panic",
     "panic_in_result_fn",
     "panicking_unwrap",
+    "partial_pub_fields",
     "partialeq_ne_impl",
     "partialeq_to_none",
     "path_buf_push_overwrite",
@@ -553,6 +558,7 @@ docs! {
     "unseparated_literal_suffix",
     "unsound_collection_transmute",
     "unused_async",
+    "unused_format_specs",
     "unused_io_amount",
     "unused_peekable",
     "unused_rounding",
diff --git a/src/tools/clippy/src/docs/as_ptr_cast_mut.txt b/src/tools/clippy/src/docs/as_ptr_cast_mut.txt
new file mode 100644
index 00000000000..228dde996bb
--- /dev/null
+++ b/src/tools/clippy/src/docs/as_ptr_cast_mut.txt
@@ -0,0 +1,19 @@
+### What it does
+Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer
+
+### Why is this bad?
+Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior
+mutability is used, making it unlikely that having it as a mutable pointer is correct.
+
+### Example
+```
+let string = String::with_capacity(1);
+let ptr = string.as_ptr() as *mut u8;
+unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR
+```
+Use instead:
+```
+let mut string = String::with_capacity(1);
+let ptr = string.as_mut_ptr();
+unsafe { ptr.write(4) };
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/box_default.txt b/src/tools/clippy/src/docs/box_default.txt
index ffac894d0c5..1c670c77333 100644
--- a/src/tools/clippy/src/docs/box_default.txt
+++ b/src/tools/clippy/src/docs/box_default.txt
@@ -7,12 +7,6 @@ First, it's more complex, involving two calls instead of one.
 Second, `Box::default()` can be faster
 [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box).
 
-### Known problems
-The lint may miss some cases (e.g. Box::new(String::from(""))).
-On the other hand, it will trigger on cases where the `default`
-code comes from a macro that does something different based on
-e.g. target operating system.
-
 ### Example
 ```
 let x: Box<String> = Box::new(Default::default());
diff --git a/src/tools/clippy/src/docs/cast_nan_to_int.txt b/src/tools/clippy/src/docs/cast_nan_to_int.txt
new file mode 100644
index 00000000000..122f5da0c92
--- /dev/null
+++ b/src/tools/clippy/src/docs/cast_nan_to_int.txt
@@ -0,0 +1,15 @@
+### What it does
+Checks for a known NaN float being cast to an integer
+
+### Why is this bad?
+NaNs are cast into zero, so one could simply use this and make the
+code more readable. The lint could also hint at a programmer error.
+
+### Example
+```
+let _: (0.0_f32 / 0.0) as u64;
+```
+Use instead:
+```
+let _: = 0_u64;
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/manual_filter.txt b/src/tools/clippy/src/docs/manual_filter.txt
new file mode 100644
index 00000000000..19a4d9319d9
--- /dev/null
+++ b/src/tools/clippy/src/docs/manual_filter.txt
@@ -0,0 +1,21 @@
+### What it does
+Checks for usages of `match` which could be implemented using `filter`
+
+### Why is this bad?
+Using the `filter` method is clearer and more concise.
+
+### Example
+```
+match Some(0) {
+    Some(x) => if x % 2 == 0 {
+                    Some(x)
+               } else {
+                    None
+                },
+    None => None,
+};
+```
+Use instead:
+```
+Some(0).filter(|&x| x % 2 == 0);
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/missing_trait_methods.txt b/src/tools/clippy/src/docs/missing_trait_methods.txt
new file mode 100644
index 00000000000..788ad764f8c
--- /dev/null
+++ b/src/tools/clippy/src/docs/missing_trait_methods.txt
@@ -0,0 +1,40 @@
+### What it does
+Checks if a provided method is used implicitly by a trait
+implementation. A usage example would be a wrapper where every method
+should perform some operation before delegating to the inner type's
+implemenation.
+
+This lint should typically be enabled on a specific trait `impl` item
+rather than globally.
+
+### Why is this bad?
+Indicates that a method is missing.
+
+### Example
+```
+trait Trait {
+    fn required();
+
+    fn provided() {}
+}
+
+#[warn(clippy::missing_trait_methods)]
+impl Trait for Type {
+    fn required() { /* ... */ }
+}
+```
+Use instead:
+```
+trait Trait {
+    fn required();
+
+    fn provided() {}
+}
+
+#[warn(clippy::missing_trait_methods)]
+impl Trait for Type {
+    fn required() { /* ... */ }
+
+    fn provided() { /* ... */ }
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/partial_pub_fields.txt b/src/tools/clippy/src/docs/partial_pub_fields.txt
new file mode 100644
index 00000000000..b529adf1547
--- /dev/null
+++ b/src/tools/clippy/src/docs/partial_pub_fields.txt
@@ -0,0 +1,27 @@
+### What it does
+Checks whether partial fields of a struct are public.
+
+Either make all fields of a type public, or make none of them public
+
+### Why is this bad?
+Most types should either be:
+* Abstract data types: complex objects with opaque implementation which guard
+interior invariants and expose intentionally limited API to the outside world.
+* Data: relatively simple objects which group a bunch of related attributes together.
+
+### Example
+```
+pub struct Color {
+    pub r: u8,
+    pub g: u8,
+    b: u8,
+}
+```
+Use instead:
+```
+pub struct Color {
+    pub r: u8,
+    pub g: u8,
+    pub b: u8,
+}
+```
\ No newline at end of file
diff --git a/src/tools/clippy/src/docs/unused_format_specs.txt b/src/tools/clippy/src/docs/unused_format_specs.txt
new file mode 100644
index 00000000000..77be3a2fb17
--- /dev/null
+++ b/src/tools/clippy/src/docs/unused_format_specs.txt
@@ -0,0 +1,24 @@
+### What it does
+Detects [formatting parameters] that have no effect on the output of
+`format!()`, `println!()` or similar macros.
+
+### Why is this bad?
+Shorter format specifiers are easier to read, it may also indicate that
+an expected formatting operation such as adding padding isn't happening.
+
+### Example
+```
+println!("{:.}", 1.0);
+
+println!("not padded: {:5}", format_args!("..."));
+```
+Use instead:
+```
+println!("{}", 1.0);
+
+println!("not padded: {}", format_args!("..."));
+// OR
+println!("padded: {:5}", format!("..."));
+```
+
+[formatting parameters]: https://doc.rust-lang.org/std/fmt/index.html#formatting-parameters
\ No newline at end of file
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index fa769222d1a..c10ee969c01 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -283,7 +283,7 @@ fn run_ui_cargo() {
                 env::set_current_dir(&src_path)?;
 
                 let cargo_toml_path = case.path().join("Cargo.toml");
-                let cargo_content = fs::read(&cargo_toml_path)?;
+                let cargo_content = fs::read(cargo_toml_path)?;
                 let cargo_parsed: toml::Value = toml::from_str(
                     std::str::from_utf8(&cargo_content).expect("`Cargo.toml` is not a valid utf-8 file!"),
                 )
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 961525bbd91..6d0022f7a5c 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -20,7 +20,14 @@ fn dogfood_clippy() {
     }
 
     // "" is the root package
-    for package in &["", "clippy_dev", "clippy_lints", "clippy_utils", "rustc_tools_util"] {
+    for package in &[
+        "",
+        "clippy_dev",
+        "clippy_lints",
+        "clippy_utils",
+        "lintcheck",
+        "rustc_tools_util",
+    ] {
         run_clippy_for_package(package, &["-D", "clippy::all", "-D", "clippy::pedantic"]);
     }
 }
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index a1b8e2ee162..07c5941013c 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -1,4 +1,4 @@
-thread 'rustc' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints.rs
+thread 'rustc' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs:28:9
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 error: internal compiler error: unexpected panic
diff --git a/src/tools/clippy/tests/ui-internal/invalid_paths.rs b/src/tools/clippy/tests/ui-internal/invalid_paths.rs
index b823ff7fe37..9a9790a4bae 100644
--- a/src/tools/clippy/tests/ui-internal/invalid_paths.rs
+++ b/src/tools/clippy/tests/ui-internal/invalid_paths.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::internal)]
-#![allow(clippy::missing_clippy_version_attribute)]
+#![allow(clippy::missing_clippy_version_attribute, clippy::unnecessary_def_path)]
 
 mod paths {
     // Good path
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
index 4c050332f2c..cbbb4652306 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
@@ -28,9 +28,9 @@ use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
 
-#[allow(unused)]
+#[allow(unused, clippy::unnecessary_def_path)]
 static OPTION: [&str; 3] = ["core", "option", "Option"];
-#[allow(unused)]
+#[allow(unused, clippy::unnecessary_def_path)]
 const RESULT: &[&str] = &["core", "result", "Result"];
 
 fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) {
@@ -38,7 +38,7 @@ fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) {
     let _ = is_type_diagnostic_item(cx, ty, sym::Result);
     let _ = is_type_diagnostic_item(cx, ty, sym::Result);
 
-    #[allow(unused)]
+    #[allow(unused, clippy::unnecessary_def_path)]
     let rc_path = &["alloc", "rc", "Rc"];
     let _ = is_type_diagnostic_item(cx, ty, sym::Rc);
 
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
index 6506f1f164a..f17fed6c653 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
@@ -28,9 +28,9 @@ use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
 
-#[allow(unused)]
+#[allow(unused, clippy::unnecessary_def_path)]
 static OPTION: [&str; 3] = ["core", "option", "Option"];
-#[allow(unused)]
+#[allow(unused, clippy::unnecessary_def_path)]
 const RESULT: &[&str] = &["core", "result", "Result"];
 
 fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) {
@@ -38,7 +38,7 @@ fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) {
     let _ = match_type(cx, ty, RESULT);
     let _ = match_type(cx, ty, &["core", "result", "Result"]);
 
-    #[allow(unused)]
+    #[allow(unused, clippy::unnecessary_def_path)]
     let rc_path = &["alloc", "rc", "Rc"];
     let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
 
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
new file mode 100644
index 00000000000..b5ff3a54205
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
@@ -0,0 +1,16 @@
+#![feature(rustc_private)]
+#![allow(unused)]
+#![warn(clippy::unnecessary_def_path)]
+
+extern crate rustc_hir;
+
+use rustc_hir::LangItem;
+
+fn main() {
+    const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
+    const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
+    const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
+
+    // Don't lint, not yet a diagnostic or language item
+    const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
+}
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
new file mode 100644
index 00000000000..af46d87bf67
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
@@ -0,0 +1,27 @@
+error: hardcoded path to a language item
+  --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
+   |
+LL |     const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: convert all references to use `LangItem::DerefMut`
+   = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
+
+error: hardcoded path to a diagnostic item
+  --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
+   |
+LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: convert all references to use `sym::deref_method`
+
+error: hardcoded path to a diagnostic item
+  --> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36
+   |
+LL |     const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: convert all references to use `sym::Deref`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs
new file mode 100644
index 00000000000..0d1d9258433
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs
@@ -0,0 +1,37 @@
+#![allow(unused)]
+#![warn(clippy::as_ptr_cast_mut)]
+#![allow(clippy::wrong_self_convention)]
+
+struct MutPtrWrapper(Vec<u8>);
+impl MutPtrWrapper {
+    fn as_ptr(&mut self) -> *const u8 {
+        self.0.as_mut_ptr() as *const u8
+    }
+}
+
+struct Covariant<T>(*const T);
+impl<T> Covariant<T> {
+    fn as_ptr(self) -> *const T {
+        self.0
+    }
+}
+
+fn main() {
+    let mut string = String::new();
+    let _ = string.as_ptr() as *mut u8;
+    let _: *mut i8 = string.as_ptr() as *mut _;
+    let _ = string.as_ptr() as *const i8;
+    let _ = string.as_mut_ptr();
+    let _ = string.as_mut_ptr() as *mut u8;
+    let _ = string.as_mut_ptr() as *const u8;
+
+    let nn = std::ptr::NonNull::new(4 as *mut u8).unwrap();
+    let _ = nn.as_ptr() as *mut u8;
+
+    let mut wrap = MutPtrWrapper(Vec::new());
+    let _ = wrap.as_ptr() as *mut u8;
+
+    let mut local = 4;
+    let ref_with_write_perm = Covariant(std::ptr::addr_of_mut!(local) as *const _);
+    let _ = ref_with_write_perm.as_ptr() as *mut u8;
+}
diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr b/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr
new file mode 100644
index 00000000000..2189c3d2f85
--- /dev/null
+++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr
@@ -0,0 +1,16 @@
+error: casting the result of `as_ptr` to *mut u8
+  --> $DIR/as_ptr_cast_mut.rs:21:13
+   |
+LL |     let _ = string.as_ptr() as *mut u8;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()`
+   |
+   = note: `-D clippy::as-ptr-cast-mut` implied by `-D warnings`
+
+error: casting the result of `as_ptr` to *mut i8
+  --> $DIR/as_ptr_cast_mut.rs:22:22
+   |
+LL |     let _: *mut i8 = string.as_ptr() as *mut _;
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui/author.stdout
index 597318a556b..27ad538f24d 100644
--- a/src/tools/clippy/tests/ui/author.stdout
+++ b/src/tools/clippy/tests/ui/author.stdout
@@ -1,14 +1,12 @@
-if_chain! {
-    if let StmtKind::Local(local) = stmt.kind;
-    if let Some(init) = local.init;
-    if let ExprKind::Cast(expr, cast_ty) = init.kind;
-    if let TyKind::Path(ref qpath) = cast_ty.kind;
-    if match_qpath(qpath, &["char"]);
-    if let ExprKind::Lit(ref lit) = expr.kind;
-    if let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node;
-    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind;
-    if name.as_str() == "x";
-    then {
-        // report your lint here
-    }
+if let StmtKind::Local(local) = stmt.kind
+    && let Some(init) = local.init
+    && let ExprKind::Cast(expr, cast_ty) = init.kind
+    && let TyKind::Path(ref qpath) = cast_ty.kind
+    && match_qpath(qpath, &["char"])
+    && let ExprKind::Lit(ref lit) = expr.kind
+    && let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node
+    && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind
+    && name.as_str() == "x"
+{
+    // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout
index a529981e2e6..9de0550d81d 100644
--- a/src/tools/clippy/tests/ui/author/blocks.stdout
+++ b/src/tools/clippy/tests/ui/author/blocks.stdout
@@ -1,64 +1,58 @@
-if_chain! {
-    if let ExprKind::Block(block, None) = expr.kind;
-    if block.stmts.len() == 3;
-    if let StmtKind::Local(local) = block.stmts[0].kind;
-    if let Some(init) = local.init;
-    if let ExprKind::Lit(ref lit) = init.kind;
-    if let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node;
-    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind;
-    if name.as_str() == "x";
-    if let StmtKind::Local(local1) = block.stmts[1].kind;
-    if let Some(init1) = local1.init;
-    if let ExprKind::Lit(ref lit1) = init1.kind;
-    if let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node;
-    if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local1.pat.kind;
-    if name1.as_str() == "_t";
-    if let StmtKind::Semi(e) = block.stmts[2].kind;
-    if let ExprKind::Unary(UnOp::Neg, inner) = e.kind;
-    if let ExprKind::Path(ref qpath) = inner.kind;
-    if match_qpath(qpath, &["x"]);
-    if block.expr.is_none();
-    then {
-        // report your lint here
-    }
+if let ExprKind::Block(block, None) = expr.kind
+    && block.stmts.len() == 3
+    && let StmtKind::Local(local) = block.stmts[0].kind
+    && let Some(init) = local.init
+    && let ExprKind::Lit(ref lit) = init.kind
+    && let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node
+    && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind
+    && name.as_str() == "x"
+    && let StmtKind::Local(local1) = block.stmts[1].kind
+    && let Some(init1) = local1.init
+    && let ExprKind::Lit(ref lit1) = init1.kind
+    && let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node
+    && let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local1.pat.kind
+    && name1.as_str() == "_t"
+    && let StmtKind::Semi(e) = block.stmts[2].kind
+    && let ExprKind::Unary(UnOp::Neg, inner) = e.kind
+    && let ExprKind::Path(ref qpath) = inner.kind
+    && match_qpath(qpath, &["x"])
+    && block.expr.is_none()
+{
+    // report your lint here
 }
-if_chain! {
-    if let ExprKind::Block(block, None) = expr.kind;
-    if block.stmts.len() == 1;
-    if let StmtKind::Local(local) = block.stmts[0].kind;
-    if let Some(init) = local.init;
-    if let ExprKind::Call(func, args) = init.kind;
-    if let ExprKind::Path(ref qpath) = func.kind;
-    if match_qpath(qpath, &["String", "new"]);
-    if args.is_empty();
-    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind;
-    if name.as_str() == "expr";
-    if let Some(trailing_expr) = block.expr;
-    if let ExprKind::Call(func1, args1) = trailing_expr.kind;
-    if let ExprKind::Path(ref qpath1) = func1.kind;
-    if match_qpath(qpath1, &["drop"]);
-    if args1.len() == 1;
-    if let ExprKind::Path(ref qpath2) = args1[0].kind;
-    if match_qpath(qpath2, &["expr"]);
-    then {
-        // report your lint here
-    }
+if let ExprKind::Block(block, None) = expr.kind
+    && block.stmts.len() == 1
+    && let StmtKind::Local(local) = block.stmts[0].kind
+    && let Some(init) = local.init
+    && let ExprKind::Call(func, args) = init.kind
+    && let ExprKind::Path(ref qpath) = func.kind
+    && match_qpath(qpath, &["String", "new"])
+    && args.is_empty()
+    && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind
+    && name.as_str() == "expr"
+    && let Some(trailing_expr) = block.expr
+    && let ExprKind::Call(func1, args1) = trailing_expr.kind
+    && let ExprKind::Path(ref qpath1) = func1.kind
+    && match_qpath(qpath1, &["drop"])
+    && args1.len() == 1
+    && let ExprKind::Path(ref qpath2) = args1[0].kind
+    && match_qpath(qpath2, &["expr"])
+{
+    // report your lint here
 }
-if_chain! {
-    if let ExprKind::Closure(CaptureBy::Value, fn_decl, body_id, _, None) = expr.kind;
-    if let FnRetTy::DefaultReturn(_) = fn_decl.output;
-    let expr1 = &cx.tcx.hir().body(body_id).value;
-    if let ExprKind::Call(func, args) = expr1.kind;
-    if let ExprKind::Path(ref qpath) = func.kind;
-    if matches!(qpath, QPath::LangItem(LangItem::FromGenerator, _));
-    if args.len() == 1;
-    if let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = args[0].kind;
-    if let FnRetTy::DefaultReturn(_) = fn_decl1.output;
-    let expr2 = &cx.tcx.hir().body(body_id1).value;
-    if let ExprKind::Block(block, None) = expr2.kind;
-    if block.stmts.is_empty();
-    if block.expr.is_none();
-    then {
-        // report your lint here
-    }
+if let ExprKind::Closure(CaptureBy::Value, fn_decl, body_id, _, None) = expr.kind
+    && let FnRetTy::DefaultReturn(_) = fn_decl.output
+    && expr1 = &cx.tcx.hir().body(body_id).value
+    && let ExprKind::Call(func, args) = expr1.kind
+    && let ExprKind::Path(ref qpath) = func.kind
+    && matches!(qpath, QPath::LangItem(LangItem::FromGenerator, _))
+    && args.len() == 1
+    && let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = args[0].kind
+    && let FnRetTy::DefaultReturn(_) = fn_decl1.output
+    && expr2 = &cx.tcx.hir().body(body_id1).value
+    && let ExprKind::Block(block, None) = expr2.kind
+    && block.stmts.is_empty()
+    && block.expr.is_none()
+{
+    // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/author/call.stdout b/src/tools/clippy/tests/ui/author/call.stdout
index 266312d63e5..f040f6330a6 100644
--- a/src/tools/clippy/tests/ui/author/call.stdout
+++ b/src/tools/clippy/tests/ui/author/call.stdout
@@ -1,16 +1,14 @@
-if_chain! {
-    if let StmtKind::Local(local) = stmt.kind;
-    if let Some(init) = local.init;
-    if let ExprKind::Call(func, args) = init.kind;
-    if let ExprKind::Path(ref qpath) = func.kind;
-    if match_qpath(qpath, &["{{root}}", "std", "cmp", "min"]);
-    if args.len() == 2;
-    if let ExprKind::Lit(ref lit) = args[0].kind;
-    if let LitKind::Int(3, LitIntType::Unsuffixed) = lit.node;
-    if let ExprKind::Lit(ref lit1) = args[1].kind;
-    if let LitKind::Int(4, LitIntType::Unsuffixed) = lit1.node;
-    if let PatKind::Wild = local.pat.kind;
-    then {
-        // report your lint here
-    }
+if let StmtKind::Local(local) = stmt.kind
+    && let Some(init) = local.init
+    && let ExprKind::Call(func, args) = init.kind
+    && let ExprKind::Path(ref qpath) = func.kind
+    && match_qpath(qpath, &["{{root}}", "std", "cmp", "min"])
+    && args.len() == 2
+    && let ExprKind::Lit(ref lit) = args[0].kind
+    && let LitKind::Int(3, LitIntType::Unsuffixed) = lit.node
+    && let ExprKind::Lit(ref lit1) = args[1].kind
+    && let LitKind::Int(4, LitIntType::Unsuffixed) = lit1.node
+    && let PatKind::Wild = local.pat.kind
+{
+    // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/author/if.stdout b/src/tools/clippy/tests/ui/author/if.stdout
index 8d92849b366..5d79618820d 100644
--- a/src/tools/clippy/tests/ui/author/if.stdout
+++ b/src/tools/clippy/tests/ui/author/if.stdout
@@ -1,50 +1,46 @@
-if_chain! {
-    if let StmtKind::Local(local) = stmt.kind;
-    if let Some(init) = local.init;
-    if let ExprKind::If(cond, then, Some(else_expr)) = init.kind;
-    if let ExprKind::DropTemps(expr) = cond.kind;
-    if let ExprKind::Lit(ref lit) = expr.kind;
-    if let LitKind::Bool(true) = lit.node;
-    if let ExprKind::Block(block, None) = then.kind;
-    if block.stmts.len() == 1;
-    if let StmtKind::Semi(e) = block.stmts[0].kind;
-    if let ExprKind::Binary(op, left, right) = e.kind;
-    if BinOpKind::Eq == op.node;
-    if let ExprKind::Lit(ref lit1) = left.kind;
-    if let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node;
-    if let ExprKind::Lit(ref lit2) = right.kind;
-    if let LitKind::Int(1, LitIntType::Unsuffixed) = lit2.node;
-    if block.expr.is_none();
-    if let ExprKind::Block(block1, None) = else_expr.kind;
-    if block1.stmts.len() == 1;
-    if let StmtKind::Semi(e1) = block1.stmts[0].kind;
-    if let ExprKind::Binary(op1, left1, right1) = e1.kind;
-    if BinOpKind::Eq == op1.node;
-    if let ExprKind::Lit(ref lit3) = left1.kind;
-    if let LitKind::Int(2, LitIntType::Unsuffixed) = lit3.node;
-    if let ExprKind::Lit(ref lit4) = right1.kind;
-    if let LitKind::Int(2, LitIntType::Unsuffixed) = lit4.node;
-    if block1.expr.is_none();
-    if let PatKind::Wild = local.pat.kind;
-    then {
-        // report your lint here
-    }
+if let StmtKind::Local(local) = stmt.kind
+    && let Some(init) = local.init
+    && let ExprKind::If(cond, then, Some(else_expr)) = init.kind
+    && let ExprKind::DropTemps(expr) = cond.kind
+    && let ExprKind::Lit(ref lit) = expr.kind
+    && let LitKind::Bool(true) = lit.node
+    && let ExprKind::Block(block, None) = then.kind
+    && block.stmts.len() == 1
+    && let StmtKind::Semi(e) = block.stmts[0].kind
+    && let ExprKind::Binary(op, left, right) = e.kind
+    && BinOpKind::Eq == op.node
+    && let ExprKind::Lit(ref lit1) = left.kind
+    && let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node
+    && let ExprKind::Lit(ref lit2) = right.kind
+    && let LitKind::Int(1, LitIntType::Unsuffixed) = lit2.node
+    && block.expr.is_none()
+    && let ExprKind::Block(block1, None) = else_expr.kind
+    && block1.stmts.len() == 1
+    && let StmtKind::Semi(e1) = block1.stmts[0].kind
+    && let ExprKind::Binary(op1, left1, right1) = e1.kind
+    && BinOpKind::Eq == op1.node
+    && let ExprKind::Lit(ref lit3) = left1.kind
+    && let LitKind::Int(2, LitIntType::Unsuffixed) = lit3.node
+    && let ExprKind::Lit(ref lit4) = right1.kind
+    && let LitKind::Int(2, LitIntType::Unsuffixed) = lit4.node
+    && block1.expr.is_none()
+    && let PatKind::Wild = local.pat.kind
+{
+    // report your lint here
 }
-if_chain! {
-    if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind;
-    if let ExprKind::Let(let_expr) = cond.kind;
-    if let PatKind::Lit(lit_expr) = let_expr.pat.kind;
-    if let ExprKind::Lit(ref lit) = lit_expr.kind;
-    if let LitKind::Bool(true) = lit.node;
-    if let ExprKind::Path(ref qpath) = let_expr.init.kind;
-    if match_qpath(qpath, &["a"]);
-    if let ExprKind::Block(block, None) = then.kind;
-    if block.stmts.is_empty();
-    if block.expr.is_none();
-    if let ExprKind::Block(block1, None) = else_expr.kind;
-    if block1.stmts.is_empty();
-    if block1.expr.is_none();
-    then {
-        // report your lint here
-    }
+if let ExprKind::If(cond, then, Some(else_expr)) = expr.kind
+    && let ExprKind::Let(let_expr) = cond.kind
+    && let PatKind::Lit(lit_expr) = let_expr.pat.kind
+    && let ExprKind::Lit(ref lit) = lit_expr.kind
+    && let LitKind::Bool(true) = lit.node
+    && let ExprKind::Path(ref qpath) = let_expr.init.kind
+    && match_qpath(qpath, &["a"])
+    && let ExprKind::Block(block, None) = then.kind
+    && block.stmts.is_empty()
+    && block.expr.is_none()
+    && let ExprKind::Block(block1, None) = else_expr.kind
+    && block1.stmts.is_empty()
+    && block1.expr.is_none()
+{
+    // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/author/issue_3849.stdout b/src/tools/clippy/tests/ui/author/issue_3849.stdout
index bce4bc70273..32a3127b85a 100644
--- a/src/tools/clippy/tests/ui/author/issue_3849.stdout
+++ b/src/tools/clippy/tests/ui/author/issue_3849.stdout
@@ -1,14 +1,12 @@
-if_chain! {
-    if let StmtKind::Local(local) = stmt.kind;
-    if let Some(init) = local.init;
-    if let ExprKind::Call(func, args) = init.kind;
-    if let ExprKind::Path(ref qpath) = func.kind;
-    if match_qpath(qpath, &["std", "mem", "transmute"]);
-    if args.len() == 1;
-    if let ExprKind::Path(ref qpath1) = args[0].kind;
-    if match_qpath(qpath1, &["ZPTR"]);
-    if let PatKind::Wild = local.pat.kind;
-    then {
-        // report your lint here
-    }
+if let StmtKind::Local(local) = stmt.kind
+    && let Some(init) = local.init
+    && let ExprKind::Call(func, args) = init.kind
+    && let ExprKind::Path(ref qpath) = func.kind
+    && match_qpath(qpath, &["std", "mem", "transmute"])
+    && args.len() == 1
+    && let ExprKind::Path(ref qpath1) = args[0].kind
+    && match_qpath(qpath1, &["ZPTR"])
+    && let PatKind::Wild = local.pat.kind
+{
+    // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui/author/loop.stdout
index ceb53fcd496..94a6436ed54 100644
--- a/src/tools/clippy/tests/ui/author/loop.stdout
+++ b/src/tools/clippy/tests/ui/author/loop.stdout
@@ -1,113 +1,101 @@
-if_chain! {
-    if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr);
-    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind;
-    if name.as_str() == "y";
-    if let ExprKind::Struct(qpath, fields, None) = arg.kind;
-    if matches!(qpath, QPath::LangItem(LangItem::Range, _));
-    if fields.len() == 2;
-    if fields[0].ident.as_str() == "start";
-    if let ExprKind::Lit(ref lit) = fields[0].expr.kind;
-    if let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node;
-    if fields[1].ident.as_str() == "end";
-    if let ExprKind::Lit(ref lit1) = fields[1].expr.kind;
-    if let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node;
-    if let ExprKind::Block(block, None) = body.kind;
-    if block.stmts.len() == 1;
-    if let StmtKind::Local(local) = block.stmts[0].kind;
-    if let Some(init) = local.init;
-    if let ExprKind::Path(ref qpath1) = init.kind;
-    if match_qpath(qpath1, &["y"]);
-    if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind;
-    if name1.as_str() == "z";
-    if block.expr.is_none();
-    then {
-        // report your lint here
-    }
+if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr)
+    && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind
+    && name.as_str() == "y"
+    && let ExprKind::Struct(qpath, fields, None) = arg.kind
+    && matches!(qpath, QPath::LangItem(LangItem::Range, _))
+    && fields.len() == 2
+    && fields[0].ident.as_str() == "start"
+    && let ExprKind::Lit(ref lit) = fields[0].expr.kind
+    && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
+    && fields[1].ident.as_str() == "end"
+    && let ExprKind::Lit(ref lit1) = fields[1].expr.kind
+    && let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node
+    && let ExprKind::Block(block, None) = body.kind
+    && block.stmts.len() == 1
+    && let StmtKind::Local(local) = block.stmts[0].kind
+    && let Some(init) = local.init
+    && let ExprKind::Path(ref qpath1) = init.kind
+    && match_qpath(qpath1, &["y"])
+    && let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind
+    && name1.as_str() == "z"
+    && block.expr.is_none()
+{
+    // report your lint here
 }
-if_chain! {
-    if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr);
-    if let PatKind::Wild = pat.kind;
-    if let ExprKind::Struct(qpath, fields, None) = arg.kind;
-    if matches!(qpath, QPath::LangItem(LangItem::Range, _));
-    if fields.len() == 2;
-    if fields[0].ident.as_str() == "start";
-    if let ExprKind::Lit(ref lit) = fields[0].expr.kind;
-    if let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node;
-    if fields[1].ident.as_str() == "end";
-    if let ExprKind::Lit(ref lit1) = fields[1].expr.kind;
-    if let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node;
-    if let ExprKind::Block(block, None) = body.kind;
-    if block.stmts.len() == 1;
-    if let StmtKind::Semi(e) = block.stmts[0].kind;
-    if let ExprKind::Break(destination, None) = e.kind;
-    if destination.label.is_none();
-    if block.expr.is_none();
-    then {
-        // report your lint here
-    }
+if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr)
+    && let PatKind::Wild = pat.kind
+    && let ExprKind::Struct(qpath, fields, None) = arg.kind
+    && matches!(qpath, QPath::LangItem(LangItem::Range, _))
+    && fields.len() == 2
+    && fields[0].ident.as_str() == "start"
+    && let ExprKind::Lit(ref lit) = fields[0].expr.kind
+    && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
+    && fields[1].ident.as_str() == "end"
+    && let ExprKind::Lit(ref lit1) = fields[1].expr.kind
+    && let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node
+    && let ExprKind::Block(block, None) = body.kind
+    && block.stmts.len() == 1
+    && let StmtKind::Semi(e) = block.stmts[0].kind
+    && let ExprKind::Break(destination, None) = e.kind
+    && destination.label.is_none()
+    && block.expr.is_none()
+{
+    // report your lint here
 }
-if_chain! {
-    if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr);
-    if let PatKind::Wild = pat.kind;
-    if let ExprKind::Struct(qpath, fields, None) = arg.kind;
-    if matches!(qpath, QPath::LangItem(LangItem::Range, _));
-    if fields.len() == 2;
-    if fields[0].ident.as_str() == "start";
-    if let ExprKind::Lit(ref lit) = fields[0].expr.kind;
-    if let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node;
-    if fields[1].ident.as_str() == "end";
-    if let ExprKind::Lit(ref lit1) = fields[1].expr.kind;
-    if let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node;
-    if let ExprKind::Block(block, None) = body.kind;
-    if block.stmts.len() == 1;
-    if let StmtKind::Semi(e) = block.stmts[0].kind;
-    if let ExprKind::Break(destination, None) = e.kind;
-    if let Some(label) = destination.label;
-    if label.ident.as_str() == "'label";
-    if block.expr.is_none();
-    then {
-        // report your lint here
-    }
+if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr)
+    && let PatKind::Wild = pat.kind
+    && let ExprKind::Struct(qpath, fields, None) = arg.kind
+    && matches!(qpath, QPath::LangItem(LangItem::Range, _))
+    && fields.len() == 2
+    && fields[0].ident.as_str() == "start"
+    && let ExprKind::Lit(ref lit) = fields[0].expr.kind
+    && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
+    && fields[1].ident.as_str() == "end"
+    && let ExprKind::Lit(ref lit1) = fields[1].expr.kind
+    && let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node
+    && let ExprKind::Block(block, None) = body.kind
+    && block.stmts.len() == 1
+    && let StmtKind::Semi(e) = block.stmts[0].kind
+    && let ExprKind::Break(destination, None) = e.kind
+    && let Some(label) = destination.label
+    && label.ident.as_str() == "'label"
+    && block.expr.is_none()
+{
+    // report your lint here
 }
-if_chain! {
-    if let Some(higher::While { condition: condition, body: body }) = higher::While::hir(expr);
-    if let ExprKind::Path(ref qpath) = condition.kind;
-    if match_qpath(qpath, &["a"]);
-    if let ExprKind::Block(block, None) = body.kind;
-    if block.stmts.len() == 1;
-    if let StmtKind::Semi(e) = block.stmts[0].kind;
-    if let ExprKind::Break(destination, None) = e.kind;
-    if destination.label.is_none();
-    if block.expr.is_none();
-    then {
-        // report your lint here
-    }
+if let Some(higher::While { condition: condition, body: body }) = higher::While::hir(expr)
+    && let ExprKind::Path(ref qpath) = condition.kind
+    && match_qpath(qpath, &["a"])
+    && let ExprKind::Block(block, None) = body.kind
+    && block.stmts.len() == 1
+    && let StmtKind::Semi(e) = block.stmts[0].kind
+    && let ExprKind::Break(destination, None) = e.kind
+    && destination.label.is_none()
+    && block.expr.is_none()
+{
+    // report your lint here
 }
-if_chain! {
-    if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr);
-    if let PatKind::Lit(lit_expr) = let_pat.kind;
-    if let ExprKind::Lit(ref lit) = lit_expr.kind;
-    if let LitKind::Bool(true) = lit.node;
-    if let ExprKind::Path(ref qpath) = let_expr.kind;
-    if match_qpath(qpath, &["a"]);
-    if let ExprKind::Block(block, None) = if_then.kind;
-    if block.stmts.len() == 1;
-    if let StmtKind::Semi(e) = block.stmts[0].kind;
-    if let ExprKind::Break(destination, None) = e.kind;
-    if destination.label.is_none();
-    if block.expr.is_none();
-    then {
-        // report your lint here
-    }
+if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr)
+    && let PatKind::Lit(lit_expr) = let_pat.kind
+    && let ExprKind::Lit(ref lit) = lit_expr.kind
+    && let LitKind::Bool(true) = lit.node
+    && let ExprKind::Path(ref qpath) = let_expr.kind
+    && match_qpath(qpath, &["a"])
+    && let ExprKind::Block(block, None) = if_then.kind
+    && block.stmts.len() == 1
+    && let StmtKind::Semi(e) = block.stmts[0].kind
+    && let ExprKind::Break(destination, None) = e.kind
+    && destination.label.is_none()
+    && block.expr.is_none()
+{
+    // report your lint here
 }
-if_chain! {
-    if let ExprKind::Loop(body, None, LoopSource::Loop, _) = expr.kind;
-    if body.stmts.len() == 1;
-    if let StmtKind::Semi(e) = body.stmts[0].kind;
-    if let ExprKind::Break(destination, None) = e.kind;
-    if destination.label.is_none();
-    if body.expr.is_none();
-    then {
-        // report your lint here
-    }
+if let ExprKind::Loop(body, None, LoopSource::Loop, _) = expr.kind
+    && body.stmts.len() == 1
+    && let StmtKind::Semi(e) = body.stmts[0].kind
+    && let ExprKind::Break(destination, None) = e.kind
+    && destination.label.is_none()
+    && body.expr.is_none()
+{
+    // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui/author/matches.stdout
index 2cf69a035b4..88e2ca656a4 100644
--- a/src/tools/clippy/tests/ui/author/matches.stdout
+++ b/src/tools/clippy/tests/ui/author/matches.stdout
@@ -1,38 +1,36 @@
-if_chain! {
-    if let StmtKind::Local(local) = stmt.kind;
-    if let Some(init) = local.init;
-    if let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = init.kind;
-    if let ExprKind::Lit(ref lit) = scrutinee.kind;
-    if let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node;
-    if arms.len() == 3;
-    if let PatKind::Lit(lit_expr) = arms[0].pat.kind;
-    if let ExprKind::Lit(ref lit1) = lit_expr.kind;
-    if let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node;
-    if arms[0].guard.is_none();
-    if let ExprKind::Lit(ref lit2) = arms[0].body.kind;
-    if let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node;
-    if let PatKind::Lit(lit_expr1) = arms[1].pat.kind;
-    if let ExprKind::Lit(ref lit3) = lit_expr1.kind;
-    if let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node;
-    if arms[1].guard.is_none();
-    if let ExprKind::Block(block, None) = arms[1].body.kind;
-    if block.stmts.len() == 1;
-    if let StmtKind::Local(local1) = block.stmts[0].kind;
-    if let Some(init1) = local1.init;
-    if let ExprKind::Lit(ref lit4) = init1.kind;
-    if let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node;
-    if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local1.pat.kind;
-    if name.as_str() == "x";
-    if let Some(trailing_expr) = block.expr;
-    if let ExprKind::Path(ref qpath) = trailing_expr.kind;
-    if match_qpath(qpath, &["x"]);
-    if let PatKind::Wild = arms[2].pat.kind;
-    if arms[2].guard.is_none();
-    if let ExprKind::Lit(ref lit5) = arms[2].body.kind;
-    if let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node;
-    if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind;
-    if name1.as_str() == "a";
-    then {
-        // report your lint here
-    }
+if let StmtKind::Local(local) = stmt.kind
+    && let Some(init) = local.init
+    && let ExprKind::Match(scrutinee, arms, MatchSource::Normal) = init.kind
+    && let ExprKind::Lit(ref lit) = scrutinee.kind
+    && let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node
+    && arms.len() == 3
+    && let PatKind::Lit(lit_expr) = arms[0].pat.kind
+    && let ExprKind::Lit(ref lit1) = lit_expr.kind
+    && let LitKind::Int(16, LitIntType::Unsuffixed) = lit1.node
+    && arms[0].guard.is_none()
+    && let ExprKind::Lit(ref lit2) = arms[0].body.kind
+    && let LitKind::Int(5, LitIntType::Unsuffixed) = lit2.node
+    && let PatKind::Lit(lit_expr1) = arms[1].pat.kind
+    && let ExprKind::Lit(ref lit3) = lit_expr1.kind
+    && let LitKind::Int(17, LitIntType::Unsuffixed) = lit3.node
+    && arms[1].guard.is_none()
+    && let ExprKind::Block(block, None) = arms[1].body.kind
+    && block.stmts.len() == 1
+    && let StmtKind::Local(local1) = block.stmts[0].kind
+    && let Some(init1) = local1.init
+    && let ExprKind::Lit(ref lit4) = init1.kind
+    && let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node
+    && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local1.pat.kind
+    && name.as_str() == "x"
+    && let Some(trailing_expr) = block.expr
+    && let ExprKind::Path(ref qpath) = trailing_expr.kind
+    && match_qpath(qpath, &["x"])
+    && let PatKind::Wild = arms[2].pat.kind
+    && arms[2].guard.is_none()
+    && let ExprKind::Lit(ref lit5) = arms[2].body.kind
+    && let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node
+    && let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind
+    && name1.as_str() == "a"
+{
+    // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/author/repeat.stdout b/src/tools/clippy/tests/ui/author/repeat.stdout
index 471bbce4f41..c2a369610cc 100644
--- a/src/tools/clippy/tests/ui/author/repeat.stdout
+++ b/src/tools/clippy/tests/ui/author/repeat.stdout
@@ -1,12 +1,10 @@
-if_chain! {
-    if let ExprKind::Repeat(value, length) = expr.kind;
-    if let ExprKind::Lit(ref lit) = value.kind;
-    if let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node;
-    if let ArrayLen::Body(anon_const) = length;
-    let expr1 = &cx.tcx.hir().body(anon_const.body).value;
-    if let ExprKind::Lit(ref lit1) = expr1.kind;
-    if let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node;
-    then {
-        // report your lint here
-    }
+if let ExprKind::Repeat(value, length) = expr.kind
+    && let ExprKind::Lit(ref lit) = value.kind
+    && let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node
+    && let ArrayLen::Body(anon_const) = length
+    && expr1 = &cx.tcx.hir().body(anon_const.body).value
+    && let ExprKind::Lit(ref lit1) = expr1.kind
+    && let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node
+{
+    // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui/author/struct.stdout
index b5bbc9e213c..0b332d5e7d0 100644
--- a/src/tools/clippy/tests/ui/author/struct.stdout
+++ b/src/tools/clippy/tests/ui/author/struct.stdout
@@ -1,64 +1,56 @@
-if_chain! {
-    if let ExprKind::Struct(qpath, fields, None) = expr.kind;
-    if match_qpath(qpath, &["Test"]);
-    if fields.len() == 1;
-    if fields[0].ident.as_str() == "field";
-    if let ExprKind::If(cond, then, Some(else_expr)) = fields[0].expr.kind;
-    if let ExprKind::DropTemps(expr1) = cond.kind;
-    if let ExprKind::Lit(ref lit) = expr1.kind;
-    if let LitKind::Bool(true) = lit.node;
-    if let ExprKind::Block(block, None) = then.kind;
-    if block.stmts.is_empty();
-    if let Some(trailing_expr) = block.expr;
-    if let ExprKind::Lit(ref lit1) = trailing_expr.kind;
-    if let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node;
-    if let ExprKind::Block(block1, None) = else_expr.kind;
-    if block1.stmts.is_empty();
-    if let Some(trailing_expr1) = block1.expr;
-    if let ExprKind::Lit(ref lit2) = trailing_expr1.kind;
-    if let LitKind::Int(0, LitIntType::Unsuffixed) = lit2.node;
-    then {
-        // report your lint here
-    }
+if let ExprKind::Struct(qpath, fields, None) = expr.kind
+    && match_qpath(qpath, &["Test"])
+    && fields.len() == 1
+    && fields[0].ident.as_str() == "field"
+    && let ExprKind::If(cond, then, Some(else_expr)) = fields[0].expr.kind
+    && let ExprKind::DropTemps(expr1) = cond.kind
+    && let ExprKind::Lit(ref lit) = expr1.kind
+    && let LitKind::Bool(true) = lit.node
+    && let ExprKind::Block(block, None) = then.kind
+    && block.stmts.is_empty()
+    && let Some(trailing_expr) = block.expr
+    && let ExprKind::Lit(ref lit1) = trailing_expr.kind
+    && let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node
+    && let ExprKind::Block(block1, None) = else_expr.kind
+    && block1.stmts.is_empty()
+    && let Some(trailing_expr1) = block1.expr
+    && let ExprKind::Lit(ref lit2) = trailing_expr1.kind
+    && let LitKind::Int(0, LitIntType::Unsuffixed) = lit2.node
+{
+    // report your lint here
 }
-if_chain! {
-    if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind;
-    if match_qpath(qpath, &["Test"]);
-    if fields.len() == 1;
-    if fields[0].ident.as_str() == "field";
-    if let PatKind::Lit(lit_expr) = fields[0].pat.kind;
-    if let ExprKind::Lit(ref lit) = lit_expr.kind;
-    if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
-    if arm.guard.is_none();
-    if let ExprKind::Block(block, None) = arm.body.kind;
-    if block.stmts.is_empty();
-    if block.expr.is_none();
-    then {
-        // report your lint here
-    }
+if let PatKind::Struct(ref qpath, fields, false) = arm.pat.kind
+    && match_qpath(qpath, &["Test"])
+    && fields.len() == 1
+    && fields[0].ident.as_str() == "field"
+    && let PatKind::Lit(lit_expr) = fields[0].pat.kind
+    && let ExprKind::Lit(ref lit) = lit_expr.kind
+    && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
+    && arm.guard.is_none()
+    && let ExprKind::Block(block, None) = arm.body.kind
+    && block.stmts.is_empty()
+    && block.expr.is_none()
+{
+    // report your lint here
 }
-if_chain! {
-    if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind;
-    if match_qpath(qpath, &["TestTuple"]);
-    if fields.len() == 1;
-    if let PatKind::Lit(lit_expr) = fields[0].kind;
-    if let ExprKind::Lit(ref lit) = lit_expr.kind;
-    if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
-    if arm.guard.is_none();
-    if let ExprKind::Block(block, None) = arm.body.kind;
-    if block.stmts.is_empty();
-    if block.expr.is_none();
-    then {
-        // report your lint here
-    }
+if let PatKind::TupleStruct(ref qpath, fields, None) = arm.pat.kind
+    && match_qpath(qpath, &["TestTuple"])
+    && fields.len() == 1
+    && let PatKind::Lit(lit_expr) = fields[0].kind
+    && let ExprKind::Lit(ref lit) = lit_expr.kind
+    && let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node
+    && arm.guard.is_none()
+    && let ExprKind::Block(block, None) = arm.body.kind
+    && block.stmts.is_empty()
+    && block.expr.is_none()
+{
+    // report your lint here
 }
-if_chain! {
-    if let ExprKind::MethodCall(method_name, receiver, args, _) = expr.kind;
-    if method_name.ident.as_str() == "test";
-    if let ExprKind::Path(ref qpath) = receiver.kind;
-    if match_qpath(qpath, &["test_method_call"]);
-    if args.is_empty();
-    then {
-        // report your lint here
-    }
+if let ExprKind::MethodCall(method_name, receiver, args, _) = expr.kind
+    && method_name.ident.as_str() == "test"
+    && let ExprKind::Path(ref qpath) = receiver.kind
+    && match_qpath(qpath, &["test_method_call"])
+    && args.is_empty()
+{
+    // report your lint here
 }
diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed
new file mode 100644
index 00000000000..911fa856aa0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/box_default.fixed
@@ -0,0 +1,57 @@
+// run-rustfix
+#![warn(clippy::box_default)]
+
+#[derive(Default)]
+struct ImplementsDefault;
+
+struct OwnDefault;
+
+impl OwnDefault {
+    fn default() -> Self {
+        Self
+    }
+}
+
+macro_rules! outer {
+    ($e: expr) => {
+        $e
+    };
+}
+
+fn main() {
+    let _string: Box<String> = Box::default();
+    let _byte = Box::<u8>::default();
+    let _vec = Box::<std::vec::Vec<u8>>::default();
+    let _impl = Box::<ImplementsDefault>::default();
+    let _impl2 = Box::<ImplementsDefault>::default();
+    let _impl3: Box<ImplementsDefault> = Box::default();
+    let _own = Box::new(OwnDefault::default()); // should not lint
+    let _in_macro = outer!(Box::<std::string::String>::default());
+    let _string_default = outer!(Box::<std::string::String>::default());
+    let _vec2: Box<Vec<ImplementsDefault>> = Box::default();
+    let _vec3: Box<Vec<bool>> = Box::default();
+    let _vec4: Box<_> = Box::<std::vec::Vec<bool>>::default();
+    let _more = ret_ty_fn();
+    call_ty_fn(Box::default());
+}
+
+fn ret_ty_fn() -> Box<bool> {
+    Box::<bool>::default()
+}
+
+#[allow(clippy::boxed_local)]
+fn call_ty_fn(_b: Box<u8>) {
+    issue_9621_dyn_trait();
+}
+
+use std::io::{Read, Result};
+
+impl Read for ImplementsDefault {
+    fn read(&mut self, _: &mut [u8]) -> Result<usize> {
+        Ok(0)
+    }
+}
+
+fn issue_9621_dyn_trait() {
+    let _: Box<dyn Read> = Box::<ImplementsDefault>::default();
+}
diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs
index dc522705bc6..20019c2ee5a 100644
--- a/src/tools/clippy/tests/ui/box_default.rs
+++ b/src/tools/clippy/tests/ui/box_default.rs
@@ -1,3 +1,4 @@
+// run-rustfix
 #![warn(clippy::box_default)]
 
 #[derive(Default)]
@@ -26,6 +27,31 @@ fn main() {
     let _impl3: Box<ImplementsDefault> = Box::new(Default::default());
     let _own = Box::new(OwnDefault::default()); // should not lint
     let _in_macro = outer!(Box::new(String::new()));
-    // false negative: default is from different expansion
+    let _string_default = outer!(Box::new(String::from("")));
     let _vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]);
+    let _vec3: Box<Vec<bool>> = Box::new(Vec::from([]));
+    let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
+    let _more = ret_ty_fn();
+    call_ty_fn(Box::new(u8::default()));
+}
+
+fn ret_ty_fn() -> Box<bool> {
+    Box::new(bool::default())
+}
+
+#[allow(clippy::boxed_local)]
+fn call_ty_fn(_b: Box<u8>) {
+    issue_9621_dyn_trait();
+}
+
+use std::io::{Read, Result};
+
+impl Read for ImplementsDefault {
+    fn read(&mut self, _: &mut [u8]) -> Result<usize> {
+        Ok(0)
+    }
+}
+
+fn issue_9621_dyn_trait() {
+    let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
 }
diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr
index b2030e95acb..5ea410331af 100644
--- a/src/tools/clippy/tests/ui/box_default.stderr
+++ b/src/tools/clippy/tests/ui/box_default.stderr
@@ -1,59 +1,88 @@
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:21:32
+  --> $DIR/box_default.rs:22:32
    |
 LL |     let _string: Box<String> = Box::new(Default::default());
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
    |
-   = help: use `Box::default()` instead
    = note: `-D clippy::box-default` implied by `-D warnings`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:22:17
+  --> $DIR/box_default.rs:23:17
    |
 LL |     let _byte = Box::new(u8::default());
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: use `Box::default()` instead
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<u8>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:23:16
+  --> $DIR/box_default.rs:24:16
    |
 LL |     let _vec = Box::new(Vec::<u8>::new());
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: use `Box::default()` instead
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::vec::Vec<u8>>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:24:17
+  --> $DIR/box_default.rs:25:17
    |
 LL |     let _impl = Box::new(ImplementsDefault::default());
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: use `Box::default()` instead
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:25:18
+  --> $DIR/box_default.rs:26:18
    |
 LL |     let _impl2 = Box::new(<ImplementsDefault as Default>::default());
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: use `Box::default()` instead
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:26:42
+  --> $DIR/box_default.rs:27:42
    |
 LL |     let _impl3: Box<ImplementsDefault> = Box::new(Default::default());
-   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: use `Box::default()` instead
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
 
 error: `Box::new(_)` of default value
-  --> $DIR/box_default.rs:28:28
+  --> $DIR/box_default.rs:29:28
    |
 LL |     let _in_macro = outer!(Box::new(String::new()));
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::string::String>::default()`
+
+error: `Box::new(_)` of default value
+  --> $DIR/box_default.rs:30:34
+   |
+LL |     let _string_default = outer!(Box::new(String::from("")));
+   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::string::String>::default()`
+
+error: `Box::new(_)` of default value
+  --> $DIR/box_default.rs:31:46
+   |
+LL |     let _vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]);
+   |                                              ^^^^^^^^^^^^^^^^ help: try: `Box::default()`
+
+error: `Box::new(_)` of default value
+  --> $DIR/box_default.rs:32:33
+   |
+LL |     let _vec3: Box<Vec<bool>> = Box::new(Vec::from([]));
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
+
+error: `Box::new(_)` of default value
+  --> $DIR/box_default.rs:33:25
+   |
+LL |     let _vec4: Box<_> = Box::new(Vec::from([false; 0]));
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<std::vec::Vec<bool>>::default()`
+
+error: `Box::new(_)` of default value
+  --> $DIR/box_default.rs:35:16
+   |
+LL |     call_ty_fn(Box::new(u8::default()));
+   |                ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()`
+
+error: `Box::new(_)` of default value
+  --> $DIR/box_default.rs:39:5
+   |
+LL |     Box::new(bool::default())
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()`
+
+error: `Box::new(_)` of default value
+  --> $DIR/box_default.rs:56:28
    |
-   = help: use `Box::default()` instead
+LL |     let _: Box<dyn Read> = Box::new(ImplementsDefault::default());
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()`
 
-error: aborting due to 7 previous errors
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/box_default_no_std.rs b/src/tools/clippy/tests/ui/box_default_no_std.rs
new file mode 100644
index 00000000000..4326abc9a54
--- /dev/null
+++ b/src/tools/clippy/tests/ui/box_default_no_std.rs
@@ -0,0 +1,33 @@
+#![feature(lang_items, start, libc)]
+#![warn(clippy::box_default)]
+#![no_std]
+
+pub struct NotBox<T> {
+    _value: T,
+}
+
+impl<T> NotBox<T> {
+    pub fn new(value: T) -> Self {
+        Self { _value: value }
+    }
+}
+
+impl<T: Default> Default for NotBox<T> {
+    fn default() -> Self {
+        Self::new(T::default())
+    }
+}
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    let _p = NotBox::new(isize::default());
+    0
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed
index a37f3fec20f..e6bf944c7a5 100644
--- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed
+++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed
@@ -1,6 +1,8 @@
 // run-rustfix
+
+#![feature(custom_inner_attributes)]
 #![warn(clippy::cast_abs_to_unsigned)]
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, unused)]
 
 fn main() {
     let x: i32 = -42;
@@ -30,3 +32,17 @@ fn main() {
 
     let _ = (x as i64 - y as i64).unsigned_abs() as u32;
 }
+
+fn msrv_1_50() {
+    #![clippy::msrv = "1.50"]
+
+    let x: i32 = 10;
+    assert_eq!(10u32, x.abs() as u32);
+}
+
+fn msrv_1_51() {
+    #![clippy::msrv = "1.51"]
+
+    let x: i32 = 10;
+    assert_eq!(10u32, x.unsigned_abs());
+}
diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs
index 5706930af5a..c87320b5209 100644
--- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs
@@ -1,6 +1,8 @@
 // run-rustfix
+
+#![feature(custom_inner_attributes)]
 #![warn(clippy::cast_abs_to_unsigned)]
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, unused)]
 
 fn main() {
     let x: i32 = -42;
@@ -30,3 +32,17 @@ fn main() {
 
     let _ = (x as i64 - y as i64).abs() as u32;
 }
+
+fn msrv_1_50() {
+    #![clippy::msrv = "1.50"]
+
+    let x: i32 = 10;
+    assert_eq!(10u32, x.abs() as u32);
+}
+
+fn msrv_1_51() {
+    #![clippy::msrv = "1.51"]
+
+    let x: i32 = 10;
+    assert_eq!(10u32, x.abs() as u32);
+}
diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr
index 7cea11c183d..1b39c554b03 100644
--- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr
+++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr
@@ -1,5 +1,5 @@
 error: casting the result of `i32::abs()` to u32
-  --> $DIR/cast_abs_to_unsigned.rs:7:18
+  --> $DIR/cast_abs_to_unsigned.rs:9:18
    |
 LL |     let y: u32 = x.abs() as u32;
    |                  ^^^^^^^^^^^^^^ help: replace with: `x.unsigned_abs()`
@@ -7,100 +7,106 @@ LL |     let y: u32 = x.abs() as u32;
    = note: `-D clippy::cast-abs-to-unsigned` implied by `-D warnings`
 
 error: casting the result of `i32::abs()` to usize
-  --> $DIR/cast_abs_to_unsigned.rs:11:20
+  --> $DIR/cast_abs_to_unsigned.rs:13:20
    |
 LL |     let _: usize = a.abs() as usize;
    |                    ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i32::abs()` to usize
-  --> $DIR/cast_abs_to_unsigned.rs:12:20
+  --> $DIR/cast_abs_to_unsigned.rs:14:20
    |
 LL |     let _: usize = a.abs() as _;
    |                    ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i32::abs()` to usize
-  --> $DIR/cast_abs_to_unsigned.rs:13:13
+  --> $DIR/cast_abs_to_unsigned.rs:15:13
    |
 LL |     let _ = a.abs() as usize;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to usize
-  --> $DIR/cast_abs_to_unsigned.rs:16:13
+  --> $DIR/cast_abs_to_unsigned.rs:18:13
    |
 LL |     let _ = a.abs() as usize;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to u8
-  --> $DIR/cast_abs_to_unsigned.rs:17:13
+  --> $DIR/cast_abs_to_unsigned.rs:19:13
    |
 LL |     let _ = a.abs() as u8;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to u16
-  --> $DIR/cast_abs_to_unsigned.rs:18:13
+  --> $DIR/cast_abs_to_unsigned.rs:20:13
    |
 LL |     let _ = a.abs() as u16;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to u32
-  --> $DIR/cast_abs_to_unsigned.rs:19:13
+  --> $DIR/cast_abs_to_unsigned.rs:21:13
    |
 LL |     let _ = a.abs() as u32;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to u64
-  --> $DIR/cast_abs_to_unsigned.rs:20:13
+  --> $DIR/cast_abs_to_unsigned.rs:22:13
    |
 LL |     let _ = a.abs() as u64;
    |             ^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to u128
-  --> $DIR/cast_abs_to_unsigned.rs:21:13
+  --> $DIR/cast_abs_to_unsigned.rs:23:13
    |
 LL |     let _ = a.abs() as u128;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `isize::abs()` to usize
-  --> $DIR/cast_abs_to_unsigned.rs:24:13
+  --> $DIR/cast_abs_to_unsigned.rs:26:13
    |
 LL |     let _ = a.abs() as usize;
    |             ^^^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `isize::abs()` to u8
-  --> $DIR/cast_abs_to_unsigned.rs:25:13
+  --> $DIR/cast_abs_to_unsigned.rs:27:13
    |
 LL |     let _ = a.abs() as u8;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `isize::abs()` to u16
-  --> $DIR/cast_abs_to_unsigned.rs:26:13
+  --> $DIR/cast_abs_to_unsigned.rs:28:13
    |
 LL |     let _ = a.abs() as u16;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `isize::abs()` to u32
-  --> $DIR/cast_abs_to_unsigned.rs:27:13
+  --> $DIR/cast_abs_to_unsigned.rs:29:13
    |
 LL |     let _ = a.abs() as u32;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `isize::abs()` to u64
-  --> $DIR/cast_abs_to_unsigned.rs:28:13
+  --> $DIR/cast_abs_to_unsigned.rs:30:13
    |
 LL |     let _ = a.abs() as u64;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `isize::abs()` to u128
-  --> $DIR/cast_abs_to_unsigned.rs:29:13
+  --> $DIR/cast_abs_to_unsigned.rs:31:13
    |
 LL |     let _ = a.abs() as u128;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
 error: casting the result of `i64::abs()` to u32
-  --> $DIR/cast_abs_to_unsigned.rs:31:13
+  --> $DIR/cast_abs_to_unsigned.rs:33:13
    |
 LL |     let _ = (x as i64 - y as i64).abs() as u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(x as i64 - y as i64).unsigned_abs()`
 
-error: aborting due to 17 previous errors
+error: casting the result of `i32::abs()` to u32
+  --> $DIR/cast_abs_to_unsigned.rs:47:23
+   |
+LL |     assert_eq!(10u32, x.abs() as u32);
+   |                       ^^^^^^^^^^^^^^ help: replace with: `x.unsigned_abs()`
+
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.fixed b/src/tools/clippy/tests/ui/cast_lossless_bool.fixed
index 9e2da45c378..af13b755e31 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_bool.fixed
+++ b/src/tools/clippy/tests/ui/cast_lossless_bool.fixed
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(custom_inner_attributes)]
 #![allow(dead_code)]
 #![warn(clippy::cast_lossless)]
 
@@ -40,3 +41,15 @@ mod cast_lossless_in_impl {
         }
     }
 }
+
+fn msrv_1_27() {
+    #![clippy::msrv = "1.27"]
+
+    let _ = true as u8;
+}
+
+fn msrv_1_28() {
+    #![clippy::msrv = "1.28"]
+
+    let _ = u8::from(true);
+}
diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.rs b/src/tools/clippy/tests/ui/cast_lossless_bool.rs
index b6f6c59a01f..3b06af899c6 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_bool.rs
+++ b/src/tools/clippy/tests/ui/cast_lossless_bool.rs
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(custom_inner_attributes)]
 #![allow(dead_code)]
 #![warn(clippy::cast_lossless)]
 
@@ -40,3 +41,15 @@ mod cast_lossless_in_impl {
         }
     }
 }
+
+fn msrv_1_27() {
+    #![clippy::msrv = "1.27"]
+
+    let _ = true as u8;
+}
+
+fn msrv_1_28() {
+    #![clippy::msrv = "1.28"]
+
+    let _ = true as u8;
+}
diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.stderr b/src/tools/clippy/tests/ui/cast_lossless_bool.stderr
index 6b148336011..768b033d10a 100644
--- a/src/tools/clippy/tests/ui/cast_lossless_bool.stderr
+++ b/src/tools/clippy/tests/ui/cast_lossless_bool.stderr
@@ -1,5 +1,5 @@
 error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
-  --> $DIR/cast_lossless_bool.rs:8:13
+  --> $DIR/cast_lossless_bool.rs:9:13
    |
 LL |     let _ = true as u8;
    |             ^^^^^^^^^^ help: try: `u8::from(true)`
@@ -7,76 +7,82 @@ LL |     let _ = true as u8;
    = note: `-D clippy::cast-lossless` implied by `-D warnings`
 
 error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
-  --> $DIR/cast_lossless_bool.rs:9:13
+  --> $DIR/cast_lossless_bool.rs:10:13
    |
 LL |     let _ = true as u16;
    |             ^^^^^^^^^^^ help: try: `u16::from(true)`
 
 error: casting `bool` to `u32` is more cleanly stated with `u32::from(_)`
-  --> $DIR/cast_lossless_bool.rs:10:13
+  --> $DIR/cast_lossless_bool.rs:11:13
    |
 LL |     let _ = true as u32;
    |             ^^^^^^^^^^^ help: try: `u32::from(true)`
 
 error: casting `bool` to `u64` is more cleanly stated with `u64::from(_)`
-  --> $DIR/cast_lossless_bool.rs:11:13
+  --> $DIR/cast_lossless_bool.rs:12:13
    |
 LL |     let _ = true as u64;
    |             ^^^^^^^^^^^ help: try: `u64::from(true)`
 
 error: casting `bool` to `u128` is more cleanly stated with `u128::from(_)`
-  --> $DIR/cast_lossless_bool.rs:12:13
+  --> $DIR/cast_lossless_bool.rs:13:13
    |
 LL |     let _ = true as u128;
    |             ^^^^^^^^^^^^ help: try: `u128::from(true)`
 
 error: casting `bool` to `usize` is more cleanly stated with `usize::from(_)`
-  --> $DIR/cast_lossless_bool.rs:13:13
+  --> $DIR/cast_lossless_bool.rs:14:13
    |
 LL |     let _ = true as usize;
    |             ^^^^^^^^^^^^^ help: try: `usize::from(true)`
 
 error: casting `bool` to `i8` is more cleanly stated with `i8::from(_)`
-  --> $DIR/cast_lossless_bool.rs:15:13
+  --> $DIR/cast_lossless_bool.rs:16:13
    |
 LL |     let _ = true as i8;
    |             ^^^^^^^^^^ help: try: `i8::from(true)`
 
 error: casting `bool` to `i16` is more cleanly stated with `i16::from(_)`
-  --> $DIR/cast_lossless_bool.rs:16:13
+  --> $DIR/cast_lossless_bool.rs:17:13
    |
 LL |     let _ = true as i16;
    |             ^^^^^^^^^^^ help: try: `i16::from(true)`
 
 error: casting `bool` to `i32` is more cleanly stated with `i32::from(_)`
-  --> $DIR/cast_lossless_bool.rs:17:13
+  --> $DIR/cast_lossless_bool.rs:18:13
    |
 LL |     let _ = true as i32;
    |             ^^^^^^^^^^^ help: try: `i32::from(true)`
 
 error: casting `bool` to `i64` is more cleanly stated with `i64::from(_)`
-  --> $DIR/cast_lossless_bool.rs:18:13
+  --> $DIR/cast_lossless_bool.rs:19:13
    |
 LL |     let _ = true as i64;
    |             ^^^^^^^^^^^ help: try: `i64::from(true)`
 
 error: casting `bool` to `i128` is more cleanly stated with `i128::from(_)`
-  --> $DIR/cast_lossless_bool.rs:19:13
+  --> $DIR/cast_lossless_bool.rs:20:13
    |
 LL |     let _ = true as i128;
    |             ^^^^^^^^^^^^ help: try: `i128::from(true)`
 
 error: casting `bool` to `isize` is more cleanly stated with `isize::from(_)`
-  --> $DIR/cast_lossless_bool.rs:20:13
+  --> $DIR/cast_lossless_bool.rs:21:13
    |
 LL |     let _ = true as isize;
    |             ^^^^^^^^^^^^^ help: try: `isize::from(true)`
 
 error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
-  --> $DIR/cast_lossless_bool.rs:23:13
+  --> $DIR/cast_lossless_bool.rs:24:13
    |
 LL |     let _ = (true | false) as u16;
    |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::from(true | false)`
 
-error: aborting due to 13 previous errors
+error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
+  --> $DIR/cast_lossless_bool.rs:54:13
+   |
+LL |     let _ = true as u8;
+   |             ^^^^^^^^^^ help: try: `u8::from(true)`
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cast_nan_to_int.rs b/src/tools/clippy/tests/ui/cast_nan_to_int.rs
new file mode 100644
index 00000000000..287c5aa216b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_nan_to_int.rs
@@ -0,0 +1,18 @@
+#![warn(clippy::cast_nan_to_int)]
+#![allow(clippy::eq_op)]
+
+fn main() {
+    let _ = (0.0_f32 / -0.0) as usize;
+    let _ = (f64::INFINITY * -0.0) as usize;
+    let _ = (0.0 * f32::INFINITY) as usize;
+
+    let _ = (f64::INFINITY + f64::NEG_INFINITY) as usize;
+    let _ = (f32::INFINITY - f32::INFINITY) as usize;
+    let _ = (f32::INFINITY / f32::NEG_INFINITY) as usize;
+
+    // those won't be linted:
+    let _ = (1.0_f32 / 0.0) as usize;
+    let _ = (f32::INFINITY * f32::NEG_INFINITY) as usize;
+    let _ = (f32::INFINITY - f32::NEG_INFINITY) as usize;
+    let _ = (f64::INFINITY - 0.0) as usize;
+}
diff --git a/src/tools/clippy/tests/ui/cast_nan_to_int.stderr b/src/tools/clippy/tests/ui/cast_nan_to_int.stderr
new file mode 100644
index 00000000000..3539be75a19
--- /dev/null
+++ b/src/tools/clippy/tests/ui/cast_nan_to_int.stderr
@@ -0,0 +1,51 @@
+error: casting a known NaN to usize
+  --> $DIR/cast_nan_to_int.rs:5:13
+   |
+LL |     let _ = (0.0_f32 / -0.0) as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this always evaluates to 0
+   = note: `-D clippy::cast-nan-to-int` implied by `-D warnings`
+
+error: casting a known NaN to usize
+  --> $DIR/cast_nan_to_int.rs:6:13
+   |
+LL |     let _ = (f64::INFINITY * -0.0) as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this always evaluates to 0
+
+error: casting a known NaN to usize
+  --> $DIR/cast_nan_to_int.rs:7:13
+   |
+LL |     let _ = (0.0 * f32::INFINITY) as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this always evaluates to 0
+
+error: casting a known NaN to usize
+  --> $DIR/cast_nan_to_int.rs:9:13
+   |
+LL |     let _ = (f64::INFINITY + f64::NEG_INFINITY) as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this always evaluates to 0
+
+error: casting a known NaN to usize
+  --> $DIR/cast_nan_to_int.rs:10:13
+   |
+LL |     let _ = (f32::INFINITY - f32::INFINITY) as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this always evaluates to 0
+
+error: casting a known NaN to usize
+  --> $DIR/cast_nan_to_int.rs:11:13
+   |
+LL |     let _ = (f32::INFINITY / f32::NEG_INFINITY) as usize;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this always evaluates to 0
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed
index 061a4ab9b2e..8a5645b22ed 100644
--- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed
+++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![feature(stmt_expr_attributes)]
+#![feature(stmt_expr_attributes, custom_inner_attributes)]
 
 #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
 #![warn(clippy::deprecated_cfg_attr)]
@@ -29,3 +29,17 @@ mod foo {
 
     pub fn f() {}
 }
+
+fn msrv_1_29() {
+    #![clippy::msrv = "1.29"]
+
+    #[cfg_attr(rustfmt, rustfmt::skip)]
+    1+29;
+}
+
+fn msrv_1_30() {
+    #![clippy::msrv = "1.30"]
+
+    #[rustfmt::skip]
+    1+30;
+}
diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs
index 035169fab85..2fb140efae7 100644
--- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs
+++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![feature(stmt_expr_attributes)]
+#![feature(stmt_expr_attributes, custom_inner_attributes)]
 
 #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
 #![warn(clippy::deprecated_cfg_attr)]
@@ -29,3 +29,17 @@ mod foo {
 
     pub fn f() {}
 }
+
+fn msrv_1_29() {
+    #![clippy::msrv = "1.29"]
+
+    #[cfg_attr(rustfmt, rustfmt::skip)]
+    1+29;
+}
+
+fn msrv_1_30() {
+    #![clippy::msrv = "1.30"]
+
+    #[cfg_attr(rustfmt, rustfmt::skip)]
+    1+30;
+}
diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr
index c1efd47db90..08df7b2b39a 100644
--- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr
+++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr
@@ -12,5 +12,11 @@ error: `cfg_attr` is deprecated for rustfmt and got replaced by tool attributes
 LL | #[cfg_attr(rustfmt, rustfmt_skip)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]`
 
-error: aborting due to 2 previous errors
+error: `cfg_attr` is deprecated for rustfmt and got replaced by tool attributes
+  --> $DIR/cfg_attr_rustfmt.rs:43:5
+   |
+LL |     #[cfg_attr(rustfmt, rustfmt::skip)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]`
+
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/checked_conversions.fixed b/src/tools/clippy/tests/ui/checked_conversions.fixed
index cb7100bc9ef..f936957cb40 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.fixed
+++ b/src/tools/clippy/tests/ui/checked_conversions.fixed
@@ -1,7 +1,9 @@
 // run-rustfix
 
+#![feature(custom_inner_attributes)]
 #![allow(
     clippy::cast_lossless,
+    unused,
     // Int::max_value will be deprecated in the future
     deprecated,
 )]
@@ -76,4 +78,18 @@ pub const fn issue_8898(i: u32) -> bool {
     i <= i32::MAX as u32
 }
 
+fn msrv_1_33() {
+    #![clippy::msrv = "1.33"]
+
+    let value: i64 = 33;
+    let _ = value <= (u32::MAX as i64) && value >= 0;
+}
+
+fn msrv_1_34() {
+    #![clippy::msrv = "1.34"]
+
+    let value: i64 = 34;
+    let _ = u32::try_from(value).is_ok();
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/checked_conversions.rs b/src/tools/clippy/tests/ui/checked_conversions.rs
index ed4e0692388..77aec713ff3 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.rs
+++ b/src/tools/clippy/tests/ui/checked_conversions.rs
@@ -1,7 +1,9 @@
 // run-rustfix
 
+#![feature(custom_inner_attributes)]
 #![allow(
     clippy::cast_lossless,
+    unused,
     // Int::max_value will be deprecated in the future
     deprecated,
 )]
@@ -76,4 +78,18 @@ pub const fn issue_8898(i: u32) -> bool {
     i <= i32::MAX as u32
 }
 
+fn msrv_1_33() {
+    #![clippy::msrv = "1.33"]
+
+    let value: i64 = 33;
+    let _ = value <= (u32::MAX as i64) && value >= 0;
+}
+
+fn msrv_1_34() {
+    #![clippy::msrv = "1.34"]
+
+    let value: i64 = 34;
+    let _ = value <= (u32::MAX as i64) && value >= 0;
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr
index 2e518040561..b2bf7af8daf 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.stderr
+++ b/src/tools/clippy/tests/ui/checked_conversions.stderr
@@ -1,5 +1,5 @@
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:15:13
+  --> $DIR/checked_conversions.rs:17:13
    |
 LL |     let _ = value <= (u32::max_value() as i64) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
@@ -7,94 +7,100 @@ LL |     let _ = value <= (u32::max_value() as i64) && value >= 0;
    = note: `-D clippy::checked-conversions` implied by `-D warnings`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:16:13
+  --> $DIR/checked_conversions.rs:18:13
    |
 LL |     let _ = value <= (u32::MAX as i64) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:20:13
+  --> $DIR/checked_conversions.rs:22:13
    |
 LL |     let _ = value <= i64::from(u16::max_value()) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:21:13
+  --> $DIR/checked_conversions.rs:23:13
    |
 LL |     let _ = value <= i64::from(u16::MAX) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:25:13
+  --> $DIR/checked_conversions.rs:27:13
    |
 LL |     let _ = value <= (u8::max_value() as isize) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:26:13
+  --> $DIR/checked_conversions.rs:28:13
    |
 LL |     let _ = value <= (u8::MAX as isize) && value >= 0;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:32:13
+  --> $DIR/checked_conversions.rs:34:13
    |
 LL |     let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:33:13
+  --> $DIR/checked_conversions.rs:35:13
    |
 LL |     let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:37:13
+  --> $DIR/checked_conversions.rs:39:13
    |
 LL |     let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:38:13
+  --> $DIR/checked_conversions.rs:40:13
    |
 LL |     let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:44:13
+  --> $DIR/checked_conversions.rs:46:13
    |
 LL |     let _ = value <= i32::max_value() as u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:45:13
+  --> $DIR/checked_conversions.rs:47:13
    |
 LL |     let _ = value <= i32::MAX as u32;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:49:13
+  --> $DIR/checked_conversions.rs:51:13
    |
 LL |     let _ = value <= isize::max_value() as usize && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:50:13
+  --> $DIR/checked_conversions.rs:52:13
    |
 LL |     let _ = value <= isize::MAX as usize && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:54:13
+  --> $DIR/checked_conversions.rs:56:13
    |
 LL |     let _ = value <= u16::max_value() as u32 && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: checked cast can be simplified
-  --> $DIR/checked_conversions.rs:55:13
+  --> $DIR/checked_conversions.rs:57:13
    |
 LL |     let _ = value <= u16::MAX as u32 && value as i32 == 5;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
-error: aborting due to 16 previous errors
+error: checked cast can be simplified
+  --> $DIR/checked_conversions.rs:92:13
+   |
+LL |     let _ = value <= (u32::MAX as i64) && value >= 0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
+
+error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed b/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed
index 4eb999e18e6..42ed232d100 100644
--- a/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed
+++ b/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed
@@ -1,5 +1,8 @@
 // run-rustfix
+
+#![feature(custom_inner_attributes)]
 #![warn(clippy::cloned_instead_of_copied)]
+#![allow(unused)]
 
 fn main() {
     // yay
@@ -13,3 +16,24 @@ fn main() {
     let _ = [String::new()].iter().cloned();
     let _ = Some(&String::new()).cloned();
 }
+
+fn msrv_1_34() {
+    #![clippy::msrv = "1.34"]
+
+    let _ = [1].iter().cloned();
+    let _ = Some(&1).cloned();
+}
+
+fn msrv_1_35() {
+    #![clippy::msrv = "1.35"]
+
+    let _ = [1].iter().cloned();
+    let _ = Some(&1).copied(); // Option::copied needs 1.35
+}
+
+fn msrv_1_36() {
+    #![clippy::msrv = "1.36"]
+
+    let _ = [1].iter().copied(); // Iterator::copied needs 1.36
+    let _ = Some(&1).copied();
+}
diff --git a/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs b/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs
index 894496c0ebb..471bd9654cc 100644
--- a/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs
+++ b/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs
@@ -1,5 +1,8 @@
 // run-rustfix
+
+#![feature(custom_inner_attributes)]
 #![warn(clippy::cloned_instead_of_copied)]
+#![allow(unused)]
 
 fn main() {
     // yay
@@ -13,3 +16,24 @@ fn main() {
     let _ = [String::new()].iter().cloned();
     let _ = Some(&String::new()).cloned();
 }
+
+fn msrv_1_34() {
+    #![clippy::msrv = "1.34"]
+
+    let _ = [1].iter().cloned();
+    let _ = Some(&1).cloned();
+}
+
+fn msrv_1_35() {
+    #![clippy::msrv = "1.35"]
+
+    let _ = [1].iter().cloned();
+    let _ = Some(&1).cloned(); // Option::copied needs 1.35
+}
+
+fn msrv_1_36() {
+    #![clippy::msrv = "1.36"]
+
+    let _ = [1].iter().cloned(); // Iterator::copied needs 1.36
+    let _ = Some(&1).cloned();
+}
diff --git a/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr b/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr
index e0707d32146..914c9a91e83 100644
--- a/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr
+++ b/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr
@@ -1,5 +1,5 @@
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:6:24
+  --> $DIR/cloned_instead_of_copied.rs:9:24
    |
 LL |     let _ = [1].iter().cloned();
    |                        ^^^^^^ help: try: `copied`
@@ -7,28 +7,46 @@ LL |     let _ = [1].iter().cloned();
    = note: `-D clippy::cloned-instead-of-copied` implied by `-D warnings`
 
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:7:31
+  --> $DIR/cloned_instead_of_copied.rs:10:31
    |
 LL |     let _ = vec!["hi"].iter().cloned();
    |                               ^^^^^^ help: try: `copied`
 
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:8:22
+  --> $DIR/cloned_instead_of_copied.rs:11:22
    |
 LL |     let _ = Some(&1).cloned();
    |                      ^^^^^^ help: try: `copied`
 
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:9:34
+  --> $DIR/cloned_instead_of_copied.rs:12:34
    |
 LL |     let _ = Box::new([1].iter()).cloned();
    |                                  ^^^^^^ help: try: `copied`
 
 error: used `cloned` where `copied` could be used instead
-  --> $DIR/cloned_instead_of_copied.rs:10:32
+  --> $DIR/cloned_instead_of_copied.rs:13:32
    |
 LL |     let _ = Box::new(Some(&1)).cloned();
    |                                ^^^^^^ help: try: `copied`
 
-error: aborting due to 5 previous errors
+error: used `cloned` where `copied` could be used instead
+  --> $DIR/cloned_instead_of_copied.rs:31:22
+   |
+LL |     let _ = Some(&1).cloned(); // Option::copied needs 1.35
+   |                      ^^^^^^ help: try: `copied`
+
+error: used `cloned` where `copied` could be used instead
+  --> $DIR/cloned_instead_of_copied.rs:37:24
+   |
+LL |     let _ = [1].iter().cloned(); // Iterator::copied needs 1.36
+   |                        ^^^^^^ help: try: `copied`
+
+error: used `cloned` where `copied` could be used instead
+  --> $DIR/cloned_instead_of_copied.rs:38:22
+   |
+LL |     let _ = Some(&1).cloned();
+   |                      ^^^^^^ help: try: `copied`
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs
index 7d53e08345d..1d7a7284641 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.rs
+++ b/src/tools/clippy/tests/ui/collapsible_match.rs
@@ -253,6 +253,27 @@ fn negative_cases(res_opt: Result<Option<u32>, String>, res_res: Result<Result<u
     };
 }
 
+pub enum Issue9647 {
+    A { a: Option<Option<u8>>, b: () },
+    B,
+}
+
+pub fn test_1(x: Issue9647) {
+    if let Issue9647::A { a, .. } = x {
+        if let Some(u) = a {
+            println!("{u:?}")
+        }
+    }
+}
+
+pub fn test_2(x: Issue9647) {
+    if let Issue9647::A { a: Some(a), .. } = x {
+        if let Some(u) = a {
+            println!("{u}")
+        }
+    }
+}
+
 fn make<T>() -> T {
     unimplemented!()
 }
diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr
index 2580bef5809..0294be60b43 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_match.stderr
@@ -175,5 +175,37 @@ LL |         Some(val) => match val {
 LL |             Some(n) => foo(n),
    |             ^^^^^^^ with this pattern
 
-error: aborting due to 10 previous errors
+error: this `if let` can be collapsed into the outer `if let`
+  --> $DIR/collapsible_match.rs:263:9
+   |
+LL | /         if let Some(u) = a {
+LL | |             println!("{u:?}")
+LL | |         }
+   | |_________^
+   |
+help: the outer pattern can be modified to include the inner pattern
+  --> $DIR/collapsible_match.rs:262:27
+   |
+LL |     if let Issue9647::A { a, .. } = x {
+   |                           ^ replace this binding
+LL |         if let Some(u) = a {
+   |                ^^^^^^^ with this pattern, prefixed by a:
+
+error: this `if let` can be collapsed into the outer `if let`
+  --> $DIR/collapsible_match.rs:271:9
+   |
+LL | /         if let Some(u) = a {
+LL | |             println!("{u}")
+LL | |         }
+   | |_________^
+   |
+help: the outer pattern can be modified to include the inner pattern
+  --> $DIR/collapsible_match.rs:270:35
+   |
+LL |     if let Issue9647::A { a: Some(a), .. } = x {
+   |                                   ^ replace this binding
+LL |         if let Some(u) = a {
+   |                ^^^^^^^ with this pattern
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9625.rs b/src/tools/clippy/tests/ui/crashes/ice-9625.rs
new file mode 100644
index 00000000000..a765882b5d8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-9625.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let x = &1;
+    let _ = &1 < x && x < &10;
+}
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed
index a28bff76755..a370ccc7696 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed
@@ -33,6 +33,7 @@ mod basic_expr {
         let x: [f64; 3] = [1., 2., 3.];
         let x: (f64, f64) = if true { (1., 2.) } else { (3., 4.) };
         let x: _ = 1.;
+        const X: f32 = 1.;
     }
 }
 
@@ -59,6 +60,14 @@ mod nested_local {
             // Should NOT lint this because this literal is bound to `_` of outer `Local`.
             2.
         };
+
+        const X: f32 = {
+            // Should lint this because this literal is not bound to any types.
+            let y = 1.0_f64;
+
+            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
+            1.
+        };
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs
index b48435cc7b2..2476fe95141 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs
@@ -33,6 +33,7 @@ mod basic_expr {
         let x: [f64; 3] = [1., 2., 3.];
         let x: (f64, f64) = if true { (1., 2.) } else { (3., 4.) };
         let x: _ = 1.;
+        const X: f32 = 1.;
     }
 }
 
@@ -59,6 +60,14 @@ mod nested_local {
             // Should NOT lint this because this literal is bound to `_` of outer `Local`.
             2.
         };
+
+        const X: f32 = {
+            // Should lint this because this literal is not bound to any types.
+            let y = 1.;
+
+            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
+            1.
+        };
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr
index f8b6c7746ed..5df2f642388 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr
@@ -61,79 +61,85 @@ LL |             _ => 1.,
    |                  ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:43:21
+  --> $DIR/default_numeric_fallback_f64.rs:44:21
    |
 LL |             let y = 1.;
    |                     ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:51:21
+  --> $DIR/default_numeric_fallback_f64.rs:52:21
    |
 LL |             let y = 1.;
    |                     ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:57:21
+  --> $DIR/default_numeric_fallback_f64.rs:58:21
    |
 LL |             let y = 1.;
    |                     ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:69:9
+  --> $DIR/default_numeric_fallback_f64.rs:66:21
+   |
+LL |             let y = 1.;
+   |                     ^^ help: consider adding suffix: `1.0_f64`
+
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback_f64.rs:78:9
    |
 LL |         1.
    |         ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:75:27
+  --> $DIR/default_numeric_fallback_f64.rs:84:27
    |
 LL |         let f = || -> _ { 1. };
    |                           ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:79:29
+  --> $DIR/default_numeric_fallback_f64.rs:88:29
    |
 LL |         let f = || -> f64 { 1. };
    |                             ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:93:21
+  --> $DIR/default_numeric_fallback_f64.rs:102:21
    |
 LL |         generic_arg(1.);
    |                     ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:96:32
+  --> $DIR/default_numeric_fallback_f64.rs:105:32
    |
 LL |         let x: _ = generic_arg(1.);
    |                                ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:114:28
+  --> $DIR/default_numeric_fallback_f64.rs:123:28
    |
 LL |         GenericStruct { x: 1. };
    |                            ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:117:36
+  --> $DIR/default_numeric_fallback_f64.rs:126:36
    |
 LL |         let _ = GenericStruct { x: 1. };
    |                                    ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:135:24
+  --> $DIR/default_numeric_fallback_f64.rs:144:24
    |
 LL |         GenericEnum::X(1.);
    |                        ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:155:23
+  --> $DIR/default_numeric_fallback_f64.rs:164:23
    |
 LL |         s.generic_arg(1.);
    |                       ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:162:21
+  --> $DIR/default_numeric_fallback_f64.rs:171:21
    |
 LL |             let x = 22.;
    |                     ^^^ help: consider adding suffix: `22.0_f64`
@@ -143,5 +149,5 @@ LL |         internal_macro!();
    |
    = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 23 previous errors
+error: aborting due to 24 previous errors
 
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
index 55451cf2f7d..3f4994f0453 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
@@ -33,6 +33,8 @@ mod basic_expr {
         let x: [i32; 3] = [1, 2, 3];
         let x: (i32, i32) = if true { (1, 2) } else { (3, 4) };
         let x: _ = 1;
+        let x: u64 = 1;
+        const CONST_X: i8 = 1;
     }
 }
 
@@ -59,6 +61,14 @@ mod nested_local {
             // Should NOT lint this because this literal is bound to `_` of outer `Local`.
             2
         };
+
+        const CONST_X: i32 = {
+            // Should lint this because this literal is not bound to any types.
+            let y = 1_i32;
+
+            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
+            1
+        };
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
index 62d72f2feba..2df0e09787f 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
@@ -33,6 +33,8 @@ mod basic_expr {
         let x: [i32; 3] = [1, 2, 3];
         let x: (i32, i32) = if true { (1, 2) } else { (3, 4) };
         let x: _ = 1;
+        let x: u64 = 1;
+        const CONST_X: i8 = 1;
     }
 }
 
@@ -59,6 +61,14 @@ mod nested_local {
             // Should NOT lint this because this literal is bound to `_` of outer `Local`.
             2
         };
+
+        const CONST_X: i32 = {
+            // Should lint this because this literal is not bound to any types.
+            let y = 1;
+
+            // Should NOT lint this because this literal is bound to `_` of outer `Local`.
+            1
+        };
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr
index f7c5e724c40..6f219c3fc2b 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr
@@ -73,79 +73,85 @@ LL |             _ => 2,
    |                  ^ help: consider adding suffix: `2_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:43:21
+  --> $DIR/default_numeric_fallback_i32.rs:45:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:51:21
+  --> $DIR/default_numeric_fallback_i32.rs:53:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:57:21
+  --> $DIR/default_numeric_fallback_i32.rs:59:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:69:9
+  --> $DIR/default_numeric_fallback_i32.rs:67:21
+   |
+LL |             let y = 1;
+   |                     ^ help: consider adding suffix: `1_i32`
+
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback_i32.rs:79:9
    |
 LL |         1
    |         ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:75:27
+  --> $DIR/default_numeric_fallback_i32.rs:85:27
    |
 LL |         let f = || -> _ { 1 };
    |                           ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:79:29
+  --> $DIR/default_numeric_fallback_i32.rs:89:29
    |
 LL |         let f = || -> i32 { 1 };
    |                             ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:93:21
+  --> $DIR/default_numeric_fallback_i32.rs:103:21
    |
 LL |         generic_arg(1);
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:96:32
+  --> $DIR/default_numeric_fallback_i32.rs:106:32
    |
 LL |         let x: _ = generic_arg(1);
    |                                ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:114:28
+  --> $DIR/default_numeric_fallback_i32.rs:124:28
    |
 LL |         GenericStruct { x: 1 };
    |                            ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:117:36
+  --> $DIR/default_numeric_fallback_i32.rs:127:36
    |
 LL |         let _ = GenericStruct { x: 1 };
    |                                    ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:135:24
+  --> $DIR/default_numeric_fallback_i32.rs:145:24
    |
 LL |         GenericEnum::X(1);
    |                        ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:155:23
+  --> $DIR/default_numeric_fallback_i32.rs:165:23
    |
 LL |         s.generic_arg(1);
    |                       ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:162:21
+  --> $DIR/default_numeric_fallback_i32.rs:172:21
    |
 LL |             let x = 22;
    |                     ^^ help: consider adding suffix: `22_i32`
@@ -155,5 +161,5 @@ LL |         internal_macro!();
    |
    = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 25 previous errors
+error: aborting due to 26 previous errors
 
diff --git a/src/tools/clippy/tests/ui/err_expect.fixed b/src/tools/clippy/tests/ui/err_expect.fixed
index 7e18d70bae4..3bac738acd6 100644
--- a/src/tools/clippy/tests/ui/err_expect.fixed
+++ b/src/tools/clippy/tests/ui/err_expect.fixed
@@ -1,5 +1,8 @@
 // run-rustfix
 
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
+
 struct MyTypeNonDebug;
 
 #[derive(Debug)]
@@ -12,3 +15,17 @@ fn main() {
     let test_non_debug: Result<MyTypeNonDebug, u32> = Ok(MyTypeNonDebug);
     test_non_debug.err().expect("Testing non debug type");
 }
+
+fn msrv_1_16() {
+    #![clippy::msrv = "1.16"]
+
+    let x: Result<u32, &str> = Ok(16);
+    x.err().expect("16");
+}
+
+fn msrv_1_17() {
+    #![clippy::msrv = "1.17"]
+
+    let x: Result<u32, &str> = Ok(17);
+    x.expect_err("17");
+}
diff --git a/src/tools/clippy/tests/ui/err_expect.rs b/src/tools/clippy/tests/ui/err_expect.rs
index bf8c3c9fb8c..6e7c47d9ad3 100644
--- a/src/tools/clippy/tests/ui/err_expect.rs
+++ b/src/tools/clippy/tests/ui/err_expect.rs
@@ -1,5 +1,8 @@
 // run-rustfix
 
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
+
 struct MyTypeNonDebug;
 
 #[derive(Debug)]
@@ -12,3 +15,17 @@ fn main() {
     let test_non_debug: Result<MyTypeNonDebug, u32> = Ok(MyTypeNonDebug);
     test_non_debug.err().expect("Testing non debug type");
 }
+
+fn msrv_1_16() {
+    #![clippy::msrv = "1.16"]
+
+    let x: Result<u32, &str> = Ok(16);
+    x.err().expect("16");
+}
+
+fn msrv_1_17() {
+    #![clippy::msrv = "1.17"]
+
+    let x: Result<u32, &str> = Ok(17);
+    x.err().expect("17");
+}
diff --git a/src/tools/clippy/tests/ui/err_expect.stderr b/src/tools/clippy/tests/ui/err_expect.stderr
index ffd97e00a5c..91a6cf8de65 100644
--- a/src/tools/clippy/tests/ui/err_expect.stderr
+++ b/src/tools/clippy/tests/ui/err_expect.stderr
@@ -1,10 +1,16 @@
 error: called `.err().expect()` on a `Result` value
-  --> $DIR/err_expect.rs:10:16
+  --> $DIR/err_expect.rs:13:16
    |
 LL |     test_debug.err().expect("Testing debug type");
    |                ^^^^^^^^^^^^ help: try: `expect_err`
    |
    = note: `-D clippy::err-expect` implied by `-D warnings`
 
-error: aborting due to previous error
+error: called `.err().expect()` on a `Result` value
+  --> $DIR/err_expect.rs:30:7
+   |
+LL |     x.err().expect("17");
+   |       ^^^^^^^^^^^^ help: try: `expect_err`
+
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed b/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed
index c3992d7e92c..41828ddd7ac 100644
--- a/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed
@@ -1,6 +1,8 @@
 // run-rustfix
 
+#![feature(custom_inner_attributes)]
 #![warn(clippy::all, clippy::pedantic)]
+#![allow(unused)]
 
 fn main() {
     let a = ["1", "lol", "3", "NaN", "5"];
@@ -8,3 +10,17 @@ fn main() {
     let element: Option<i32> = a.iter().find_map(|s| s.parse().ok());
     assert_eq!(element, Some(1));
 }
+
+fn msrv_1_29() {
+    #![clippy::msrv = "1.29"]
+
+    let a = ["1", "lol", "3", "NaN", "5"];
+    let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+}
+
+fn msrv_1_30() {
+    #![clippy::msrv = "1.30"]
+
+    let a = ["1", "lol", "3", "NaN", "5"];
+    let _: Option<i32> = a.iter().find_map(|s| s.parse().ok());
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.rs b/src/tools/clippy/tests/ui/filter_map_next_fixable.rs
index 447219a9683..be492a81b45 100644
--- a/src/tools/clippy/tests/ui/filter_map_next_fixable.rs
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.rs
@@ -1,6 +1,8 @@
 // run-rustfix
 
+#![feature(custom_inner_attributes)]
 #![warn(clippy::all, clippy::pedantic)]
+#![allow(unused)]
 
 fn main() {
     let a = ["1", "lol", "3", "NaN", "5"];
@@ -8,3 +10,17 @@ fn main() {
     let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
     assert_eq!(element, Some(1));
 }
+
+fn msrv_1_29() {
+    #![clippy::msrv = "1.29"]
+
+    let a = ["1", "lol", "3", "NaN", "5"];
+    let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+}
+
+fn msrv_1_30() {
+    #![clippy::msrv = "1.30"]
+
+    let a = ["1", "lol", "3", "NaN", "5"];
+    let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
index 3bb062ffd7a..e789efeabd5 100644
--- a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
@@ -1,10 +1,16 @@
 error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead
-  --> $DIR/filter_map_next_fixable.rs:8:32
+  --> $DIR/filter_map_next_fixable.rs:10:32
    |
 LL |     let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())`
    |
    = note: `-D clippy::filter-map-next` implied by `-D warnings`
 
-error: aborting due to previous error
+error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead
+  --> $DIR/filter_map_next_fixable.rs:25:26
+   |
+LL |     let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())`
+
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/format_args.fixed b/src/tools/clippy/tests/ui/format_args.fixed
index 24cf0847dd5..825e122be5a 100644
--- a/src/tools/clippy/tests/ui/format_args.fixed
+++ b/src/tools/clippy/tests/ui/format_args.fixed
@@ -3,6 +3,7 @@
 #![allow(unused)]
 #![allow(
     clippy::assertions_on_constants,
+    clippy::double_parens,
     clippy::eq_op,
     clippy::print_literal,
     clippy::uninlined_format_args
@@ -114,6 +115,8 @@ fn main() {
     println!("error: something failed at {}", my_other_macro!());
     // https://github.com/rust-lang/rust-clippy/issues/7903
     println!("{foo}{foo:?}", foo = "foo".to_string());
+    print!("{}", (Location::caller()));
+    print!("{}", ((Location::caller())));
 }
 
 fn issue8643(vendor_id: usize, product_id: usize, name: &str) {
diff --git a/src/tools/clippy/tests/ui/format_args.rs b/src/tools/clippy/tests/ui/format_args.rs
index 753babf0afd..a41e53389e5 100644
--- a/src/tools/clippy/tests/ui/format_args.rs
+++ b/src/tools/clippy/tests/ui/format_args.rs
@@ -3,6 +3,7 @@
 #![allow(unused)]
 #![allow(
     clippy::assertions_on_constants,
+    clippy::double_parens,
     clippy::eq_op,
     clippy::print_literal,
     clippy::uninlined_format_args
@@ -114,6 +115,8 @@ fn main() {
     println!("error: something failed at {}", my_other_macro!());
     // https://github.com/rust-lang/rust-clippy/issues/7903
     println!("{foo}{foo:?}", foo = "foo".to_string());
+    print!("{}", (Location::caller().to_string()));
+    print!("{}", ((Location::caller()).to_string()));
 }
 
 fn issue8643(vendor_id: usize, product_id: usize, name: &str) {
diff --git a/src/tools/clippy/tests/ui/format_args.stderr b/src/tools/clippy/tests/ui/format_args.stderr
index 68b0bb9e089..f1832b97019 100644
--- a/src/tools/clippy/tests/ui/format_args.stderr
+++ b/src/tools/clippy/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:77:72
    |
 LL |     let _ = format!("error: something failed at {}", Location::caller().to_string());
    |                                                                        ^^^^^^^^^^^^ help: remove this
@@ -7,136 +7,148 @@ 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:81: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:86: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:88: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:89: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:90: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:91: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:92: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:93: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:94: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:95: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:96: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:97: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:98: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:99: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:100: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:101: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:103: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:104: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:105: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:106:52
    |
 LL |     println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
    |                                                    ^^^^^^^^^^^^ help: remove this
 
+error: `to_string` applied to a type that implements `Display` in `print!` args
+  --> $DIR/format_args.rs:118:37
+   |
+LL |     print!("{}", (Location::caller().to_string()));
+   |                                     ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `print!` args
+  --> $DIR/format_args.rs:119:39
+   |
+LL |     print!("{}", ((Location::caller()).to_string()));
+   |                                       ^^^^^^^^^^^^ help: remove this
+
 error: `to_string` applied to a type that implements `Display` in `format!` args
-  --> $DIR/format_args.rs:144:38
+  --> $DIR/format_args.rs:147: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:158:24
+  --> $DIR/format_args.rs:161:24
    |
 LL |         println!("{}", original[..10].to_string());
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use this: `&original[..10]`
 
-error: aborting due to 23 previous errors
+error: aborting due to 25 previous errors
 
diff --git a/src/tools/clippy/tests/ui/from_over_into.fixed b/src/tools/clippy/tests/ui/from_over_into.fixed
new file mode 100644
index 00000000000..1cf49ca45f4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/from_over_into.fixed
@@ -0,0 +1,87 @@
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::from_over_into)]
+#![allow(unused)]
+
+// this should throw an error
+struct StringWrapper(String);
+
+impl From<String> for StringWrapper {
+    fn from(val: String) -> Self {
+        StringWrapper(val)
+    }
+}
+
+struct SelfType(String);
+
+impl From<String> for SelfType {
+    fn from(val: String) -> Self {
+        SelfType(String::new())
+    }
+}
+
+#[derive(Default)]
+struct X;
+
+impl X {
+    const FOO: &'static str = "a";
+}
+
+struct SelfKeywords;
+
+impl From<X> for SelfKeywords {
+    fn from(val: X) -> Self {
+        let _ = X::default();
+        let _ = X::FOO;
+        let _: X = val;
+
+        SelfKeywords
+    }
+}
+
+struct ExplicitPaths(bool);
+
+impl core::convert::From<crate::ExplicitPaths> for bool {
+    fn from(mut val: crate::ExplicitPaths) -> Self {
+        let in_closure = || val.0;
+
+        val.0 = false;
+        val.0
+    }
+}
+
+// this is fine
+struct A(String);
+
+impl From<String> for A {
+    fn from(s: String) -> A {
+        A(s)
+    }
+}
+
+fn msrv_1_40() {
+    #![clippy::msrv = "1.40"]
+
+    struct FromOverInto<T>(Vec<T>);
+
+    impl<T> Into<FromOverInto<T>> for Vec<T> {
+        fn into(self) -> FromOverInto<T> {
+            FromOverInto(self)
+        }
+    }
+}
+
+fn msrv_1_41() {
+    #![clippy::msrv = "1.41"]
+
+    struct FromOverInto<T>(Vec<T>);
+
+    impl<T> From<Vec<T>> for FromOverInto<T> {
+        fn from(val: Vec<T>) -> Self {
+            FromOverInto(val)
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/from_over_into.rs b/src/tools/clippy/tests/ui/from_over_into.rs
index 292d0924fb1..d30f3c3fc92 100644
--- a/src/tools/clippy/tests/ui/from_over_into.rs
+++ b/src/tools/clippy/tests/ui/from_over_into.rs
@@ -1,4 +1,8 @@
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
 #![warn(clippy::from_over_into)]
+#![allow(unused)]
 
 // this should throw an error
 struct StringWrapper(String);
@@ -9,6 +13,44 @@ impl Into<StringWrapper> for String {
     }
 }
 
+struct SelfType(String);
+
+impl Into<SelfType> for String {
+    fn into(self) -> SelfType {
+        SelfType(Self::new())
+    }
+}
+
+#[derive(Default)]
+struct X;
+
+impl X {
+    const FOO: &'static str = "a";
+}
+
+struct SelfKeywords;
+
+impl Into<SelfKeywords> for X {
+    fn into(self) -> SelfKeywords {
+        let _ = Self::default();
+        let _ = Self::FOO;
+        let _: Self = self;
+
+        SelfKeywords
+    }
+}
+
+struct ExplicitPaths(bool);
+
+impl core::convert::Into<bool> for crate::ExplicitPaths {
+    fn into(mut self) -> bool {
+        let in_closure = || self.0;
+
+        self.0 = false;
+        self.0
+    }
+}
+
 // this is fine
 struct A(String);
 
@@ -18,4 +60,28 @@ impl From<String> for A {
     }
 }
 
+fn msrv_1_40() {
+    #![clippy::msrv = "1.40"]
+
+    struct FromOverInto<T>(Vec<T>);
+
+    impl<T> Into<FromOverInto<T>> for Vec<T> {
+        fn into(self) -> FromOverInto<T> {
+            FromOverInto(self)
+        }
+    }
+}
+
+fn msrv_1_41() {
+    #![clippy::msrv = "1.41"]
+
+    struct FromOverInto<T>(Vec<T>);
+
+    impl<T> Into<FromOverInto<T>> for Vec<T> {
+        fn into(self) -> FromOverInto<T> {
+            FromOverInto(self)
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr
index 469adadd219..9c2a7c04c36 100644
--- a/src/tools/clippy/tests/ui/from_over_into.stderr
+++ b/src/tools/clippy/tests/ui/from_over_into.stderr
@@ -1,11 +1,75 @@
 error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
-  --> $DIR/from_over_into.rs:6:1
+  --> $DIR/from_over_into.rs:10:1
    |
 LL | impl Into<StringWrapper> for String {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider to implement `From<std::string::String>` instead
    = note: `-D clippy::from-over-into` implied by `-D warnings`
+help: replace the `Into` implentation with `From<std::string::String>`
+   |
+LL ~ impl From<String> for StringWrapper {
+LL ~     fn from(val: String) -> Self {
+LL ~         StringWrapper(val)
+   |
+
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+  --> $DIR/from_over_into.rs:18:1
+   |
+LL | impl Into<SelfType> for String {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace the `Into` implentation with `From<std::string::String>`
+   |
+LL ~ impl From<String> for SelfType {
+LL ~     fn from(val: String) -> Self {
+LL ~         SelfType(String::new())
+   |
+
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+  --> $DIR/from_over_into.rs:33:1
+   |
+LL | impl Into<SelfKeywords> for X {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace the `Into` implentation with `From<X>`
+   |
+LL ~ impl From<X> for SelfKeywords {
+LL ~     fn from(val: X) -> Self {
+LL ~         let _ = X::default();
+LL ~         let _ = X::FOO;
+LL ~         let _: X = val;
+   |
+
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+  --> $DIR/from_over_into.rs:45:1
+   |
+LL | impl core::convert::Into<bool> for crate::ExplicitPaths {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
+           https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
+help: replace the `Into` implentation with `From<ExplicitPaths>`
+   |
+LL ~ impl core::convert::From<crate::ExplicitPaths> for bool {
+LL ~     fn from(mut val: crate::ExplicitPaths) -> Self {
+LL ~         let in_closure = || val.0;
+LL | 
+LL ~         val.0 = false;
+LL ~         val.0
+   |
+
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+  --> $DIR/from_over_into.rs:80:5
+   |
+LL |     impl<T> Into<FromOverInto<T>> for Vec<T> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace the `Into` implentation with `From<std::vec::Vec<T>>`
+   |
+LL ~     impl<T> From<Vec<T>> for FromOverInto<T> {
+LL ~         fn from(val: Vec<T>) -> Self {
+LL ~             FromOverInto(val)
+   |
 
-error: aborting due to previous error
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.rs b/src/tools/clippy/tests/ui/from_over_into_unfixable.rs
new file mode 100644
index 00000000000..3b280b7488a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.rs
@@ -0,0 +1,35 @@
+#![warn(clippy::from_over_into)]
+
+struct InMacro(String);
+
+macro_rules! in_macro {
+    ($e:ident) => {
+        $e
+    };
+}
+
+impl Into<InMacro> for String {
+    fn into(self) -> InMacro {
+        InMacro(in_macro!(self))
+    }
+}
+
+struct WeirdUpperSelf;
+
+impl Into<WeirdUpperSelf> for &'static [u8] {
+    fn into(self) -> WeirdUpperSelf {
+        let _ = Self::default();
+        WeirdUpperSelf
+    }
+}
+
+struct ContainsVal;
+
+impl Into<u8> for ContainsVal {
+    fn into(self) -> u8 {
+        let val = 1;
+        val + 1
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr
new file mode 100644
index 00000000000..6f6ce351921
--- /dev/null
+++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr
@@ -0,0 +1,29 @@
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+  --> $DIR/from_over_into_unfixable.rs:11:1
+   |
+LL | impl Into<InMacro> for String {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: replace the `Into` implentation with `From<std::string::String>`
+   = note: `-D clippy::from-over-into` implied by `-D warnings`
+
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+  --> $DIR/from_over_into_unfixable.rs:19:1
+   |
+LL | impl Into<WeirdUpperSelf> for &'static [u8] {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: replace the `Into` implentation with `From<&'static [u8]>`
+
+error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true
+  --> $DIR/from_over_into_unfixable.rs:28:1
+   |
+LL | impl Into<u8> for ContainsVal {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see
+           https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence
+   = help: replace the `Into` implentation with `From<ContainsVal>`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed b/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed
index e6f57e9267e..93df81b1a7f 100644
--- a/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed
+++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed
@@ -2,6 +2,21 @@
 #![allow(unused_assignments, unused_mut, clippy::assign_op_pattern)]
 #![warn(clippy::implicit_saturating_sub)]
 
+use std::cmp::PartialEq;
+use std::ops::SubAssign;
+// Mock type
+struct Mock;
+
+impl PartialEq<u32> for Mock {
+    fn eq(&self, _: &u32) -> bool {
+        true
+    }
+}
+
+impl SubAssign<u32> for Mock {
+    fn sub_assign(&mut self, _: u32) {}
+}
+
 fn main() {
     // Tests for unsigned integers
 
@@ -165,4 +180,39 @@ fn main() {
     } else {
         println!("side effect");
     }
+
+    // Extended tests
+    let mut m = Mock;
+    let mut u_32 = 3000;
+    let a = 200;
+    let mut _b = 8;
+
+    if m != 0 {
+        m -= 1;
+    }
+
+    if a > 0 {
+        _b -= 1;
+    }
+
+    if 0 > a {
+        _b -= 1;
+    }
+
+    if u_32 > 0 {
+        u_32 -= 1;
+    } else {
+        println!("don't lint this");
+    }
+
+    if u_32 > 0 {
+        println!("don't lint this");
+        u_32 -= 1;
+    }
+
+    if u_32 > 42 {
+        println!("brace yourself!");
+    } else if u_32 > 0 {
+        u_32 -= 1;
+    }
 }
diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs
index 8bb28d149c6..8340bc8264d 100644
--- a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs
+++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs
@@ -2,6 +2,21 @@
 #![allow(unused_assignments, unused_mut, clippy::assign_op_pattern)]
 #![warn(clippy::implicit_saturating_sub)]
 
+use std::cmp::PartialEq;
+use std::ops::SubAssign;
+// Mock type
+struct Mock;
+
+impl PartialEq<u32> for Mock {
+    fn eq(&self, _: &u32) -> bool {
+        true
+    }
+}
+
+impl SubAssign<u32> for Mock {
+    fn sub_assign(&mut self, _: u32) {}
+}
+
 fn main() {
     // Tests for unsigned integers
 
@@ -211,4 +226,39 @@ fn main() {
     } else {
         println!("side effect");
     }
+
+    // Extended tests
+    let mut m = Mock;
+    let mut u_32 = 3000;
+    let a = 200;
+    let mut _b = 8;
+
+    if m != 0 {
+        m -= 1;
+    }
+
+    if a > 0 {
+        _b -= 1;
+    }
+
+    if 0 > a {
+        _b -= 1;
+    }
+
+    if u_32 > 0 {
+        u_32 -= 1;
+    } else {
+        println!("don't lint this");
+    }
+
+    if u_32 > 0 {
+        println!("don't lint this");
+        u_32 -= 1;
+    }
+
+    if u_32 > 42 {
+        println!("brace yourself!");
+    } else if u_32 > 0 {
+        u_32 -= 1;
+    }
 }
diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr b/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr
index 5bb9a606422..5e589d931e4 100644
--- a/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr
+++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr
@@ -1,5 +1,5 @@
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:13:5
+  --> $DIR/implicit_saturating_sub.rs:28:5
    |
 LL | /     if u_8 > 0 {
 LL | |         u_8 = u_8 - 1;
@@ -9,7 +9,7 @@ LL | |     }
    = note: `-D clippy::implicit-saturating-sub` implied by `-D warnings`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:20:13
+  --> $DIR/implicit_saturating_sub.rs:35:13
    |
 LL | /             if u_8 > 0 {
 LL | |                 u_8 -= 1;
@@ -17,7 +17,7 @@ LL | |             }
    | |_____________^ help: try: `u_8 = u_8.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:34:5
+  --> $DIR/implicit_saturating_sub.rs:49:5
    |
 LL | /     if u_16 > 0 {
 LL | |         u_16 -= 1;
@@ -25,7 +25,7 @@ LL | |     }
    | |_____^ help: try: `u_16 = u_16.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:44:5
+  --> $DIR/implicit_saturating_sub.rs:59:5
    |
 LL | /     if u_32 != 0 {
 LL | |         u_32 -= 1;
@@ -33,7 +33,7 @@ LL | |     }
    | |_____^ help: try: `u_32 = u_32.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:65:5
+  --> $DIR/implicit_saturating_sub.rs:80:5
    |
 LL | /     if u_64 > 0 {
 LL | |         u_64 -= 1;
@@ -41,7 +41,7 @@ LL | |     }
    | |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:70:5
+  --> $DIR/implicit_saturating_sub.rs:85:5
    |
 LL | /     if 0 < u_64 {
 LL | |         u_64 -= 1;
@@ -49,7 +49,7 @@ LL | |     }
    | |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:75:5
+  --> $DIR/implicit_saturating_sub.rs:90:5
    |
 LL | /     if 0 != u_64 {
 LL | |         u_64 -= 1;
@@ -57,7 +57,7 @@ LL | |     }
    | |_____^ help: try: `u_64 = u_64.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:96:5
+  --> $DIR/implicit_saturating_sub.rs:111:5
    |
 LL | /     if u_usize > 0 {
 LL | |         u_usize -= 1;
@@ -65,7 +65,7 @@ LL | |     }
    | |_____^ help: try: `u_usize = u_usize.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:108:5
+  --> $DIR/implicit_saturating_sub.rs:123:5
    |
 LL | /     if i_8 > i8::MIN {
 LL | |         i_8 -= 1;
@@ -73,7 +73,7 @@ LL | |     }
    | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:113:5
+  --> $DIR/implicit_saturating_sub.rs:128:5
    |
 LL | /     if i_8 > i8::MIN {
 LL | |         i_8 -= 1;
@@ -81,7 +81,7 @@ LL | |     }
    | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:118:5
+  --> $DIR/implicit_saturating_sub.rs:133:5
    |
 LL | /     if i_8 != i8::MIN {
 LL | |         i_8 -= 1;
@@ -89,7 +89,7 @@ LL | |     }
    | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:123:5
+  --> $DIR/implicit_saturating_sub.rs:138:5
    |
 LL | /     if i_8 != i8::MIN {
 LL | |         i_8 -= 1;
@@ -97,7 +97,7 @@ LL | |     }
    | |_____^ help: try: `i_8 = i_8.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:133:5
+  --> $DIR/implicit_saturating_sub.rs:148:5
    |
 LL | /     if i_16 > i16::MIN {
 LL | |         i_16 -= 1;
@@ -105,7 +105,7 @@ LL | |     }
    | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:138:5
+  --> $DIR/implicit_saturating_sub.rs:153:5
    |
 LL | /     if i_16 > i16::MIN {
 LL | |         i_16 -= 1;
@@ -113,7 +113,7 @@ LL | |     }
    | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:143:5
+  --> $DIR/implicit_saturating_sub.rs:158:5
    |
 LL | /     if i_16 != i16::MIN {
 LL | |         i_16 -= 1;
@@ -121,7 +121,7 @@ LL | |     }
    | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:148:5
+  --> $DIR/implicit_saturating_sub.rs:163:5
    |
 LL | /     if i_16 != i16::MIN {
 LL | |         i_16 -= 1;
@@ -129,7 +129,7 @@ LL | |     }
    | |_____^ help: try: `i_16 = i_16.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:158:5
+  --> $DIR/implicit_saturating_sub.rs:173:5
    |
 LL | /     if i_32 > i32::MIN {
 LL | |         i_32 -= 1;
@@ -137,7 +137,7 @@ LL | |     }
    | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:163:5
+  --> $DIR/implicit_saturating_sub.rs:178:5
    |
 LL | /     if i_32 > i32::MIN {
 LL | |         i_32 -= 1;
@@ -145,7 +145,7 @@ LL | |     }
    | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:168:5
+  --> $DIR/implicit_saturating_sub.rs:183:5
    |
 LL | /     if i_32 != i32::MIN {
 LL | |         i_32 -= 1;
@@ -153,7 +153,7 @@ LL | |     }
    | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:173:5
+  --> $DIR/implicit_saturating_sub.rs:188:5
    |
 LL | /     if i_32 != i32::MIN {
 LL | |         i_32 -= 1;
@@ -161,7 +161,7 @@ LL | |     }
    | |_____^ help: try: `i_32 = i_32.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:183:5
+  --> $DIR/implicit_saturating_sub.rs:198:5
    |
 LL | /     if i64::MIN < i_64 {
 LL | |         i_64 -= 1;
@@ -169,7 +169,7 @@ LL | |     }
    | |_____^ help: try: `i_64 = i_64.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:188:5
+  --> $DIR/implicit_saturating_sub.rs:203:5
    |
 LL | /     if i64::MIN != i_64 {
 LL | |         i_64 -= 1;
@@ -177,7 +177,7 @@ LL | |     }
    | |_____^ help: try: `i_64 = i_64.saturating_sub(1);`
 
 error: implicitly performing saturating subtraction
-  --> $DIR/implicit_saturating_sub.rs:193:5
+  --> $DIR/implicit_saturating_sub.rs:208:5
    |
 LL | /     if i64::MIN < i_64 {
 LL | |         i_64 -= 1;
diff --git a/src/tools/clippy/tests/ui/literals.rs b/src/tools/clippy/tests/ui/literals.rs
index 0cadd5a3da1..1a646e49ce3 100644
--- a/src/tools/clippy/tests/ui/literals.rs
+++ b/src/tools/clippy/tests/ui/literals.rs
@@ -40,3 +40,10 @@ fn main() {
     let ok26 = 0x6_A0_BF;
     let ok27 = 0b1_0010_0101;
 }
+
+fn issue9651() {
+    // lint but octal form is not possible here
+    let _ = 08;
+    let _ = 09;
+    let _ = 089;
+}
diff --git a/src/tools/clippy/tests/ui/literals.stderr b/src/tools/clippy/tests/ui/literals.stderr
index 365b2407473..603d47bacca 100644
--- a/src/tools/clippy/tests/ui/literals.stderr
+++ b/src/tools/clippy/tests/ui/literals.stderr
@@ -135,5 +135,38 @@ error: digits of hex or binary literal not grouped by four
 LL |     let fail25 = 0b01_100_101;
    |                  ^^^^^^^^^^^^ help: consider: `0b0110_0101`
 
-error: aborting due to 18 previous errors
+error: this is a decimal constant
+  --> $DIR/literals.rs:46:13
+   |
+LL |     let _ = 08;
+   |             ^^
+   |
+help: if you mean to use a decimal constant, remove the `0` to avoid confusion
+   |
+LL |     let _ = 8;
+   |             ~
+
+error: this is a decimal constant
+  --> $DIR/literals.rs:47:13
+   |
+LL |     let _ = 09;
+   |             ^^
+   |
+help: if you mean to use a decimal constant, remove the `0` to avoid confusion
+   |
+LL |     let _ = 9;
+   |             ~
+
+error: this is a decimal constant
+  --> $DIR/literals.rs:48:13
+   |
+LL |     let _ = 089;
+   |             ^^^
+   |
+help: if you mean to use a decimal constant, remove the `0` to avoid confusion
+   |
+LL |     let _ = 89;
+   |             ~~
+
+error: aborting due to 21 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
index 26e3b8f63e7..c9a819ba535 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
@@ -1,6 +1,6 @@
 // revisions: edition2018 edition2021
-// [edition2018] edition:2018
-// [edition2021] edition:2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
 // run-rustfix
 
 #![warn(clippy::manual_assert)]
@@ -29,7 +29,9 @@ fn main() {
         panic!("qaqaq{:?}", a);
     }
     assert!(a.is_empty(), "qaqaq{:?}", a);
-    assert!(a.is_empty(), "qwqwq");
+    if !a.is_empty() {
+        panic!("qwqwq");
+    }
     if a.len() == 3 {
         println!("qwq");
         println!("qwq");
@@ -44,21 +46,32 @@ fn main() {
         println!("qwq");
     }
     let b = vec![1, 2, 3];
-    assert!(!b.is_empty(), "panic1");
-    assert!(!(b.is_empty() && a.is_empty()), "panic2");
-    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
-    assert!(!(b.is_empty() || a.is_empty()), "panic4");
-    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+    if b.is_empty() {
+        panic!("panic1");
+    }
+    if b.is_empty() && a.is_empty() {
+        panic!("panic2");
+    }
+    if a.is_empty() && !b.is_empty() {
+        panic!("panic3");
+    }
+    if b.is_empty() || a.is_empty() {
+        panic!("panic4");
+    }
+    if a.is_empty() || !b.is_empty() {
+        panic!("panic5");
+    }
     assert!(!a.is_empty(), "with expansion {}", one!());
 }
 
 fn issue7730(a: u8) {
     // Suggestion should preserve comment
-    // comment
-/* this is a
+    if a > 2 {
+        // comment
+        /* this is a
         multiline
         comment */
-/// Doc comment
-// comment after `panic!`
-assert!(!(a > 2), "panic with comment");
+        /// Doc comment
+        panic!("panic with comment") // comment after `panic!`
+    }
 }
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
index 237638ee134..1f2e1e3087b 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
@@ -9,54 +9,6 @@ LL | |     }
    = note: `-D clippy::manual-assert` implied by `-D warnings`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:34:5
-   |
-LL | /     if !a.is_empty() {
-LL | |         panic!("qwqwq");
-LL | |     }
-   | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");`
-
-error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:51:5
-   |
-LL | /     if b.is_empty() {
-LL | |         panic!("panic1");
-LL | |     }
-   | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");`
-
-error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:54:5
-   |
-LL | /     if b.is_empty() && a.is_empty() {
-LL | |         panic!("panic2");
-LL | |     }
-   | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
-
-error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:57:5
-   |
-LL | /     if a.is_empty() && !b.is_empty() {
-LL | |         panic!("panic3");
-LL | |     }
-   | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
-
-error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:60:5
-   |
-LL | /     if b.is_empty() || a.is_empty() {
-LL | |         panic!("panic4");
-LL | |     }
-   | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
-
-error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:63:5
-   |
-LL | /     if a.is_empty() || !b.is_empty() {
-LL | |         panic!("panic5");
-LL | |     }
-   | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
-
-error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:66:5
    |
 LL | /     if a.is_empty() {
@@ -64,22 +16,5 @@ LL | |         panic!("with expansion {}", one!())
 LL | |     }
    | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
 
-error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:73:5
-   |
-LL | /     if a > 2 {
-LL | |         // comment
-LL | |         /* this is a
-LL | |         multiline
-...  |
-LL | |         panic!("panic with comment") // comment after `panic!`
-LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(a > 2), "panic with comment");
-   |
-
-error: aborting due to 9 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
index 26e3b8f63e7..2f62de51cad 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
@@ -1,6 +1,6 @@
 // revisions: edition2018 edition2021
-// [edition2018] edition:2018
-// [edition2021] edition:2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
 // run-rustfix
 
 #![warn(clippy::manual_assert)]
diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs
index 8c37753071d..6a4cc2468d4 100644
--- a/src/tools/clippy/tests/ui/manual_assert.rs
+++ b/src/tools/clippy/tests/ui/manual_assert.rs
@@ -1,6 +1,6 @@
 // revisions: edition2018 edition2021
-// [edition2018] edition:2018
-// [edition2021] edition:2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
 // run-rustfix
 
 #![warn(clippy::manual_assert)]
diff --git a/src/tools/clippy/tests/ui/manual_clamp.rs b/src/tools/clippy/tests/ui/manual_clamp.rs
index 54fd888af99..331fd29b74e 100644
--- a/src/tools/clippy/tests/ui/manual_clamp.rs
+++ b/src/tools/clippy/tests/ui/manual_clamp.rs
@@ -1,3 +1,4 @@
+#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_clamp)]
 #![allow(
     unused,
@@ -302,3 +303,29 @@ fn dont_tell_me_what_to_do() {
 fn cmp_min_max(input: i32) -> i32 {
     input * 3
 }
+
+fn msrv_1_49() {
+    #![clippy::msrv = "1.49"]
+
+    let (input, min, max) = (0, -1, 2);
+    let _ = if input < min {
+        min
+    } else if input > max {
+        max
+    } else {
+        input
+    };
+}
+
+fn msrv_1_50() {
+    #![clippy::msrv = "1.50"]
+
+    let (input, min, max) = (0, -1, 2);
+    let _ = if input < min {
+        min
+    } else if input > max {
+        max
+    } else {
+        input
+    };
+}
diff --git a/src/tools/clippy/tests/ui/manual_clamp.stderr b/src/tools/clippy/tests/ui/manual_clamp.stderr
index 0604f8606c3..70abe28091c 100644
--- a/src/tools/clippy/tests/ui/manual_clamp.stderr
+++ b/src/tools/clippy/tests/ui/manual_clamp.stderr
@@ -1,5 +1,5 @@
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:76:5
+  --> $DIR/manual_clamp.rs:77:5
    |
 LL | /     if x9 < min {
 LL | |         x9 = min;
@@ -13,7 +13,7 @@ LL | |     }
    = note: `-D clippy::manual-clamp` implied by `-D warnings`
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:91:5
+  --> $DIR/manual_clamp.rs:92:5
    |
 LL | /     if x11 > max {
 LL | |         x11 = max;
@@ -26,7 +26,7 @@ LL | |     }
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:99:5
+  --> $DIR/manual_clamp.rs:100:5
    |
 LL | /     if min > x12 {
 LL | |         x12 = min;
@@ -39,7 +39,7 @@ LL | |     }
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:107:5
+  --> $DIR/manual_clamp.rs:108:5
    |
 LL | /     if max < x13 {
 LL | |         x13 = max;
@@ -52,7 +52,7 @@ LL | |     }
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:161:5
+  --> $DIR/manual_clamp.rs:162:5
    |
 LL | /     if max < x33 {
 LL | |         x33 = max;
@@ -65,7 +65,7 @@ LL | |     }
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:21:14
+  --> $DIR/manual_clamp.rs:22:14
    |
 LL |       let x0 = if max < input {
    |  ______________^
@@ -80,7 +80,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:29:14
+  --> $DIR/manual_clamp.rs:30:14
    |
 LL |       let x1 = if input > max {
    |  ______________^
@@ -95,7 +95,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:37:14
+  --> $DIR/manual_clamp.rs:38:14
    |
 LL |       let x2 = if input < min {
    |  ______________^
@@ -110,7 +110,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:45:14
+  --> $DIR/manual_clamp.rs:46:14
    |
 LL |       let x3 = if min > input {
    |  ______________^
@@ -125,7 +125,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:53:14
+  --> $DIR/manual_clamp.rs:54:14
    |
 LL |     let x4 = input.max(min).min(max);
    |              ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(min, max)`
@@ -133,7 +133,7 @@ LL |     let x4 = input.max(min).min(max);
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:55:14
+  --> $DIR/manual_clamp.rs:56:14
    |
 LL |     let x5 = input.min(max).max(min);
    |              ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(min, max)`
@@ -141,7 +141,7 @@ LL |     let x5 = input.min(max).max(min);
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:57:14
+  --> $DIR/manual_clamp.rs:58:14
    |
 LL |       let x6 = match input {
    |  ______________^
@@ -154,7 +154,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:63:14
+  --> $DIR/manual_clamp.rs:64:14
    |
 LL |       let x7 = match input {
    |  ______________^
@@ -167,7 +167,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:69:14
+  --> $DIR/manual_clamp.rs:70:14
    |
 LL |       let x8 = match input {
    |  ______________^
@@ -180,7 +180,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:83:15
+  --> $DIR/manual_clamp.rs:84:15
    |
 LL |       let x10 = match input {
    |  _______________^
@@ -193,7 +193,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:114:15
+  --> $DIR/manual_clamp.rs:115:15
    |
 LL |       let x14 = if input > CONST_MAX {
    |  _______________^
@@ -208,7 +208,7 @@ LL | |     };
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:123:19
+  --> $DIR/manual_clamp.rs:124:19
    |
 LL |           let x15 = if input > max {
    |  ___________________^
@@ -224,7 +224,7 @@ LL | |         };
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:134:19
+  --> $DIR/manual_clamp.rs:135:19
    |
 LL |         let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -232,7 +232,7 @@ LL |         let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN);
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:135:19
+  --> $DIR/manual_clamp.rs:136:19
    |
 LL |         let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -240,7 +240,7 @@ LL |         let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX);
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:136:19
+  --> $DIR/manual_clamp.rs:137:19
    |
 LL |         let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -248,7 +248,7 @@ LL |         let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX));
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:137:19
+  --> $DIR/manual_clamp.rs:138:19
    |
 LL |         let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -256,7 +256,7 @@ LL |         let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN));
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:138:19
+  --> $DIR/manual_clamp.rs:139:19
    |
 LL |         let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -264,7 +264,7 @@ LL |         let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN);
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:139:19
+  --> $DIR/manual_clamp.rs:140:19
    |
 LL |         let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -272,7 +272,7 @@ LL |         let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX);
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:140:19
+  --> $DIR/manual_clamp.rs:141:19
    |
 LL |         let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -280,7 +280,7 @@ LL |         let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input));
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:141:19
+  --> $DIR/manual_clamp.rs:142:19
    |
 LL |         let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)`
@@ -288,7 +288,7 @@ LL |         let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input));
    = note: clamp will panic if max < min
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:143:19
+  --> $DIR/manual_clamp.rs:144:19
    |
 LL |         let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -297,7 +297,7 @@ LL |         let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN);
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:144:19
+  --> $DIR/manual_clamp.rs:145:19
    |
 LL |         let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -306,7 +306,7 @@ LL |         let x25 = f64::min(f64::max(input, CONST_F64_MIN), CONST_F64_MAX);
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:145:19
+  --> $DIR/manual_clamp.rs:146:19
    |
 LL |         let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -315,7 +315,7 @@ LL |         let x26 = f64::max(CONST_F64_MIN, f64::min(input, CONST_F64_MAX));
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:146:19
+  --> $DIR/manual_clamp.rs:147:19
    |
 LL |         let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -324,7 +324,7 @@ LL |         let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN));
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:147:19
+  --> $DIR/manual_clamp.rs:148:19
    |
 LL |         let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -333,7 +333,7 @@ LL |         let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN);
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:148:19
+  --> $DIR/manual_clamp.rs:149:19
    |
 LL |         let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -342,7 +342,7 @@ LL |         let x29 = f64::min(f64::max(CONST_F64_MIN, input), CONST_F64_MAX);
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:149:19
+  --> $DIR/manual_clamp.rs:150:19
    |
 LL |         let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -351,7 +351,7 @@ LL |         let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input));
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:150:19
+  --> $DIR/manual_clamp.rs:151:19
    |
 LL |         let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_F64_MIN, CONST_F64_MAX)`
@@ -360,7 +360,7 @@ LL |         let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input));
    = note: clamp returns NaN if the input is NaN
 
 error: clamp-like pattern without using clamp function
-  --> $DIR/manual_clamp.rs:153:5
+  --> $DIR/manual_clamp.rs:154:5
    |
 LL | /     if x32 < min {
 LL | |         x32 = min;
@@ -371,5 +371,20 @@ LL | |     }
    |
    = note: clamp will panic if max < min
 
-error: aborting due to 34 previous errors
+error: clamp-like pattern without using clamp function
+  --> $DIR/manual_clamp.rs:324:13
+   |
+LL |       let _ = if input < min {
+   |  _____________^
+LL | |         min
+LL | |     } else if input > max {
+LL | |         max
+LL | |     } else {
+LL | |         input
+LL | |     };
+   | |_____^ help: replace with clamp: `input.clamp(min, max)`
+   |
+   = note: clamp will panic if max < min
+
+error: aborting due to 35 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_filter.fixed b/src/tools/clippy/tests/ui/manual_filter.fixed
new file mode 100644
index 00000000000..3553291b87d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_filter.fixed
@@ -0,0 +1,119 @@
+// run-rustfix
+
+#![warn(clippy::manual_filter)]
+#![allow(unused_variables, dead_code)]
+
+fn main() {
+    Some(0).filter(|&x| x <= 0);
+
+    Some(1).filter(|&x| x <= 0);
+
+    Some(2).filter(|&x| x <= 0);
+
+    Some(3).filter(|&x| x > 0);
+
+    let y = Some(4);
+    y.filter(|&x| x <= 0);
+
+    Some(5).filter(|&x| x > 0);
+
+    Some(6).as_ref().filter(|&x| x > &0);
+
+    let external_cond = true;
+    Some(String::new()).filter(|x| external_cond);
+
+    Some(7).filter(|&x| external_cond);
+
+    Some(8).filter(|&x| x != 0);
+
+    Some(9).filter(|&x| x > 10 && x < 100);
+
+    const fn f1() {
+        // Don't lint, `.filter` is not const
+        match Some(10) {
+            Some(x) => {
+                if x > 10 && x < 100 {
+                    Some(x)
+                } else {
+                    None
+                }
+            },
+            None => None,
+        };
+    }
+
+    #[allow(clippy::blocks_in_if_conditions)]
+    Some(11).filter(|&x| {
+                println!("foo");
+                x > 10 && x < 100
+            });
+
+    match Some(12) {
+        // Don't Lint, statement is lost by `.filter`
+        Some(x) => {
+            if x > 10 && x < 100 {
+                println!("foo");
+                Some(x)
+            } else {
+                None
+            }
+        },
+        None => None,
+    };
+
+    match Some(13) {
+        // Don't Lint, because of `None => Some(1)`
+        Some(x) => {
+            if x > 10 && x < 100 {
+                println!("foo");
+                Some(x)
+            } else {
+                None
+            }
+        },
+        None => Some(1),
+    };
+
+    unsafe fn f(x: u32) -> bool {
+        true
+    }
+    let _ = Some(14).filter(|&x| unsafe { f(x) });
+    let _ = Some(15).filter(|&x| unsafe { f(x) });
+
+    #[allow(clippy::redundant_pattern_matching)]
+    if let Some(_) = Some(16) {
+        Some(16)
+    } else { Some(16).filter(|&x| x % 2 == 0) };
+
+    match Some((17, 17)) {
+        // Not linted for now could be
+        Some((x, y)) => {
+            if y != x {
+                Some((x, y))
+            } else {
+                None
+            }
+        },
+        None => None,
+    };
+
+    struct NamedTuple {
+        pub x: u8,
+        pub y: (i32, u32),
+    }
+
+    match Some(NamedTuple {
+        // Not linted for now could be
+        x: 17,
+        y: (18, 19),
+    }) {
+        Some(NamedTuple { x, y }) => {
+            if y.1 != x as u32 {
+                Some(NamedTuple { x, y })
+            } else {
+                None
+            }
+        },
+        None => None,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/manual_filter.rs b/src/tools/clippy/tests/ui/manual_filter.rs
new file mode 100644
index 00000000000..aa9f90f752b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_filter.rs
@@ -0,0 +1,243 @@
+// run-rustfix
+
+#![warn(clippy::manual_filter)]
+#![allow(unused_variables, dead_code)]
+
+fn main() {
+    match Some(0) {
+        None => None,
+        Some(x) => {
+            if x > 0 {
+                None
+            } else {
+                Some(x)
+            }
+        },
+    };
+
+    match Some(1) {
+        Some(x) => {
+            if x > 0 {
+                None
+            } else {
+                Some(x)
+            }
+        },
+        None => None,
+    };
+
+    match Some(2) {
+        Some(x) => {
+            if x > 0 {
+                None
+            } else {
+                Some(x)
+            }
+        },
+        _ => None,
+    };
+
+    match Some(3) {
+        Some(x) => {
+            if x > 0 {
+                Some(x)
+            } else {
+                None
+            }
+        },
+        None => None,
+    };
+
+    let y = Some(4);
+    match y {
+        // Some(4)
+        None => None,
+        Some(x) => {
+            if x > 0 {
+                None
+            } else {
+                Some(x)
+            }
+        },
+    };
+
+    match Some(5) {
+        Some(x) => {
+            if x > 0 {
+                Some(x)
+            } else {
+                None
+            }
+        },
+        _ => None,
+    };
+
+    match Some(6) {
+        Some(ref x) => {
+            if x > &0 {
+                Some(x)
+            } else {
+                None
+            }
+        },
+        _ => None,
+    };
+
+    let external_cond = true;
+    match Some(String::new()) {
+        Some(x) => {
+            if external_cond {
+                Some(x)
+            } else {
+                None
+            }
+        },
+        _ => None,
+    };
+
+    if let Some(x) = Some(7) {
+        if external_cond { Some(x) } else { None }
+    } else {
+        None
+    };
+
+    match &Some(8) {
+        &Some(x) => {
+            if x != 0 {
+                Some(x)
+            } else {
+                None
+            }
+        },
+        _ => None,
+    };
+
+    match Some(9) {
+        Some(x) => {
+            if x > 10 && x < 100 {
+                Some(x)
+            } else {
+                None
+            }
+        },
+        None => None,
+    };
+
+    const fn f1() {
+        // Don't lint, `.filter` is not const
+        match Some(10) {
+            Some(x) => {
+                if x > 10 && x < 100 {
+                    Some(x)
+                } else {
+                    None
+                }
+            },
+            None => None,
+        };
+    }
+
+    #[allow(clippy::blocks_in_if_conditions)]
+    match Some(11) {
+        // Lint, statement is preserved by `.filter`
+        Some(x) => {
+            if {
+                println!("foo");
+                x > 10 && x < 100
+            } {
+                Some(x)
+            } else {
+                None
+            }
+        },
+        None => None,
+    };
+
+    match Some(12) {
+        // Don't Lint, statement is lost by `.filter`
+        Some(x) => {
+            if x > 10 && x < 100 {
+                println!("foo");
+                Some(x)
+            } else {
+                None
+            }
+        },
+        None => None,
+    };
+
+    match Some(13) {
+        // Don't Lint, because of `None => Some(1)`
+        Some(x) => {
+            if x > 10 && x < 100 {
+                println!("foo");
+                Some(x)
+            } else {
+                None
+            }
+        },
+        None => Some(1),
+    };
+
+    unsafe fn f(x: u32) -> bool {
+        true
+    }
+    let _ = match Some(14) {
+        Some(x) => {
+            if unsafe { f(x) } {
+                Some(x)
+            } else {
+                None
+            }
+        },
+        None => None,
+    };
+    let _ = match Some(15) {
+        Some(x) => unsafe {
+            if f(x) { Some(x) } else { None }
+        },
+        None => None,
+    };
+
+    #[allow(clippy::redundant_pattern_matching)]
+    if let Some(_) = Some(16) {
+        Some(16)
+    } else if let Some(x) = Some(16) {
+        // Lint starting from here
+        if x % 2 == 0 { Some(x) } else { None }
+    } else {
+        None
+    };
+
+    match Some((17, 17)) {
+        // Not linted for now could be
+        Some((x, y)) => {
+            if y != x {
+                Some((x, y))
+            } else {
+                None
+            }
+        },
+        None => None,
+    };
+
+    struct NamedTuple {
+        pub x: u8,
+        pub y: (i32, u32),
+    }
+
+    match Some(NamedTuple {
+        // Not linted for now could be
+        x: 17,
+        y: (18, 19),
+    }) {
+        Some(NamedTuple { x, y }) => {
+            if y.1 != x as u32 {
+                Some(NamedTuple { x, y })
+            } else {
+                None
+            }
+        },
+        None => None,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/manual_filter.stderr b/src/tools/clippy/tests/ui/manual_filter.stderr
new file mode 100644
index 00000000000..53dea922930
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_filter.stderr
@@ -0,0 +1,191 @@
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:7:5
+   |
+LL | /     match Some(0) {
+LL | |         None => None,
+LL | |         Some(x) => {
+LL | |             if x > 0 {
+...  |
+LL | |         },
+LL | |     };
+   | |_____^ help: try this: `Some(0).filter(|&x| x <= 0)`
+   |
+   = note: `-D clippy::manual-filter` implied by `-D warnings`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:18:5
+   |
+LL | /     match Some(1) {
+LL | |         Some(x) => {
+LL | |             if x > 0 {
+LL | |                 None
+...  |
+LL | |         None => None,
+LL | |     };
+   | |_____^ help: try this: `Some(1).filter(|&x| x <= 0)`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:29:5
+   |
+LL | /     match Some(2) {
+LL | |         Some(x) => {
+LL | |             if x > 0 {
+LL | |                 None
+...  |
+LL | |         _ => None,
+LL | |     };
+   | |_____^ help: try this: `Some(2).filter(|&x| x <= 0)`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:40:5
+   |
+LL | /     match Some(3) {
+LL | |         Some(x) => {
+LL | |             if x > 0 {
+LL | |                 Some(x)
+...  |
+LL | |         None => None,
+LL | |     };
+   | |_____^ help: try this: `Some(3).filter(|&x| x > 0)`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:52:5
+   |
+LL | /     match y {
+LL | |         // Some(4)
+LL | |         None => None,
+LL | |         Some(x) => {
+...  |
+LL | |         },
+LL | |     };
+   | |_____^ help: try this: `y.filter(|&x| x <= 0)`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:64:5
+   |
+LL | /     match Some(5) {
+LL | |         Some(x) => {
+LL | |             if x > 0 {
+LL | |                 Some(x)
+...  |
+LL | |         _ => None,
+LL | |     };
+   | |_____^ help: try this: `Some(5).filter(|&x| x > 0)`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:75:5
+   |
+LL | /     match Some(6) {
+LL | |         Some(ref x) => {
+LL | |             if x > &0 {
+LL | |                 Some(x)
+...  |
+LL | |         _ => None,
+LL | |     };
+   | |_____^ help: try this: `Some(6).as_ref().filter(|&x| x > &0)`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:87:5
+   |
+LL | /     match Some(String::new()) {
+LL | |         Some(x) => {
+LL | |             if external_cond {
+LL | |                 Some(x)
+...  |
+LL | |         _ => None,
+LL | |     };
+   | |_____^ help: try this: `Some(String::new()).filter(|x| external_cond)`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:98:5
+   |
+LL | /     if let Some(x) = Some(7) {
+LL | |         if external_cond { Some(x) } else { None }
+LL | |     } else {
+LL | |         None
+LL | |     };
+   | |_____^ help: try this: `Some(7).filter(|&x| external_cond)`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:104:5
+   |
+LL | /     match &Some(8) {
+LL | |         &Some(x) => {
+LL | |             if x != 0 {
+LL | |                 Some(x)
+...  |
+LL | |         _ => None,
+LL | |     };
+   | |_____^ help: try this: `Some(8).filter(|&x| x != 0)`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:115:5
+   |
+LL | /     match Some(9) {
+LL | |         Some(x) => {
+LL | |             if x > 10 && x < 100 {
+LL | |                 Some(x)
+...  |
+LL | |         None => None,
+LL | |     };
+   | |_____^ help: try this: `Some(9).filter(|&x| x > 10 && x < 100)`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:141:5
+   |
+LL | /     match Some(11) {
+LL | |         // Lint, statement is preserved by `.filter`
+LL | |         Some(x) => {
+LL | |             if {
+...  |
+LL | |         None => None,
+LL | |     };
+   | |_____^
+   |
+help: try this
+   |
+LL ~     Some(11).filter(|&x| {
+LL +                 println!("foo");
+LL +                 x > 10 && x < 100
+LL ~             });
+   |
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:185:13
+   |
+LL |       let _ = match Some(14) {
+   |  _____________^
+LL | |         Some(x) => {
+LL | |             if unsafe { f(x) } {
+LL | |                 Some(x)
+...  |
+LL | |         None => None,
+LL | |     };
+   | |_____^ help: try this: `Some(14).filter(|&x| unsafe { f(x) })`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:195:13
+   |
+LL |       let _ = match Some(15) {
+   |  _____________^
+LL | |         Some(x) => unsafe {
+LL | |             if f(x) { Some(x) } else { None }
+LL | |         },
+LL | |         None => None,
+LL | |     };
+   | |_____^ help: try this: `Some(15).filter(|&x| unsafe { f(x) })`
+
+error: manual implementation of `Option::filter`
+  --> $DIR/manual_filter.rs:205:12
+   |
+LL |       } else if let Some(x) = Some(16) {
+   |  ____________^
+LL | |         // Lint starting from here
+LL | |         if x % 2 == 0 { Some(x) } else { None }
+LL | |     } else {
+LL | |         None
+LL | |     };
+   | |_____^ help: try this: `{ Some(16).filter(|&x| x % 2 == 0) }`
+
+error: aborting due to 15 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.fixed b/src/tools/clippy/tests/ui/manual_rem_euclid.fixed
index 5601c96c10b..b942fbfe930 100644
--- a/src/tools/clippy/tests/ui/manual_rem_euclid.fixed
+++ b/src/tools/clippy/tests/ui/manual_rem_euclid.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 // aux-build:macro_rules.rs
 
+#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_rem_euclid)]
 
 #[macro_use]
@@ -53,3 +54,32 @@ pub fn rem_euclid_4(num: i32) -> i32 {
 pub const fn const_rem_euclid_4(num: i32) -> i32 {
     num.rem_euclid(4)
 }
+
+pub fn msrv_1_37() {
+    #![clippy::msrv = "1.37"]
+
+    let x: i32 = 10;
+    let _: i32 = ((x % 4) + 4) % 4;
+}
+
+pub fn msrv_1_38() {
+    #![clippy::msrv = "1.38"]
+
+    let x: i32 = 10;
+    let _: i32 = x.rem_euclid(4);
+}
+
+// For const fns:
+pub const fn msrv_1_51() {
+    #![clippy::msrv = "1.51"]
+
+    let x: i32 = 10;
+    let _: i32 = ((x % 4) + 4) % 4;
+}
+
+pub const fn msrv_1_52() {
+    #![clippy::msrv = "1.52"]
+
+    let x: i32 = 10;
+    let _: i32 = x.rem_euclid(4);
+}
diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.rs b/src/tools/clippy/tests/ui/manual_rem_euclid.rs
index 52135be26b7..7462d532169 100644
--- a/src/tools/clippy/tests/ui/manual_rem_euclid.rs
+++ b/src/tools/clippy/tests/ui/manual_rem_euclid.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 // aux-build:macro_rules.rs
 
+#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_rem_euclid)]
 
 #[macro_use]
@@ -53,3 +54,32 @@ pub fn rem_euclid_4(num: i32) -> i32 {
 pub const fn const_rem_euclid_4(num: i32) -> i32 {
     ((num % 4) + 4) % 4
 }
+
+pub fn msrv_1_37() {
+    #![clippy::msrv = "1.37"]
+
+    let x: i32 = 10;
+    let _: i32 = ((x % 4) + 4) % 4;
+}
+
+pub fn msrv_1_38() {
+    #![clippy::msrv = "1.38"]
+
+    let x: i32 = 10;
+    let _: i32 = ((x % 4) + 4) % 4;
+}
+
+// For const fns:
+pub const fn msrv_1_51() {
+    #![clippy::msrv = "1.51"]
+
+    let x: i32 = 10;
+    let _: i32 = ((x % 4) + 4) % 4;
+}
+
+pub const fn msrv_1_52() {
+    #![clippy::msrv = "1.52"]
+
+    let x: i32 = 10;
+    let _: i32 = ((x % 4) + 4) % 4;
+}
diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.stderr b/src/tools/clippy/tests/ui/manual_rem_euclid.stderr
index a237fd0213c..d51bac03b56 100644
--- a/src/tools/clippy/tests/ui/manual_rem_euclid.stderr
+++ b/src/tools/clippy/tests/ui/manual_rem_euclid.stderr
@@ -1,5 +1,5 @@
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:19:18
+  --> $DIR/manual_rem_euclid.rs:20:18
    |
 LL |     let _: i32 = ((value % 4) + 4) % 4;
    |                  ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
@@ -7,31 +7,31 @@ LL |     let _: i32 = ((value % 4) + 4) % 4;
    = note: `-D clippy::manual-rem-euclid` implied by `-D warnings`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:20:18
+  --> $DIR/manual_rem_euclid.rs:21:18
    |
 LL |     let _: i32 = (4 + (value % 4)) % 4;
    |                  ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:21:18
+  --> $DIR/manual_rem_euclid.rs:22:18
    |
 LL |     let _: i32 = (value % 4 + 4) % 4;
    |                  ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:22:18
+  --> $DIR/manual_rem_euclid.rs:23:18
    |
 LL |     let _: i32 = (4 + value % 4) % 4;
    |                  ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:23:22
+  --> $DIR/manual_rem_euclid.rs:24:22
    |
 LL |     let _: i32 = 1 + (4 + value % 4) % 4;
    |                      ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:12:22
+  --> $DIR/manual_rem_euclid.rs:13:22
    |
 LL |         let _: i32 = ((value % 4) + 4) % 4;
    |                      ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
@@ -42,16 +42,28 @@ LL |     internal_rem_euclid!();
    = note: this error originates in the macro `internal_rem_euclid` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:49:5
+  --> $DIR/manual_rem_euclid.rs:50:5
    |
 LL |     ((num % 4) + 4) % 4
    |     ^^^^^^^^^^^^^^^^^^^ help: consider using: `num.rem_euclid(4)`
 
 error: manual `rem_euclid` implementation
-  --> $DIR/manual_rem_euclid.rs:54:5
+  --> $DIR/manual_rem_euclid.rs:55:5
    |
 LL |     ((num % 4) + 4) % 4
    |     ^^^^^^^^^^^^^^^^^^^ help: consider using: `num.rem_euclid(4)`
 
-error: aborting due to 8 previous errors
+error: manual `rem_euclid` implementation
+  --> $DIR/manual_rem_euclid.rs:69:18
+   |
+LL |     let _: i32 = ((x % 4) + 4) % 4;
+   |                  ^^^^^^^^^^^^^^^^^ help: consider using: `x.rem_euclid(4)`
+
+error: manual `rem_euclid` implementation
+  --> $DIR/manual_rem_euclid.rs:84:18
+   |
+LL |     let _: i32 = ((x % 4) + 4) % 4;
+   |                  ^^^^^^^^^^^^^^^^^ help: consider using: `x.rem_euclid(4)`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_strip.rs b/src/tools/clippy/tests/ui/manual_strip.rs
index cbb84eb5c7e..85009d78558 100644
--- a/src/tools/clippy/tests/ui/manual_strip.rs
+++ b/src/tools/clippy/tests/ui/manual_strip.rs
@@ -1,3 +1,4 @@
+#![feature(custom_inner_attributes)]
 #![warn(clippy::manual_strip)]
 
 fn main() {
@@ -64,3 +65,21 @@ fn main() {
         s4[2..].to_string();
     }
 }
+
+fn msrv_1_44() {
+    #![clippy::msrv = "1.44"]
+
+    let s = "abc";
+    if s.starts_with('a') {
+        s[1..].to_string();
+    }
+}
+
+fn msrv_1_45() {
+    #![clippy::msrv = "1.45"]
+
+    let s = "abc";
+    if s.starts_with('a') {
+        s[1..].to_string();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_strip.stderr b/src/tools/clippy/tests/ui/manual_strip.stderr
index 2191ccb85dd..ad2a362f3e7 100644
--- a/src/tools/clippy/tests/ui/manual_strip.stderr
+++ b/src/tools/clippy/tests/ui/manual_strip.stderr
@@ -1,11 +1,11 @@
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:7:24
+  --> $DIR/manual_strip.rs:8:24
    |
 LL |         str::to_string(&s["ab".len()..]);
    |                        ^^^^^^^^^^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:6:5
+  --> $DIR/manual_strip.rs:7:5
    |
 LL |     if s.starts_with("ab") {
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -21,13 +21,13 @@ LL ~         <stripped>.to_string();
    |
 
 error: stripping a suffix manually
-  --> $DIR/manual_strip.rs:15:24
+  --> $DIR/manual_strip.rs:16:24
    |
 LL |         str::to_string(&s[..s.len() - "bc".len()]);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the suffix was tested here
-  --> $DIR/manual_strip.rs:14:5
+  --> $DIR/manual_strip.rs:15:5
    |
 LL |     if s.ends_with("bc") {
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -42,13 +42,13 @@ LL ~         <stripped>.to_string();
    |
 
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:24:24
+  --> $DIR/manual_strip.rs:25:24
    |
 LL |         str::to_string(&s[1..]);
    |                        ^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:23:5
+  --> $DIR/manual_strip.rs:24:5
    |
 LL |     if s.starts_with('a') {
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -60,13 +60,13 @@ LL ~         <stripped>.to_string();
    |
 
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:31:24
+  --> $DIR/manual_strip.rs:32:24
    |
 LL |         str::to_string(&s[prefix.len()..]);
    |                        ^^^^^^^^^^^^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:30:5
+  --> $DIR/manual_strip.rs:31:5
    |
 LL |     if s.starts_with(prefix) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -77,13 +77,13 @@ LL ~         str::to_string(<stripped>);
    |
 
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:37:24
+  --> $DIR/manual_strip.rs:38:24
    |
 LL |         str::to_string(&s[PREFIX.len()..]);
    |                        ^^^^^^^^^^^^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:36:5
+  --> $DIR/manual_strip.rs:37:5
    |
 LL |     if s.starts_with(PREFIX) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -95,13 +95,13 @@ LL ~         str::to_string(<stripped>);
    |
 
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:44:24
+  --> $DIR/manual_strip.rs:45:24
    |
 LL |         str::to_string(&TARGET[prefix.len()..]);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:43:5
+  --> $DIR/manual_strip.rs:44:5
    |
 LL |     if TARGET.starts_with(prefix) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,13 +112,13 @@ LL ~         str::to_string(<stripped>);
    |
 
 error: stripping a prefix manually
-  --> $DIR/manual_strip.rs:50:9
+  --> $DIR/manual_strip.rs:51:9
    |
 LL |         s1[2..].to_uppercase();
    |         ^^^^^^^
    |
 note: the prefix was tested here
-  --> $DIR/manual_strip.rs:49:5
+  --> $DIR/manual_strip.rs:50:5
    |
 LL |     if s1.starts_with("ab") {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -128,5 +128,22 @@ LL ~     if let Some(<stripped>) = s1.strip_prefix("ab") {
 LL ~         <stripped>.to_uppercase();
    |
 
-error: aborting due to 7 previous errors
+error: stripping a prefix manually
+  --> $DIR/manual_strip.rs:83:9
+   |
+LL |         s[1..].to_string();
+   |         ^^^^^^
+   |
+note: the prefix was tested here
+  --> $DIR/manual_strip.rs:82:5
+   |
+LL |     if s.starts_with('a') {
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+help: try using the `strip_prefix` method
+   |
+LL ~     if let Some(<stripped>) = s.strip_prefix('a') {
+LL ~         <stripped>.to_string();
+   |
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.rs b/src/tools/clippy/tests/ui/map_unwrap_or.rs
index 5429fb4e454..396b22a9abb 100644
--- a/src/tools/clippy/tests/ui/map_unwrap_or.rs
+++ b/src/tools/clippy/tests/ui/map_unwrap_or.rs
@@ -1,6 +1,8 @@
 // aux-build:option_helpers.rs
+
+#![feature(custom_inner_attributes)]
 #![warn(clippy::map_unwrap_or)]
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, clippy::unnecessary_lazy_evaluations)]
 
 #[macro_use]
 extern crate option_helpers;
@@ -79,3 +81,19 @@ fn main() {
     option_methods();
     result_methods();
 }
+
+fn msrv_1_40() {
+    #![clippy::msrv = "1.40"]
+
+    let res: Result<i32, ()> = Ok(1);
+
+    let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0);
+}
+
+fn msrv_1_41() {
+    #![clippy::msrv = "1.41"]
+
+    let res: Result<i32, ()> = Ok(1);
+
+    let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0);
+}
diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.stderr b/src/tools/clippy/tests/ui/map_unwrap_or.stderr
index abc9c1ece32..d17d24a403e 100644
--- a/src/tools/clippy/tests/ui/map_unwrap_or.stderr
+++ b/src/tools/clippy/tests/ui/map_unwrap_or.stderr
@@ -1,5 +1,5 @@
 error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:16:13
+  --> $DIR/map_unwrap_or.rs:18:13
    |
 LL |       let _ = opt.map(|x| x + 1)
    |  _____________^
@@ -15,7 +15,7 @@ LL +     let _ = opt.map_or(0, |x| x + 1);
    |
 
 error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:20:13
+  --> $DIR/map_unwrap_or.rs:22:13
    |
 LL |       let _ = opt.map(|x| {
    |  _____________^
@@ -33,7 +33,7 @@ LL ~     );
    |
 
 error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:24:13
+  --> $DIR/map_unwrap_or.rs:26:13
    |
 LL |       let _ = opt.map(|x| x + 1)
    |  _____________^
@@ -50,7 +50,7 @@ LL ~         }, |x| x + 1);
    |
 
 error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead
-  --> $DIR/map_unwrap_or.rs:29:13
+  --> $DIR/map_unwrap_or.rs:31:13
    |
 LL |     let _ = opt.map(|x| Some(x + 1)).unwrap_or(None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -62,7 +62,7 @@ LL +     let _ = opt.and_then(|x| Some(x + 1));
    |
 
 error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead
-  --> $DIR/map_unwrap_or.rs:31:13
+  --> $DIR/map_unwrap_or.rs:33:13
    |
 LL |       let _ = opt.map(|x| {
    |  _____________^
@@ -80,7 +80,7 @@ LL ~     );
    |
 
 error: called `map(<f>).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(<f>)` instead
-  --> $DIR/map_unwrap_or.rs:35:13
+  --> $DIR/map_unwrap_or.rs:37:13
    |
 LL |       let _ = opt
    |  _____________^
@@ -95,7 +95,7 @@ LL +         .and_then(|x| Some(x + 1));
    |
 
 error: called `map(<f>).unwrap_or(<a>)` on an `Option` value. This can be done more directly by calling `map_or(<a>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:46:13
+  --> $DIR/map_unwrap_or.rs:48:13
    |
 LL |     let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -107,7 +107,7 @@ LL +     let _ = Some("prefix").map_or(id, |p| format!("{}.", p));
    |
 
 error: called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:50:13
+  --> $DIR/map_unwrap_or.rs:52:13
    |
 LL |       let _ = opt.map(|x| {
    |  _____________^
@@ -117,7 +117,7 @@ LL | |     ).unwrap_or_else(|| 0);
    | |__________________________^
 
 error: called `map(<f>).unwrap_or_else(<g>)` on an `Option` value. This can be done more directly by calling `map_or_else(<g>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:54:13
+  --> $DIR/map_unwrap_or.rs:56:13
    |
 LL |       let _ = opt.map(|x| x + 1)
    |  _____________^
@@ -127,7 +127,7 @@ LL | |         );
    | |_________^
 
 error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:66:13
+  --> $DIR/map_unwrap_or.rs:68:13
    |
 LL |       let _ = res.map(|x| {
    |  _____________^
@@ -137,7 +137,7 @@ LL | |     ).unwrap_or_else(|_e| 0);
    | |____________________________^
 
 error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead
-  --> $DIR/map_unwrap_or.rs:70:13
+  --> $DIR/map_unwrap_or.rs:72:13
    |
 LL |       let _ = res.map(|x| x + 1)
    |  _____________^
@@ -146,5 +146,11 @@ LL | |             0
 LL | |         });
    | |__________^
 
-error: aborting due to 11 previous errors
+error: called `map(<f>).unwrap_or_else(<g>)` on a `Result` value. This can be done more directly by calling `.map_or_else(<g>, <f>)` instead
+  --> $DIR/map_unwrap_or.rs:98:13
+   |
+LL |     let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)`
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
index 95ca571d07b..2498007694c 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(custom_inner_attributes)]
 #![warn(clippy::match_like_matches_macro)]
 #![allow(unreachable_patterns, dead_code, clippy::equatable_if_let)]
 
@@ -193,3 +194,18 @@ fn main() {
         _ => false,
     };
 }
+
+fn msrv_1_41() {
+    #![clippy::msrv = "1.41"]
+
+    let _y = match Some(5) {
+        Some(0) => true,
+        _ => false,
+    };
+}
+
+fn msrv_1_42() {
+    #![clippy::msrv = "1.42"]
+
+    let _y = matches!(Some(5), Some(0));
+}
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
index 3b9c8cadadc..b4e48499bd0 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(custom_inner_attributes)]
 #![warn(clippy::match_like_matches_macro)]
 #![allow(unreachable_patterns, dead_code, clippy::equatable_if_let)]
 
@@ -234,3 +235,21 @@ fn main() {
         _ => false,
     };
 }
+
+fn msrv_1_41() {
+    #![clippy::msrv = "1.41"]
+
+    let _y = match Some(5) {
+        Some(0) => true,
+        _ => false,
+    };
+}
+
+fn msrv_1_42() {
+    #![clippy::msrv = "1.42"]
+
+    let _y = match Some(5) {
+        Some(0) => true,
+        _ => false,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
index e94555e2744..f1d1c23aeb0 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
@@ -1,5 +1,5 @@
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:10:14
+  --> $DIR/match_expr_like_matches_macro.rs:11:14
    |
 LL |       let _y = match x {
    |  ______________^
@@ -11,7 +11,7 @@ LL | |     };
    = note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:16:14
+  --> $DIR/match_expr_like_matches_macro.rs:17:14
    |
 LL |       let _w = match x {
    |  ______________^
@@ -21,7 +21,7 @@ LL | |     };
    | |_____^ help: try this: `matches!(x, Some(_))`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/match_expr_like_matches_macro.rs:22:14
+  --> $DIR/match_expr_like_matches_macro.rs:23:14
    |
 LL |       let _z = match x {
    |  ______________^
@@ -33,7 +33,7 @@ LL | |     };
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:28:15
+  --> $DIR/match_expr_like_matches_macro.rs:29:15
    |
 LL |       let _zz = match x {
    |  _______________^
@@ -43,13 +43,13 @@ LL | |     };
    | |_____^ help: try this: `!matches!(x, Some(r) if r == 0)`
 
 error: if let .. else expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:34:16
+  --> $DIR/match_expr_like_matches_macro.rs:35:16
    |
 LL |     let _zzz = if let Some(5) = x { true } else { false };
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `matches!(x, Some(5))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:58:20
+  --> $DIR/match_expr_like_matches_macro.rs:59:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -60,7 +60,7 @@ LL | |         };
    | |_________^ help: try this: `matches!(x, E::A(_) | E::B(_))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:68:20
+  --> $DIR/match_expr_like_matches_macro.rs:69:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -73,7 +73,7 @@ LL | |         };
    | |_________^ help: try this: `matches!(x, E::A(_) | E::B(_))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:78:20
+  --> $DIR/match_expr_like_matches_macro.rs:79:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -84,7 +84,7 @@ LL | |         };
    | |_________^ help: try this: `!matches!(x, E::B(_) | E::C)`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:138:18
+  --> $DIR/match_expr_like_matches_macro.rs:139:18
    |
 LL |           let _z = match &z {
    |  __________________^
@@ -94,7 +94,7 @@ LL | |         };
    | |_________^ help: try this: `matches!(z, Some(3))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:147:18
+  --> $DIR/match_expr_like_matches_macro.rs:148:18
    |
 LL |           let _z = match &z {
    |  __________________^
@@ -104,7 +104,7 @@ LL | |         };
    | |_________^ help: try this: `matches!(&z, Some(3))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:164:21
+  --> $DIR/match_expr_like_matches_macro.rs:165:21
    |
 LL |               let _ = match &z {
    |  _____________________^
@@ -114,7 +114,7 @@ LL | |             };
    | |_____________^ help: try this: `matches!(&z, AnEnum::X)`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:178:20
+  --> $DIR/match_expr_like_matches_macro.rs:179:20
    |
 LL |           let _res = match &val {
    |  ____________________^
@@ -124,7 +124,7 @@ LL | |         };
    | |_________^ help: try this: `matches!(&val, &Some(ref _a))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:190:20
+  --> $DIR/match_expr_like_matches_macro.rs:191:20
    |
 LL |           let _res = match &val {
    |  ____________________^
@@ -133,5 +133,15 @@ LL | |             _ => false,
 LL | |         };
    | |_________^ help: try this: `matches!(&val, &Some(ref _a))`
 
-error: aborting due to 13 previous errors
+error: match expression looks like `matches!` macro
+  --> $DIR/match_expr_like_matches_macro.rs:251:14
+   |
+LL |       let _y = match Some(5) {
+   |  ______________^
+LL | |         Some(0) => true,
+LL | |         _ => false,
+LL | |     };
+   | |_____^ help: try this: `matches!(Some(5), Some(0))`
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.rs b/src/tools/clippy/tests/ui/match_overlapping_arm.rs
index 22b04b208f8..b4097fa9604 100644
--- a/src/tools/clippy/tests/ui/match_overlapping_arm.rs
+++ b/src/tools/clippy/tests/ui/match_overlapping_arm.rs
@@ -1,5 +1,4 @@
 #![feature(exclusive_range_pattern)]
-
 #![warn(clippy::match_overlapping_arm)]
 #![allow(clippy::redundant_pattern_matching)]
 #![allow(clippy::if_same_then_else, clippy::equatable_if_let)]
diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.stderr b/src/tools/clippy/tests/ui/match_overlapping_arm.stderr
index a72becbeb66..b98d4799e42 100644
--- a/src/tools/clippy/tests/ui/match_overlapping_arm.stderr
+++ b/src/tools/clippy/tests/ui/match_overlapping_arm.stderr
@@ -1,96 +1,96 @@
 error: some ranges overlap
-  --> $DIR/match_overlapping_arm.rs:13:9
+  --> $DIR/match_overlapping_arm.rs:12:9
    |
 LL |         0..=10 => println!("0..=10"),
    |         ^^^^^^
    |
 note: overlaps with this
-  --> $DIR/match_overlapping_arm.rs:14:9
+  --> $DIR/match_overlapping_arm.rs:13:9
    |
 LL |         0..=11 => println!("0..=11"),
    |         ^^^^^^
    = note: `-D clippy::match-overlapping-arm` implied by `-D warnings`
 
 error: some ranges overlap
-  --> $DIR/match_overlapping_arm.rs:19:9
+  --> $DIR/match_overlapping_arm.rs:18:9
    |
 LL |         0..=5 => println!("0..=5"),
    |         ^^^^^
    |
 note: overlaps with this
-  --> $DIR/match_overlapping_arm.rs:21:9
+  --> $DIR/match_overlapping_arm.rs:20:9
    |
 LL |         FOO..=11 => println!("FOO..=11"),
    |         ^^^^^^^^
 
 error: some ranges overlap
-  --> $DIR/match_overlapping_arm.rs:56:9
+  --> $DIR/match_overlapping_arm.rs:55:9
    |
 LL |         0..11 => println!("0..11"),
    |         ^^^^^
    |
 note: overlaps with this
-  --> $DIR/match_overlapping_arm.rs:57:9
+  --> $DIR/match_overlapping_arm.rs:56:9
    |
 LL |         0..=11 => println!("0..=11"),
    |         ^^^^^^
 
 error: some ranges overlap
-  --> $DIR/match_overlapping_arm.rs:81:9
+  --> $DIR/match_overlapping_arm.rs:80:9
    |
 LL |         0..=10 => println!("0..=10"),
    |         ^^^^^^
    |
 note: overlaps with this
-  --> $DIR/match_overlapping_arm.rs:80:9
+  --> $DIR/match_overlapping_arm.rs:79:9
    |
 LL |         5..14 => println!("5..14"),
    |         ^^^^^
 
 error: some ranges overlap
-  --> $DIR/match_overlapping_arm.rs:86:9
+  --> $DIR/match_overlapping_arm.rs:85:9
    |
 LL |         0..7 => println!("0..7"),
    |         ^^^^
    |
 note: overlaps with this
-  --> $DIR/match_overlapping_arm.rs:87:9
+  --> $DIR/match_overlapping_arm.rs:86:9
    |
 LL |         0..=10 => println!("0..=10"),
    |         ^^^^^^
 
 error: some ranges overlap
-  --> $DIR/match_overlapping_arm.rs:98:9
+  --> $DIR/match_overlapping_arm.rs:97:9
    |
 LL |         ..=23 => println!("..=23"),
    |         ^^^^^
    |
 note: overlaps with this
-  --> $DIR/match_overlapping_arm.rs:99:9
+  --> $DIR/match_overlapping_arm.rs:98:9
    |
 LL |         ..26 => println!("..26"),
    |         ^^^^
 
 error: some ranges overlap
-  --> $DIR/match_overlapping_arm.rs:107:9
+  --> $DIR/match_overlapping_arm.rs:106:9
    |
 LL |         21..=30 => (),
    |         ^^^^^^^
    |
 note: overlaps with this
-  --> $DIR/match_overlapping_arm.rs:108:9
+  --> $DIR/match_overlapping_arm.rs:107:9
    |
 LL |         21..=40 => (),
    |         ^^^^^^^
 
 error: some ranges overlap
-  --> $DIR/match_overlapping_arm.rs:121:9
+  --> $DIR/match_overlapping_arm.rs:120:9
    |
 LL |         0..=0x0000_0000_0000_00ff => (),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: overlaps with this
-  --> $DIR/match_overlapping_arm.rs:122:9
+  --> $DIR/match_overlapping_arm.rs:121:9
    |
 LL |         0..=0x0000_0000_0000_ffff => (),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed
index 951f552eb32..a6e315e4773 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.fixed
+++ b/src/tools/clippy/tests/ui/match_single_binding.fixed
@@ -124,3 +124,12 @@ fn issue_8723() {
 
     let _ = val;
 }
+
+#[allow(dead_code)]
+fn issue_9575() {
+    fn side_effects() {}
+    let _ = || {
+        side_effects();
+        println!("Needs curlies");
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs
index 19c0fee8fd6..cecbd703e56 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.rs
+++ b/src/tools/clippy/tests/ui/match_single_binding.rs
@@ -140,3 +140,11 @@ fn issue_8723() {
 
     let _ = val;
 }
+
+#[allow(dead_code)]
+fn issue_9575() {
+    fn side_effects() {}
+    let _ = || match side_effects() {
+        _ => println!("Needs curlies"),
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr
index 5d4e7314b21..2b9ec7ee702 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.stderr
+++ b/src/tools/clippy/tests/ui/match_single_binding.stderr
@@ -196,5 +196,22 @@ LL +         suf
 LL ~     };
    |
 
-error: aborting due to 13 previous errors
+error: this match could be replaced by its scrutinee and body
+  --> $DIR/match_single_binding.rs:147:16
+   |
+LL |       let _ = || match side_effects() {
+   |  ________________^
+LL | |         _ => println!("Needs curlies"),
+LL | |     };
+   | |_____^
+   |
+help: consider using the scrutinee and body instead
+   |
+LL ~     let _ = || {
+LL +         side_effects();
+LL +         println!("Needs curlies");
+LL ~     };
+   |
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr
deleted file mode 100644
index 525533bf07b..00000000000
--- a/src/tools/clippy/tests/ui/match_wild_err_arm.edition2021.stderr
+++ /dev/null
@@ -1,35 +0,0 @@
-error: `Err(_)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:14:9
-   |
-LL |         Err(_) => panic!("err"),
-   |         ^^^^^^
-   |
-   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
-   = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
-
-error: `Err(_)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:20:9
-   |
-LL |         Err(_) => panic!(),
-   |         ^^^^^^
-   |
-   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
-
-error: `Err(_)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:26:9
-   |
-LL |         Err(_) => {
-   |         ^^^^^^
-   |
-   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
-
-error: `Err(_e)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:34:9
-   |
-LL |         Err(_e) => panic!(),
-   |         ^^^^^^^
-   |
-   = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
-
-error: aborting due to 4 previous errors
-
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.rs b/src/tools/clippy/tests/ui/match_wild_err_arm.rs
index 0a86144b95d..823be65efe0 100644
--- a/src/tools/clippy/tests/ui/match_wild_err_arm.rs
+++ b/src/tools/clippy/tests/ui/match_wild_err_arm.rs
@@ -1,6 +1,3 @@
-// revisions: edition2018 edition2021
-// [edition2018] edition:2018
-// [edition2021] edition:2021
 #![feature(exclusive_range_pattern)]
 #![allow(clippy::match_same_arms)]
 #![warn(clippy::match_wild_err_arm)]
diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr
index 525533bf07b..b016d682698 100644
--- a/src/tools/clippy/tests/ui/match_wild_err_arm.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr
@@ -1,5 +1,5 @@
 error: `Err(_)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:14:9
+  --> $DIR/match_wild_err_arm.rs:11:9
    |
 LL |         Err(_) => panic!("err"),
    |         ^^^^^^
@@ -8,7 +8,7 @@ LL |         Err(_) => panic!("err"),
    = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
 
 error: `Err(_)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:20:9
+  --> $DIR/match_wild_err_arm.rs:17:9
    |
 LL |         Err(_) => panic!(),
    |         ^^^^^^
@@ -16,7 +16,7 @@ LL |         Err(_) => panic!(),
    = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:26:9
+  --> $DIR/match_wild_err_arm.rs:23:9
    |
 LL |         Err(_) => {
    |         ^^^^^^
@@ -24,7 +24,7 @@ LL |         Err(_) => {
    = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable
 
 error: `Err(_e)` matches all errors
-  --> $DIR/match_wild_err_arm.rs:34:9
+  --> $DIR/match_wild_err_arm.rs:31:9
    |
 LL |         Err(_e) => panic!(),
    |         ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/mem_replace.fixed b/src/tools/clippy/tests/ui/mem_replace.fixed
index b609ba65946..ae237395b95 100644
--- a/src/tools/clippy/tests/ui/mem_replace.fixed
+++ b/src/tools/clippy/tests/ui/mem_replace.fixed
@@ -1,5 +1,7 @@
 // run-rustfix
-#![allow(unused_imports)]
+
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
 #![warn(
     clippy::all,
     clippy::style,
@@ -77,3 +79,17 @@ fn main() {
     replace_with_default();
     dont_lint_primitive();
 }
+
+fn msrv_1_39() {
+    #![clippy::msrv = "1.39"]
+
+    let mut s = String::from("foo");
+    let _ = std::mem::replace(&mut s, String::default());
+}
+
+fn msrv_1_40() {
+    #![clippy::msrv = "1.40"]
+
+    let mut s = String::from("foo");
+    let _ = std::mem::take(&mut s);
+}
diff --git a/src/tools/clippy/tests/ui/mem_replace.rs b/src/tools/clippy/tests/ui/mem_replace.rs
index 93f6dcdec83..3202e99e0be 100644
--- a/src/tools/clippy/tests/ui/mem_replace.rs
+++ b/src/tools/clippy/tests/ui/mem_replace.rs
@@ -1,5 +1,7 @@
 // run-rustfix
-#![allow(unused_imports)]
+
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
 #![warn(
     clippy::all,
     clippy::style,
@@ -77,3 +79,17 @@ fn main() {
     replace_with_default();
     dont_lint_primitive();
 }
+
+fn msrv_1_39() {
+    #![clippy::msrv = "1.39"]
+
+    let mut s = String::from("foo");
+    let _ = std::mem::replace(&mut s, String::default());
+}
+
+fn msrv_1_40() {
+    #![clippy::msrv = "1.40"]
+
+    let mut s = String::from("foo");
+    let _ = std::mem::replace(&mut s, String::default());
+}
diff --git a/src/tools/clippy/tests/ui/mem_replace.stderr b/src/tools/clippy/tests/ui/mem_replace.stderr
index 90dc6c95f85..dd8a50dab90 100644
--- a/src/tools/clippy/tests/ui/mem_replace.stderr
+++ b/src/tools/clippy/tests/ui/mem_replace.stderr
@@ -1,5 +1,5 @@
 error: replacing an `Option` with `None`
-  --> $DIR/mem_replace.rs:15:13
+  --> $DIR/mem_replace.rs:17:13
    |
 LL |     let _ = mem::replace(&mut an_option, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
@@ -7,13 +7,13 @@ LL |     let _ = mem::replace(&mut an_option, None);
    = note: `-D clippy::mem-replace-option-with-none` implied by `-D warnings`
 
 error: replacing an `Option` with `None`
-  --> $DIR/mem_replace.rs:17:13
+  --> $DIR/mem_replace.rs:19:13
    |
 LL |     let _ = mem::replace(an_option, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:22:13
+  --> $DIR/mem_replace.rs:24:13
    |
 LL |     let _ = std::mem::replace(&mut s, String::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
@@ -21,100 +21,106 @@ LL |     let _ = std::mem::replace(&mut s, String::default());
    = note: `-D clippy::mem-replace-with-default` implied by `-D warnings`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:25:13
+  --> $DIR/mem_replace.rs:27:13
    |
 LL |     let _ = std::mem::replace(s, String::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:26:13
+  --> $DIR/mem_replace.rs:28:13
    |
 LL |     let _ = std::mem::replace(s, Default::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:29:13
+  --> $DIR/mem_replace.rs:31:13
    |
 LL |     let _ = std::mem::replace(&mut v, Vec::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:30:13
+  --> $DIR/mem_replace.rs:32:13
    |
 LL |     let _ = std::mem::replace(&mut v, Default::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:31:13
+  --> $DIR/mem_replace.rs:33:13
    |
 LL |     let _ = std::mem::replace(&mut v, Vec::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:32:13
+  --> $DIR/mem_replace.rs:34:13
    |
 LL |     let _ = std::mem::replace(&mut v, vec![]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:35:13
+  --> $DIR/mem_replace.rs:37:13
    |
 LL |     let _ = std::mem::replace(&mut hash_map, HashMap::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_map)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:38:13
+  --> $DIR/mem_replace.rs:40:13
    |
 LL |     let _ = std::mem::replace(&mut btree_map, BTreeMap::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_map)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:41:13
+  --> $DIR/mem_replace.rs:43:13
    |
 LL |     let _ = std::mem::replace(&mut vd, VecDeque::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut vd)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:44:13
+  --> $DIR/mem_replace.rs:46:13
    |
 LL |     let _ = std::mem::replace(&mut hash_set, HashSet::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_set)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:47:13
+  --> $DIR/mem_replace.rs:49:13
    |
 LL |     let _ = std::mem::replace(&mut btree_set, BTreeSet::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_set)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:50:13
+  --> $DIR/mem_replace.rs:52:13
    |
 LL |     let _ = std::mem::replace(&mut list, LinkedList::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut list)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:53:13
+  --> $DIR/mem_replace.rs:55:13
    |
 LL |     let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut binary_heap)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:56:13
+  --> $DIR/mem_replace.rs:58:13
    |
 LL |     let _ = std::mem::replace(&mut tuple, (vec![], BinaryHeap::new()));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut tuple)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:59:13
+  --> $DIR/mem_replace.rs:61:13
    |
 LL |     let _ = std::mem::replace(&mut refstr, "");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut refstr)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> $DIR/mem_replace.rs:62:13
+  --> $DIR/mem_replace.rs:64:13
    |
 LL |     let _ = std::mem::replace(&mut slice, &[]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut slice)`
 
-error: aborting due to 19 previous errors
+error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
+  --> $DIR/mem_replace.rs:94:13
+   |
+LL |     let _ = std::mem::replace(&mut s, String::default());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
+
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/min_rust_version_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_attr.rs
index c4c6391bb4c..cd148063bf0 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_attr.rs
+++ b/src/tools/clippy/tests/ui/min_rust_version_attr.rs
@@ -1,240 +1,29 @@
 #![allow(clippy::redundant_clone)]
 #![feature(custom_inner_attributes)]
-#![clippy::msrv = "1.0.0"]
 
-use std::ops::{Deref, RangeFrom};
+fn main() {}
 
-fn approx_const() {
+fn just_under_msrv() {
+    #![clippy::msrv = "1.42.0"]
     let log2_10 = 3.321928094887362;
-    let log10_2 = 0.301029995663981;
 }
 
-fn cloned_instead_of_copied() {
-    let _ = [1].iter().cloned();
-}
-
-fn option_as_ref_deref() {
-    let mut opt = Some(String::from("123"));
-
-    let _ = opt.as_ref().map(String::as_str);
-    let _ = opt.as_ref().map(|x| x.as_str());
-    let _ = opt.as_mut().map(String::as_mut_str);
-    let _ = opt.as_mut().map(|x| x.as_mut_str());
-}
-
-fn match_like_matches() {
-    let _y = match Some(5) {
-        Some(0) => true,
-        _ => false,
-    };
-}
-
-fn match_same_arms() {
-    match (1, 2, 3) {
-        (1, .., 3) => 42,
-        (.., 3) => 42, //~ ERROR match arms have same body
-        _ => 0,
-    };
-}
-
-fn match_same_arms2() {
-    let _ = match Some(42) {
-        Some(_) => 24,
-        None => 24, //~ ERROR match arms have same body
-    };
-}
-
-pub fn manual_strip_msrv() {
-    let s = "hello, world!";
-    if s.starts_with("hello, ") {
-        assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
-    }
-}
-
-pub fn redundant_fieldnames() {
-    let start = 0;
-    let _ = RangeFrom { start: start };
-}
-
-pub fn redundant_static_lifetime() {
-    const VAR_ONE: &'static str = "Test constant #1";
-}
-
-pub fn checked_conversion() {
-    let value: i64 = 42;
-    let _ = value <= (u32::max_value() as i64) && value >= 0;
-    let _ = value <= (u32::MAX as i64) && value >= 0;
-}
-
-pub struct FromOverInto(String);
-
-impl Into<FromOverInto> for String {
-    fn into(self) -> FromOverInto {
-        FromOverInto(self)
-    }
-}
-
-pub fn filter_map_next() {
-    let a = ["1", "lol", "3", "NaN", "5"];
-
-    #[rustfmt::skip]
-    let _: Option<u32> = vec![1, 2, 3, 4, 5, 6]
-        .into_iter()
-        .filter_map(|x| {
-            if x == 2 {
-                Some(x * 2)
-            } else {
-                None
-            }
-        })
-        .next();
-}
-
-#[allow(clippy::no_effect)]
-#[allow(clippy::short_circuit_statement)]
-#[allow(clippy::unnecessary_operation)]
-pub fn manual_range_contains() {
-    let x = 5;
-    x >= 8 && x < 12;
-}
-
-pub fn use_self() {
-    struct Foo;
-
-    impl Foo {
-        fn new() -> Foo {
-            Foo {}
-        }
-        fn test() -> Foo {
-            Foo::new()
-        }
-    }
-}
-
-fn replace_with_default() {
-    let mut s = String::from("foo");
-    let _ = std::mem::replace(&mut s, String::default());
-}
-
-fn map_unwrap_or() {
-    let opt = Some(1);
-
-    // Check for `option.map(_).unwrap_or(_)` use.
-    // Single line case.
-    let _ = opt
-        .map(|x| x + 1)
-        // Should lint even though this call is on a separate line.
-        .unwrap_or(0);
-}
-
-// Could be const
-fn missing_const_for_fn() -> i32 {
-    1
-}
-
-fn unnest_or_patterns() {
-    struct TS(u8, u8);
-    if let TS(0, x) | TS(1, x) = TS(0, 0) {}
-}
-
-#[cfg_attr(rustfmt, rustfmt_skip)]
-fn deprecated_cfg_attr() {}
-
-#[warn(clippy::cast_lossless)]
-fn int_from_bool() -> u8 {
-    true as u8
-}
-
-fn err_expect() {
-    let x: Result<u32, &str> = Ok(10);
-    x.err().expect("Testing expect_err");
-}
-
-fn cast_abs_to_unsigned() {
-    let x: i32 = 10;
-    assert_eq!(10u32, x.abs() as u32);
-}
-
-fn manual_rem_euclid() {
-    let x: i32 = 10;
-    let _: i32 = ((x % 4) + 4) % 4;
-}
-
-fn manual_clamp() {
-    let (input, min, max) = (0, -1, 2);
-    let _ = if input < min {
-        min
-    } else if input > max {
-        max
-    } else {
-        input
-    };
-}
-
-fn main() {
-    filter_map_next();
-    checked_conversion();
-    redundant_fieldnames();
-    redundant_static_lifetime();
-    option_as_ref_deref();
-    match_like_matches();
-    match_same_arms();
-    match_same_arms2();
-    manual_strip_msrv();
-    manual_range_contains();
-    use_self();
-    replace_with_default();
-    map_unwrap_or();
-    missing_const_for_fn();
-    unnest_or_patterns();
-    int_from_bool();
-    err_expect();
-    cast_abs_to_unsigned();
-    manual_rem_euclid();
-    manual_clamp();
+fn meets_msrv() {
+    #![clippy::msrv = "1.43.0"]
+    let log2_10 = 3.321928094887362;
 }
 
-mod just_under_msrv {
-    #![feature(custom_inner_attributes)]
+fn just_above_msrv() {
     #![clippy::msrv = "1.44.0"]
-
-    fn main() {
-        let s = "hello, world!";
-        if s.starts_with("hello, ") {
-            assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
-        }
-    }
-}
-
-mod meets_msrv {
-    #![feature(custom_inner_attributes)]
-    #![clippy::msrv = "1.45.0"]
-
-    fn main() {
-        let s = "hello, world!";
-        if s.starts_with("hello, ") {
-            assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
-        }
-    }
+    let log2_10 = 3.321928094887362;
 }
 
-mod just_above_msrv {
-    #![feature(custom_inner_attributes)]
-    #![clippy::msrv = "1.46.0"]
-
-    fn main() {
-        let s = "hello, world!";
-        if s.starts_with("hello, ") {
-            assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
-        }
-    }
+fn no_patch_under() {
+    #![clippy::msrv = "1.42"]
+    let log2_10 = 3.321928094887362;
 }
 
-mod const_rem_euclid {
-    #![feature(custom_inner_attributes)]
-    #![clippy::msrv = "1.50.0"]
-
-    pub const fn const_rem_euclid_4(num: i32) -> i32 {
-        ((num % 4) + 4) % 4
-    }
+fn no_patch_meets() {
+    #![clippy::msrv = "1.43"]
+    let log2_10 = 3.321928094887362;
 }
diff --git a/src/tools/clippy/tests/ui/min_rust_version_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_attr.stderr
index d1cffc26a83..68aa5874819 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_attr.stderr
+++ b/src/tools/clippy/tests/ui/min_rust_version_attr.stderr
@@ -1,37 +1,27 @@
-error: stripping a prefix manually
-  --> $DIR/min_rust_version_attr.rs:216:24
+error: approximate value of `f{32, 64}::consts::LOG2_10` found
+  --> $DIR/min_rust_version_attr.rs:13:19
    |
-LL |             assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
-   |                        ^^^^^^^^^^^^^^^^^^^^
-   |
-note: the prefix was tested here
-  --> $DIR/min_rust_version_attr.rs:215:9
-   |
-LL |         if s.starts_with("hello, ") {
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: `-D clippy::manual-strip` implied by `-D warnings`
-help: try using the `strip_prefix` method
-   |
-LL ~         if let Some(<stripped>) = s.strip_prefix("hello, ") {
-LL ~             assert_eq!(<stripped>.to_uppercase(), "WORLD!");
+LL |     let log2_10 = 3.321928094887362;
+   |                   ^^^^^^^^^^^^^^^^^
    |
+   = help: consider using the constant directly
+   = note: `#[deny(clippy::approx_constant)]` on by default
 
-error: stripping a prefix manually
-  --> $DIR/min_rust_version_attr.rs:228:24
+error: approximate value of `f{32, 64}::consts::LOG2_10` found
+  --> $DIR/min_rust_version_attr.rs:18:19
    |
-LL |             assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
-   |                        ^^^^^^^^^^^^^^^^^^^^
+LL |     let log2_10 = 3.321928094887362;
+   |                   ^^^^^^^^^^^^^^^^^
    |
-note: the prefix was tested here
-  --> $DIR/min_rust_version_attr.rs:227:9
-   |
-LL |         if s.starts_with("hello, ") {
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: try using the `strip_prefix` method
+   = help: consider using the constant directly
+
+error: approximate value of `f{32, 64}::consts::LOG2_10` found
+  --> $DIR/min_rust_version_attr.rs:28:19
    |
-LL ~         if let Some(<stripped>) = s.strip_prefix("hello, ") {
-LL ~             assert_eq!(<stripped>.to_uppercase(), "WORLD!");
+LL |     let log2_10 = 3.321928094887362;
+   |                   ^^^^^^^^^^^^^^^^^
    |
+   = help: consider using the constant directly
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs
index f20841891a7..02892f329af 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs
+++ b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs
@@ -2,3 +2,17 @@
 #![clippy::msrv = "invalid.version"]
 
 fn main() {}
+
+#[clippy::msrv = "invalid.version"]
+fn outer_attr() {}
+
+mod multiple {
+    #![clippy::msrv = "1.40"]
+    #![clippy::msrv = "=1.35.0"]
+    #![clippy::msrv = "1.10.1"]
+
+    mod foo {
+        #![clippy::msrv = "1"]
+        #![clippy::msrv = "1.0.0"]
+    }
+}
diff --git a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr
index 6ff88ca56f8..93370a0fa9c 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr
+++ b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr
@@ -4,5 +4,47 @@ error: `invalid.version` is not a valid Rust version
 LL | #![clippy::msrv = "invalid.version"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: `msrv` cannot be an outer attribute
+  --> $DIR/min_rust_version_invalid_attr.rs:6:1
+   |
+LL | #[clippy::msrv = "invalid.version"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `msrv` is defined multiple times
+  --> $DIR/min_rust_version_invalid_attr.rs:11:5
+   |
+LL |     #![clippy::msrv = "=1.35.0"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first definition found here
+  --> $DIR/min_rust_version_invalid_attr.rs:10:5
+   |
+LL |     #![clippy::msrv = "1.40"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `msrv` is defined multiple times
+  --> $DIR/min_rust_version_invalid_attr.rs:12:5
+   |
+LL |     #![clippy::msrv = "1.10.1"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first definition found here
+  --> $DIR/min_rust_version_invalid_attr.rs:10:5
+   |
+LL |     #![clippy::msrv = "1.40"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `msrv` is defined multiple times
+  --> $DIR/min_rust_version_invalid_attr.rs:16:9
+   |
+LL |         #![clippy::msrv = "1.0.0"]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first definition found here
+  --> $DIR/min_rust_version_invalid_attr.rs:15:9
+   |
+LL |         #![clippy::msrv = "1"]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.rs
deleted file mode 100644
index e882d5ccf91..00000000000
--- a/src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(custom_inner_attributes)]
-#![clippy::msrv = "1.40"]
-#![clippy::msrv = "=1.35.0"]
-#![clippy::msrv = "1.10.1"]
-
-mod foo {
-    #![clippy::msrv = "1"]
-    #![clippy::msrv = "1.0.0"]
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.stderr
deleted file mode 100644
index e3ff6605cde..00000000000
--- a/src/tools/clippy/tests/ui/min_rust_version_multiple_inner_attr.stderr
+++ /dev/null
@@ -1,38 +0,0 @@
-error: `msrv` is defined multiple times
-  --> $DIR/min_rust_version_multiple_inner_attr.rs:3:1
-   |
-LL | #![clippy::msrv = "=1.35.0"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: first definition found here
-  --> $DIR/min_rust_version_multiple_inner_attr.rs:2:1
-   |
-LL | #![clippy::msrv = "1.40"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `msrv` is defined multiple times
-  --> $DIR/min_rust_version_multiple_inner_attr.rs:4:1
-   |
-LL | #![clippy::msrv = "1.10.1"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: first definition found here
-  --> $DIR/min_rust_version_multiple_inner_attr.rs:2:1
-   |
-LL | #![clippy::msrv = "1.40"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `msrv` is defined multiple times
-  --> $DIR/min_rust_version_multiple_inner_attr.rs:8:5
-   |
-LL |     #![clippy::msrv = "1.0.0"]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: first definition found here
-  --> $DIR/min_rust_version_multiple_inner_attr.rs:7:5
-   |
-LL |     #![clippy::msrv = "1"]
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/src/tools/clippy/tests/ui/min_rust_version_no_patch.rs b/src/tools/clippy/tests/ui/min_rust_version_no_patch.rs
deleted file mode 100644
index 98fffe1e351..00000000000
--- a/src/tools/clippy/tests/ui/min_rust_version_no_patch.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-#![allow(clippy::redundant_clone)]
-#![feature(custom_inner_attributes)]
-#![clippy::msrv = "1.0"]
-
-fn manual_strip_msrv() {
-    let s = "hello, world!";
-    if s.starts_with("hello, ") {
-        assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
-    }
-}
-
-fn main() {
-    manual_strip_msrv()
-}
diff --git a/src/tools/clippy/tests/ui/min_rust_version_outer_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_outer_attr.rs
deleted file mode 100644
index 551948bd72e..00000000000
--- a/src/tools/clippy/tests/ui/min_rust_version_outer_attr.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![feature(custom_inner_attributes)]
-
-#[clippy::msrv = "invalid.version"]
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/min_rust_version_outer_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_outer_attr.stderr
deleted file mode 100644
index 579ee7a87d2..00000000000
--- a/src/tools/clippy/tests/ui/min_rust_version_outer_attr.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `msrv` cannot be an outer attribute
-  --> $DIR/min_rust_version_outer_attr.rs:3:1
-   |
-LL | #[clippy::msrv = "invalid.version"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index 88f6935d224..b85e8878491 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -77,5 +77,17 @@ mod const_fn_stabilized_before_msrv {
     }
 }
 
+fn msrv_1_45() -> i32 {
+    #![clippy::msrv = "1.45"]
+
+    45
+}
+
+fn msrv_1_46() -> i32 {
+    #![clippy::msrv = "1.46"]
+
+    46
+}
+
 // Should not be const
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index 3eb52b68274..f8e221c82f1 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -81,5 +81,15 @@ LL | |         byte.is_ascii_digit();
 LL | |     }
    | |_____^
 
-error: aborting due to 10 previous errors
+error: this could be a `const fn`
+  --> $DIR/could_be_const.rs:86:1
+   |
+LL | / fn msrv_1_46() -> i32 {
+LL | |     #![clippy::msrv = "1.46"]
+LL | |
+LL | |     46
+LL | | }
+   | |_^
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_trait_methods.rs b/src/tools/clippy/tests/ui/missing_trait_methods.rs
new file mode 100644
index 00000000000..8df885919a3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_trait_methods.rs
@@ -0,0 +1,50 @@
+#![allow(unused, clippy::needless_lifetimes)]
+#![warn(clippy::missing_trait_methods)]
+
+trait A {
+    fn provided() {}
+}
+
+trait B {
+    fn required();
+
+    fn a(_: usize) -> usize {
+        1
+    }
+
+    fn b<'a, T: AsRef<[u8]>>(a: &'a T) -> &'a [u8] {
+        a.as_ref()
+    }
+}
+
+struct Partial;
+
+impl A for Partial {}
+
+impl B for Partial {
+    fn required() {}
+
+    fn a(_: usize) -> usize {
+        2
+    }
+}
+
+struct Complete;
+
+impl A for Complete {
+    fn provided() {}
+}
+
+impl B for Complete {
+    fn required() {}
+
+    fn a(_: usize) -> usize {
+        2
+    }
+
+    fn b<T: AsRef<[u8]>>(a: &T) -> &[u8] {
+        a.as_ref()
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_trait_methods.stderr b/src/tools/clippy/tests/ui/missing_trait_methods.stderr
new file mode 100644
index 00000000000..0c5205e1965
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_trait_methods.stderr
@@ -0,0 +1,27 @@
+error: missing trait method provided by default: `provided`
+  --> $DIR/missing_trait_methods.rs:22:1
+   |
+LL | impl A for Partial {}
+   | ^^^^^^^^^^^^^^^^^^
+   |
+help: implement the method
+  --> $DIR/missing_trait_methods.rs:5:5
+   |
+LL |     fn provided() {}
+   |     ^^^^^^^^^^^^^
+   = note: `-D clippy::missing-trait-methods` implied by `-D warnings`
+
+error: missing trait method provided by default: `b`
+  --> $DIR/missing_trait_methods.rs:24:1
+   |
+LL | impl B for Partial {
+   | ^^^^^^^^^^^^^^^^^^
+   |
+help: implement the method
+  --> $DIR/missing_trait_methods.rs:15:5
+   |
+LL |     fn b<'a, T: AsRef<[u8]>>(a: &'a T) -> &'a [u8] {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index aa2687159ef..340e89d2db1 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -3,7 +3,11 @@
 
 #[warn(clippy::all, clippy::needless_borrow)]
 #[allow(unused_variables)]
-#[allow(clippy::uninlined_format_args, clippy::unnecessary_mut_passed)]
+#[allow(
+    clippy::uninlined_format_args,
+    clippy::unnecessary_mut_passed,
+    clippy::unnecessary_to_owned
+)]
 fn main() {
     let a = 5;
     let ref_a = &a;
@@ -134,6 +138,7 @@ fn main() {
     multiple_constraints([[""]]);
     multiple_constraints_normalizes_to_same(X, X);
     let _ = Some("").unwrap_or("");
+    let _ = std::fs::write("x", "".to_string());
 
     only_sized(&""); // Don't lint. `Sized` is only bound
     let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound
@@ -276,8 +281,9 @@ mod copyable_iterator {
     fn dont_warn(mut x: Iter) {
         takes_iter(&mut x);
     }
+    #[allow(unused_mut)]
     fn warn(mut x: &mut Iter) {
-        takes_iter(&mut x)
+        takes_iter(x)
     }
 }
 
@@ -327,3 +333,55 @@ fn issue9383() {
         ManuallyDrop::drop(&mut ocean.coral);
     }
 }
+
+#[allow(dead_code)]
+fn closure_test() {
+    let env = "env".to_owned();
+    let arg = "arg".to_owned();
+    let f = |arg| {
+        let loc = "loc".to_owned();
+        let _ = std::fs::write("x", &env); // Don't lint. In environment
+        let _ = std::fs::write("x", arg);
+        let _ = std::fs::write("x", loc);
+    };
+    let _ = std::fs::write("x", &env); // Don't lint. Borrowed by `f`
+    f(arg);
+}
+
+#[allow(dead_code)]
+mod significant_drop {
+    #[derive(Debug)]
+    struct X;
+
+    #[derive(Debug)]
+    struct Y;
+
+    impl Drop for Y {
+        fn drop(&mut self) {}
+    }
+
+    fn foo(x: X, y: Y) {
+        debug(x);
+        debug(&y); // Don't lint. Has significant drop
+    }
+
+    fn debug(_: impl std::fmt::Debug) {}
+}
+
+#[allow(dead_code)]
+mod used_exactly_once {
+    fn foo(x: String) {
+        use_x(x);
+    }
+    fn use_x(_: impl AsRef<str>) {}
+}
+
+#[allow(dead_code)]
+mod used_more_than_once {
+    fn foo(x: String) {
+        use_x(&x);
+        use_x_again(&x);
+    }
+    fn use_x(_: impl AsRef<str>) {}
+    fn use_x_again(_: impl AsRef<str>) {}
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
index d41251e8f6a..c93711ac8e2 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -3,7 +3,11 @@
 
 #[warn(clippy::all, clippy::needless_borrow)]
 #[allow(unused_variables)]
-#[allow(clippy::uninlined_format_args, clippy::unnecessary_mut_passed)]
+#[allow(
+    clippy::uninlined_format_args,
+    clippy::unnecessary_mut_passed,
+    clippy::unnecessary_to_owned
+)]
 fn main() {
     let a = 5;
     let ref_a = &a;
@@ -134,6 +138,7 @@ fn main() {
     multiple_constraints(&[[""]]);
     multiple_constraints_normalizes_to_same(&X, X);
     let _ = Some("").unwrap_or(&"");
+    let _ = std::fs::write("x", &"".to_string());
 
     only_sized(&""); // Don't lint. `Sized` is only bound
     let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound
@@ -276,6 +281,7 @@ mod copyable_iterator {
     fn dont_warn(mut x: Iter) {
         takes_iter(&mut x);
     }
+    #[allow(unused_mut)]
     fn warn(mut x: &mut Iter) {
         takes_iter(&mut x)
     }
@@ -327,3 +333,55 @@ fn issue9383() {
         ManuallyDrop::drop(&mut ocean.coral);
     }
 }
+
+#[allow(dead_code)]
+fn closure_test() {
+    let env = "env".to_owned();
+    let arg = "arg".to_owned();
+    let f = |arg| {
+        let loc = "loc".to_owned();
+        let _ = std::fs::write("x", &env); // Don't lint. In environment
+        let _ = std::fs::write("x", &arg);
+        let _ = std::fs::write("x", &loc);
+    };
+    let _ = std::fs::write("x", &env); // Don't lint. Borrowed by `f`
+    f(arg);
+}
+
+#[allow(dead_code)]
+mod significant_drop {
+    #[derive(Debug)]
+    struct X;
+
+    #[derive(Debug)]
+    struct Y;
+
+    impl Drop for Y {
+        fn drop(&mut self) {}
+    }
+
+    fn foo(x: X, y: Y) {
+        debug(&x);
+        debug(&y); // Don't lint. Has significant drop
+    }
+
+    fn debug(_: impl std::fmt::Debug) {}
+}
+
+#[allow(dead_code)]
+mod used_exactly_once {
+    fn foo(x: String) {
+        use_x(&x);
+    }
+    fn use_x(_: impl AsRef<str>) {}
+}
+
+#[allow(dead_code)]
+mod used_more_than_once {
+    fn foo(x: String) {
+        use_x(&x);
+        use_x_again(&x);
+    }
+    fn use_x(_: impl AsRef<str>) {}
+    fn use_x_again(_: impl AsRef<str>) {}
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr
index 5af68706d4b..8b593268bec 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -1,5 +1,5 @@
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:11:15
+  --> $DIR/needless_borrow.rs:15:15
    |
 LL |     let _ = x(&&a); // warn
    |               ^^^ help: change this to: `&a`
@@ -7,172 +7,208 @@ LL |     let _ = x(&&a); // warn
    = note: `-D clippy::needless-borrow` implied by `-D warnings`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:15:13
+  --> $DIR/needless_borrow.rs:19:13
    |
 LL |     mut_ref(&mut &mut b); // warn
    |             ^^^^^^^^^^^ help: change this to: `&mut b`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:27:13
+  --> $DIR/needless_borrow.rs:31:13
    |
 LL |             &&a
    |             ^^^ help: change this to: `&a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:29:15
+  --> $DIR/needless_borrow.rs:33:15
    |
 LL |         46 => &&a,
    |               ^^^ help: change this to: `&a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:35:27
+  --> $DIR/needless_borrow.rs:39:27
    |
 LL |                     break &ref_a;
    |                           ^^^^^^ help: change this to: `ref_a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:42:15
+  --> $DIR/needless_borrow.rs:46:15
    |
 LL |     let _ = x(&&&a);
    |               ^^^^ help: change this to: `&a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:43:15
+  --> $DIR/needless_borrow.rs:47:15
    |
 LL |     let _ = x(&mut &&a);
    |               ^^^^^^^^ help: change this to: `&a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:44:15
+  --> $DIR/needless_borrow.rs:48:15
    |
 LL |     let _ = x(&&&mut b);
    |               ^^^^^^^^ help: change this to: `&mut b`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:45:15
+  --> $DIR/needless_borrow.rs:49:15
    |
 LL |     let _ = x(&&ref_a);
    |               ^^^^^^^ help: change this to: `ref_a`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:48:11
+  --> $DIR/needless_borrow.rs:52:11
    |
 LL |         x(&b);
    |           ^^ help: change this to: `b`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:55:13
+  --> $DIR/needless_borrow.rs:59:13
    |
 LL |     mut_ref(&mut x);
    |             ^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:56:13
+  --> $DIR/needless_borrow.rs:60:13
    |
 LL |     mut_ref(&mut &mut x);
    |             ^^^^^^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:57:23
+  --> $DIR/needless_borrow.rs:61:23
    |
 LL |     let y: &mut i32 = &mut x;
    |                       ^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:58:23
+  --> $DIR/needless_borrow.rs:62:23
    |
 LL |     let y: &mut i32 = &mut &mut x;
    |                       ^^^^^^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:67:14
+  --> $DIR/needless_borrow.rs:71:14
    |
 LL |         0 => &mut x,
    |              ^^^^^^ help: change this to: `x`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:73:14
+  --> $DIR/needless_borrow.rs:77:14
    |
 LL |         0 => &mut x,
    |              ^^^^^^ help: change this to: `x`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:85:13
+  --> $DIR/needless_borrow.rs:89:13
    |
 LL |     let _ = (&x).0;
    |             ^^^^ help: change this to: `x`
 
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:87:22
+  --> $DIR/needless_borrow.rs:91:22
    |
 LL |     let _ = unsafe { (&*x).0 };
    |                      ^^^^^ help: change this to: `(*x)`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:97:5
+  --> $DIR/needless_borrow.rs:101:5
    |
 LL |     (&&()).foo();
    |     ^^^^^^ help: change this to: `(&())`
 
 error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:106:5
+  --> $DIR/needless_borrow.rs:110:5
    |
 LL |     (&&5).foo();
    |     ^^^^^ help: change this to: `(&5)`
 
 error: the borrowed expression implements the required traits
-  --> $DIR/needless_borrow.rs:131:51
+  --> $DIR/needless_borrow.rs:135: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
+  --> $DIR/needless_borrow.rs:136: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
+  --> $DIR/needless_borrow.rs:137: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
+  --> $DIR/needless_borrow.rs:138:26
    |
 LL |     multiple_constraints(&[[""]]);
    |                          ^^^^^^^ help: change this to: `[[""]]`
 
 error: the borrowed expression implements the required traits
-  --> $DIR/needless_borrow.rs:135:45
+  --> $DIR/needless_borrow.rs:139: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
+  --> $DIR/needless_borrow.rs:140:32
    |
 LL |     let _ = Some("").unwrap_or(&"");
    |                                ^^^ help: change this to: `""`
 
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:141:33
+   |
+LL |     let _ = std::fs::write("x", &"".to_string());
+   |                                 ^^^^^^^^^^^^^^^ help: change this to: `"".to_string()`
+
 error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:187:13
+  --> $DIR/needless_borrow.rs:192: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:196:13
+  --> $DIR/needless_borrow.rs:201:13
    |
 LL |             (&mut self.f)()
    |             ^^^^^^^^^^^^^ help: change this to: `(self.f)`
 
 error: the borrowed expression implements the required traits
-  --> $DIR/needless_borrow.rs:298:55
+  --> $DIR/needless_borrow.rs:286:20
+   |
+LL |         takes_iter(&mut x)
+   |                    ^^^^^^ help: change this to: `x`
+
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:304: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
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:344:37
+   |
+LL |         let _ = std::fs::write("x", &arg);
+   |                                     ^^^^ help: change this to: `arg`
+
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:345:37
+   |
+LL |         let _ = std::fs::write("x", &loc);
+   |                                     ^^^^ help: change this to: `loc`
+
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:364:15
+   |
+LL |         debug(&x);
+   |               ^^ help: change this to: `x`
+
+error: the borrowed expression implements the required traits
+  --> $DIR/needless_borrow.rs:374:15
+   |
+LL |         use_x(&x);
+   |               ^^ help: change this to: `x`
+
+error: aborting due to 35 previous errors
 
diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.fixed b/src/tools/clippy/tests/ui/option_as_ref_deref.fixed
index 07d7f0b45b0..bc376d0d7fb 100644
--- a/src/tools/clippy/tests/ui/option_as_ref_deref.fixed
+++ b/src/tools/clippy/tests/ui/option_as_ref_deref.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 
-#![allow(unused_imports, clippy::redundant_clone)]
+#![feature(custom_inner_attributes)]
+#![allow(unused, clippy::redundant_clone)]
 #![warn(clippy::option_as_ref_deref)]
 
 use std::ffi::{CString, OsString};
@@ -42,3 +43,17 @@ fn main() {
     // Issue #5927
     let _ = opt.as_deref();
 }
+
+fn msrv_1_39() {
+    #![clippy::msrv = "1.39"]
+
+    let opt = Some(String::from("123"));
+    let _ = opt.as_ref().map(String::as_str);
+}
+
+fn msrv_1_40() {
+    #![clippy::msrv = "1.40"]
+
+    let opt = Some(String::from("123"));
+    let _ = opt.as_deref();
+}
diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.rs b/src/tools/clippy/tests/ui/option_as_ref_deref.rs
index 6ae059c9425..ba3a2eedc22 100644
--- a/src/tools/clippy/tests/ui/option_as_ref_deref.rs
+++ b/src/tools/clippy/tests/ui/option_as_ref_deref.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 
-#![allow(unused_imports, clippy::redundant_clone)]
+#![feature(custom_inner_attributes)]
+#![allow(unused, clippy::redundant_clone)]
 #![warn(clippy::option_as_ref_deref)]
 
 use std::ffi::{CString, OsString};
@@ -45,3 +46,17 @@ fn main() {
     // Issue #5927
     let _ = opt.as_ref().map(std::ops::Deref::deref);
 }
+
+fn msrv_1_39() {
+    #![clippy::msrv = "1.39"]
+
+    let opt = Some(String::from("123"));
+    let _ = opt.as_ref().map(String::as_str);
+}
+
+fn msrv_1_40() {
+    #![clippy::msrv = "1.40"]
+
+    let opt = Some(String::from("123"));
+    let _ = opt.as_ref().map(String::as_str);
+}
diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr
index 62f28232475..7de8b3b6ba4 100644
--- a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr
+++ b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr
@@ -1,5 +1,5 @@
 error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:13:13
+  --> $DIR/option_as_ref_deref.rs:14:13
    |
 LL |     let _ = opt.clone().as_ref().map(Deref::deref).map(str::len);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.clone().as_deref()`
@@ -7,7 +7,7 @@ LL |     let _ = opt.clone().as_ref().map(Deref::deref).map(str::len);
    = note: `-D clippy::option-as-ref-deref` implied by `-D warnings`
 
 error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:16:13
+  --> $DIR/option_as_ref_deref.rs:17:13
    |
 LL |       let _ = opt.clone()
    |  _____________^
@@ -17,94 +17,100 @@ LL | |         )
    | |_________^ help: try using as_deref instead: `opt.clone().as_deref()`
 
 error: called `.as_mut().map(DerefMut::deref_mut)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
-  --> $DIR/option_as_ref_deref.rs:22:13
+  --> $DIR/option_as_ref_deref.rs:23:13
    |
 LL |     let _ = opt.as_mut().map(DerefMut::deref_mut);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
 
 error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:24:13
+  --> $DIR/option_as_ref_deref.rs:25:13
    |
 LL |     let _ = opt.as_ref().map(String::as_str);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 
 error: called `.as_ref().map(|x| x.as_str())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:25:13
+  --> $DIR/option_as_ref_deref.rs:26:13
    |
 LL |     let _ = opt.as_ref().map(|x| x.as_str());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 
 error: called `.as_mut().map(String::as_mut_str)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
-  --> $DIR/option_as_ref_deref.rs:26:13
+  --> $DIR/option_as_ref_deref.rs:27:13
    |
 LL |     let _ = opt.as_mut().map(String::as_mut_str);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
 
 error: called `.as_mut().map(|x| x.as_mut_str())` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
-  --> $DIR/option_as_ref_deref.rs:27:13
+  --> $DIR/option_as_ref_deref.rs:28:13
    |
 LL |     let _ = opt.as_mut().map(|x| x.as_mut_str());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
 
 error: called `.as_ref().map(CString::as_c_str)` on an Option value. This can be done more directly by calling `Some(CString::new(vec![]).unwrap()).as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:28:13
+  --> $DIR/option_as_ref_deref.rs:29:13
    |
 LL |     let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(CString::new(vec![]).unwrap()).as_deref()`
 
 error: called `.as_ref().map(OsString::as_os_str)` on an Option value. This can be done more directly by calling `Some(OsString::new()).as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:29:13
+  --> $DIR/option_as_ref_deref.rs:30:13
    |
 LL |     let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(OsString::new()).as_deref()`
 
 error: called `.as_ref().map(PathBuf::as_path)` on an Option value. This can be done more directly by calling `Some(PathBuf::new()).as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:30:13
+  --> $DIR/option_as_ref_deref.rs:31:13
    |
 LL |     let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(PathBuf::new()).as_deref()`
 
 error: called `.as_ref().map(Vec::as_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:31:13
+  --> $DIR/option_as_ref_deref.rs:32:13
    |
 LL |     let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(Vec::<()>::new()).as_deref()`
 
 error: called `.as_mut().map(Vec::as_mut_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref_mut()` instead
-  --> $DIR/option_as_ref_deref.rs:32:13
+  --> $DIR/option_as_ref_deref.rs:33:13
    |
 LL |     let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `Some(Vec::<()>::new()).as_deref_mut()`
 
 error: called `.as_ref().map(|x| x.deref())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:34:13
+  --> $DIR/option_as_ref_deref.rs:35:13
    |
 LL |     let _ = opt.as_ref().map(|x| x.deref());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 
 error: called `.as_mut().map(|x| x.deref_mut())` on an Option value. This can be done more directly by calling `opt.clone().as_deref_mut()` instead
-  --> $DIR/option_as_ref_deref.rs:35:13
+  --> $DIR/option_as_ref_deref.rs:36:13
    |
 LL |     let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.clone().as_deref_mut()`
 
 error: called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:42:13
+  --> $DIR/option_as_ref_deref.rs:43:13
    |
 LL |     let _ = opt.as_ref().map(|x| &**x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 
 error: called `.as_mut().map(|x| &mut **x)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
-  --> $DIR/option_as_ref_deref.rs:43:13
+  --> $DIR/option_as_ref_deref.rs:44:13
    |
 LL |     let _ = opt.as_mut().map(|x| &mut **x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
 
 error: called `.as_ref().map(std::ops::Deref::deref)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
-  --> $DIR/option_as_ref_deref.rs:46:13
+  --> $DIR/option_as_ref_deref.rs:47:13
    |
 LL |     let _ = opt.as_ref().map(std::ops::Deref::deref);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
 
-error: aborting due to 17 previous errors
+error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
+  --> $DIR/option_as_ref_deref.rs:61:13
+   |
+LL |     let _ = opt.as_ref().map(String::as_str);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
+
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 896430780ea..23b1aa8bebd 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -225,4 +225,15 @@ mod issue8239 {
     }
 }
 
+mod issue9608 {
+    fn sig_drop() {
+        enum X {
+            X(std::fs::File),
+            Y(u32),
+        }
+
+        let _ = None.unwrap_or(X::Y(0));
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index 2473163d4fd..039998f22dd 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -225,4 +225,15 @@ mod issue8239 {
     }
 }
 
+mod issue9608 {
+    fn sig_drop() {
+        enum X {
+            X(std::fs::File),
+            Y(u32),
+        }
+
+        let _ = None.unwrap_or(X::Y(0));
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/partial_pub_fields.rs b/src/tools/clippy/tests/ui/partial_pub_fields.rs
new file mode 100644
index 00000000000..668545da844
--- /dev/null
+++ b/src/tools/clippy/tests/ui/partial_pub_fields.rs
@@ -0,0 +1,40 @@
+#![allow(unused)]
+#![warn(clippy::partial_pub_fields)]
+
+fn main() {
+    use std::collections::HashMap;
+
+    #[derive(Default)]
+    pub struct FileSet {
+        files: HashMap<String, u32>,
+        pub paths: HashMap<u32, String>,
+    }
+
+    pub struct Color {
+        pub r: u8,
+        pub g: u8,
+        b: u8,
+    }
+
+    pub struct Point(i32, pub i32);
+
+    pub struct Visibility {
+        r#pub: bool,
+        pub pos: u32,
+    }
+
+    // Don't lint on empty structs;
+    pub struct Empty1;
+    pub struct Empty2();
+    pub struct Empty3 {};
+
+    // Don't lint on structs with one field.
+    pub struct Single1(i32);
+    pub struct Single2(pub i32);
+    pub struct Single3 {
+        v1: i32,
+    }
+    pub struct Single4 {
+        pub v1: i32,
+    }
+}
diff --git a/src/tools/clippy/tests/ui/partial_pub_fields.stderr b/src/tools/clippy/tests/ui/partial_pub_fields.stderr
new file mode 100644
index 00000000000..84cfc1a9194
--- /dev/null
+++ b/src/tools/clippy/tests/ui/partial_pub_fields.stderr
@@ -0,0 +1,35 @@
+error: mixed usage of pub and non-pub fields
+  --> $DIR/partial_pub_fields.rs:10:9
+   |
+LL |         pub paths: HashMap<u32, String>,
+   |         ^^^
+   |
+   = help: consider using private field here
+   = note: `-D clippy::partial-pub-fields` implied by `-D warnings`
+
+error: mixed usage of pub and non-pub fields
+  --> $DIR/partial_pub_fields.rs:16:9
+   |
+LL |         b: u8,
+   |         ^
+   |
+   = help: consider using public field here
+
+error: mixed usage of pub and non-pub fields
+  --> $DIR/partial_pub_fields.rs:19:27
+   |
+LL |     pub struct Point(i32, pub i32);
+   |                           ^^^
+   |
+   = help: consider using private field here
+
+error: mixed usage of pub and non-pub fields
+  --> $DIR/partial_pub_fields.rs:23:9
+   |
+LL |         pub pos: u32,
+   |         ^^^
+   |
+   = help: consider using private field here
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index fd15001e540..5f54101ca15 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -3,7 +3,7 @@
 #![warn(clippy::ptr_arg)]
 
 use std::borrow::Cow;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 
 fn do_vec(x: &Vec<i64>) {
     //Nothing here
@@ -207,3 +207,31 @@ fn cow_conditional_to_mut(a: &mut Cow<str>) {
         a.to_mut().push_str("foo");
     }
 }
+
+// Issue #9542
+fn dyn_trait_ok(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
+    trait T {}
+    impl<U> T for Vec<U> {}
+    impl T for String {}
+    impl T for PathBuf {}
+    fn takes_dyn(_: &mut dyn T) {}
+
+    takes_dyn(a);
+    takes_dyn(b);
+    takes_dyn(c);
+}
+
+fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
+    trait T {}
+    impl<U> T for Vec<U> {}
+    impl<U> T for [U] {}
+    impl T for String {}
+    impl T for str {}
+    impl T for PathBuf {}
+    impl T for Path {}
+    fn takes_dyn(_: &mut dyn T) {}
+
+    takes_dyn(a);
+    takes_dyn(b);
+    takes_dyn(c);
+}
diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr
index d64b5f454a5..6b4de98ce88 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.stderr
+++ b/src/tools/clippy/tests/ui/ptr_arg.stderr
@@ -162,5 +162,23 @@ error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a sl
 LL | fn mut_vec_slice_methods(v: &mut Vec<u32>) {
    |                             ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
 
-error: aborting due to 17 previous errors
+error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
+  --> $DIR/ptr_arg.rs:224:17
+   |
+LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
+   |                 ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
+
+error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do
+  --> $DIR/ptr_arg.rs:224:35
+   |
+LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
+   |                                   ^^^^^^^^^^^ help: change this to: `&mut str`
+
+error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do
+  --> $DIR/ptr_arg.rs:224:51
+   |
+LL | fn dyn_trait(a: &mut Vec<u32>, b: &mut String, c: &mut PathBuf) {
+   |                                                   ^^^^^^^^^^^^ help: change this to: `&mut Path`
+
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/range_contains.fixed b/src/tools/clippy/tests/ui/range_contains.fixed
index 85d021b2f25..824f00cb99e 100644
--- a/src/tools/clippy/tests/ui/range_contains.fixed
+++ b/src/tools/clippy/tests/ui/range_contains.fixed
@@ -1,10 +1,12 @@
 // run-rustfix
 
-#[warn(clippy::manual_range_contains)]
-#[allow(unused)]
-#[allow(clippy::no_effect)]
-#[allow(clippy::short_circuit_statement)]
-#[allow(clippy::unnecessary_operation)]
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_range_contains)]
+#![allow(unused)]
+#![allow(clippy::no_effect)]
+#![allow(clippy::short_circuit_statement)]
+#![allow(clippy::unnecessary_operation)]
+
 fn main() {
     let x = 9_i32;
 
@@ -62,3 +64,17 @@ fn main() {
 pub const fn in_range(a: i32) -> bool {
     3 <= a && a <= 20
 }
+
+fn msrv_1_34() {
+    #![clippy::msrv = "1.34"]
+
+    let x = 5;
+    x >= 8 && x < 34;
+}
+
+fn msrv_1_35() {
+    #![clippy::msrv = "1.35"]
+
+    let x = 5;
+    (8..35).contains(&x);
+}
diff --git a/src/tools/clippy/tests/ui/range_contains.rs b/src/tools/clippy/tests/ui/range_contains.rs
index 9a7a75dc132..df925eeadfe 100644
--- a/src/tools/clippy/tests/ui/range_contains.rs
+++ b/src/tools/clippy/tests/ui/range_contains.rs
@@ -1,10 +1,12 @@
 // run-rustfix
 
-#[warn(clippy::manual_range_contains)]
-#[allow(unused)]
-#[allow(clippy::no_effect)]
-#[allow(clippy::short_circuit_statement)]
-#[allow(clippy::unnecessary_operation)]
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_range_contains)]
+#![allow(unused)]
+#![allow(clippy::no_effect)]
+#![allow(clippy::short_circuit_statement)]
+#![allow(clippy::unnecessary_operation)]
+
 fn main() {
     let x = 9_i32;
 
@@ -62,3 +64,17 @@ fn main() {
 pub const fn in_range(a: i32) -> bool {
     3 <= a && a <= 20
 }
+
+fn msrv_1_34() {
+    #![clippy::msrv = "1.34"]
+
+    let x = 5;
+    x >= 8 && x < 34;
+}
+
+fn msrv_1_35() {
+    #![clippy::msrv = "1.35"]
+
+    let x = 5;
+    x >= 8 && x < 35;
+}
diff --git a/src/tools/clippy/tests/ui/range_contains.stderr b/src/tools/clippy/tests/ui/range_contains.stderr
index 936859db5a1..9689e665b05 100644
--- a/src/tools/clippy/tests/ui/range_contains.stderr
+++ b/src/tools/clippy/tests/ui/range_contains.stderr
@@ -1,5 +1,5 @@
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:12:5
+  --> $DIR/range_contains.rs:14:5
    |
 LL |     x >= 8 && x < 12;
    |     ^^^^^^^^^^^^^^^^ help: use: `(8..12).contains(&x)`
@@ -7,118 +7,124 @@ LL |     x >= 8 && x < 12;
    = note: `-D clippy::manual-range-contains` implied by `-D warnings`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:13:5
+  --> $DIR/range_contains.rs:15:5
    |
 LL |     x < 42 && x >= 21;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(21..42).contains(&x)`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:14:5
+  --> $DIR/range_contains.rs:16:5
    |
 LL |     100 > x && 1 <= x;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(1..100).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:17:5
+  --> $DIR/range_contains.rs:19:5
    |
 LL |     x >= 9 && x <= 99;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(9..=99).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:18:5
+  --> $DIR/range_contains.rs:20:5
    |
 LL |     x <= 33 && x >= 1;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(1..=33).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:19:5
+  --> $DIR/range_contains.rs:21:5
    |
 LL |     999 >= x && 1 <= x;
    |     ^^^^^^^^^^^^^^^^^^ help: use: `(1..=999).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:22:5
+  --> $DIR/range_contains.rs:24:5
    |
 LL |     x < 8 || x >= 12;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(8..12).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:23:5
+  --> $DIR/range_contains.rs:25:5
    |
 LL |     x >= 42 || x < 21;
    |     ^^^^^^^^^^^^^^^^^ help: use: `!(21..42).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:24:5
+  --> $DIR/range_contains.rs:26:5
    |
 LL |     100 <= x || 1 > x;
    |     ^^^^^^^^^^^^^^^^^ help: use: `!(1..100).contains(&x)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:27:5
+  --> $DIR/range_contains.rs:29:5
    |
 LL |     x < 9 || x > 99;
    |     ^^^^^^^^^^^^^^^ help: use: `!(9..=99).contains(&x)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:28:5
+  --> $DIR/range_contains.rs:30:5
    |
 LL |     x > 33 || x < 1;
    |     ^^^^^^^^^^^^^^^ help: use: `!(1..=33).contains(&x)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:29:5
+  --> $DIR/range_contains.rs:31:5
    |
 LL |     999 < x || 1 > x;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(1..=999).contains(&x)`
 
 error: manual `Range::contains` implementation
-  --> $DIR/range_contains.rs:44:5
+  --> $DIR/range_contains.rs:46:5
    |
 LL |     y >= 0. && y < 1.;
    |     ^^^^^^^^^^^^^^^^^ help: use: `(0. ..1.).contains(&y)`
 
 error: manual `!RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:45:5
+  --> $DIR/range_contains.rs:47:5
    |
 LL |     y < 0. || y > 1.;
    |     ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:48:5
+  --> $DIR/range_contains.rs:50:5
    |
 LL |     x >= -10 && x <= 10;
    |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-10..=10).contains(&x)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:50:5
+  --> $DIR/range_contains.rs:52:5
    |
 LL |     y >= -3. && y <= 3.;
    |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-3. ..=3.).contains(&y)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:55:30
+  --> $DIR/range_contains.rs:57:30
    |
 LL |     (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
    |                              ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&z)`
 
 error: manual `RangeInclusive::contains` implementation
-  --> $DIR/range_contains.rs:55:5
+  --> $DIR/range_contains.rs:57:5
    |
 LL |     (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
    |     ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&x)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:56:29
+  --> $DIR/range_contains.rs:58:29
    |
 LL |     (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
    |                             ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&z)`
 
 error: manual `!Range::contains` implementation
-  --> $DIR/range_contains.rs:56:5
+  --> $DIR/range_contains.rs:58:5
    |
 LL |     (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
    |     ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&x)`
 
-error: aborting due to 20 previous errors
+error: manual `Range::contains` implementation
+  --> $DIR/range_contains.rs:79:5
+   |
+LL |     x >= 8 && x < 35;
+   |     ^^^^^^^^^^^^^^^^ help: use: `(8..35).contains(&x)`
+
+error: aborting due to 21 previous errors
 
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.fixed b/src/tools/clippy/tests/ui/redundant_field_names.fixed
index 5b4b8eeedd4..34ab552cb1d 100644
--- a/src/tools/clippy/tests/ui/redundant_field_names.fixed
+++ b/src/tools/clippy/tests/ui/redundant_field_names.fixed
@@ -1,4 +1,6 @@
 // run-rustfix
+
+#![feature(custom_inner_attributes)]
 #![warn(clippy::redundant_field_names)]
 #![allow(clippy::no_effect, dead_code, unused_variables)]
 
@@ -69,3 +71,17 @@ fn issue_3476() {
 
     S { foo: foo::<i32> };
 }
+
+fn msrv_1_16() {
+    #![clippy::msrv = "1.16"]
+
+    let start = 0;
+    let _ = RangeFrom { start: start };
+}
+
+fn msrv_1_17() {
+    #![clippy::msrv = "1.17"]
+
+    let start = 0;
+    let _ = RangeFrom { start };
+}
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.rs b/src/tools/clippy/tests/ui/redundant_field_names.rs
index 3f97b80c568..a051b1f96f0 100644
--- a/src/tools/clippy/tests/ui/redundant_field_names.rs
+++ b/src/tools/clippy/tests/ui/redundant_field_names.rs
@@ -1,4 +1,6 @@
 // run-rustfix
+
+#![feature(custom_inner_attributes)]
 #![warn(clippy::redundant_field_names)]
 #![allow(clippy::no_effect, dead_code, unused_variables)]
 
@@ -69,3 +71,17 @@ fn issue_3476() {
 
     S { foo: foo::<i32> };
 }
+
+fn msrv_1_16() {
+    #![clippy::msrv = "1.16"]
+
+    let start = 0;
+    let _ = RangeFrom { start: start };
+}
+
+fn msrv_1_17() {
+    #![clippy::msrv = "1.17"]
+
+    let start = 0;
+    let _ = RangeFrom { start: start };
+}
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.stderr b/src/tools/clippy/tests/ui/redundant_field_names.stderr
index 7976292df22..8b82e062b93 100644
--- a/src/tools/clippy/tests/ui/redundant_field_names.stderr
+++ b/src/tools/clippy/tests/ui/redundant_field_names.stderr
@@ -1,5 +1,5 @@
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:34:9
+  --> $DIR/redundant_field_names.rs:36:9
    |
 LL |         gender: gender,
    |         ^^^^^^^^^^^^^^ help: replace it with: `gender`
@@ -7,40 +7,46 @@ LL |         gender: gender,
    = note: `-D clippy::redundant-field-names` implied by `-D warnings`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:35:9
+  --> $DIR/redundant_field_names.rs:37:9
    |
 LL |         age: age,
    |         ^^^^^^^^ help: replace it with: `age`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:56:25
+  --> $DIR/redundant_field_names.rs:58:25
    |
 LL |     let _ = RangeFrom { start: start };
    |                         ^^^^^^^^^^^^ help: replace it with: `start`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:57:23
+  --> $DIR/redundant_field_names.rs:59:23
    |
 LL |     let _ = RangeTo { end: end };
    |                       ^^^^^^^^ help: replace it with: `end`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:58:21
+  --> $DIR/redundant_field_names.rs:60:21
    |
 LL |     let _ = Range { start: start, end: end };
    |                     ^^^^^^^^^^^^ help: replace it with: `start`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:58:35
+  --> $DIR/redundant_field_names.rs:60:35
    |
 LL |     let _ = Range { start: start, end: end };
    |                                   ^^^^^^^^ help: replace it with: `end`
 
 error: redundant field names in struct initialization
-  --> $DIR/redundant_field_names.rs:60:32
+  --> $DIR/redundant_field_names.rs:62:32
    |
 LL |     let _ = RangeToInclusive { end: end };
    |                                ^^^^^^^^ help: replace it with: `end`
 
-error: aborting due to 7 previous errors
+error: redundant field names in struct initialization
+  --> $DIR/redundant_field_names.rs:86:25
+   |
+LL |     let _ = RangeFrom { start: start };
+   |                         ^^^^^^^^^^^^ help: replace it with: `start`
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
index acc8f1e25b6..42110dbe81e 100644
--- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(custom_inner_attributes)]
 #![allow(unused)]
 
 #[derive(Debug)]
@@ -54,3 +55,15 @@ impl Foo {
 impl Bar for Foo {
     const TRAIT_VAR: &'static str = "foo";
 }
+
+fn msrv_1_16() {
+    #![clippy::msrv = "1.16"]
+
+    static V: &'static u8 = &16;
+}
+
+fn msrv_1_17() {
+    #![clippy::msrv = "1.17"]
+
+    static V: &u8 = &17;
+}
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
index f2f0f78659c..bc5200bc862 100644
--- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(custom_inner_attributes)]
 #![allow(unused)]
 
 #[derive(Debug)]
@@ -54,3 +55,15 @@ impl Foo {
 impl Bar for Foo {
     const TRAIT_VAR: &'static str = "foo";
 }
+
+fn msrv_1_16() {
+    #![clippy::msrv = "1.16"]
+
+    static V: &'static u8 = &16;
+}
+
+fn msrv_1_17() {
+    #![clippy::msrv = "1.17"]
+
+    static V: &'static u8 = &17;
+}
diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
index 649831f9c06..735113460d2 100644
--- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr
@@ -1,5 +1,5 @@
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:8:17
+  --> $DIR/redundant_static_lifetimes.rs:9:17
    |
 LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removing 'static.
    |                -^^^^^^^---- help: consider removing `'static`: `&str`
@@ -7,94 +7,100 @@ LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR Consider removin
    = note: `-D clippy::redundant-static-lifetimes` implied by `-D warnings`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:12:21
+  --> $DIR/redundant_static_lifetimes.rs:13:21
    |
 LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
    |                    -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:14:32
+  --> $DIR/redundant_static_lifetimes.rs:15:32
    |
 LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
    |                               -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:14:47
+  --> $DIR/redundant_static_lifetimes.rs:15:47
    |
 LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR Consider removing 'static
    |                                              -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:16:17
+  --> $DIR/redundant_static_lifetimes.rs:17:17
    |
 LL | const VAR_SIX: &'static u8 = &5;
    |                -^^^^^^^--- help: consider removing `'static`: `&u8`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:18:20
+  --> $DIR/redundant_static_lifetimes.rs:19:20
    |
 LL | const VAR_HEIGHT: &'static Foo = &Foo {};
    |                   -^^^^^^^---- help: consider removing `'static`: `&Foo`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:20:19
+  --> $DIR/redundant_static_lifetimes.rs:21:19
    |
 LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR Consider removing 'static.
    |                  -^^^^^^^----- help: consider removing `'static`: `&[u8]`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:22:19
+  --> $DIR/redundant_static_lifetimes.rs:23:19
    |
 LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
    |                  -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
 
 error: constants have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:24:19
+  --> $DIR/redundant_static_lifetimes.rs:25:19
    |
 LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
    |                  -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:26:25
+  --> $DIR/redundant_static_lifetimes.rs:27:25
    |
 LL | static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR Consider removing 'static.
    |                        -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:30:29
+  --> $DIR/redundant_static_lifetimes.rs:31:29
    |
 LL | static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR Consider removing 'static
    |                            -^^^^^^^---- help: consider removing `'static`: `&str`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:32:25
+  --> $DIR/redundant_static_lifetimes.rs:33:25
    |
 LL | static STATIC_VAR_SIX: &'static u8 = &5;
    |                        -^^^^^^^--- help: consider removing `'static`: `&u8`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:34:28
+  --> $DIR/redundant_static_lifetimes.rs:35:28
    |
 LL | static STATIC_VAR_HEIGHT: &'static Foo = &Foo {};
    |                           -^^^^^^^---- help: consider removing `'static`: `&Foo`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:36:27
+  --> $DIR/redundant_static_lifetimes.rs:37:27
    |
 LL | static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR Consider removing 'static.
    |                          -^^^^^^^----- help: consider removing `'static`: `&[u8]`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:38:27
+  --> $DIR/redundant_static_lifetimes.rs:39:27
    |
 LL | static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR Consider removing 'static.
    |                          -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)`
 
 error: statics have by default a `'static` lifetime
-  --> $DIR/redundant_static_lifetimes.rs:40:27
+  --> $DIR/redundant_static_lifetimes.rs:41:27
    |
 LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR Consider removing 'static.
    |                          -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]`
 
-error: aborting due to 16 previous errors
+error: statics have by default a `'static` lifetime
+  --> $DIR/redundant_static_lifetimes.rs:68:16
+   |
+LL |     static V: &'static u8 = &17;
+   |               -^^^^^^^--- help: consider removing `'static`: `&u8`
+
+error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ref_option_ref.rs b/src/tools/clippy/tests/ui/ref_option_ref.rs
index 2df45c927d7..e487799e152 100644
--- a/src/tools/clippy/tests/ui/ref_option_ref.rs
+++ b/src/tools/clippy/tests/ui/ref_option_ref.rs
@@ -45,3 +45,8 @@ impl RefOptTrait for u32 {
 fn main() {
     let x: &Option<&u32> = &None;
 }
+
+fn issue9682(arg: &Option<&mut String>) {
+    // Should not lint, as the inner ref is mutable making it non `Copy`
+    println!("{arg:?}");
+}
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.fixed b/src/tools/clippy/tests/ui/uninlined_format_args.fixed
index 3ca7a401902..10627447975 100644
--- a/src/tools/clippy/tests/ui/uninlined_format_args.fixed
+++ b/src/tools/clippy/tests/ui/uninlined_format_args.fixed
@@ -150,6 +150,19 @@ fn tester(fn_arg: i32) {
 
     println!(with_span!("{0} {1}" "{1} {0}"), local_i32, local_f64);
     println!("{}", with_span!(span val));
+
+    if local_i32 > 0 {
+        panic!("p1 {local_i32}");
+    }
+    if local_i32 > 0 {
+        panic!("p2 {local_i32}");
+    }
+    if local_i32 > 0 {
+        panic!("p3 {local_i32}");
+    }
+    if local_i32 > 0 {
+        panic!("p4 {local_i32}");
+    }
 }
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.rs b/src/tools/clippy/tests/ui/uninlined_format_args.rs
index 924191f4324..8e495ebd083 100644
--- a/src/tools/clippy/tests/ui/uninlined_format_args.rs
+++ b/src/tools/clippy/tests/ui/uninlined_format_args.rs
@@ -150,6 +150,19 @@ fn tester(fn_arg: i32) {
 
     println!(with_span!("{0} {1}" "{1} {0}"), local_i32, local_f64);
     println!("{}", with_span!(span val));
+
+    if local_i32 > 0 {
+        panic!("p1 {}", local_i32);
+    }
+    if local_i32 > 0 {
+        panic!("p2 {0}", local_i32);
+    }
+    if local_i32 > 0 {
+        panic!("p3 {local_i32}", local_i32 = local_i32);
+    }
+    if local_i32 > 0 {
+        panic!("p4 {local_i32}");
+    }
 }
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.stderr b/src/tools/clippy/tests/ui/uninlined_format_args.stderr
index d1a77492634..2ce3b7fa960 100644
--- a/src/tools/clippy/tests/ui/uninlined_format_args.stderr
+++ b/src/tools/clippy/tests/ui/uninlined_format_args.stderr
@@ -828,7 +828,43 @@ LL +     println!("{val}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:168:5
+  --> $DIR/uninlined_format_args.rs:155:9
+   |
+LL |         panic!("p1 {}", local_i32);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -         panic!("p1 {}", local_i32);
+LL +         panic!("p1 {local_i32}");
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:158:9
+   |
+LL |         panic!("p2 {0}", local_i32);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -         panic!("p2 {0}", local_i32);
+LL +         panic!("p2 {local_i32}");
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:161:9
+   |
+LL |         panic!("p3 {local_i32}", local_i32 = local_i32);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -         panic!("p3 {local_i32}", local_i32 = local_i32);
+LL +         panic!("p3 {local_i32}");
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:181:5
    |
 LL |     println!("expand='{}'", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -839,5 +875,5 @@ LL -     println!("expand='{}'", local_i32);
 LL +     println!("expand='{local_i32}'");
    |
 
-error: aborting due to 70 previous errors
+error: aborting due to 73 previous errors
 
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed
new file mode 100644
index 00000000000..96cc0877960
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed
@@ -0,0 +1,29 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+
+#![warn(clippy::uninlined_format_args)]
+
+fn main() {
+    let var = 1;
+
+    println!("val='{var}'");
+
+    if var > 0 {
+        panic!("p1 {}", var);
+    }
+    if var > 0 {
+        panic!("p2 {0}", var);
+    }
+    if var > 0 {
+        panic!("p3 {var}", var = var);
+    }
+
+    #[allow(non_fmt_panics)]
+    {
+        if var > 0 {
+            panic!("p4 {var}");
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.stderr b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.stderr
new file mode 100644
index 00000000000..2c806125922
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.stderr
@@ -0,0 +1,15 @@
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args_panic.rs:11:5
+   |
+LL |     println!("val='{}'", var);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::uninlined-format-args` implied by `-D warnings`
+help: change this to
+   |
+LL -     println!("val='{}'", var);
+LL +     println!("val='{var}'");
+   |
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed
new file mode 100644
index 00000000000..faf8ca4d3a7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed
@@ -0,0 +1,29 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+
+#![warn(clippy::uninlined_format_args)]
+
+fn main() {
+    let var = 1;
+
+    println!("val='{var}'");
+
+    if var > 0 {
+        panic!("p1 {var}");
+    }
+    if var > 0 {
+        panic!("p2 {var}");
+    }
+    if var > 0 {
+        panic!("p3 {var}");
+    }
+
+    #[allow(non_fmt_panics)]
+    {
+        if var > 0 {
+            panic!("p4 {var}");
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr
new file mode 100644
index 00000000000..0f09c45f413
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr
@@ -0,0 +1,51 @@
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args_panic.rs:11:5
+   |
+LL |     println!("val='{}'", var);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::uninlined-format-args` implied by `-D warnings`
+help: change this to
+   |
+LL -     println!("val='{}'", var);
+LL +     println!("val='{var}'");
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args_panic.rs:14:9
+   |
+LL |         panic!("p1 {}", var);
+   |         ^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -         panic!("p1 {}", var);
+LL +         panic!("p1 {var}");
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args_panic.rs:17:9
+   |
+LL |         panic!("p2 {0}", var);
+   |         ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -         panic!("p2 {0}", var);
+LL +         panic!("p2 {var}");
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args_panic.rs:20:9
+   |
+LL |         panic!("p3 {var}", var = var);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -         panic!("p3 {var}", var = var);
+LL +         panic!("p3 {var}");
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs b/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs
new file mode 100644
index 00000000000..6421c5bbed2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs
@@ -0,0 +1,29 @@
+// revisions: edition2018 edition2021
+//[edition2018] edition:2018
+//[edition2021] edition:2021
+// run-rustfix
+
+#![warn(clippy::uninlined_format_args)]
+
+fn main() {
+    let var = 1;
+
+    println!("val='{}'", var);
+
+    if var > 0 {
+        panic!("p1 {}", var);
+    }
+    if var > 0 {
+        panic!("p2 {0}", var);
+    }
+    if var > 0 {
+        panic!("p3 {var}", var = var);
+    }
+
+    #[allow(non_fmt_panics)]
+    {
+        if var > 0 {
+            panic!("p4 {var}");
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
index 94dc9642726..ec8c6abfab9 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
@@ -111,4 +111,8 @@ mod fixable {
 
         let _num = foo();
     }
+
+    fn issue_9603() {
+        let _: f32 = -0x400 as f32;
+    }
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs
index e5150256f69..5213cdc269b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs
@@ -111,4 +111,8 @@ mod fixable {
 
         let _num = foo() as f32;
     }
+
+    fn issue_9603() {
+        let _: f32 = -0x400 as f32;
+    }
 }
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
index f97583aa22f..fe09aad06bc 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(clippy::ptr_arg)]
+#![allow(clippy::needless_borrow, clippy::ptr_arg)]
 #![warn(clippy::unnecessary_to_owned)]
 #![feature(custom_inner_attributes)]
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
index aa5394a5657..3de6d0903c0 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(clippy::ptr_arg)]
+#![allow(clippy::needless_borrow, clippy::ptr_arg)]
 #![warn(clippy::unnecessary_to_owned)]
 #![feature(custom_inner_attributes)]
 
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
index c223b5bc711..9786c7b1212 100644
--- a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
@@ -1,9 +1,9 @@
 // run-rustfix
 
-#![feature(box_patterns)]
+#![feature(box_patterns, custom_inner_attributes)]
 #![warn(clippy::unnested_or_patterns)]
 #![allow(clippy::cognitive_complexity, clippy::match_ref_pats, clippy::upper_case_acronyms)]
-#![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)]
+#![allow(unreachable_patterns, irrefutable_let_patterns, unused)]
 
 fn main() {
     // Should be ignored by this lint, as nesting requires more characters.
@@ -33,3 +33,15 @@ fn main() {
     if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {}
     if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
 }
+
+fn msrv_1_52() {
+    #![clippy::msrv = "1.52"]
+
+    if let [1] | [52] = [0] {}
+}
+
+fn msrv_1_53() {
+    #![clippy::msrv = "1.53"]
+
+    if let [1 | 53] = [0] {}
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.rs b/src/tools/clippy/tests/ui/unnested_or_patterns.rs
index 04cd11036e4..f57322396d4 100644
--- a/src/tools/clippy/tests/ui/unnested_or_patterns.rs
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.rs
@@ -1,9 +1,9 @@
 // run-rustfix
 
-#![feature(box_patterns)]
+#![feature(box_patterns, custom_inner_attributes)]
 #![warn(clippy::unnested_or_patterns)]
 #![allow(clippy::cognitive_complexity, clippy::match_ref_pats, clippy::upper_case_acronyms)]
-#![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)]
+#![allow(unreachable_patterns, irrefutable_let_patterns, unused)]
 
 fn main() {
     // Should be ignored by this lint, as nesting requires more characters.
@@ -33,3 +33,15 @@ fn main() {
     if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
     if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
 }
+
+fn msrv_1_52() {
+    #![clippy::msrv = "1.52"]
+
+    if let [1] | [52] = [0] {}
+}
+
+fn msrv_1_53() {
+    #![clippy::msrv = "1.53"]
+
+    if let [1] | [53] = [0] {}
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
index 453c66cbba8..fbc12fff0b0 100644
--- a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
@@ -175,5 +175,16 @@ help: nest the patterns
 LL |     if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {}
    |            ~~~~~~~~~~~~~~~~~
 
-error: aborting due to 16 previous errors
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:46:12
+   |
+LL |     if let [1] | [53] = [0] {}
+   |            ^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let [1 | 53] = [0] {}
+   |            ~~~~~~~~
+
+error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unused_format_specs.fixed b/src/tools/clippy/tests/ui/unused_format_specs.fixed
new file mode 100644
index 00000000000..2930722b42d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_format_specs.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#![warn(clippy::unused_format_specs)]
+#![allow(unused)]
+
+fn main() {
+    let f = 1.0f64;
+    println!("{}", 1.0);
+    println!("{f} {f:?}");
+
+    println!("{}", 1);
+}
+
+fn should_not_lint() {
+    let f = 1.0f64;
+    println!("{:.1}", 1.0);
+    println!("{f:.w$} {f:.*?}", 3, w = 2);
+}
diff --git a/src/tools/clippy/tests/ui/unused_format_specs.rs b/src/tools/clippy/tests/ui/unused_format_specs.rs
new file mode 100644
index 00000000000..ee192a000d4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_format_specs.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#![warn(clippy::unused_format_specs)]
+#![allow(unused)]
+
+fn main() {
+    let f = 1.0f64;
+    println!("{:.}", 1.0);
+    println!("{f:.} {f:.?}");
+
+    println!("{:.}", 1);
+}
+
+fn should_not_lint() {
+    let f = 1.0f64;
+    println!("{:.1}", 1.0);
+    println!("{f:.w$} {f:.*?}", 3, w = 2);
+}
diff --git a/src/tools/clippy/tests/ui/unused_format_specs.stderr b/src/tools/clippy/tests/ui/unused_format_specs.stderr
new file mode 100644
index 00000000000..7231c17e74c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_format_specs.stderr
@@ -0,0 +1,54 @@
+error: empty precision specifier has no effect
+  --> $DIR/unused_format_specs.rs:8:17
+   |
+LL |     println!("{:.}", 1.0);
+   |                 ^
+   |
+   = note: a precision specifier is not required to format floats
+   = note: `-D clippy::unused-format-specs` implied by `-D warnings`
+help: remove the `.`
+   |
+LL -     println!("{:.}", 1.0);
+LL +     println!("{}", 1.0);
+   |
+
+error: empty precision specifier has no effect
+  --> $DIR/unused_format_specs.rs:9:18
+   |
+LL |     println!("{f:.} {f:.?}");
+   |                  ^
+   |
+   = note: a precision specifier is not required to format floats
+help: remove the `.`
+   |
+LL -     println!("{f:.} {f:.?}");
+LL +     println!("{f} {f:.?}");
+   |
+
+error: empty precision specifier has no effect
+  --> $DIR/unused_format_specs.rs:9:24
+   |
+LL |     println!("{f:.} {f:.?}");
+   |                        ^
+   |
+   = note: a precision specifier is not required to format floats
+help: remove the `.`
+   |
+LL -     println!("{f:.} {f:.?}");
+LL +     println!("{f:.} {f:?}");
+   |
+
+error: empty precision specifier has no effect
+  --> $DIR/unused_format_specs.rs:11:17
+   |
+LL |     println!("{:.}", 1);
+   |                 ^
+   |
+help: remove the `.`
+   |
+LL -     println!("{:.}", 1);
+LL +     println!("{}", 1);
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unused_format_specs_unfixable.rs b/src/tools/clippy/tests/ui/unused_format_specs_unfixable.rs
new file mode 100644
index 00000000000..78601a3483d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_format_specs_unfixable.rs
@@ -0,0 +1,30 @@
+#![warn(clippy::unused_format_specs)]
+#![allow(unused)]
+
+macro_rules! format_args_from_macro {
+    () => {
+        format_args!("from macro")
+    };
+}
+
+fn main() {
+    // prints `.`, not `     .`
+    println!("{:5}.", format_args!(""));
+    //prints `abcde`, not `abc`
+    println!("{:.3}", format_args!("abcde"));
+
+    println!("{:5}.", format_args_from_macro!());
+
+    let args = format_args!("");
+    println!("{args:5}");
+}
+
+fn should_not_lint() {
+    println!("{}", format_args!(""));
+    // Technically the same as `{}`, but the `format_args` docs specifically mention that you can use
+    // debug formatting so allow it
+    println!("{:?}", format_args!(""));
+
+    let args = format_args!("");
+    println!("{args}");
+}
diff --git a/src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr b/src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr
new file mode 100644
index 00000000000..9f1890282e6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_format_specs_unfixable.stderr
@@ -0,0 +1,69 @@
+error: format specifiers have no effect on `format_args!()`
+  --> $DIR/unused_format_specs_unfixable.rs:12:15
+   |
+LL |     println!("{:5}.", format_args!(""));
+   |               ^^^^
+   |
+   = note: `-D clippy::unused-format-specs` implied by `-D warnings`
+help: for the width to apply consider using `format!()`
+   |
+LL |     println!("{:5}.", format!(""));
+   |                       ~~~~~~
+help: if the current behavior is intentional, remove the format specifiers
+   |
+LL -     println!("{:5}.", format_args!(""));
+LL +     println!("{}.", format_args!(""));
+   |
+
+error: format specifiers have no effect on `format_args!()`
+  --> $DIR/unused_format_specs_unfixable.rs:14:15
+   |
+LL |     println!("{:.3}", format_args!("abcde"));
+   |               ^^^^^
+   |
+help: for the precision to apply consider using `format!()`
+   |
+LL |     println!("{:.3}", format!("abcde"));
+   |                       ~~~~~~
+help: if the current behavior is intentional, remove the format specifiers
+   |
+LL -     println!("{:.3}", format_args!("abcde"));
+LL +     println!("{}", format_args!("abcde"));
+   |
+
+error: format specifiers have no effect on `format_args!()`
+  --> $DIR/unused_format_specs_unfixable.rs:16:15
+   |
+LL |     println!("{:5}.", format_args_from_macro!());
+   |               ^^^^
+   |
+help: for the width to apply consider using `format!()`
+  --> $DIR/unused_format_specs_unfixable.rs:16:17
+   |
+LL |     println!("{:5}.", format_args_from_macro!());
+   |                 ^
+help: if the current behavior is intentional, remove the format specifiers
+   |
+LL -     println!("{:5}.", format_args_from_macro!());
+LL +     println!("{}.", format_args_from_macro!());
+   |
+
+error: format specifiers have no effect on `format_args!()`
+  --> $DIR/unused_format_specs_unfixable.rs:19:15
+   |
+LL |     println!("{args:5}");
+   |               ^^^^^^^^
+   |
+help: for the width to apply consider using `format!()`
+  --> $DIR/unused_format_specs_unfixable.rs:19:21
+   |
+LL |     println!("{args:5}");
+   |                     ^
+help: if the current behavior is intentional, remove the format specifiers
+   |
+LL -     println!("{args:5}");
+LL +     println!("{args}");
+   |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed
index 37986187da1..3b54fe9d5ff 100644
--- a/src/tools/clippy/tests/ui/use_self.fixed
+++ b/src/tools/clippy/tests/ui/use_self.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 // aux-build:proc_macro_derive.rs
 
+#![feature(custom_inner_attributes)]
 #![warn(clippy::use_self)]
 #![allow(dead_code, unreachable_code)]
 #![allow(
@@ -617,3 +618,35 @@ mod issue6902 {
         Bar = 1,
     }
 }
+
+fn msrv_1_36() {
+    #![clippy::msrv = "1.36"]
+
+    enum E {
+        A,
+    }
+
+    impl E {
+        fn foo(self) {
+            match self {
+                E::A => {},
+            }
+        }
+    }
+}
+
+fn msrv_1_37() {
+    #![clippy::msrv = "1.37"]
+
+    enum E {
+        A,
+    }
+
+    impl E {
+        fn foo(self) {
+            match self {
+                Self::A => {},
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs
index 1b2b3337c92..bf87633cd2d 100644
--- a/src/tools/clippy/tests/ui/use_self.rs
+++ b/src/tools/clippy/tests/ui/use_self.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 // aux-build:proc_macro_derive.rs
 
+#![feature(custom_inner_attributes)]
 #![warn(clippy::use_self)]
 #![allow(dead_code, unreachable_code)]
 #![allow(
@@ -617,3 +618,35 @@ mod issue6902 {
         Bar = 1,
     }
 }
+
+fn msrv_1_36() {
+    #![clippy::msrv = "1.36"]
+
+    enum E {
+        A,
+    }
+
+    impl E {
+        fn foo(self) {
+            match self {
+                E::A => {},
+            }
+        }
+    }
+}
+
+fn msrv_1_37() {
+    #![clippy::msrv = "1.37"]
+
+    enum E {
+        A,
+    }
+
+    impl E {
+        fn foo(self) {
+            match self {
+                E::A => {},
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr
index f06bb959b3b..16fb0609242 100644
--- a/src/tools/clippy/tests/ui/use_self.stderr
+++ b/src/tools/clippy/tests/ui/use_self.stderr
@@ -1,5 +1,5 @@
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:22:21
+  --> $DIR/use_self.rs:23:21
    |
 LL |         fn new() -> Foo {
    |                     ^^^ help: use the applicable keyword: `Self`
@@ -7,244 +7,250 @@ LL |         fn new() -> Foo {
    = note: `-D clippy::use-self` implied by `-D warnings`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:23:13
+  --> $DIR/use_self.rs:24:13
    |
 LL |             Foo {}
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:25:22
+  --> $DIR/use_self.rs:26:22
    |
 LL |         fn test() -> Foo {
    |                      ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:26:13
+  --> $DIR/use_self.rs:27:13
    |
 LL |             Foo::new()
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:31:25
+  --> $DIR/use_self.rs:32:25
    |
 LL |         fn default() -> Foo {
    |                         ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:32:13
+  --> $DIR/use_self.rs:33:13
    |
 LL |             Foo::new()
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:97:24
+  --> $DIR/use_self.rs:98:24
    |
 LL |         fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
    |                        ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:97:55
+  --> $DIR/use_self.rs:98:55
    |
 LL |         fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
    |                                                       ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:112:13
+  --> $DIR/use_self.rs:113:13
    |
 LL |             TS(0)
    |             ^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:147:29
+  --> $DIR/use_self.rs:148:29
    |
 LL |                 fn bar() -> Bar {
    |                             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:148:21
+  --> $DIR/use_self.rs:149:21
    |
 LL |                     Bar { foo: Foo {} }
    |                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:159:21
+  --> $DIR/use_self.rs:160:21
    |
 LL |         fn baz() -> Foo {
    |                     ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:160:13
+  --> $DIR/use_self.rs:161:13
    |
 LL |             Foo {}
    |             ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:177:21
+  --> $DIR/use_self.rs:178:21
    |
 LL |             let _ = Enum::B(42);
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:178:21
+  --> $DIR/use_self.rs:179:21
    |
 LL |             let _ = Enum::C { field: true };
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:179:21
+  --> $DIR/use_self.rs:180:21
    |
 LL |             let _ = Enum::A;
    |                     ^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:221:13
+  --> $DIR/use_self.rs:222:13
    |
 LL |             nested::A::fun_1();
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:222:13
+  --> $DIR/use_self.rs:223:13
    |
 LL |             nested::A::A;
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:224:13
+  --> $DIR/use_self.rs:225:13
    |
 LL |             nested::A {};
    |             ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:243:13
+  --> $DIR/use_self.rs:244:13
    |
 LL |             TestStruct::from_something()
    |             ^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:257:25
+  --> $DIR/use_self.rs:258:25
    |
 LL |         async fn g() -> S {
    |                         ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:258:13
+  --> $DIR/use_self.rs:259:13
    |
 LL |             S {}
    |             ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:262:16
+  --> $DIR/use_self.rs:263:16
    |
 LL |             &p[S::A..S::B]
    |                ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:262:22
+  --> $DIR/use_self.rs:263:22
    |
 LL |             &p[S::A..S::B]
    |                      ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:285:29
+  --> $DIR/use_self.rs:286:29
    |
 LL |         fn foo(value: T) -> Foo<T> {
    |                             ^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:286:13
+  --> $DIR/use_self.rs:287:13
    |
 LL |             Foo::<T> { value }
    |             ^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:458:13
+  --> $DIR/use_self.rs:459:13
    |
 LL |             A::new::<submod::B>(submod::B {})
    |             ^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:495:13
+  --> $DIR/use_self.rs:496:13
    |
 LL |             S2::new()
    |             ^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:532:17
+  --> $DIR/use_self.rs:533:17
    |
 LL |                 Foo::Bar => unimplemented!(),
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:533:17
+  --> $DIR/use_self.rs:534:17
    |
 LL |                 Foo::Baz => unimplemented!(),
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:539:20
+  --> $DIR/use_self.rs:540:20
    |
 LL |             if let Foo::Bar = self {
    |                    ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:563:17
+  --> $DIR/use_self.rs:564:17
    |
 LL |                 Something::Num(n) => *n,
    |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:564:17
+  --> $DIR/use_self.rs:565:17
    |
 LL |                 Something::TupleNums(n, _m) => *n,
    |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:565:17
+  --> $DIR/use_self.rs:566:17
    |
 LL |                 Something::StructNums { one, two: _ } => *one,
    |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:571:17
+  --> $DIR/use_self.rs:572:17
    |
 LL |                 crate::issue8845::Something::Num(n) => *n,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:572:17
+  --> $DIR/use_self.rs:573:17
    |
 LL |                 crate::issue8845::Something::TupleNums(n, _m) => *n,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:573:17
+  --> $DIR/use_self.rs:574:17
    |
 LL |                 crate::issue8845::Something::StructNums { one, two: _ } => *one,
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:589:17
+  --> $DIR/use_self.rs:590:17
    |
 LL |             let Foo(x) = self;
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:594:17
+  --> $DIR/use_self.rs:595:17
    |
 LL |             let crate::issue8845::Foo(x) = self;
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:601:17
+  --> $DIR/use_self.rs:602:17
    |
 LL |             let Bar { x, .. } = self;
    |                 ^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
-  --> $DIR/use_self.rs:606:17
+  --> $DIR/use_self.rs:607:17
    |
 LL |             let crate::issue8845::Bar { x, .. } = self;
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
 
-error: aborting due to 41 previous errors
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:648:17
+   |
+LL |                 E::A => {},
+   |                 ^ help: use the applicable keyword: `Self`
+
+error: aborting due to 42 previous errors
 
diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs
index 9e07769a8e4..a6d8d0307ce 100644
--- a/src/tools/clippy/tests/versioncheck.rs
+++ b/src/tools/clippy/tests/versioncheck.rs
@@ -48,7 +48,7 @@ fn check_that_clippy_has_the_same_major_version_as_rustc() {
     // `RUSTC_REAL` if Clippy is build in the Rust repo with `./x.py`.
     let rustc = std::env::var("RUSTC_REAL").unwrap_or_else(|_| "rustc".to_string());
     let rustc_version = String::from_utf8(
-        std::process::Command::new(&rustc)
+        std::process::Command::new(rustc)
             .arg("--version")
             .output()
             .expect("failed to run `rustc --version`")
diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html
index c5d602ea303..e46ad2c6e0e 100644
--- a/src/tools/clippy/util/gh-pages/index.html
+++ b/src/tools/clippy/util/gh-pages/index.html
@@ -443,6 +443,12 @@ Otherwise, have a great day =^.^=
                                     </label>
                                 </li>
                                 <li class="checkbox">
+                                    <label ng-click="resetGroupsToDefault()">
+                                        <input type="checkbox" class="invisible" />
+                                        Default
+                                    </label>
+                                </li>
+                                <li class="checkbox">
                                     <label ng-click="toggleGroups(false)">
                                         <input type="checkbox" class="invisible" />
                                         None
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js
index 366e7c8843f..1c16ecd6b0b 100644
--- a/src/tools/clippy/util/gh-pages/script.js
+++ b/src/tools/clippy/util/gh-pages/script.js
@@ -114,7 +114,7 @@
                 return $scope.levels[lint.level];
             };
 
-            var GROUPS_FILTER_DEFAULT = {
+            const GROUPS_FILTER_DEFAULT = {
                 cargo: true,
                 complexity: true,
                 correctness: true,
@@ -125,8 +125,12 @@
                 restriction: true,
                 style: true,
                 suspicious: true,
+            }
+
+            $scope.groups = {
+                ...GROUPS_FILTER_DEFAULT
             };
-            $scope.groups = GROUPS_FILTER_DEFAULT;
+
             const THEMES_DEFAULT = {
                 light: "Light",
                 rust: "Rust",
@@ -164,6 +168,13 @@
                 }
             };
 
+            $scope.resetGroupsToDefault = function () {
+                const groups = $scope.groups;
+                for (const [key, value] of Object.entries(GROUPS_FILTER_DEFAULT)) {
+                    groups[key] = value;
+                }
+            };
+
             $scope.selectedValuesCount = function (obj) {
                 return Object.values(obj).filter(x => x).length;
             }