about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md6
-rw-r--r--Cargo.toml4
-rw-r--r--book/src/development/adding_lints.md2
-rw-r--r--book/src/development/basics.md2
-rw-r--r--book/src/development/common_tools_writing_lints.md6
-rw-r--r--book/src/development/macro_expansions.md6
-rw-r--r--book/src/lint_configuration.md26
-rw-r--r--clippy_config/src/conf.rs20
-rw-r--r--clippy_config/src/types.rs85
-rw-r--r--clippy_dev/src/fmt.rs9
-rw-r--r--clippy_dev/src/lint.rs4
-rw-r--r--clippy_dev/src/main.rs5
-rw-r--r--clippy_dev/src/update_lints.rs28
-rw-r--r--clippy_lints/src/almost_complete_range.rs5
-rw-r--r--clippy_lints/src/arbitrary_source_item_ordering.rs11
-rw-r--r--clippy_lints/src/as_conversions.rs3
-rw-r--r--clippy_lints/src/attrs/allow_attributes.rs3
-rw-r--r--clippy_lints/src/attrs/allow_attributes_without_reason.rs3
-rw-r--r--clippy_lints/src/attrs/useless_attribute.rs3
-rw-r--r--clippy_lints/src/await_holding_invalid.rs21
-rw-r--r--clippy_lints/src/blocks_in_conditions.rs3
-rw-r--r--clippy_lints/src/booleans.rs4
-rw-r--r--clippy_lints/src/box_default.rs3
-rw-r--r--clippy_lints/src/casts/mod.rs3
-rw-r--r--clippy_lints/src/casts/unnecessary_cast.rs3
-rw-r--r--clippy_lints/src/checked_conversions.rs3
-rw-r--r--clippy_lints/src/copies.rs16
-rw-r--r--clippy_lints/src/ctfe.rs2
-rw-r--r--clippy_lints/src/dbg_macro.rs3
-rw-r--r--clippy_lints/src/declared_lints.rs5
-rw-r--r--clippy_lints/src/default_numeric_fallback.rs3
-rw-r--r--clippy_lints/src/deprecated_lints.rs2
-rw-r--r--clippy_lints/src/dereference.rs67
-rw-r--r--clippy_lints/src/disallowed_macros.rs13
-rw-r--r--clippy_lints/src/disallowed_methods.rs14
-rw-r--r--clippy_lints/src/disallowed_types.rs24
-rw-r--r--clippy_lints/src/doc/empty_line_after.rs11
-rw-r--r--clippy_lints/src/doc/mod.rs109
-rw-r--r--clippy_lints/src/else_if_without_else.rs3
-rw-r--r--clippy_lints/src/endian_bytes.rs3
-rw-r--r--clippy_lints/src/entry.rs4
-rw-r--r--clippy_lints/src/equatable_if_let.rs5
-rw-r--r--clippy_lints/src/excessive_nesting.rs5
-rw-r--r--clippy_lints/src/extra_unused_type_parameters.rs5
-rw-r--r--clippy_lints/src/formatting.rs3
-rw-r--r--clippy_lints/src/functions/must_use.rs5
-rw-r--r--clippy_lints/src/functions/result.rs3
-rw-r--r--clippy_lints/src/functions/too_many_lines.rs3
-rw-r--r--clippy_lints/src/future_not_send.rs2
-rw-r--r--clippy_lints/src/if_not_else.rs5
-rw-r--r--clippy_lints/src/if_then_some_else_none.rs5
-rw-r--r--clippy_lints/src/implicit_return.rs3
-rw-r--r--clippy_lints/src/invalid_upcast_comparisons.rs3
-rw-r--r--clippy_lints/src/items_after_statements.rs3
-rw-r--r--clippy_lints/src/iter_without_into_iter.rs5
-rw-r--r--clippy_lints/src/large_const_arrays.rs5
-rw-r--r--clippy_lints/src/large_enum_variant.rs3
-rw-r--r--clippy_lints/src/large_stack_arrays.rs5
-rw-r--r--clippy_lints/src/legacy_numeric_constants.rs5
-rw-r--r--clippy_lints/src/let_underscore.rs3
-rw-r--r--clippy_lints/src/let_with_type_underscore.rs3
-rw-r--r--clippy_lints/src/lib.rs4
-rw-r--r--clippy_lints/src/lifetimes.rs3
-rw-r--r--clippy_lints/src/lines_filter_map_ok.rs24
-rw-r--r--clippy_lints/src/literal_representation.rs5
-rw-r--r--clippy_lints/src/literal_string_with_formatting_args.rs16
-rw-r--r--clippy_lints/src/loops/infinite_loop.rs3
-rw-r--r--clippy_lints/src/loops/manual_flatten.rs3
-rw-r--r--clippy_lints/src/loops/manual_slice_fill.rs7
-rw-r--r--clippy_lints/src/loops/mod.rs2
-rw-r--r--clippy_lints/src/manual_async_fn.rs1
-rw-r--r--clippy_lints/src/manual_div_ceil.rs15
-rw-r--r--clippy_lints/src/manual_float_methods.rs3
-rw-r--r--clippy_lints/src/manual_let_else.rs12
-rw-r--r--clippy_lints/src/manual_range_patterns.rs3
-rw-r--r--clippy_lints/src/manual_rem_euclid.rs3
-rw-r--r--clippy_lints/src/manual_unwrap_or_default.rs4
-rw-r--r--clippy_lints/src/matches/collapsible_match.rs8
-rw-r--r--clippy_lints/src/matches/manual_ok_err.rs13
-rw-r--r--clippy_lints/src/matches/manual_unwrap_or.rs10
-rw-r--r--clippy_lints/src/matches/manual_utils.rs34
-rw-r--r--clippy_lints/src/matches/match_same_arms.rs8
-rw-r--r--clippy_lints/src/matches/match_wild_enum.rs11
-rw-r--r--clippy_lints/src/matches/mod.rs3
-rw-r--r--clippy_lints/src/matches/needless_match.rs12
-rw-r--r--clippy_lints/src/matches/redundant_pattern_match.rs36
-rw-r--r--clippy_lints/src/matches/significant_drop_in_scrutinee.rs6
-rw-r--r--clippy_lints/src/matches/single_match.rs21
-rw-r--r--clippy_lints/src/mem_replace.rs151
-rw-r--r--clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs5
-rw-r--r--clippy_lints/src/methods/filter_map.rs5
-rw-r--r--clippy_lints/src/methods/filter_map_bool_then.rs3
-rw-r--r--clippy_lints/src/methods/is_empty.rs3
-rw-r--r--clippy_lints/src/methods/iter_filter.rs5
-rw-r--r--clippy_lints/src/methods/manual_ok_or.rs2
-rw-r--r--clippy_lints/src/methods/manual_try_fold.rs3
-rw-r--r--clippy_lints/src/methods/mod.rs83
-rw-r--r--clippy_lints/src/methods/obfuscated_if_else.rs12
-rw-r--r--clippy_lints/src/methods/option_map_or_err_ok.rs41
-rw-r--r--clippy_lints/src/methods/or_fun_call.rs2
-rw-r--r--clippy_lints/src/methods/path_buf_push_overwrite.rs2
-rw-r--r--clippy_lints/src/methods/range_zip_with_len.rs13
-rw-r--r--clippy_lints/src/methods/return_and_then.rs2
-rw-r--r--clippy_lints/src/methods/unbuffered_bytes.rs31
-rw-r--r--clippy_lints/src/methods/unnecessary_fold.rs68
-rw-r--r--clippy_lints/src/methods/unnecessary_map_or.rs6
-rw-r--r--clippy_lints/src/methods/unwrap_expect_used.rs7
-rw-r--r--clippy_lints/src/methods/useless_asref.rs19
-rw-r--r--clippy_lints/src/min_ident_chars.rs3
-rw-r--r--clippy_lints/src/misc.rs7
-rw-r--r--clippy_lints/src/misc_early/mod.rs5
-rw-r--r--clippy_lints/src/misc_early/redundant_at_rest_pattern.rs3
-rw-r--r--clippy_lints/src/missing_const_for_fn.rs3
-rw-r--r--clippy_lints/src/missing_inline.rs4
-rw-r--r--clippy_lints/src/multiple_bound_locations.rs4
-rw-r--r--clippy_lints/src/multiple_unsafe_ops_per_block.rs26
-rw-r--r--clippy_lints/src/mut_mut.rs5
-rw-r--r--clippy_lints/src/mut_reference.rs5
-rw-r--r--clippy_lints/src/needless_continue.rs2
-rw-r--r--clippy_lints/src/needless_if.rs3
-rw-r--r--clippy_lints/src/needless_pass_by_value.rs11
-rw-r--r--clippy_lints/src/neg_cmp_op_on_partial_ord.rs3
-rw-r--r--clippy_lints/src/new_without_default.rs3
-rw-r--r--clippy_lints/src/no_effect.rs3
-rw-r--r--clippy_lints/src/non_canonical_impls.rs3
-rw-r--r--clippy_lints/src/non_copy_const.rs6
-rw-r--r--clippy_lints/src/non_expressive_names.rs8
-rw-r--r--clippy_lints/src/non_send_fields_in_send_ty.rs3
-rw-r--r--clippy_lints/src/non_std_lazy_statics.rs3
-rw-r--r--clippy_lints/src/octal_escapes.rs3
-rw-r--r--clippy_lints/src/option_if_let_else.rs10
-rw-r--r--clippy_lints/src/panicking_overflow_checks.rs3
-rw-r--r--clippy_lints/src/pathbuf_init_then_push.rs5
-rw-r--r--clippy_lints/src/pattern_type_mismatch.rs5
-rw-r--r--clippy_lints/src/raw_strings.rs5
-rw-r--r--clippy_lints/src/redundant_async_block.rs3
-rw-r--r--clippy_lints/src/redundant_clone.rs12
-rw-r--r--clippy_lints/src/redundant_closure_call.rs3
-rw-r--r--clippy_lints/src/redundant_else.rs13
-rw-r--r--clippy_lints/src/redundant_field_names.rs3
-rw-r--r--clippy_lints/src/redundant_locals.rs3
-rw-r--r--clippy_lints/src/redundant_pub_crate.rs3
-rw-r--r--clippy_lints/src/reserve_after_initialization.rs5
-rw-r--r--clippy_lints/src/return_self_not_must_use.rs3
-rw-r--r--clippy_lints/src/returns.rs14
-rw-r--r--clippy_lints/src/same_name_method.rs11
-rw-r--r--clippy_lints/src/single_call_fn.rs3
-rw-r--r--clippy_lints/src/single_char_lifetime_names.rs3
-rw-r--r--clippy_lints/src/single_option_map.rs91
-rw-r--r--clippy_lints/src/std_instead_of_core.rs3
-rw-r--r--clippy_lints/src/strings.rs5
-rw-r--r--clippy_lints/src/suspicious_xor_used_as_pow.rs3
-rw-r--r--clippy_lints/src/swap.rs3
-rw-r--r--clippy_lints/src/to_digit_is_some.rs12
-rw-r--r--clippy_lints/src/transmute/missing_transmute_annotations.rs3
-rw-r--r--clippy_lints/src/transmute/mod.rs1
-rw-r--r--clippy_lints/src/tuple_array_conversions.rs3
-rw-r--r--clippy_lints/src/types/mod.rs64
-rw-r--r--clippy_lints/src/unconditional_recursion.rs11
-rw-r--r--clippy_lints/src/undocumented_unsafe_blocks.rs9
-rw-r--r--clippy_lints/src/uninhabited_references.rs5
-rw-r--r--clippy_lints/src/uninit_vec.rs3
-rw-r--r--clippy_lints/src/unit_types/let_unit_value.rs5
-rw-r--r--clippy_lints/src/unit_types/unit_arg.rs5
-rw-r--r--clippy_lints/src/unused_result_ok.rs3
-rw-r--r--clippy_lints/src/unused_trait_names.rs3
-rw-r--r--clippy_lints/src/unwrap.rs3
-rw-r--r--clippy_lints/src/upper_case_acronyms.rs3
-rw-r--r--clippy_lints/src/use_self.rs41
-rw-r--r--clippy_lints/src/utils/author.rs5
-rw-r--r--clippy_lints/src/vec_init_then_push.rs5
-rw-r--r--clippy_lints/src/visibility.rs3
-rw-r--r--clippy_lints/src/zero_sized_map_values.rs17
-rw-r--r--clippy_utils/README.md2
-rw-r--r--clippy_utils/src/ast_utils/mod.rs20
-rw-r--r--clippy_utils/src/hir_utils.rs22
-rw-r--r--clippy_utils/src/lib.rs216
-rw-r--r--clippy_utils/src/mir/mod.rs12
-rw-r--r--clippy_utils/src/msrvs.rs2
-rw-r--r--clippy_utils/src/paths.rs1
-rw-r--r--clippy_utils/src/qualify_min_const_fn.rs9
-rw-r--r--clippy_utils/src/source.rs71
-rw-r--r--clippy_utils/src/str_utils.rs10
-rw-r--r--clippy_utils/src/ty/mod.rs40
-rw-r--r--rust-toolchain2
-rw-r--r--rustc_tools_util/Cargo.toml4
-rw-r--r--rustc_tools_util/README.md4
-rw-r--r--rustc_tools_util/src/lib.rs55
-rw-r--r--src/driver.rs7
-rw-r--r--tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.rs1
-rw-r--r--tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr11
-rw-r--r--tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml3
-rw-r--r--tests/ui-toml/expect_used/clippy.toml1
-rw-r--r--tests/ui-toml/expect_used/expect_used.rs9
-rw-r--r--tests/ui-toml/expect_used/expect_used.stderr22
-rw-r--r--tests/ui-toml/replaceable_disallowed_types/clippy.toml3
-rw-r--r--tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.fixed16
-rw-r--r--tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.rs16
-rw-r--r--tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.stderr11
-rw-r--r--tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs2
-rw-r--r--tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr28
-rw-r--r--tests/ui-toml/toml_replaceable_disallowed_methods/clippy.toml4
-rw-r--r--tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.fixed8
-rw-r--r--tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.rs8
-rw-r--r--tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.stderr17
-rw-r--r--tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr6
-rw-r--r--tests/ui-toml/unwrap_used/clippy.toml1
-rw-r--r--tests/ui-toml/unwrap_used/unwrap_used_const.rs11
-rw-r--r--tests/ui-toml/unwrap_used/unwrap_used_const.stderr22
-rw-r--r--tests/ui/borrow_interior_mutable_const/projections.rs42
-rw-r--r--tests/ui/borrow_interior_mutable_const/projections.stderr44
-rw-r--r--tests/ui/bytes_count_to_len.fixed6
-rw-r--r--tests/ui/bytes_count_to_len.rs6
-rw-r--r--tests/ui/crashes/ice-10508a.rs19
-rw-r--r--tests/ui/crashes/ice-10508b.rs24
-rw-r--r--tests/ui/crashes/ice-10508c.rs7
-rw-r--r--tests/ui/deprecated.rs1
-rw-r--r--tests/ui/deprecated.stderr8
-rw-r--r--tests/ui/derivable_impls.fixed34
-rw-r--r--tests/ui/derivable_impls.rs49
-rw-r--r--tests/ui/derivable_impls.stderr57
-rw-r--r--tests/ui/doc/link_adjacent.fixed52
-rw-r--r--tests/ui/doc/link_adjacent.rs52
-rw-r--r--tests/ui/doc/link_adjacent.stderr124
-rw-r--r--tests/ui/ignored_unit_patterns.fixed15
-rw-r--r--tests/ui/ignored_unit_patterns.rs15
-rw-r--r--tests/ui/ignored_unit_patterns.stderr18
-rw-r--r--tests/ui/large_enum_variant.32bit.stderr34
-rw-r--r--tests/ui/large_enum_variant.64bit.stderr66
-rw-r--r--tests/ui/large_enum_variant.rs77
-rw-r--r--tests/ui/let_and_return.edition2021.fixed265
-rw-r--r--tests/ui/let_and_return.edition2021.stderr152
-rw-r--r--tests/ui/let_and_return.edition2024.fixed265
-rw-r--r--tests/ui/let_and_return.edition2024.stderr228
-rw-r--r--tests/ui/let_and_return.fixed10
-rw-r--r--tests/ui/let_and_return.rs18
-rw-r--r--tests/ui/lines_filter_map_ok.fixed7
-rw-r--r--tests/ui/lines_filter_map_ok.rs7
-rw-r--r--tests/ui/literal_string_with_formatting_arg.rs26
-rw-r--r--tests/ui/literal_string_with_formatting_arg.stderr40
-rw-r--r--tests/ui/manual_async_fn.fixed26
-rw-r--r--tests/ui/manual_async_fn.rs26
-rw-r--r--tests/ui/manual_map_option.fixed11
-rw-r--r--tests/ui/manual_map_option.rs6
-rw-r--r--tests/ui/manual_map_option.stderr17
-rw-r--r--tests/ui/manual_map_option_2.fixed93
-rw-r--r--tests/ui/manual_map_option_2.rs99
-rw-r--r--tests/ui/manual_map_option_2.stderr39
-rw-r--r--tests/ui/manual_ok_or.stderr11
-rw-r--r--tests/ui/manual_slice_fill.fixed18
-rw-r--r--tests/ui/manual_slice_fill.rs18
-rw-r--r--tests/ui/match_bool.fixed6
-rw-r--r--tests/ui/match_bool.rs10
-rw-r--r--tests/ui/match_bool.stderr21
-rw-r--r--tests/ui/mem_replace.fixed24
-rw-r--r--tests/ui/mem_replace.rs24
-rw-r--r--tests/ui/mem_replace.stderr77
-rw-r--r--tests/ui/nonminimal_bool.rs6
-rw-r--r--tests/ui/nonminimal_bool.stderr8
-rw-r--r--tests/ui/obfuscated_if_else.fixed32
-rw-r--r--tests/ui/obfuscated_if_else.rs32
-rw-r--r--tests/ui/obfuscated_if_else.stderr60
-rw-r--r--tests/ui/option_map_or_err_ok.fixed7
-rw-r--r--tests/ui/option_map_or_err_ok.rs7
-rw-r--r--tests/ui/option_map_or_err_ok.stderr11
-rw-r--r--tests/ui/range.fixed18
-rw-r--r--tests/ui/range.rs3
-rw-r--r--tests/ui/range.stderr4
-rw-r--r--tests/ui/single_option_map.rs69
-rw-r--r--tests/ui/single_option_map.stderr37
-rw-r--r--tests/ui/string_add.rs2
-rw-r--r--tests/ui/string_add.stderr17
-rw-r--r--tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed8
-rw-r--r--tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs8
-rw-r--r--tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr13
-rw-r--r--tests/ui/unbuffered_bytes.rs37
-rw-r--r--tests/ui/unbuffered_bytes.stderr36
-rw-r--r--tests/ui/unnecessary_map_or.fixed6
-rw-r--r--tests/ui/unnecessary_map_or.rs6
-rw-r--r--tests/ui/unnecessary_map_or.stderr26
-rw-r--r--tests/ui/unwrap_expect_used.rs11
-rw-r--r--tests/ui/use_self.fixed45
-rw-r--r--tests/ui/use_self.rs45
-rw-r--r--tests/ui/useless_asref.fixed5
-rw-r--r--tests/ui/useless_asref.rs5
-rw-r--r--tests/ui/{literal_string_with_formatting_args}.rs46
-rw-r--r--tests/versioncheck.rs6
287 files changed, 4483 insertions, 998 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fa03c953aa5..a1ea3ce8f79 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5530,6 +5530,7 @@ Released 2018-09-13
 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
 [`doc_include_without_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_include_without_cfg
 [`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation
+[`doc_link_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_code
 [`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 [`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs
@@ -5812,6 +5813,7 @@ Released 2018-09-13
 [`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum
 [`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget
 [`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none
+[`mem_replace_option_with_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_some
 [`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default
 [`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit
 [`min_ident_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars
@@ -6067,6 +6069,7 @@ Released 2018-09-13
 [`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop
 [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match
 [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else
+[`single_option_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_option_map
 [`single_range_in_vec_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_range_in_vec_init
 [`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count
 [`size_of_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_ref
@@ -6143,6 +6146,7 @@ Released 2018-09-13
 [`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
 [`type_id_on_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_id_on_box
 [`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
+[`unbuffered_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#unbuffered_bytes
 [`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction
 [`unconditional_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#unconditional_recursion
 [`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
@@ -6267,6 +6271,7 @@ Released 2018-09-13
 [`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement
 [`allow-comparison-to-zero`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-comparison-to-zero
 [`allow-dbg-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-dbg-in-tests
+[`allow-expect-in-consts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-consts
 [`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests
 [`allow-indexing-slicing-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-indexing-slicing-in-tests
 [`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args
@@ -6275,6 +6280,7 @@ Released 2018-09-13
 [`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests
 [`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception
 [`allow-renamed-params-for`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-renamed-params-for
+[`allow-unwrap-in-consts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-consts
 [`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests
 [`allow-useless-vec-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-useless-vec-in-tests
 [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles
diff --git a/Cargo.toml b/Cargo.toml
index b615bb9e6f6..6c19e7af5f8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -25,7 +25,7 @@ path = "src/driver.rs"
 [dependencies]
 clippy_config = { path = "clippy_config" }
 clippy_lints = { path = "clippy_lints" }
-rustc_tools_util = "0.4.0"
+rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" }
 tempfile = { version = "3.3", optional = true }
 termize = "0.1"
 color-print = "0.3.4"
@@ -54,7 +54,7 @@ parking_lot = "0.12"
 tokio = { version = "1", features = ["io-util"] }
 
 [build-dependencies]
-rustc_tools_util = "0.4.0"
+rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" }
 
 [features]
 integration = ["tempfile"]
diff --git a/book/src/development/adding_lints.md b/book/src/development/adding_lints.md
index c26ad319f4f..48506127dee 100644
--- a/book/src/development/adding_lints.md
+++ b/book/src/development/adding_lints.md
@@ -788,7 +788,7 @@ don't hesitate to ask on [Zulip] or in the issue/PR.
 [`snippet`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/source/fn.snippet.html
 [let-chains]: https://github.com/rust-lang/rust/pull/94927
 [from_expansion]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
-[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
+[in_external_macro]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html#method.in_external_macro
 [span]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/struct.Span.html
 [applicability]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/enum.Applicability.html
 [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/
diff --git a/book/src/development/basics.md b/book/src/development/basics.md
index 166b6aab9fb..931e5c3a294 100644
--- a/book/src/development/basics.md
+++ b/book/src/development/basics.md
@@ -75,7 +75,7 @@ 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
 > only commit the files you wanted to update.
 
-[UI test]: https://rustc-dev-guide.rust-lang.org/tests/adding.html#guide-to-the-ui-tests
+[UI test]: https://rustc-dev-guide.rust-lang.org/tests/adding.html#ui-test-walkthrough
 
 ## `cargo dev`
 
diff --git a/book/src/development/common_tools_writing_lints.md b/book/src/development/common_tools_writing_lints.md
index b44ad80a25c..051febc2ca5 100644
--- a/book/src/development/common_tools_writing_lints.md
+++ b/book/src/development/common_tools_writing_lints.md
@@ -218,7 +218,7 @@ functions to deal with macros:
   > context. And so just using `span.from_expansion()` is often good enough.
 
 
-- `in_external_macro(span)`: detect if the given span is from a macro defined in
+- `span.in_external_macro(sm)`: detect if the given span is from a macro defined in
   a foreign crate. If you want the lint to work with macro-generated code, this
   is the next line of defense to avoid macros not defined in the current crate.
   It doesn't make sense to lint code that the coder can't change.
@@ -227,15 +227,13 @@ functions to deal with macros:
   crates
 
   ```rust
-  use rustc_middle::lint::in_external_macro;
-
   use a_crate_with_macros::foo;
 
   // `foo` is defined in `a_crate_with_macros`
   foo!("bar");
 
   // if we lint the `match` of `foo` call and test its span
-  assert_eq!(in_external_macro(cx.sess(), match_span), true);
+  assert_eq!(match_span.in_external_macro(cx.sess().source_map()), true);
   ```
 
 - `span.ctxt()`: the span's context represents whether it is from expansion, and
diff --git a/book/src/development/macro_expansions.md b/book/src/development/macro_expansions.md
index 125b6c4bc5b..36092f82e26 100644
--- a/book/src/development/macro_expansions.md
+++ b/book/src/development/macro_expansions.md
@@ -120,7 +120,7 @@ assert_ne!(x_is_some_span.ctxt(), x_unwrap_span.ctxt());
 
 ### The `in_external_macro` function
 
-`rustc_middle::lint` provides a function ([`in_external_macro`]) that can
+`Span` provides a method ([`in_external_macro`]) that can
 detect if the given span is from a macro defined in a foreign crate.
 
 Therefore, if we really want a new lint to work with macro-generated code,
@@ -144,7 +144,7 @@ Also assume that we get the corresponding variable `foo_span` for the
 results in `true` (note that `cx` can be `EarlyContext` or `LateContext`):
 
 ```rust
-if in_external_macro(cx.sess(), foo_span) {
+if foo_span.in_external_macro(cx.sess().source_map()) {
     // We should ignore macro from a foreign crate.
     return;
 }
@@ -153,6 +153,6 @@ if in_external_macro(cx.sess(), foo_span) {
 [`ctxt`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.ctxt
 [expansion]: https://rustc-dev-guide.rust-lang.org/macro-expansion.html#expansion-and-ast-integration
 [`from_expansion`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion
-[`in_external_macro`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html
+[`in_external_macro`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.in_external_macro
 [Span]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html
 [SyntaxContext]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/hygiene/struct.SyntaxContext.html
diff --git a/book/src/lint_configuration.md b/book/src/lint_configuration.md
index dab2630a56f..0e264cdcd4a 100644
--- a/book/src/lint_configuration.md
+++ b/book/src/lint_configuration.md
@@ -71,6 +71,16 @@ Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
 * [`dbg_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro)
 
 
+## `allow-expect-in-consts`
+Whether `expect` should be allowed in code always evaluated at compile time
+
+**Default Value:** `true`
+
+---
+**Affected lints:**
+* [`expect_used`](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used)
+
+
 ## `allow-expect-in-tests`
 Whether `expect` should be allowed in test functions or `#[cfg(test)]`
 
@@ -108,7 +118,7 @@ Whether to allow `r#""#` when `r""` can be used
 
 ---
 **Affected lints:**
-* [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes)
+* [`needless_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_string_hashes)
 
 
 ## `allow-panic-in-tests`
@@ -164,6 +174,16 @@ default configuration of Clippy. By default, any configuration will replace the
 * [`renamed_function_params`](https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params)
 
 
+## `allow-unwrap-in-consts`
+Whether `unwrap` should be allowed in code always evaluated at compile time
+
+**Default Value:** `true`
+
+---
+**Affected lints:**
+* [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used)
+
+
 ## `allow-unwrap-in-tests`
 Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
 
@@ -740,13 +760,16 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
 * [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map)
 * [`legacy_numeric_constants`](https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants)
+* [`lines_filter_map_ok`](https://rust-lang.github.io/rust-clippy/master/index.html#lines_filter_map_ok)
 * [`manual_bits`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits)
 * [`manual_c_str_literals`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals)
 * [`manual_clamp`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp)
+* [`manual_flatten`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten)
 * [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one)
 * [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check)
 * [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
 * [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive)
+* [`manual_option_as_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_option_as_slice)
 * [`manual_pattern_char_comparison`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison)
 * [`manual_range_contains`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains)
 * [`manual_rem_euclid`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid)
@@ -761,6 +784,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
 * [`map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or)
 * [`map_with_unused_argument_over_ranges`](https://rust-lang.github.io/rust-clippy/master/index.html#map_with_unused_argument_over_ranges)
 * [`match_like_matches_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro)
+* [`mem_replace_option_with_some`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_some)
 * [`mem_replace_with_default`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default)
 * [`missing_const_for_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn)
 * [`needless_borrow`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow)
diff --git a/clippy_config/src/conf.rs b/clippy_config/src/conf.rs
index a1591188bee..cac4408fff0 100644
--- a/clippy_config/src/conf.rs
+++ b/clippy_config/src/conf.rs
@@ -1,8 +1,8 @@
 use crate::ClippyConfiguration;
 use crate::types::{
-    DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering,
-    SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind,
-    SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds,
+    DisallowedPath, DisallowedPathWithoutReplacement, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour,
+    Rename, SourceItemOrdering, SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings,
+    SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds,
 };
 use clippy_utils::msrvs::Msrv;
 use rustc_errors::Applicability;
@@ -288,6 +288,9 @@ define_Conf! {
     /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
     #[lints(dbg_macro)]
     allow_dbg_in_tests: bool = false,
+    /// Whether `expect` should be allowed in code always evaluated at compile time
+    #[lints(expect_used)]
+    allow_expect_in_consts: bool = true,
     /// Whether `expect` should be allowed in test functions or `#[cfg(test)]`
     #[lints(expect_used)]
     allow_expect_in_tests: bool = false,
@@ -298,7 +301,7 @@ define_Conf! {
     #[lints(uninlined_format_args)]
     allow_mixed_uninlined_format_args: bool = true,
     /// Whether to allow `r#""#` when `r""` can be used
-    #[lints(unnecessary_raw_string_hashes)]
+    #[lints(needless_raw_string_hashes)]
     allow_one_hash_in_raw_strings: bool = false,
     /// Whether `panic` should be allowed in test functions or `#[cfg(test)]`
     #[lints(panic)]
@@ -325,6 +328,9 @@ define_Conf! {
     #[lints(renamed_function_params)]
     allow_renamed_params_for: Vec<String> =
         DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect(),
+    /// Whether `unwrap` should be allowed in code always evaluated at compile time
+    #[lints(unwrap_used)]
+    allow_unwrap_in_consts: bool = true,
     /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
     #[lints(unwrap_used)]
     allow_unwrap_in_tests: bool = false,
@@ -448,7 +454,7 @@ define_Conf! {
     avoid_breaking_exported_api: bool = true,
     /// The list of types which may not be held across an await point.
     #[lints(await_holding_invalid_type)]
-    await_holding_invalid_types: Vec<DisallowedPath> = Vec::new(),
+    await_holding_invalid_types: Vec<DisallowedPathWithoutReplacement> = Vec::new(),
     /// DEPRECATED LINT: BLACKLISTED_NAME.
     ///
     /// Use the Disallowed Names lint instead
@@ -609,13 +615,16 @@ define_Conf! {
         index_refutable_slice,
         iter_kv_map,
         legacy_numeric_constants,
+        lines_filter_map_ok,
         manual_bits,
         manual_c_str_literals,
         manual_clamp,
+        manual_flatten,
         manual_hash_one,
         manual_is_ascii_check,
         manual_let_else,
         manual_non_exhaustive,
+        manual_option_as_slice,
         manual_pattern_char_comparison,
         manual_range_contains,
         manual_rem_euclid,
@@ -630,6 +639,7 @@ define_Conf! {
         map_unwrap_or,
         map_with_unused_argument_over_ranges,
         match_like_matches_macro,
+        mem_replace_option_with_some,
         mem_replace_with_default,
         missing_const_for_fn,
         needless_borrow,
diff --git a/clippy_config/src/types.rs b/clippy_config/src/types.rs
index c949db9109d..c72291e9799 100644
--- a/clippy_config/src/types.rs
+++ b/clippy_config/src/types.rs
@@ -1,6 +1,8 @@
 use clippy_utils::def_path_def_ids;
+use rustc_errors::{Applicability, Diag};
 use rustc_hir::def_id::DefIdMap;
 use rustc_middle::ty::TyCtxt;
+use rustc_span::Span;
 use serde::de::{self, Deserializer, Visitor};
 use serde::{Deserialize, Serialize, ser};
 use std::collections::HashMap;
@@ -12,37 +14,99 @@ pub struct Rename {
     pub rename: String,
 }
 
-#[derive(Debug, Deserialize)]
+pub type DisallowedPathWithoutReplacement = DisallowedPath<false>;
+
+#[derive(Debug, Serialize)]
+pub struct DisallowedPath<const REPLACEMENT_ALLOWED: bool = true> {
+    path: String,
+    reason: Option<String>,
+    replacement: Option<String>,
+}
+
+impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath<REPLACEMENT_ALLOWED> {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        let enum_ = DisallowedPathEnum::deserialize(deserializer)?;
+        if !REPLACEMENT_ALLOWED && enum_.replacement().is_some() {
+            return Err(de::Error::custom("replacement not allowed for this configuration"));
+        }
+        Ok(Self {
+            path: enum_.path().to_owned(),
+            reason: enum_.reason().map(ToOwned::to_owned),
+            replacement: enum_.replacement().map(ToOwned::to_owned),
+        })
+    }
+}
+
+// `DisallowedPathEnum` is an implementation detail to enable the `Deserialize` implementation just
+// above. `DisallowedPathEnum` is not meant to be used outside of this file.
+#[derive(Debug, Deserialize, Serialize)]
 #[serde(untagged)]
-pub enum DisallowedPath {
+enum DisallowedPathEnum {
     Simple(String),
-    WithReason { path: String, reason: Option<String> },
+    WithReason {
+        path: String,
+        reason: Option<String>,
+        replacement: Option<String>,
+    },
 }
 
-impl DisallowedPath {
+impl<const REPLACEMENT_ALLOWED: bool> DisallowedPath<REPLACEMENT_ALLOWED> {
+    pub fn path(&self) -> &str {
+        &self.path
+    }
+
+    pub fn diag_amendment(&self, span: Span) -> impl FnOnce(&mut Diag<'_, ()>) + use<'_, REPLACEMENT_ALLOWED> {
+        move |diag| {
+            if let Some(replacement) = &self.replacement {
+                diag.span_suggestion(
+                    span,
+                    self.reason.as_ref().map_or_else(|| String::from("use"), Clone::clone),
+                    replacement,
+                    Applicability::MachineApplicable,
+                );
+            } else if let Some(reason) = &self.reason {
+                diag.note(reason.clone());
+            }
+        }
+    }
+}
+
+impl DisallowedPathEnum {
     pub fn path(&self) -> &str {
         let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
 
         path
     }
 
-    pub fn reason(&self) -> Option<&str> {
+    fn reason(&self) -> Option<&str> {
         match &self {
             Self::WithReason { reason, .. } => reason.as_deref(),
             Self::Simple(_) => None,
         }
     }
+
+    fn replacement(&self) -> Option<&str> {
+        match &self {
+            Self::WithReason { replacement, .. } => replacement.as_deref(),
+            Self::Simple(_) => None,
+        }
+    }
 }
 
 /// Creates a map of disallowed items to the reason they were disallowed.
-pub fn create_disallowed_map(
+pub fn create_disallowed_map<const REPLACEMENT_ALLOWED: bool>(
     tcx: TyCtxt<'_>,
-    disallowed: &'static [DisallowedPath],
-) -> DefIdMap<(&'static str, Option<&'static str>)> {
+    disallowed: &'static [DisallowedPath<REPLACEMENT_ALLOWED>],
+) -> DefIdMap<(&'static str, &'static DisallowedPath<REPLACEMENT_ALLOWED>)> {
     disallowed
         .iter()
-        .map(|x| (x.path(), x.path().split("::").collect::<Vec<_>>(), x.reason()))
-        .flat_map(|(name, path, reason)| def_path_def_ids(tcx, &path).map(move |id| (id, (name, reason))))
+        .map(|x| (x.path(), x.path().split("::").collect::<Vec<_>>(), x))
+        .flat_map(|(name, path, disallowed_path)| {
+            def_path_def_ids(tcx, &path).map(move |id| (id, (name, disallowed_path)))
+        })
         .collect()
 }
 
@@ -436,7 +500,6 @@ macro_rules! unimplemented_serialize {
 }
 
 unimplemented_serialize! {
-    DisallowedPath,
     Rename,
     MacroMatcher,
 }
diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs
index 790dafa811f..bdddf46a2cb 100644
--- a/clippy_dev/src/fmt.rs
+++ b/clippy_dev/src/fmt.rs
@@ -290,8 +290,13 @@ fn run_rustfmt(context: &FmtContext) -> Result<(), Error> {
         .filter_map(|entry| {
             let entry = entry.expect("failed to find tests");
             let path = entry.path();
-
-            if path.extension() != Some("rs".as_ref()) || entry.file_name() == "ice-3891.rs" {
+            if path.extension() != Some("rs".as_ref())
+                || path
+                    .components()
+                    .nth_back(1)
+                    .is_some_and(|c| c.as_os_str() == "syntax-error-recovery")
+                || entry.file_name() == "ice-3891.rs"
+            {
                 None
             } else {
                 Some(entry.into_path().into_os_string())
diff --git a/clippy_dev/src/lint.rs b/clippy_dev/src/lint.rs
index 125195397e6..e0e036757d5 100644
--- a/clippy_dev/src/lint.rs
+++ b/clippy_dev/src/lint.rs
@@ -2,7 +2,7 @@ use crate::utils::{cargo_clippy_path, exit_if_err};
 use std::process::{self, Command};
 use std::{env, fs};
 
-pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
+pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>) {
     let is_file = match fs::metadata(path) {
         Ok(metadata) => metadata.is_file(),
         Err(e) => {
@@ -17,7 +17,7 @@ pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) {
                 .args(["run", "--bin", "clippy-driver", "--"])
                 .args(["-L", "./target/debug"])
                 .args(["-Z", "no-codegen"])
-                .args(["--edition", "2021"])
+                .args(["--edition", edition])
                 .arg(path)
                 .args(args)
                 // Prevent rustc from creating `rustc-ice-*` files the console output is enough.
diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs
index 56ed60256f1..93a74ba8387 100644
--- a/clippy_dev/src/main.rs
+++ b/clippy_dev/src/main.rs
@@ -68,7 +68,7 @@ fn main() {
             RemoveSubcommand::VscodeTasks => setup::vscode::remove_tasks(),
         },
         DevCommand::Serve { port, lint } => serve::run(port, lint),
-        DevCommand::Lint { path, args } => lint::run(&path, args.iter()),
+        DevCommand::Lint { path, edition, args } => lint::run(&path, &edition, args.iter()),
         DevCommand::RenameLint {
             old_name,
             new_name,
@@ -206,6 +206,9 @@ enum DevCommand {
     ///     cargo dev lint file.rs -- -W clippy::pedantic {n}
     ///     cargo dev lint ~/my-project -- -- -W clippy::pedantic
     Lint {
+        /// The Rust edition to use
+        #[arg(long, default_value = "2024")]
+        edition: String,
         /// The path to a file or package directory to lint
         path: String,
         /// Pass extra arguments to cargo/clippy-driver
diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs
index fc0780f89a7..b80ee5aac7e 100644
--- a/clippy_dev/src/update_lints.rs
+++ b/clippy_dev/src/update_lints.rs
@@ -985,17 +985,23 @@ mod tests {
             Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
         ];
         let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
-        expected.insert("group1".to_string(), vec![
-            Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
-            Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
-        ]);
-        expected.insert("group2".to_string(), vec![Lint::new(
-            "should_assert_eq2",
-            "group2",
-            "\"abc\"",
-            "module_name",
-            Range::default(),
-        )]);
+        expected.insert(
+            "group1".to_string(),
+            vec![
+                Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
+                Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
+            ],
+        );
+        expected.insert(
+            "group2".to_string(),
+            vec![Lint::new(
+                "should_assert_eq2",
+                "group2",
+                "\"abc\"",
+                "module_name",
+                Range::default(),
+            )],
+        );
         assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
     }
 }
diff --git a/clippy_lints/src/almost_complete_range.rs b/clippy_lints/src/almost_complete_range.rs
index 2af5178920d..0f7f779e8ea 100644
--- a/clippy_lints/src/almost_complete_range.rs
+++ b/clippy_lints/src/almost_complete_range.rs
@@ -5,7 +5,6 @@ use clippy_utils::source::{trim_span, walk_span_to_context};
 use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -45,7 +44,7 @@ impl EarlyLintPass for AlmostCompleteRange {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
         if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind
             && is_incomplete_range(start, end)
-            && !in_external_macro(cx.sess(), e.span)
+            && !e.span.in_external_macro(cx.sess().source_map())
         {
             span_lint_and_then(
                 cx,
@@ -74,7 +73,7 @@ impl EarlyLintPass for AlmostCompleteRange {
         if let PatKind::Range(Some(start), Some(end), kind) = &p.kind
             && matches!(kind.node, RangeEnd::Excluded)
             && is_incomplete_range(start, end)
-            && !in_external_macro(cx.sess(), p.span)
+            && !p.span.in_external_macro(cx.sess().source_map())
         {
             span_lint_and_then(
                 cx,
diff --git a/clippy_lints/src/arbitrary_source_item_ordering.rs b/clippy_lints/src/arbitrary_source_item_ordering.rs
index 0389223c3e0..f519a65fc27 100644
--- a/clippy_lints/src/arbitrary_source_item_ordering.rs
+++ b/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -9,7 +9,6 @@ use rustc_hir::{
     Variant, VariantData,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -248,7 +247,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
             ItemKind::Enum(enum_def, _generics) if self.enable_ordering_for_enum => {
                 let mut cur_v: Option<&Variant<'_>> = None;
                 for variant in enum_def.variants {
-                    if in_external_macro(cx.sess(), variant.span) {
+                    if variant.span.in_external_macro(cx.sess().source_map()) {
                         continue;
                     }
 
@@ -263,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
             ItemKind::Struct(VariantData::Struct { fields, .. }, _generics) if self.enable_ordering_for_struct => {
                 let mut cur_f: Option<&FieldDef<'_>> = None;
                 for field in *fields {
-                    if in_external_macro(cx.sess(), field.span) {
+                    if field.span.in_external_macro(cx.sess().source_map()) {
                         continue;
                     }
 
@@ -281,7 +280,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
                 let mut cur_t: Option<&TraitItemRef> = None;
 
                 for item in *item_ref {
-                    if in_external_macro(cx.sess(), item.span) {
+                    if item.span.in_external_macro(cx.sess().source_map()) {
                         continue;
                     }
 
@@ -304,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
                 let mut cur_t: Option<&ImplItemRef> = None;
 
                 for item in trait_impl.items {
-                    if in_external_macro(cx.sess(), item.span) {
+                    if item.span.in_external_macro(cx.sess().source_map()) {
                         continue;
                     }
 
@@ -348,7 +347,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering {
         // as no sorting by source map/line of code has to be applied.
         //
         for item in items {
-            if in_external_macro(cx.sess(), item.span) {
+            if item.span.in_external_macro(cx.sess().source_map()) {
                 continue;
             }
 
diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs
index fefd8195f8e..847653ed6e9 100644
--- a/clippy_lints/src/as_conversions.rs
+++ b/clippy_lints/src/as_conversions.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -49,7 +48,7 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]);
 impl<'tcx> LateLintPass<'tcx> for AsConversions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         if let ExprKind::Cast(_, _) = expr.kind
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && !is_from_proc_macro(cx, expr)
         {
             #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
diff --git a/clippy_lints/src/attrs/allow_attributes.rs b/clippy_lints/src/attrs/allow_attributes.rs
index 1879391ec29..53d9725703c 100644
--- a/clippy_lints/src/attrs/allow_attributes.rs
+++ b/clippy_lints/src/attrs/allow_attributes.rs
@@ -4,11 +4,10 @@ use clippy_utils::is_from_proc_macro;
 use rustc_ast::{AttrStyle, Attribute};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 
 // Separate each crate's features.
 pub fn check<'cx>(cx: &EarlyContext<'cx>, attr: &'cx Attribute) {
-    if !in_external_macro(cx.sess(), attr.span)
+    if !attr.span.in_external_macro(cx.sess().source_map())
         && let AttrStyle::Outer = attr.style
         && let Some(ident) = attr.ident()
         && !is_from_proc_macro(cx, attr)
diff --git a/clippy_lints/src/attrs/allow_attributes_without_reason.rs b/clippy_lints/src/attrs/allow_attributes_without_reason.rs
index 788377fe83c..5bf077990e1 100644
--- a/clippy_lints/src/attrs/allow_attributes_without_reason.rs
+++ b/clippy_lints/src/attrs/allow_attributes_without_reason.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_from_proc_macro;
 use rustc_ast::{MetaItemInner, MetaItemKind};
 use rustc_lint::{EarlyContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
 
@@ -17,7 +16,7 @@ pub(super) fn check<'cx>(cx: &EarlyContext<'cx>, name: Symbol, items: &[MetaItem
     }
 
     // Check if the attribute is in an external macro and therefore out of the developer's control
-    if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, attr) {
+    if attr.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, attr) {
         return;
     }
 
diff --git a/clippy_lints/src/attrs/useless_attribute.rs b/clippy_lints/src/attrs/useless_attribute.rs
index e7158a6a6b6..e3e081ce08e 100644
--- a/clippy_lints/src/attrs/useless_attribute.rs
+++ b/clippy_lints/src/attrs/useless_attribute.rs
@@ -5,14 +5,13 @@ use clippy_utils::source::{SpanRangeExt, first_line_of_span};
 use rustc_ast::{Attribute, Item, ItemKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_span::sym;
 
 pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
     let skip_unused_imports = attrs.iter().any(|attr| attr.has_name(sym::macro_use));
 
     for attr in attrs {
-        if in_external_macro(cx.sess(), attr.span) {
+        if attr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         if let Some(lint_list) = &attr.meta_item_list() {
diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs
index 2eb0566bf9a..92a0c7f9acb 100644
--- a/clippy_lints/src/await_holding_invalid.rs
+++ b/clippy_lints/src/await_holding_invalid.rs
@@ -1,5 +1,5 @@
 use clippy_config::Conf;
-use clippy_config::types::create_disallowed_map;
+use clippy_config::types::{DisallowedPathWithoutReplacement, create_disallowed_map};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{match_def_path, paths};
 use rustc_hir as hir;
@@ -174,7 +174,7 @@ declare_clippy_lint! {
 impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF, AWAIT_HOLDING_INVALID_TYPE]);
 
 pub struct AwaitHolding {
-    def_ids: DefIdMap<(&'static str, Option<&'static str>)>,
+    def_ids: DefIdMap<(&'static str, &'static DisallowedPathWithoutReplacement)>,
 }
 
 impl AwaitHolding {
@@ -247,25 +247,26 @@ impl AwaitHolding {
                             );
                         },
                     );
-                } else if let Some(&(path, reason)) = self.def_ids.get(&adt.did()) {
-                    emit_invalid_type(cx, ty_cause.source_info.span, path, reason);
+                } else if let Some(&(path, disallowed_path)) = self.def_ids.get(&adt.did()) {
+                    emit_invalid_type(cx, ty_cause.source_info.span, path, disallowed_path);
                 }
             }
         }
     }
 }
 
-fn emit_invalid_type(cx: &LateContext<'_>, span: Span, path: &'static str, reason: Option<&'static str>) {
+fn emit_invalid_type(
+    cx: &LateContext<'_>,
+    span: Span,
+    path: &'static str,
+    disallowed_path: &'static DisallowedPathWithoutReplacement,
+) {
     span_lint_and_then(
         cx,
         AWAIT_HOLDING_INVALID_TYPE,
         span,
         format!("holding a disallowed type across an await point `{path}`"),
-        |diag| {
-            if let Some(reason) = reason {
-                diag.note(reason);
-            }
-        },
+        disallowed_path.diag_amendment(span),
     );
 }
 
diff --git a/clippy_lints/src/blocks_in_conditions.rs b/clippy_lints/src/blocks_in_conditions.rs
index eb05dc96cde..aab0af0d743 100644
--- a/clippy_lints/src/blocks_in_conditions.rs
+++ b/clippy_lints/src/blocks_in_conditions.rs
@@ -4,7 +4,6 @@ use clippy_utils::{higher, is_from_proc_macro};
 use rustc_errors::Applicability;
 use rustc_hir::{BlockCheckMode, Expr, ExprKind, MatchSource};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -54,7 +53,7 @@ const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression conditio
 
 impl<'tcx> LateLintPass<'tcx> for BlocksInConditions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span) {
+        if expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs
index f8c30d1c881..ee21f9379a5 100644
--- a/clippy_lints/src/booleans.rs
+++ b/clippy_lints/src/booleans.rs
@@ -3,6 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::eq_expr_value;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::SpanRangeExt;
+use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use rustc_ast::ast::LitKind;
 use rustc_attr_parsing::RustcVersion;
@@ -353,7 +354,8 @@ impl SuggestContext<'_, '_, '_> {
                         self.output.push_str(&str);
                     } else {
                         self.output.push('!');
-                        self.output.push_str(&terminal.span.get_source_text(self.cx)?);
+                        self.output
+                            .push_str(&Sugg::hir_opt(self.cx, terminal)?.maybe_par().to_string());
                     }
                 },
                 True | False | Not(_) => {
diff --git a/clippy_lints/src/box_default.rs b/clippy_lints/src/box_default.rs
index 79fd6ffe46c..3b861848f94 100644
--- a/clippy_lints/src/box_default.rs
+++ b/clippy_lints/src/box_default.rs
@@ -7,7 +7,6 @@ use rustc_hir::def::Res;
 use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
 use rustc_hir::{AmbigArg, Block, Expr, ExprKind, HirId, LetStmt, Node, QPath, Ty, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::{Span, sym};
 
@@ -50,7 +49,7 @@ impl LateLintPass<'_> for BoxDefault {
             // This is the `T::default()` (or default equivalent) of `Box::new(T::default())`
             && let ExprKind::Call(arg_path, _) = arg.kind
             // And we are not in a foreign crate's macro
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             // And the argument expression has the same context as the outer call expression
             // or that we are inside a `vec!` macro expansion
             && (expr.span.eq_ctxt(arg.span) || is_local_vec_expn(cx, arg, expr))
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index d90cf124fe4..521bd394901 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -29,7 +29,6 @@ use clippy_utils::is_hir_ty_cfg_dependant;
 use clippy_utils::msrvs::{self, Msrv};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -796,7 +795,7 @@ impl_lint_pass!(Casts => [
 
 impl<'tcx> LateLintPass<'tcx> for Casts {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span) {
+        if expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs
index 9e1876e40f9..7885f171461 100644
--- a/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/clippy_lints/src/casts/unnecessary_cast.rs
@@ -8,7 +8,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, FloatTy, InferTy, Ty};
 use std::ops::ControlFlow;
 
@@ -142,7 +141,7 @@ pub(super) fn check<'tcx>(
         }
     }
 
-    if cast_from.kind() == cast_to.kind() && !in_external_macro(cx.sess(), expr.span) {
+    if cast_from.kind() == cast_to.kind() && !expr.span.in_external_macro(cx.sess().source_map()) {
         if let Some(id) = path_to_local(cast_expr)
             && !cx.tcx.hir().span(id).eq_ctxt(cast_expr.span)
         {
diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs
index 1edfde97422..9516af7334d 100644
--- a/clippy_lints/src/checked_conversions.rs
+++ b/clippy_lints/src/checked_conversions.rs
@@ -6,7 +6,6 @@ use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -64,7 +63,7 @@ impl LateLintPass<'_> for CheckedConversions {
                 },
                 _ => return,
             }
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
             && !is_in_const_context(cx)
             && self.msrv.meets(msrvs::TRY_FROM)
             && let Some(cv) = match op2 {
diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs
index 89808d38b9f..03ed9c657b3 100644
--- a/clippy_lints/src/copies.rs
+++ b/clippy_lints/src/copies.rs
@@ -18,7 +18,6 @@ use rustc_session::impl_lint_pass;
 use rustc_span::hygiene::walk_chain;
 use rustc_span::source_map::SourceMap;
 use rustc_span::{Span, Symbol};
-use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -130,11 +129,6 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// Duplicate code is less maintainable.
     ///
-    /// ### Known problems
-    /// * The lint doesn't check if the moved expressions modify values that are being used in
-    ///   the if condition. The suggestion can in that case modify the behavior of the program.
-    ///   See [rust-clippy#7452](https://github.com/rust-lang/rust-clippy/issues/7452)
-    ///
     /// ### Example
     /// ```ignore
     /// let foo = if … {
@@ -248,18 +242,18 @@ fn lint_branches_sharing_code<'tcx>(
         let first_line_span = first_line_of_span(cx, expr.span);
         let replace_span = first_line_span.with_hi(span.hi());
         let cond_span = first_line_span.until(first_block.span);
-        let cond_snippet = reindent_multiline(snippet(cx, cond_span, "_"), false, None);
+        let cond_snippet = reindent_multiline(&snippet(cx, cond_span, "_"), false, None);
         let cond_indent = indent_of(cx, cond_span);
-        let moved_snippet = reindent_multiline(snippet(cx, span, "_"), true, None);
+        let moved_snippet = reindent_multiline(&snippet(cx, span, "_"), true, None);
         let suggestion = moved_snippet.to_string() + "\n" + &cond_snippet + "{";
-        let suggestion = reindent_multiline(Cow::Borrowed(&suggestion), true, cond_indent);
+        let suggestion = reindent_multiline(&suggestion, true, cond_indent);
         (replace_span, suggestion.to_string())
     });
     let end_suggestion = res.end_span(last_block, sm).map(|span| {
-        let moved_snipped = reindent_multiline(snippet(cx, span, "_"), true, None);
+        let moved_snipped = reindent_multiline(&snippet(cx, span, "_"), true, None);
         let indent = indent_of(cx, expr.span.shrink_to_hi());
         let suggestion = "}\n".to_string() + &moved_snipped;
-        let suggestion = reindent_multiline(Cow::Borrowed(&suggestion), true, indent);
+        let suggestion = reindent_multiline(&suggestion, true, indent);
 
         let span = span.with_hi(last_block.span.hi());
         // Improve formatting if the inner block has indention (i.e. normal Rust formatting)
diff --git a/clippy_lints/src/ctfe.rs b/clippy_lints/src/ctfe.rs
index 589b99518a0..7bae04a10f1 100644
--- a/clippy_lints/src/ctfe.rs
+++ b/clippy_lints/src/ctfe.rs
@@ -21,6 +21,6 @@ impl<'tcx> LateLintPass<'tcx> for ClippyCtfe {
         _: Span,
         defid: LocalDefId,
     ) {
-        cx.tcx.ensure().mir_drops_elaborated_and_const_checked(defid); // Lint
+        cx.tcx.ensure_ok().mir_drops_elaborated_and_const_checked(defid); // Lint
     }
 }
diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs
index a96c86f0765..06376c57119 100644
--- a/clippy_lints/src/dbg_macro.rs
+++ b/clippy_lints/src/dbg_macro.rs
@@ -7,7 +7,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Node};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, SyntaxContext, sym};
 
@@ -60,7 +59,7 @@ impl LateLintPass<'_> for DbgMacro {
 
         if cur_syntax_ctxt != self.prev_ctxt &&
             let Some(macro_call) = first_dbg_macro_in_expansion(cx, expr.span) &&
-            !in_external_macro(cx.sess(), macro_call.span) &&
+            !macro_call.span.in_external_macro(cx.sess().source_map()) &&
             self.checked_dbg_call_site.insert(macro_call.span) &&
             // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
             !(self.allow_dbg_in_tests && is_in_test(cx.tcx, expr.hir_id))
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 9fbeab5bf2e..1f00fb82c6d 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -139,6 +139,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::disallowed_types::DISALLOWED_TYPES_INFO,
     crate::doc::DOC_INCLUDE_WITHOUT_CFG_INFO,
     crate::doc::DOC_LAZY_CONTINUATION_INFO,
+    crate::doc::DOC_LINK_CODE_INFO,
     crate::doc::DOC_LINK_WITH_QUOTES_INFO,
     crate::doc::DOC_MARKDOWN_INFO,
     crate::doc::DOC_NESTED_REFDEFS_INFO,
@@ -362,6 +363,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::matches::WILDCARD_ENUM_MATCH_ARM_INFO,
     crate::matches::WILDCARD_IN_OR_PATTERNS_INFO,
     crate::mem_replace::MEM_REPLACE_OPTION_WITH_NONE_INFO,
+    crate::mem_replace::MEM_REPLACE_OPTION_WITH_SOME_INFO,
     crate::mem_replace::MEM_REPLACE_WITH_DEFAULT_INFO,
     crate::mem_replace::MEM_REPLACE_WITH_UNINIT_INFO,
     crate::methods::BIND_INSTEAD_OF_MAP_INFO,
@@ -452,7 +454,6 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::methods::OPTION_AS_REF_CLONED_INFO,
     crate::methods::OPTION_AS_REF_DEREF_INFO,
     crate::methods::OPTION_FILTER_MAP_INFO,
-    crate::methods::OPTION_MAP_OR_ERR_OK_INFO,
     crate::methods::OPTION_MAP_OR_NONE_INFO,
     crate::methods::OR_FUN_CALL_INFO,
     crate::methods::OR_THEN_UNWRAP_INFO,
@@ -483,6 +484,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::methods::SUSPICIOUS_SPLITN_INFO,
     crate::methods::SUSPICIOUS_TO_OWNED_INFO,
     crate::methods::TYPE_ID_ON_BOX_INFO,
+    crate::methods::UNBUFFERED_BYTES_INFO,
     crate::methods::UNINIT_ASSUMED_INIT_INFO,
     crate::methods::UNIT_HASH_INFO,
     crate::methods::UNNECESSARY_FALLIBLE_CONVERSIONS_INFO,
@@ -684,6 +686,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::single_call_fn::SINGLE_CALL_FN_INFO,
     crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
     crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
+    crate::single_option_map::SINGLE_OPTION_MAP_INFO,
     crate::single_range_in_vec_init::SINGLE_RANGE_IN_VEC_INIT_INFO,
     crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
     crate::size_of_ref::SIZE_OF_REF_INFO,
diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs
index ca3eaae7b85..772268e7899 100644
--- a/clippy_lints/src/default_numeric_fallback.rs
+++ b/clippy_lints/src/default_numeric_fallback.rs
@@ -9,7 +9,6 @@ use rustc_hir::{
     StructTailExpr,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
 use rustc_session::declare_lint_pass;
 use std::iter;
@@ -86,7 +85,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
 
     /// Check whether a passed literal has potential to cause fallback or not.
     fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>, emit_hir_id: HirId) {
-        if !in_external_macro(self.cx.sess(), lit.span)
+        if !lit.span.in_external_macro(self.cx.sess().source_map())
             && matches!(self.ty_bounds.last(), Some(ExplicitTyBound(false)))
             && matches!(
                 lit.node,
diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs
index 5604172d6f3..0031da406f1 100644
--- a/clippy_lints/src/deprecated_lints.rs
+++ b/clippy_lints/src/deprecated_lints.rs
@@ -40,6 +40,8 @@ declare_with_version! { DEPRECATED(DEPRECATED_VERSION): &[(&str, &str)] = &[
     ("clippy::pub_enum_variant_names", "`clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config"),
     #[clippy::version = "1.54.0"]
     ("clippy::wrong_pub_self_convention", "`clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config"),
+    #[clippy::version = "1.86.0"]
+    ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"),
     // end deprecated lints. used by `cargo dev deprecate_lint`
 ]}
 
diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index 123e358d7c3..233ebe00d8e 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -291,10 +291,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                             && let Some(ty) = use_node.defined_ty(cx)
                             && TyCoercionStability::for_defined_ty(cx, ty, use_node.is_return()).is_deref_stable()
                         {
-                            self.state = Some((State::ExplicitDeref { mutability: None }, StateData {
-                                first_expr: expr,
-                                adjusted_ty,
-                            }));
+                            self.state = Some((
+                                State::ExplicitDeref { mutability: None },
+                                StateData {
+                                    first_expr: expr,
+                                    adjusted_ty,
+                                },
+                            ));
                         }
                     },
                     RefOp::Method { mutbl, is_ufcs }
@@ -456,10 +459,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                             && next_adjust.is_none_or(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
                             && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
                         {
-                            self.state = Some((State::Borrow { mutability }, StateData {
-                                first_expr: expr,
-                                adjusted_ty,
-                            }));
+                            self.state = Some((
+                                State::Borrow { mutability },
+                                StateData {
+                                    first_expr: expr,
+                                    adjusted_ty,
+                                },
+                            ));
                         }
                     },
                     _ => {},
@@ -503,10 +509,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                 let stability = state.stability;
                 report(cx, expr, State::DerefedBorrow(state), data, typeck);
                 if stability.is_deref_stable() {
-                    self.state = Some((State::Borrow { mutability }, StateData {
-                        first_expr: expr,
-                        adjusted_ty,
-                    }));
+                    self.state = Some((
+                        State::Borrow { mutability },
+                        StateData {
+                            first_expr: expr,
+                            adjusted_ty,
+                        },
+                    ));
                 }
             },
             (Some((State::DerefedBorrow(state), data)), RefOp::Deref) => {
@@ -531,10 +540,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                 } else if stability.is_deref_stable()
                     && let Some(parent) = get_parent_expr(cx, expr)
                 {
-                    self.state = Some((State::ExplicitDeref { mutability: None }, StateData {
-                        first_expr: parent,
-                        adjusted_ty,
-                    }));
+                    self.state = Some((
+                        State::ExplicitDeref { mutability: None },
+                        StateData {
+                            first_expr: parent,
+                            adjusted_ty,
+                        },
+                    ));
                 }
             },
 
@@ -1124,17 +1136,20 @@ impl<'tcx> Dereferencing<'tcx> {
         if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
             if let Some(pat) = outer_pat {
                 // Check for auto-deref
-                if !matches!(cx.typeck_results().expr_adjustments(e), [
-                    Adjustment {
-                        kind: Adjust::Deref(_),
-                        ..
-                    },
-                    Adjustment {
-                        kind: Adjust::Deref(_),
+                if !matches!(
+                    cx.typeck_results().expr_adjustments(e),
+                    [
+                        Adjustment {
+                            kind: Adjust::Deref(_),
+                            ..
+                        },
+                        Adjustment {
+                            kind: Adjust::Deref(_),
+                            ..
+                        },
                         ..
-                    },
-                    ..
-                ]) {
+                    ]
+                ) {
                     match get_parent_expr(cx, e) {
                         // Field accesses are the same no matter the number of references.
                         Some(Expr {
diff --git a/clippy_lints/src/disallowed_macros.rs b/clippy_lints/src/disallowed_macros.rs
index 4e8853821c3..22310bc0798 100644
--- a/clippy_lints/src/disallowed_macros.rs
+++ b/clippy_lints/src/disallowed_macros.rs
@@ -1,9 +1,8 @@
 use clippy_config::Conf;
-use clippy_config::types::create_disallowed_map;
+use clippy_config::types::{DisallowedPath, create_disallowed_map};
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::macros::macro_backtrace;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::Diag;
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{
     AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
@@ -59,7 +58,7 @@ declare_clippy_lint! {
 }
 
 pub struct DisallowedMacros {
-    disallowed: DefIdMap<(&'static str, Option<&'static str>)>,
+    disallowed: DefIdMap<(&'static str, &'static DisallowedPath)>,
     seen: FxHashSet<ExpnId>,
     // Track the most recently seen node that can have a `derive` attribute.
     // Needed to use the correct lint level.
@@ -90,13 +89,9 @@ impl DisallowedMacros {
                 return;
             }
 
-            if let Some(&(path, reason)) = self.disallowed.get(&mac.def_id) {
+            if let Some(&(path, disallowed_path)) = self.disallowed.get(&mac.def_id) {
                 let msg = format!("use of a disallowed macro `{path}`");
-                let add_note = |diag: &mut Diag<'_, _>| {
-                    if let Some(reason) = reason {
-                        diag.note(reason);
-                    }
-                };
+                let add_note = disallowed_path.diag_amendment(mac.span);
                 if matches!(mac.kind, MacroKind::Derive)
                     && let Some(derive_src) = derive_src
                 {
diff --git a/clippy_lints/src/disallowed_methods.rs b/clippy_lints/src/disallowed_methods.rs
index c4ed118b7c9..149cf1cf2de 100644
--- a/clippy_lints/src/disallowed_methods.rs
+++ b/clippy_lints/src/disallowed_methods.rs
@@ -1,5 +1,5 @@
 use clippy_config::Conf;
-use clippy_config::types::create_disallowed_map;
+use clippy_config::types::{DisallowedPath, create_disallowed_map};
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefIdMap;
@@ -31,6 +31,8 @@ declare_clippy_lint! {
     ///     # When using an inline table, can add a `reason` for why the method
     ///     # is disallowed.
     ///     { path = "std::vec::Vec::leak", reason = "no leaking memory" },
+    ///     # Can also add a `replacement` that will be offered as a suggestion.
+    ///     { path = "std::sync::Mutex::new", reason = "prefer faster & simpler non-poisonable mutex", replacement = "parking_lot::Mutex::new" },
     /// ]
     /// ```
     ///
@@ -56,7 +58,7 @@ declare_clippy_lint! {
 }
 
 pub struct DisallowedMethods {
-    disallowed: DefIdMap<(&'static str, Option<&'static str>)>,
+    disallowed: DefIdMap<(&'static str, &'static DisallowedPath)>,
 }
 
 impl DisallowedMethods {
@@ -83,17 +85,13 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
             },
             _ => return,
         };
-        if let Some(&(path, reason)) = self.disallowed.get(&id) {
+        if let Some(&(path, disallowed_path)) = self.disallowed.get(&id) {
             span_lint_and_then(
                 cx,
                 DISALLOWED_METHODS,
                 span,
                 format!("use of a disallowed method `{path}`"),
-                |diag| {
-                    if let Some(reason) = reason {
-                        diag.note(reason);
-                    }
-                },
+                disallowed_path.diag_amendment(span),
             );
         }
     }
diff --git a/clippy_lints/src/disallowed_types.rs b/clippy_lints/src/disallowed_types.rs
index 947677e14bd..3659946b704 100644
--- a/clippy_lints/src/disallowed_types.rs
+++ b/clippy_lints/src/disallowed_types.rs
@@ -1,4 +1,5 @@
 use clippy_config::Conf;
+use clippy_config::types::DisallowedPath;
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::Res;
@@ -31,6 +32,8 @@ declare_clippy_lint! {
     ///     # When using an inline table, can add a `reason` for why the type
     ///     # is disallowed.
     ///     { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
+    ///     # Can also add a `replacement` that will be offered as a suggestion.
+    ///     { path = "std::sync::Mutex", reason = "prefer faster & simpler non-poisonable mutex", replacement = "parking_lot::Mutex" },
     /// ]
     /// ```
     ///
@@ -51,24 +54,23 @@ declare_clippy_lint! {
 }
 
 pub struct DisallowedTypes {
-    def_ids: DefIdMap<(&'static str, Option<&'static str>)>,
-    prim_tys: FxHashMap<PrimTy, (&'static str, Option<&'static str>)>,
+    def_ids: DefIdMap<(&'static str, &'static DisallowedPath)>,
+    prim_tys: FxHashMap<PrimTy, (&'static str, &'static DisallowedPath)>,
 }
 
 impl DisallowedTypes {
     pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
         let mut def_ids = DefIdMap::default();
         let mut prim_tys = FxHashMap::default();
-        for x in &conf.disallowed_types {
-            let path: Vec<_> = x.path().split("::").collect::<Vec<_>>();
-            let reason = x.reason();
+        for disallowed_path in &conf.disallowed_types {
+            let path: Vec<_> = disallowed_path.path().split("::").collect::<Vec<_>>();
             for res in clippy_utils::def_path_res(tcx, &path) {
                 match res {
                     Res::Def(_, id) => {
-                        def_ids.insert(id, (x.path(), reason));
+                        def_ids.insert(id, (disallowed_path.path(), disallowed_path));
                     },
                     Res::PrimTy(ty) => {
-                        prim_tys.insert(ty, (x.path(), reason));
+                        prim_tys.insert(ty, (disallowed_path.path(), disallowed_path));
                     },
                     _ => {},
                 }
@@ -78,7 +80,7 @@ impl DisallowedTypes {
     }
 
     fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
-        let (path, reason) = match res {
+        let (path, disallowed_path) = match res {
             Res::Def(_, did) if let Some(&x) = self.def_ids.get(did) => x,
             Res::PrimTy(prim) if let Some(&x) = self.prim_tys.get(prim) => x,
             _ => return,
@@ -88,11 +90,7 @@ impl DisallowedTypes {
             DISALLOWED_TYPES,
             span,
             format!("use of a disallowed type `{path}`"),
-            |diag| {
-                if let Some(reason) = reason {
-                    diag.note(reason);
-                }
-            },
+            disallowed_path.diag_amendment(span),
         );
     }
 }
diff --git a/clippy_lints/src/doc/empty_line_after.rs b/clippy_lints/src/doc/empty_line_after.rs
index 099194d4e74..6e85c6af642 100644
--- a/clippy_lints/src/doc/empty_line_after.rs
+++ b/clippy_lints/src/doc/empty_line_after.rs
@@ -233,10 +233,13 @@ fn check_gaps(cx: &LateContext<'_>, gaps: &[Gap<'_>]) -> bool {
             if let Some(owner) = cx.last_node_with_lint_attrs.as_owner() {
                 let def_id = owner.to_def_id();
                 let def_descr = cx.tcx.def_descr(def_id);
-                diag.span_label(cx.tcx.def_span(def_id), match kind {
-                    StopKind::Attr => format!("the attribute applies to this {def_descr}"),
-                    StopKind::Doc(_) => format!("the comment documents this {def_descr}"),
-                });
+                diag.span_label(
+                    cx.tcx.def_span(def_id),
+                    match kind {
+                        StopKind::Attr => format!("the attribute applies to this {def_descr}"),
+                        StopKind::Doc(_) => format!("the comment documents this {def_descr}"),
+                    },
+                );
             }
 
             diag.multipart_suggestion_with_style(
diff --git a/clippy_lints/src/doc/mod.rs b/clippy_lints/src/doc/mod.rs
index 15530c3dbc5..7b07d302d4f 100644
--- a/clippy_lints/src/doc/mod.rs
+++ b/clippy_lints/src/doc/mod.rs
@@ -22,7 +22,6 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{AnonConst, Attribute, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_resolve::rustdoc::{
     DocFragment, add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range,
@@ -86,6 +85,28 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for links with code directly adjacent to code text:
+    /// `` [`MyItem`]`<`[`u32`]`>` ``.
+    ///
+    /// ### Why is this bad?
+    /// It can be written more simply using HTML-style `<code>` tags.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// //! [`first`](x)`second`
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// //! <code>[first](x)second</code>
+    /// ```
+    #[clippy::version = "1.86.0"]
+    pub DOC_LINK_CODE,
+    nursery,
+    "link with code back-to-back with other code"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for the doc comments of publicly visible
     /// unsafe functions and warns if there is no `# Safety` section.
     ///
@@ -455,7 +476,7 @@ declare_clippy_lint! {
     /// ///   and this line is overindented.
     /// # fn foo() {}
     /// ```
-    #[clippy::version = "1.80.0"]
+    #[clippy::version = "1.86.0"]
     pub DOC_OVERINDENTED_LIST_ITEMS,
     style,
     "ensure list items are not overindented"
@@ -638,6 +659,7 @@ impl Documentation {
 }
 
 impl_lint_pass!(Documentation => [
+    DOC_LINK_CODE,
     DOC_LINK_WITH_QUOTES,
     DOC_MARKDOWN,
     DOC_NESTED_REFDEFS,
@@ -675,7 +697,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
                 match item.kind {
                     ItemKind::Fn { sig, body: body_id, .. } => {
                         if !(is_entrypoint_fn(cx, item.owner_id.to_def_id())
-                            || in_external_macro(cx.tcx.sess, item.span))
+                            || item.span.in_external_macro(cx.tcx.sess.source_map()))
                         {
                             let body = cx.tcx.hir().body(body_id);
 
@@ -711,7 +733,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
             },
             Node::TraitItem(trait_item) => {
                 if let TraitItemKind::Fn(sig, ..) = trait_item.kind
-                    && !in_external_macro(cx.tcx.sess, trait_item.span)
+                    && !trait_item.span.in_external_macro(cx.tcx.sess.source_map())
                 {
                     missing_headers::check(
                         cx,
@@ -726,7 +748,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation {
             },
             Node::ImplItem(impl_item) => {
                 if let ImplItemKind::Fn(sig, body_id) = impl_item.kind
-                    && !in_external_macro(cx.tcx.sess, impl_item.span)
+                    && !impl_item.span.in_external_macro(cx.tcx.sess.source_map())
                     && !is_trait_impl_item(cx, impl_item.hir_id())
                 {
                     let body = cx.tcx.hir().body(body_id);
@@ -791,7 +813,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
 
     let (fragments, _) = attrs_to_doc_fragments(
         attrs.iter().filter_map(|attr| {
-            if in_external_macro(cx.sess(), attr.span) {
+            if attr.span.in_external_macro(cx.sess().source_map()) {
                 None
             } else {
                 Some((attr, None))
@@ -821,6 +843,21 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
 
     let mut cb = fake_broken_link_callback;
 
+    check_for_code_clusters(
+        cx,
+        pulldown_cmark::Parser::new_with_broken_link_callback(
+            &doc,
+            main_body_opts() - Options::ENABLE_SMART_PUNCTUATION,
+            Some(&mut cb),
+        )
+        .into_offset_iter(),
+        &doc,
+        Fragments {
+            doc: &doc,
+            fragments: &fragments,
+        },
+    );
+
     // disable smart punctuation to pick up ['link'] more easily
     let opts = main_body_opts() - Options::ENABLE_SMART_PUNCTUATION;
     let parser = pulldown_cmark::Parser::new_with_broken_link_callback(&doc, opts, Some(&mut cb));
@@ -844,6 +881,66 @@ enum Container {
     List(usize),
 }
 
+/// Scan the documentation for code links that are back-to-back with code spans.
+///
+/// This is done separately from the rest of the docs, because that makes it easier to produce
+/// the correct messages.
+fn check_for_code_clusters<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>(
+    cx: &LateContext<'_>,
+    events: Events,
+    doc: &str,
+    fragments: Fragments<'_>,
+) {
+    let mut events = events.peekable();
+    let mut code_starts_at = None;
+    let mut code_ends_at = None;
+    let mut code_includes_link = false;
+    while let Some((event, range)) = events.next() {
+        match event {
+            Start(Link { .. }) if matches!(events.peek(), Some((Code(_), _range))) => {
+                if code_starts_at.is_some() {
+                    code_ends_at = Some(range.end);
+                } else {
+                    code_starts_at = Some(range.start);
+                }
+                code_includes_link = true;
+                // skip the nested "code", because we're already handling it here
+                let _ = events.next();
+            },
+            Code(_) => {
+                if code_starts_at.is_some() {
+                    code_ends_at = Some(range.end);
+                } else {
+                    code_starts_at = Some(range.start);
+                }
+            },
+            End(TagEnd::Link) => {},
+            _ => {
+                if let Some(start) = code_starts_at
+                    && let Some(end) = code_ends_at
+                    && code_includes_link
+                {
+                    if let Some(span) = fragments.span(cx, start..end) {
+                        span_lint_and_then(cx, DOC_LINK_CODE, span, "code link adjacent to code text", |diag| {
+                            let sugg = format!("<code>{}</code>", doc[start..end].replace('`', ""));
+                            diag.span_suggestion_verbose(
+                                span,
+                                "wrap the entire group in `<code>` tags",
+                                sugg,
+                                Applicability::MaybeIncorrect,
+                            );
+                            diag.help("separate code snippets will be shown with a gap");
+                        });
+                    }
+                }
+                code_includes_link = false;
+                code_starts_at = None;
+                code_ends_at = None;
+            },
+        }
+    }
+}
+
 /// Checks parsed documentation.
 /// This walks the "events" (think sections of markdown) produced by `pulldown_cmark`,
 /// so lints here will generally access that information.
diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs
index 5315f55ba38..a38e853172f 100644
--- a/clippy_lints/src/else_if_without_else.rs
+++ b/clippy_lints/src/else_if_without_else.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -50,7 +49,7 @@ impl EarlyLintPass for ElseIfWithoutElse {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
         if let ExprKind::If(_, _, Some(ref els)) = item.kind
             && let ExprKind::If(_, _, None) = els.kind
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
         {
             #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
             span_lint_and_then(
diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs
index f3208497b3c..a7670ffce88 100644
--- a/clippy_lints/src/endian_bytes.rs
+++ b/clippy_lints/src/endian_bytes.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_lint_allowed;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::Symbol;
@@ -120,7 +119,7 @@ impl LateLintPass<'_> for EndianBytes {
             },
             _ => return,
         };
-        if !in_external_macro(cx.sess(), expr.span)
+        if !expr.span.in_external_macro(cx.sess().source_map())
             && let ty = cx.typeck_results().expr_ty(ty_expr)
             && ty.is_primitive_ty()
         {
diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs
index 2bec4f2f99e..99d635aa5cc 100644
--- a/clippy_lints/src/entry.rs
+++ b/clippy_lints/src/entry.rs
@@ -135,8 +135,8 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
                 format!(
                     "match {map_str}.entry({key_str}) {{\n{indent_str}    {entry}::{then_entry} => {}\n\
                         {indent_str}    {entry}::{else_entry} => {}\n{indent_str}}}",
-                    reindent_multiline(then_str.into(), true, Some(4 + indent_str.len())),
-                    reindent_multiline(else_str.into(), true, Some(4 + indent_str.len())),
+                    reindent_multiline(&then_str, true, Some(4 + indent_str.len())),
+                    reindent_multiline(&else_str, true, Some(4 + indent_str.len())),
                     entry = map_ty.entry_path(),
                 )
             }
diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs
index 8a5cf7f56d5..cd9ab2764ac 100644
--- a/clippy_lints/src/equatable_if_let.rs
+++ b/clippy_lints/src/equatable_if_let.rs
@@ -4,7 +4,6 @@ use clippy_utils::ty::implements_trait;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Ty;
 use rustc_session::declare_lint_pass;
 
@@ -56,7 +55,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
         PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
         PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
         PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
-        PatKind::Path(_) | PatKind::Expr(_) => true,
+        PatKind::Expr(_) => true,
     }
 }
 
@@ -72,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::Let(let_expr) = expr.kind
             && unary_pattern(let_expr.pat)
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
         {
             let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
             let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs
index dfea40db182..1d3ae894944 100644
--- a/clippy_lints/src/excessive_nesting.rs
+++ b/clippy_lints/src/excessive_nesting.rs
@@ -5,7 +5,6 @@ use rustc_ast::node_id::NodeSet;
 use rustc_ast::visit::{Visitor, walk_block, walk_item};
 use rustc_ast::{Block, Crate, Inline, Item, ItemKind, ModKind, NodeId};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 
@@ -125,7 +124,9 @@ struct NestingVisitor<'conf, 'cx> {
 
 impl NestingVisitor<'_, '_> {
     fn check_indent(&mut self, span: Span, id: NodeId) -> bool {
-        if self.nest_level > self.conf.excessive_nesting_threshold && !in_external_macro(self.cx.sess(), span) {
+        if self.nest_level > self.conf.excessive_nesting_threshold
+            && !span.in_external_macro(self.cx.sess().source_map())
+        {
             self.conf.nodes.insert(id);
 
             return true;
diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs
index cdbfe7af8f9..5d93aceb33f 100644
--- a/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/clippy_lints/src/extra_unused_type_parameters.rs
@@ -10,7 +10,6 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::{DefId, LocalDefId};
@@ -261,7 +260,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
             && !generics.params.is_empty()
             && !is_empty_body(cx, body_id)
             && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id))
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
             && !is_from_proc_macro(cx, item)
         {
             let mut walker = TypeWalker::new(cx, generics);
@@ -277,7 +276,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
             && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
             && !is_empty_body(cx, body_id)
             && (!self.avoid_breaking_exported_api || !cx.effective_visibilities.is_exported(item.owner_id.def_id))
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
             && !is_from_proc_macro(cx, item)
         {
             let mut walker = TypeWalker::new(cx, item.generics);
diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs
index 34e93bdb9b9..c8fe7ac73cb 100644
--- a/clippy_lints/src/formatting.rs
+++ b/clippy_lints/src/formatting.rs
@@ -3,7 +3,6 @@ use clippy_utils::is_span_if;
 use clippy_utils::source::snippet_opt;
 use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 
@@ -202,7 +201,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
     if let ExprKind::If(_, then, Some(else_)) = &expr.kind
         && (is_block(else_) || is_if(else_))
         && !then.span.from_expansion() && !else_.span.from_expansion()
-        && !in_external_macro(cx.sess(), expr.span)
+        && !expr.span.in_external_macro(cx.sess().source_map())
 
         // workaround for rust-lang/rust#43081
         && expr.span.lo().0 != 0 && expr.span.hi().0 != 0
diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs
index 90d3db2700f..e480805cac2 100644
--- a/clippy_lints/src/functions/must_use.rs
+++ b/clippy_lints/src/functions/must_use.rs
@@ -5,7 +5,6 @@ use rustc_hir::def_id::DefIdSet;
 use rustc_hir::{self as hir, Attribute, QPath};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{Span, sym};
 
@@ -107,7 +106,7 @@ fn check_needless_must_use(
     attrs: &[Attribute],
     sig: &FnSig<'_>,
 ) {
-    if in_external_macro(cx.sess(), item_span) {
+    if item_span.in_external_macro(cx.sess().source_map()) {
         return;
     }
     if returns_unit(decl) {
@@ -185,7 +184,7 @@ fn check_must_use_candidate<'tcx>(
 ) {
     if has_mutable_arg(cx, body)
         || mutates_static(cx, body)
-        || in_external_macro(cx.sess(), item_span)
+        || item_span.in_external_macro(cx.sess().source_map())
         || returns_unit(decl)
         || !cx.effective_visibilities.is_exported(item_id.def_id)
         || is_must_use_ty(cx, return_ty(cx, item_id))
diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs
index 9c396986f62..74d365a7255 100644
--- a/clippy_lints/src/functions/result.rs
+++ b/clippy_lints/src/functions/result.rs
@@ -2,7 +2,6 @@ use clippy_utils::msrvs::{self, Msrv};
 use rustc_errors::Diag;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{Span, sym};
 
@@ -20,7 +19,7 @@ fn result_err_ty<'tcx>(
     id: hir::def_id::LocalDefId,
     item_span: Span,
 ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
-    if !in_external_macro(cx.sess(), item_span)
+    if !item_span.in_external_macro(cx.sess().source_map())
         && let hir::FnRetTy::Return(hir_ty) = decl.output
         && let ty = cx
             .tcx
diff --git a/clippy_lints/src/functions/too_many_lines.rs b/clippy_lints/src/functions/too_many_lines.rs
index 0f5ce340c44..4f90d9655b4 100644
--- a/clippy_lints/src/functions/too_many_lines.rs
+++ b/clippy_lints/src/functions/too_many_lines.rs
@@ -3,7 +3,6 @@ use clippy_utils::source::SpanRangeExt;
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_span::Span;
 
 use super::TOO_MANY_LINES;
@@ -17,7 +16,7 @@ pub(super) fn check_fn(
 ) {
     // Closures must be contained in a parent body, which will be checked for `too_many_lines`.
     // Don't check closures for `too_many_lines` to avoid duplicated lints.
-    if matches!(kind, FnKind::Closure) || in_external_macro(cx.sess(), span) {
+    if matches!(kind, FnKind::Closure) || span.in_external_macro(cx.sess().source_map()) {
         return;
     }
 
diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs
index bb2dc9995df..3ccfa51ab70 100644
--- a/clippy_lints/src/future_not_send.rs
+++ b/clippy_lints/src/future_not_send.rs
@@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
             && let Some(future_trait) = cx.tcx.lang_items().future_trait()
             && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send)
         {
-            let preds = cx.tcx.explicit_item_super_predicates(def_id);
+            let preds = cx.tcx.explicit_item_self_bounds(def_id);
             let is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| {
                 p.as_trait_clause()
                     .is_some_and(|trait_pred| trait_pred.skip_binder().trait_ref.def_id == future_trait)
diff --git a/clippy_lints/src/if_not_else.rs b/clippy_lints/src/if_not_else.rs
index 2806d4d0e5d..45f9aa0a53e 100644
--- a/clippy_lints/src/if_not_else.rs
+++ b/clippy_lints/src/if_not_else.rs
@@ -7,7 +7,6 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
-use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -107,7 +106,7 @@ fn make_sugg<'a>(
     els_span: Span,
     default: &'a str,
     indent_relative_to: Option<Span>,
-) -> Cow<'a, str> {
+) -> String {
     let cond_inner_snip = snippet(sess, cond_inner, default);
     let els_snip = snippet(sess, els_span, default);
     let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
@@ -130,5 +129,5 @@ fn make_sugg<'a>(
         _ => String::new(),
     };
 
-    reindent_multiline(suggestion.into(), true, indent)
+    reindent_multiline(&suggestion, true, indent)
 }
diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs
index 3fc0a696522..28e6344186f 100644
--- a/clippy_lints/src/if_then_some_else_none.rs
+++ b/clippy_lints/src/if_then_some_else_none.rs
@@ -11,7 +11,6 @@ use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -79,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
             && is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
             && !is_else_clause(cx.tcx, expr)
             && !is_in_const_context(cx)
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && self.msrv.meets(msrvs::BOOL_THEN)
             && !contains_return(then_block.stmts)
         {
@@ -95,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
                 expr.span,
                 format!("this could be simplified with `bool::{method_name}`"),
                 |diag| {
-                    let mut app = Applicability::Unspecified;
+                    let mut app = Applicability::MachineApplicable;
                     let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app)
                         .maybe_par()
                         .to_string();
diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs
index ba06567b957..5f95464e4d4 100644
--- a/clippy_lints/src/implicit_return.rs
+++ b/clippy_lints/src/implicit_return.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, FnRetTy, HirId};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{Span, SyntaxContext};
@@ -227,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitReturn {
     ) {
         if (!matches!(kind, FnKind::Closure) && matches!(decl.output, FnRetTy::DefaultReturn(_)))
             || !span.eq_ctxt(body.value.span)
-            || in_external_macro(cx.sess(), span)
+            || span.in_external_macro(cx.sess().source_map())
         {
             return;
         }
diff --git a/clippy_lints/src/invalid_upcast_comparisons.rs b/clippy_lints/src/invalid_upcast_comparisons.rs
index 1929fbded3b..b42664340d1 100644
--- a/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -22,9 +22,6 @@ declare_clippy_lint! {
     /// will mistakenly imply that it is possible for `x` to be outside the range of
     /// `u8`.
     ///
-    /// ### Known problems
-    /// https://github.com/rust-lang/rust-clippy/issues/886
-    ///
     /// ### Example
     /// ```no_run
     /// let x: u8 = 1;
diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs
index 4f066113aea..f5ad79a0027 100644
--- a/clippy_lints/src/items_after_statements.rs
+++ b/clippy_lints/src/items_after_statements.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_hir;
 use rustc_hir::{Block, ItemKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -70,7 +69,7 @@ impl LateLintPass<'_> for ItemsAfterStatements {
                 // Don't use `next` due to the complex filter chain.
                 .for_each(|item| {
                     // Only do the macro check once, but delay it until it's needed.
-                    if !*in_external.get_or_insert_with(|| in_external_macro(cx.sess(), block.span)) {
+                    if !*in_external.get_or_insert_with(|| block.span.in_external_macro(cx.sess().source_map())) {
                         span_lint_hir(
                             cx,
                             ITEMS_AFTER_STATEMENTS,
diff --git a/clippy_lints/src/iter_without_into_iter.rs b/clippy_lints/src/iter_without_into_iter.rs
index 906da81b183..238f66d6675 100644
--- a/clippy_lints/src/iter_without_into_iter.rs
+++ b/clippy_lints/src/iter_without_into_iter.rs
@@ -6,7 +6,6 @@ use rustc_ast::Mutability;
 use rustc_errors::Applicability;
 use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -131,7 +130,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
             && trait_ref
                 .trait_def_id()
                 .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did))
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
             && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind()
             && let expected_method_name = match mtbl {
                 Mutability::Mut => sym::iter_mut,
@@ -193,7 +192,7 @@ impl {self_ty_without_ref} {{
             _ => return,
         };
 
-        if !in_external_macro(cx.sess(), item.span)
+        if !item.span.in_external_macro(cx.sess().source_map())
             && let ImplItemKind::Fn(sig, _) = item.kind
             && let FnRetTy::Return(ret) = sig.decl.output
             && is_nameable_in_impl_trait(ret)
diff --git a/clippy_lints/src/large_const_arrays.rs b/clippy_lints/src/large_const_arrays.rs
index 623b6b4fcc1..cabf10b7e0e 100644
--- a/clippy_lints/src/large_const_arrays.rs
+++ b/clippy_lints/src/large_const_arrays.rs
@@ -56,9 +56,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
             && !item.span.from_expansion()
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let ty::Array(element_type, cst) = ty.kind()
-            && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx
-                .try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_valtree()
-            && let element_count = element_count.to_target_usize(cx.tcx)
+            && let Some(element_count) = cx.tcx
+                .try_normalize_erasing_regions(cx.typing_env(), *cst).unwrap_or(*cst).try_to_target_usize(cx.tcx)
             && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
             && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
         {
diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs
index 923089c7223..d9953dbc261 100644
--- a/clippy_lints/src/large_enum_variant.rs
+++ b/clippy_lints/src/large_enum_variant.rs
@@ -5,7 +5,6 @@ use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_copy};
 use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
@@ -78,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let ty::Adt(adt, subst) = ty.kind()
             && adt.variants().len() > 1
-            && !in_external_macro(cx.tcx.sess, item.span)
+            && !item.span.in_external_macro(cx.tcx.sess.source_map())
         {
             let variants_size = AdtVariantInfo::new(cx, *adt, subst);
 
diff --git a/clippy_lints/src/large_stack_arrays.rs b/clippy_lints/src/large_stack_arrays.rs
index 46d7df6995a..c68499ce9f7 100644
--- a/clippy_lints/src/large_stack_arrays.rs
+++ b/clippy_lints/src/large_stack_arrays.rs
@@ -7,8 +7,8 @@ use clippy_utils::macros::macro_backtrace;
 use clippy_utils::source::snippet;
 use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, ConstKind};
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, sym};
 
@@ -81,8 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
             && let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind
             && !self.is_from_vec_macro(cx, expr.span)
             && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind()
-            && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()
-            && let element_count = element_count.to_target_usize(cx.tcx)
+            && let Some(element_count) = cst.try_to_target_usize(cx.tcx)
             && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
             && !cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| {
                 matches!(
diff --git a/clippy_lints/src/legacy_numeric_constants.rs b/clippy_lints/src/legacy_numeric_constants.rs
index fb46bdcab6e..6f2ce04e8f8 100644
--- a/clippy_lints/src/legacy_numeric_constants.rs
+++ b/clippy_lints/src/legacy_numeric_constants.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::{ExprKind, Item, ItemKind, QPath, UseKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::kw;
 use rustc_span::{Symbol, sym};
@@ -54,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
         // so lint on the `use` statement directly.
         if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind
             && self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
             && let Some(def_id) = path.res[0].opt_def_id()
         {
             let module = if is_integer_module(cx, def_id) {
@@ -139,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
         };
 
         if self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS)
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && !is_from_proc_macro(cx, expr)
         {
             span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| {
diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs
index b522c22a44d..bdbf5b37c5f 100644
--- a/clippy_lints/src/let_underscore.rs
+++ b/clippy_lints/src/let_underscore.rs
@@ -3,7 +3,6 @@ use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type};
 use clippy_utils::{is_from_proc_macro, is_must_use_func_call, paths};
 use rustc_hir::{LetStmt, LocalSource, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{GenericArgKind, IsSuggestable};
 use rustc_session::declare_lint_pass;
 use rustc_span::{BytePos, Span};
@@ -141,7 +140,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
         if matches!(local.source, LocalSource::Normal)
             && let PatKind::Wild = local.pat.kind
             && let Some(init) = local.init
-            && !in_external_macro(cx.tcx.sess, local.span)
+            && !local.span.in_external_macro(cx.tcx.sess.source_map())
         {
             let init_ty = cx.typeck_results().expr_ty(init);
             let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs
index 34ded6c6500..9c8488ff381 100644
--- a/clippy_lints/src/let_with_type_underscore.rs
+++ b/clippy_lints/src/let_with_type_underscore.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::is_from_proc_macro;
 use rustc_hir::{LetStmt, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -30,7 +29,7 @@ impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
         if let Some(ty) = local.ty // Ensure that it has a type defined
             && let TyKind::Infer(()) = &ty.kind // that type is '_'
             && local.span.eq_ctxt(ty.span)
-            && !in_external_macro(cx.tcx.sess, local.span)
+            && !local.span.in_external_macro(cx.tcx.sess.source_map())
             && !is_from_proc_macro(cx, ty)
         {
             span_lint_and_help(
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 8887ab7ec0d..6708be5b332 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -339,6 +339,7 @@ mod significant_drop_tightening;
 mod single_call_fn;
 mod single_char_lifetime_names;
 mod single_component_path_imports;
+mod single_option_map;
 mod single_range_in_vec_init;
 mod size_of_in_element_count;
 mod size_of_ref;
@@ -901,7 +902,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(conf)));
     store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct));
     store.register_late_pass(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf)));
-    store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk));
+    store.register_late_pass(move |_| Box::new(lines_filter_map_ok::LinesFilterMapOk::new(conf)));
     store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule));
     store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
     store.register_early_pass(move || Box::new(excessive_nesting::ExcessiveNesting::new(conf)));
@@ -978,5 +979,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::<unnecessary_semicolon::UnnecessarySemicolon>::default());
     store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf)));
     store.register_late_pass(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf)));
+    store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs
index c9ab0beb5df..860c0584acc 100644
--- a/clippy_lints/src/lifetimes.rs
+++ b/clippy_lints/src/lifetimes.rs
@@ -21,7 +21,6 @@ use rustc_hir::{
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter as middle_nested_filter;
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
@@ -164,7 +163,7 @@ fn check_fn_inner<'tcx>(
     report_extra_lifetimes: bool,
     msrv: &Msrv,
 ) {
-    if in_external_macro(cx.sess(), span) || has_where_lifetimes(cx, generics) {
+    if span.in_external_macro(cx.sess().source_map()) || has_where_lifetimes(cx, generics) {
         return;
     }
 
diff --git a/clippy_lints/src/lines_filter_map_ok.rs b/clippy_lints/src/lines_filter_map_ok.rs
index 8206c75927b..8c237191405 100644
--- a/clippy_lints/src/lines_filter_map_ok.rs
+++ b/clippy_lints/src/lines_filter_map_ok.rs
@@ -1,12 +1,26 @@
+use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id};
 use rustc_errors::Applicability;
 use rustc_hir::{Body, Closure, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 use rustc_span::sym;
 
+pub struct LinesFilterMapOk {
+    msrv: Msrv,
+}
+
+impl LinesFilterMapOk {
+    pub fn new(conf: &Conf) -> Self {
+        Self {
+            msrv: conf.msrv.clone(),
+        }
+    }
+}
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for usage of `lines.filter_map(Result::ok)` or `lines.flat_map(Result::ok)`
@@ -55,11 +69,13 @@ declare_clippy_lint! {
     suspicious,
     "filtering `std::io::Lines` with `filter_map()`, `flat_map()`, or `flatten()` might cause an infinite loop"
 }
-declare_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]);
+
+impl_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]);
 
 impl LateLintPass<'_> for LinesFilterMapOk {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind
+        if self.msrv.meets(msrvs::MAP_WHILE)
+            && let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind
             && is_trait_method(cx, expr, sym::Iterator)
             && let fm_method_str = fm_method.ident.as_str()
             && matches!(fm_method_str, "filter_map" | "flat_map" | "flatten")
@@ -85,6 +101,8 @@ impl LateLintPass<'_> for LinesFilterMapOk {
             );
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> bool {
diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs
index a4cedf3bed3..805de23408b 100644
--- a/clippy_lints/src/literal_representation.rs
+++ b/clippy_lints/src/literal_representation.rs
@@ -6,7 +6,6 @@ use rustc_ast::ast::{Expr, ExprKind, LitKind};
 use rustc_ast::token;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, Lint, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use std::iter;
@@ -207,7 +206,7 @@ impl_lint_pass!(LiteralDigitGrouping => [
 impl EarlyLintPass for LiteralDigitGrouping {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::Lit(lit) = expr.kind
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
         {
             self.check_lit(cx, lit, expr.span);
         }
@@ -421,7 +420,7 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION]
 impl EarlyLintPass for DecimalLiteralRepresentation {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::Lit(lit) = expr.kind
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
         {
             self.check_lit(cx, lit, expr.span);
         }
diff --git a/clippy_lints/src/literal_string_with_formatting_args.rs b/clippy_lints/src/literal_string_with_formatting_args.rs
index a957c0e22a2..975e6833a35 100644
--- a/clippy_lints/src/literal_string_with_formatting_args.rs
+++ b/clippy_lints/src/literal_string_with_formatting_args.rs
@@ -7,6 +7,7 @@ use rustc_session::declare_lint_pass;
 use rustc_span::{BytePos, Span};
 
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::mir::enclosing_mir;
 
 declare_clippy_lint! {
@@ -79,9 +80,9 @@ fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, spans: &[(Span, Option<Strin
     }
 }
 
-impl LateLintPass<'_> for LiteralStringWithFormattingArg {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if expr.span.from_expansion() {
+impl<'tcx> LateLintPass<'tcx> for LiteralStringWithFormattingArg {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        if expr.span.from_expansion() || expr.span.is_dummy() {
             return;
         }
         if let ExprKind::Lit(lit) = expr.kind {
@@ -95,6 +96,9 @@ impl LateLintPass<'_> for LiteralStringWithFormattingArg {
                 },
                 _ => return,
             };
+            if is_from_proc_macro(cx, expr) {
+                return;
+            }
             let fmt_str = symbol.as_str();
             let lo = expr.span.lo();
             let mut current = fmt_str;
@@ -124,7 +128,11 @@ impl LateLintPass<'_> for LiteralStringWithFormattingArg {
                     pos.start += diff_len;
                     pos.end += diff_len;
 
-                    let start = fmt_str[..pos.start].rfind('{').unwrap_or(pos.start);
+                    let mut start = pos.start;
+                    while start < fmt_str.len() && !fmt_str.is_char_boundary(start) {
+                        start += 1;
+                    }
+                    let start = fmt_str[..start].rfind('{').unwrap_or(start);
                     // If this is a unicode character escape, we don't want to lint.
                     if start > 1 && fmt_str[..start].ends_with("\\u") {
                         continue;
diff --git a/clippy_lints/src/loops/infinite_loop.rs b/clippy_lints/src/loops/infinite_loop.rs
index 6be30f3c957..4d206850c99 100644
--- a/clippy_lints/src/loops/infinite_loop.rs
+++ b/clippy_lints/src/loops/infinite_loop.rs
@@ -6,7 +6,6 @@ use rustc_ast::Label;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_span::sym;
 
 use super::INFINITE_LOOP;
@@ -30,7 +29,7 @@ pub(super) fn check<'tcx>(
         return;
     }
 
-    if in_external_macro(cx.sess(), expr.span) || is_from_proc_macro(cx, expr) {
+    if expr.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, expr) {
         return;
     }
 
diff --git a/clippy_lints/src/loops/manual_flatten.rs b/clippy_lints/src/loops/manual_flatten.rs
index 366c310592f..ffeb7e889c2 100644
--- a/clippy_lints/src/loops/manual_flatten.rs
+++ b/clippy_lints/src/loops/manual_flatten.rs
@@ -1,6 +1,7 @@
 use super::MANUAL_FLATTEN;
 use super::utils::make_iterator_snippet;
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::visitors::is_local_used;
 use clippy_utils::{higher, path_to_local_id, peel_blocks_with_stmt};
 use rustc_errors::Applicability;
@@ -18,6 +19,7 @@ pub(super) fn check<'tcx>(
     arg: &'tcx Expr<'_>,
     body: &'tcx Expr<'_>,
     span: Span,
+    msrv: &Msrv,
 ) {
     let inner_expr = peel_blocks_with_stmt(body);
     if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None, .. })
@@ -34,6 +36,7 @@ pub(super) fn check<'tcx>(
         && (some_ctor || ok_ctor)
         // Ensure expr in `if let` is not used afterwards
         && !is_local_used(cx, if_then, pat_hir_id)
+        && msrv.meets(msrvs::ITER_FLATTEN)
     {
         let if_let_type = if some_ctor { "Some" } else { "Ok" };
         // Prepare the error message
diff --git a/clippy_lints/src/loops/manual_slice_fill.rs b/clippy_lints/src/loops/manual_slice_fill.rs
index 7c656423579..bece83eaf3d 100644
--- a/clippy_lints/src/loops/manual_slice_fill.rs
+++ b/clippy_lints/src/loops/manual_slice_fill.rs
@@ -4,6 +4,7 @@ use clippy_utils::macros::span_is_local;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{HasSession, snippet_with_applicability};
 use clippy_utils::ty::implements_trait;
+use clippy_utils::visitors::is_local_used;
 use clippy_utils::{higher, peel_blocks_with_stmt, span_contains_comment};
 use rustc_ast::ast::LitKind;
 use rustc_ast::{RangeLimits, UnOp};
@@ -43,7 +44,7 @@ pub(super) fn check<'tcx>(
         && let ExprKind::Block(..) = body.kind
         // Check if the body is an assignment to a slice element.
         && let ExprKind::Assign(assignee, assignval, _) = peel_blocks_with_stmt(body).kind
-        && let ExprKind::Index(slice, _, _) = assignee.kind
+        && let ExprKind::Index(slice, idx, _) = assignee.kind
         // Check if `len()` is used for the range end.
         && let ExprKind::MethodCall(path, recv,..) = end.kind
         && path.ident.name == sym::len
@@ -58,6 +59,10 @@ pub(super) fn check<'tcx>(
         // The `fill` method requires that the slice's element type implements the `Clone` trait.
         && let Some(clone_trait) = cx.tcx.lang_items().clone_trait()
         && implements_trait(cx, cx.typeck_results().expr_ty(slice), clone_trait, &[])
+        // https://github.com/rust-lang/rust-clippy/issues/14192
+        && let ExprKind::Path(Resolved(_, idx_path)) = idx.kind
+        && let Res::Local(idx_hir) = idx_path.res
+        && !is_local_used(cx, assignval, idx_hir)
     {
         sugg(cx, body, expr, slice.span, assignval.span);
     }
diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs
index cdc8c18c3b7..ffe7566f5fb 100644
--- a/clippy_lints/src/loops/mod.rs
+++ b/clippy_lints/src/loops/mod.rs
@@ -859,7 +859,7 @@ impl Loops {
         mut_range_bound::check(cx, arg, body);
         single_element_loop::check(cx, pat, arg, body, expr);
         same_item_push::check(cx, pat, arg, body, expr, &self.msrv);
-        manual_flatten::check(cx, pat, arg, body, span);
+        manual_flatten::check(cx, pat, arg, body, span, &self.msrv);
         manual_find::check(cx, pat, arg, body, span, expr);
         unused_enumerate_index::check(cx, pat, arg, body);
     }
diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs
index 9f3b0957eab..ba63f980316 100644
--- a/clippy_lints/src/manual_async_fn.rs
+++ b/clippy_lints/src/manual_async_fn.rs
@@ -62,6 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
             && let Some(closure_body) = desugared_async_block(cx, block)
             && let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) =
                 cx.tcx.hir_node_by_def_id(fn_def_id)
+            && !span.from_expansion()
         {
             let header_span = span.with_hi(ret_ty.span.hi());
 
diff --git a/clippy_lints/src/manual_div_ceil.rs b/clippy_lints/src/manual_div_ceil.rs
index 816ca17b3d2..04357cdd8f6 100644
--- a/clippy_lints/src/manual_div_ceil.rs
+++ b/clippy_lints/src/manual_div_ceil.rs
@@ -181,13 +181,16 @@ fn build_suggestion(
             ExprKind::Lit(Spanned {
                 node: LitKind::Int(_, LitIntType::Unsuffixed),
                 ..
-            }) | ExprKind::Unary(UnOp::Neg, Expr {
-                kind: ExprKind::Lit(Spanned {
-                    node: LitKind::Int(_, LitIntType::Unsuffixed),
+            }) | ExprKind::Unary(
+                UnOp::Neg,
+                Expr {
+                    kind: ExprKind::Lit(Spanned {
+                        node: LitKind::Int(_, LitIntType::Unsuffixed),
+                        ..
+                    }),
                     ..
-                }),
-                ..
-            })
+                }
+            )
         ) {
         format!("_{}", cx.typeck_results().expr_ty(rhs))
     } else {
diff --git a/clippy_lints/src/manual_float_methods.rs b/clippy_lints/src/manual_float_methods.rs
index a1951b9da44..052e6502da9 100644
--- a/clippy_lints/src/manual_float_methods.rs
+++ b/clippy_lints/src/manual_float_methods.rs
@@ -9,7 +9,6 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BinOpKind, Constness, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::impl_lint_pass;
 
@@ -142,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
             // 16 possible alignments of constants/operands. For now, let's use `partition`.
             && let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
             && exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && (
                 is_not_const(cx.tcx, cx.tcx.hir().enclosing_body_owner(expr.hir_id).into())
                     || self.msrv.meets(msrvs::CONST_FLOAT_CLASSIFY)
diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs
index 8503dde3fb6..3643b8c4425 100644
--- a/clippy_lints/src/manual_let_else.rs
+++ b/clippy_lints/src/manual_let_else.rs
@@ -7,9 +7,8 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{is_lint_allowed, is_never_expr, msrvs, pat_and_expr_can_be_question_mark, peel_blocks};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 
 use rustc_span::Span;
 use rustc_span::symbol::{Symbol, sym};
@@ -55,7 +54,7 @@ impl<'tcx> QuestionMark {
             && init.span.eq_ctxt(stmt.span)
             && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
             && self.msrv.meets(msrvs::LET_ELSE)
-            && !in_external_macro(cx.sess(), stmt.span)
+            && !stmt.span.in_external_macro(cx.sess().source_map())
         {
             match if_let_or_match {
                 IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => {
@@ -292,7 +291,12 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo
         // Only do the check if the type is "spelled out" in the pattern
         if !matches!(
             pat.kind,
-            PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..)
+            PatKind::Struct(..)
+                | PatKind::TupleStruct(..)
+                | PatKind::Expr(PatExpr {
+                    kind: PatExprKind::Path(..),
+                    ..
+                },)
         ) {
             return;
         }
diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs
index 2e5a92915d9..bf4f2bff319 100644
--- a/clippy_lints/src/manual_range_patterns.rs
+++ b/clippy_lints/src/manual_range_patterns.rs
@@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::{PatExpr, PatExprKind, PatKind, RangeEnd};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::{DUMMY_SP, Span};
 
@@ -80,7 +79,7 @@ impl LateLintPass<'_> for ManualRangePatterns {
         // like described https://github.com/rust-lang/rust-clippy/issues/11825)
         if let PatKind::Or(pats) = pat.kind
             && (pats.len() >= 3 || (pats.len() > 1 && pats.iter().any(|p| matches!(p.kind, PatKind::Range(..)))))
-            && !in_external_macro(cx.sess(), pat.span)
+            && !pat.span.in_external_macro(cx.sess().source_map())
         {
             let mut min = Num::dummy(i128::MAX);
             let mut max = Num::dummy(i128::MIN);
diff --git a/clippy_lints/src/manual_rem_euclid.rs b/clippy_lints/src/manual_rem_euclid.rs
index 8aeec89f0bf..469b4b7cf89 100644
--- a/clippy_lints/src/manual_rem_euclid.rs
+++ b/clippy_lints/src/manual_rem_euclid.rs
@@ -7,7 +7,6 @@ use clippy_utils::{is_in_const_context, path_to_local};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -60,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
             && rem_rhs.span.ctxt() == ctxt
             && add_lhs.span.ctxt() == ctxt
             && add_rhs.span.ctxt() == ctxt
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && self.msrv.meets(msrvs::REM_EUCLID)
             && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !is_in_const_context(cx))
             && let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs)
diff --git a/clippy_lints/src/manual_unwrap_or_default.rs b/clippy_lints/src/manual_unwrap_or_default.rs
index 8ad2ef96cfc..87d2faa225c 100644
--- a/clippy_lints/src/manual_unwrap_or_default.rs
+++ b/clippy_lints/src/manual_unwrap_or_default.rs
@@ -1,6 +1,6 @@
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::GenericArgKind;
 use rustc_session::declare_lint_pass;
@@ -68,7 +68,7 @@ fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<HirId> {
 }
 
 fn get_none<'tcx>(cx: &LateContext<'tcx>, arm: &Arm<'tcx>) -> Option<&'tcx Expr<'tcx>> {
-    if let PatKind::Path(QPath::Resolved(_, path)) = arm.pat.kind
+    if let PatKind::Expr(PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. }) = arm.pat.kind
         && let Some(def_id) = path.res.opt_def_id()
         // Since it comes from a pattern binding, we need to get the parent to actually match
         // against it.
diff --git a/clippy_lints/src/matches/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs
index 99a7b8c74be..97e8423695d 100644
--- a/clippy_lints/src/matches/collapsible_match.rs
+++ b/clippy_lints/src/matches/collapsible_match.rs
@@ -8,7 +8,7 @@ use clippy_utils::{
 };
 use rustc_errors::MultiSpan;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, Expr, HirId, Pat, PatKind};
+use rustc_hir::{Arm, Expr, HirId, Pat, PatExpr, PatExprKind, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::Span;
 
@@ -119,7 +119,11 @@ fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     }
     match arm.pat.kind {
         PatKind::Binding(..) | PatKind::Wild => true,
-        PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
+        PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(qpath),
+            hir_id,
+            ..
+        }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
         _ => false,
     }
 }
diff --git a/clippy_lints/src/matches/manual_ok_err.rs b/clippy_lints/src/matches/manual_ok_err.rs
index b1a555b91d1..3deaaf96c1e 100644
--- a/clippy_lints/src/matches/manual_ok_err.rs
+++ b/clippy_lints/src/matches/manual_ok_err.rs
@@ -6,7 +6,7 @@ use rustc_ast::BindingMode;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind, Path, QPath};
+use rustc_hir::{Arm, Expr, ExprKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty::Ty;
 use rustc_span::symbol::Ident;
@@ -60,7 +60,16 @@ pub(crate) fn check_match(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Exp
 /// accepted.
 fn is_variant_or_wildcard(cx: &LateContext<'_>, pat: &Pat<'_>, can_be_wild: bool, must_match_err: bool) -> bool {
     match pat.kind {
-        PatKind::Wild | PatKind::Path(..) | PatKind::Binding(_, _, _, None) if can_be_wild => true,
+        PatKind::Wild
+        | PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(_),
+            ..
+        })
+        | PatKind::Binding(_, _, _, None)
+            if can_be_wild =>
+        {
+            true
+        },
         PatKind::TupleStruct(qpath, ..) => {
             is_res_lang_ctor(cx, cx.qpath_res(&qpath, pat.hir_id), ResultErr) == must_match_err
         },
diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs
index 59d37520011..2bf7ec8ab7d 100644
--- a/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -7,7 +7,7 @@ use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, ResultErr};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Arm, Expr, Pat, PatKind};
+use rustc_hir::{Arm, Expr, Pat, PatExpr, PatExprKind, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
 use rustc_span::sym;
@@ -89,7 +89,11 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<(&
     if arms.len() == 2
         && arms.iter().all(|arm| arm.guard.is_none())
         && let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind {
-            PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
+            PatKind::Expr(PatExpr {
+                hir_id,
+                kind: PatExprKind::Path(qpath),
+                ..
+            }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
             PatKind::TupleStruct(ref qpath, [pat], _) => {
                 matches!(pat.kind, PatKind::Wild)
                     && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)
@@ -113,7 +117,7 @@ fn lint<'tcx>(
     or_body_snippet: &str,
     indent: usize,
 ) {
-    let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent));
+    let reindented_or_body = reindent_multiline(or_body_snippet, true, Some(indent));
 
     let mut app = Applicability::MachineApplicable;
     let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par();
diff --git a/clippy_lints/src/matches/manual_utils.rs b/clippy_lints/src/matches/manual_utils.rs
index 0b57740064c..09440c396ee 100644
--- a/clippy_lints/src/matches/manual_utils.rs
+++ b/clippy_lints/src/matches/manual_utils.rs
@@ -4,14 +4,14 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
 use clippy_utils::{
-    CaptureKind, 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, can_move_expr_to_closure, expr_requires_coercion, 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,
 };
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::def::Res;
-use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath};
+use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatExpr, PatExprKind, PatKind, Path, QPath};
 use rustc_lint::LateContext;
 use rustc_span::{SyntaxContext, sym};
 
@@ -73,7 +73,7 @@ where
     }
 
     // `map` won't perform any adjustments.
-    if !cx.typeck_results().expr_adjustments(some_expr.expr).is_empty() {
+    if expr_requires_coercion(cx, expr) {
         return None;
     }
 
@@ -124,6 +124,12 @@ where
     };
 
     let closure_expr_snip = some_expr.to_snippet_with_context(cx, expr_ctxt, &mut app);
+    let closure_body = if some_expr.needs_unsafe_block {
+        format!("unsafe {}", closure_expr_snip.blockify())
+    } else {
+        closure_expr_snip.to_string()
+    };
+
     let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
         if !some_expr.needs_unsafe_block
             && let Some(func) = can_pass_as_func(cx, id, some_expr.expr)
@@ -145,20 +151,12 @@ where
                 ""
             };
 
-            if some_expr.needs_unsafe_block {
-                format!("|{annotation}{some_binding}| unsafe {{ {closure_expr_snip} }}")
-            } else {
-                format!("|{annotation}{some_binding}| {closure_expr_snip}")
-            }
+            format!("|{annotation}{some_binding}| {closure_body}")
         }
     } 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}")
-        }
+        format!("|{pat_snip}| {closure_body}")
     } else {
         // Refutable bindings and mixed reference annotations can't be handled by `map`.
         return None;
@@ -256,9 +254,11 @@ pub(super) fn try_parse_pattern<'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::Expr(PatExpr {
+                kind: PatExprKind::Path(qpath),
+                hir_id,
+                ..
+            }) if is_res_lang_ctor(cx, cx.qpath_res(qpath, *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 =>
             {
diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs
index 28e05c273d5..41e4c75f843 100644
--- a/clippy_lints/src/matches/match_same_arms.rs
+++ b/clippy_lints/src/matches/match_same_arms.rs
@@ -7,7 +7,7 @@ use rustc_arena::DroplessArena;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExprKind, PatKind, RangeEnd};
+use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExpr, PatExprKind, PatKind, RangeEnd};
 use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty;
@@ -292,7 +292,11 @@ impl<'a> NormalizedPat<'a> {
                 Self::Tuple(var_id, pats)
             },
             PatKind::Or(pats) => Self::Or(arena.alloc_from_iter(pats.iter().map(|pat| Self::from_pat(cx, arena, pat)))),
-            PatKind::Path(ref path) => Self::Path(cx.qpath_res(path, pat.hir_id).opt_def_id()),
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(path),
+                hir_id,
+                ..
+            }) => Self::Path(cx.qpath_res(path, *hir_id).opt_def_id()),
             PatKind::Tuple(pats, wild_idx) => {
                 let field_count = match cx.typeck_results().pat_ty(pat).kind() {
                     ty::Tuple(subs) => subs.len(),
diff --git a/clippy_lints/src/matches/match_wild_enum.rs b/clippy_lints/src/matches/match_wild_enum.rs
index 59565560089..11b588b3355 100644
--- a/clippy_lints/src/matches/match_wild_enum.rs
+++ b/clippy_lints/src/matches/match_wild_enum.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns};
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::{Arm, Expr, PatKind, PathSegment, QPath, Ty, TyKind};
+use rustc_hir::{Arm, Expr, PatExpr, PatExprKind, PatKind, PathSegment, QPath, Ty, TyKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, VariantDef};
 use rustc_span::sym;
@@ -60,8 +60,13 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
         // covered by the set of guards that cover it, but that's really hard to do.
         recurse_or_patterns(arm.pat, |pat| {
             let path = match &peel_hir_pat_refs(pat).0.kind {
-                PatKind::Path(path) => {
-                    let id = match cx.qpath_res(path, pat.hir_id) {
+                PatKind::Expr(PatExpr {
+                    hir_id,
+                    kind: PatExprKind::Path(path),
+                    ..
+                }) => {
+                    // FIXME(clippy): don't you want to use the hir id of the peeled pat?
+                    let id = match cx.qpath_res(path, *hir_id) {
                         Res::Def(
                             DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
                             _,
diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs
index a7fdd483c16..9ca914af281 100644
--- a/clippy_lints/src/matches/mod.rs
+++ b/clippy_lints/src/matches/mod.rs
@@ -33,7 +33,6 @@ use clippy_utils::{
 };
 use rustc_hir::{Arm, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{SpanData, SyntaxContext};
 
@@ -1054,7 +1053,7 @@ impl_lint_pass!(Matches => [
 impl<'tcx> LateLintPass<'tcx> for Matches {
     #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if is_direct_expn_of(expr.span, "matches").is_none() && in_external_macro(cx.sess(), expr.span) {
+        if is_direct_expn_of(expr.span, "matches").is_none() && expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         let from_expansion = expr.span.from_expansion();
diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs
index 0d5575efc22..7e65d586110 100644
--- a/clippy_lints/src/matches/needless_match.rs
+++ b/clippy_lints/src/matches/needless_match.rs
@@ -8,7 +8,9 @@ use clippy_utils::{
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExprKind, PatKind, Path, QPath};
+use rustc_hir::{
+    Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExpr, PatExprKind, PatKind, Path, QPath,
+};
 use rustc_lint::LateContext;
 use rustc_span::sym;
 
@@ -183,7 +185,13 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
             return !matches!(annot, BindingMode(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name;
         },
         // Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
-        (PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {
+        (
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(QPath::Resolved(_, p_path)),
+                ..
+            }),
+            ExprKind::Path(QPath::Resolved(_, e_path)),
+        ) => {
             return over(p_path.segments, e_path.segments, |p_seg, e_seg| {
                 p_seg.ident.name == e_seg.ident.name
             });
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index edac97344a0..39339966013 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExprKind, PatKind, QPath, UnOp};
+use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExpr, PatExprKind, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_span::{Span, Symbol, sym};
@@ -149,8 +149,12 @@ fn find_method_and_type<'tcx>(
                 None
             }
         },
-        PatKind::Path(ref path) => {
-            if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, check_pat.hir_id)
+        PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(path),
+            hir_id,
+            ..
+        }) => {
+            if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, *hir_id)
                 && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
             {
                 let method = if cx.tcx.lang_items().option_none_variant() == Some(variant_id) {
@@ -351,10 +355,20 @@ fn found_good_method<'tcx>(
                 None
             }
         },
-        (PatKind::TupleStruct(path_left, patterns, _), PatKind::Path(path_right))
-        | (PatKind::Path(path_left), PatKind::TupleStruct(path_right, patterns, _))
-            if patterns.len() == 1 =>
-        {
+        (
+            PatKind::TupleStruct(path_left, patterns, _),
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(path_right),
+                ..
+            }),
+        )
+        | (
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(path_left),
+                ..
+            }),
+            PatKind::TupleStruct(path_right, patterns, _),
+        ) if patterns.len() == 1 => {
             if let PatKind::Wild = patterns[0].kind {
                 find_good_method_for_match(
                     cx,
@@ -389,7 +403,13 @@ fn found_good_method<'tcx>(
                 None
             }
         },
-        (PatKind::Path(path_left), PatKind::Wild) => get_good_method(cx, arms, path_left),
+        (
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(path_left),
+                ..
+            }),
+            PatKind::Wild,
+        ) => get_good_method(cx, arms, path_left),
         _ => None,
     }
 }
diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 35f2e780d2e..37bac561a6e 100644
--- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -199,7 +199,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
             return false;
         }
 
-        let result = match ty.kind() {
+        match ty.kind() {
             rustc_middle::ty::Adt(adt, args) => {
                 // if some field has significant drop,
                 adt.all_fields()
@@ -223,9 +223,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
             rustc_middle::ty::Tuple(tys) => tys.iter().any(|ty| self.has_sig_drop_attr_impl(ty)),
             rustc_middle::ty::Array(ty, _) | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr_impl(*ty),
             _ => false,
-        };
-
-        result
+        }
     }
 }
 
diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs
index 38f876fed80..2f46eaaabb3 100644
--- a/clippy_lints/src/matches/single_match.rs
+++ b/clippy_lints/src/matches/single_match.rs
@@ -114,7 +114,7 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
     }
 
     let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
-    let (msg, sugg) = if let PatKind::Path(_) | PatKind::Expr(_) = pat.kind
+    let (msg, sugg) = if let PatKind::Expr(_) = pat.kind
         && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
         && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
         && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
@@ -331,14 +331,16 @@ impl<'a> PatState<'a> {
     #[expect(clippy::similar_names)]
     fn add_pat<'tcx>(&mut self, cx: &'a PatCtxt<'tcx>, pat: &'tcx Pat<'_>) -> bool {
         match pat.kind {
-            PatKind::Path(_)
-                if match *cx.typeck.pat_ty(pat).peel_refs().kind() {
-                    ty::Adt(adt, _) => adt.is_enum() || (adt.is_struct() && !adt.non_enum_variant().fields.is_empty()),
-                    ty::Tuple(tys) => !tys.is_empty(),
-                    ty::Array(_, len) => len.try_to_target_usize(cx.tcx) != Some(1),
-                    ty::Slice(..) => true,
-                    _ => false,
-                } =>
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(_),
+                ..
+            }) if match *cx.typeck.pat_ty(pat).peel_refs().kind() {
+                ty::Adt(adt, _) => adt.is_enum() || (adt.is_struct() && !adt.non_enum_variant().fields.is_empty()),
+                ty::Tuple(tys) => !tys.is_empty(),
+                ty::Array(_, len) => len.try_to_target_usize(cx.tcx) != Some(1),
+                ty::Slice(..) => true,
+                _ => false,
+            } =>
             {
                 matches!(self, Self::Wild)
             },
@@ -386,7 +388,6 @@ impl<'a> PatState<'a> {
             | PatKind::Binding(_, _, _, None)
             | PatKind::Expr(_)
             | PatKind::Range(..)
-            | PatKind::Path(_)
             | PatKind::Never
             | PatKind::Err(_) => {
                 *self = PatState::Wild;
diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs
index 5597cd85abc..2fe5f6a3a37 100644
--- a/clippy_lints/src/mem_replace.rs
+++ b/clippy_lints/src/mem_replace.rs
@@ -8,10 +8,9 @@ use clippy_utils::{
     is_default_equivalent, is_expr_used_or_unified, is_res_lang_ctor, path_res, peel_ref_operators, std_or_core,
 };
 use rustc_errors::Applicability;
-use rustc_hir::LangItem::OptionNone;
+use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_span::symbol::sym;
@@ -46,6 +45,31 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for `mem::replace()` on an `Option` with `Some(…)`.
+    ///
+    /// ### Why is this bad?
+    /// `Option` already has the method `replace()` for
+    /// taking its current value (Some(…) or None) and replacing it with
+    /// `Some(…)`.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let mut an_option = Some(0);
+    /// let replaced = std::mem::replace(&mut an_option, Some(1));
+    /// ```
+    /// Is better expressed with:
+    /// ```no_run
+    /// let mut an_option = Some(0);
+    /// let taken = an_option.replace(1);
+    /// ```
+    #[clippy::version = "1.86.0"]
+    pub MEM_REPLACE_OPTION_WITH_SOME,
+    style,
+    "replacing an `Option` with `Some` instead of `replace()`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for `mem::replace(&mut _, mem::uninitialized())`
     /// and `mem::replace(&mut _, mem::zeroed())`.
     ///
@@ -102,28 +126,67 @@ declare_clippy_lint! {
 }
 
 impl_lint_pass!(MemReplace =>
-    [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]);
+    [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_OPTION_WITH_SOME, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]);
+
+fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) -> bool {
+    if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) {
+        // Since this is a late pass (already type-checked),
+        // and we already know that the second argument is an
+        // `Option`, we do not need to check the first
+        // argument's type. All that's left is to get
+        // the replacee's expr after peeling off the `&mut`
+        let sugg_expr = peel_ref_operators(cx, dest);
+        let mut applicability = Applicability::MachineApplicable;
+        span_lint_and_sugg(
+            cx,
+            MEM_REPLACE_OPTION_WITH_NONE,
+            expr_span,
+            "replacing an `Option` with `None`",
+            "consider `Option::take()` instead",
+            format!(
+                "{}.take()",
+                Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "", &mut applicability).maybe_par()
+            ),
+            applicability,
+        );
+        true
+    } else {
+        false
+    }
+}
 
-fn check_replace_option_with_none(cx: &LateContext<'_>, dest: &Expr<'_>, expr_span: Span) {
-    // Since this is a late pass (already type-checked),
-    // and we already know that the second argument is an
-    // `Option`, we do not need to check the first
-    // argument's type. All that's left is to get
-    // the replacee's expr after peeling off the `&mut`
-    let sugg_expr = peel_ref_operators(cx, dest);
-    let mut applicability = Applicability::MachineApplicable;
-    span_lint_and_sugg(
-        cx,
-        MEM_REPLACE_OPTION_WITH_NONE,
-        expr_span,
-        "replacing an `Option` with `None`",
-        "consider `Option::take()` instead",
-        format!(
-            "{}.take()",
-            Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "", &mut applicability).maybe_par()
-        ),
-        applicability,
-    );
+fn check_replace_option_with_some(
+    cx: &LateContext<'_>,
+    src: &Expr<'_>,
+    dest: &Expr<'_>,
+    expr_span: Span,
+    msrv: &Msrv,
+) -> bool {
+    if msrv.meets(msrvs::OPTION_REPLACE)
+        && let ExprKind::Call(src_func, [src_arg]) = src.kind
+        && is_res_lang_ctor(cx, path_res(cx, src_func), OptionSome)
+    {
+        // We do not have to check for a `const` context here, because `core::mem::replace()` and
+        // `Option::replace()` have been const-stabilized simultaneously in version 1.83.0.
+        let sugg_expr = peel_ref_operators(cx, dest);
+        let mut applicability = Applicability::MachineApplicable;
+        span_lint_and_sugg(
+            cx,
+            MEM_REPLACE_OPTION_WITH_SOME,
+            expr_span,
+            "replacing an `Option` with `Some(..)`",
+            "consider `Option::replace()` instead",
+            format!(
+                "{}.replace({})",
+                Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "_", &mut applicability).maybe_par(),
+                snippet_with_applicability(cx, src_arg.span, "_", &mut applicability)
+            ),
+            applicability,
+        );
+        true
+    } else {
+        false
+    }
 }
 
 fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
@@ -182,27 +245,34 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'
     }
 }
 
-fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) {
-    // disable lint for primitives
-    let expr_type = cx.typeck_results().expr_ty_adjusted(src);
-    if is_non_aggregate_primitive_type(expr_type) {
-        return;
-    }
-    if is_default_equivalent(cx, src) && !in_external_macro(cx.tcx.sess, expr_span) {
-        let Some(top_crate) = std_or_core(cx) else { return };
+fn check_replace_with_default(
+    cx: &LateContext<'_>,
+    src: &Expr<'_>,
+    dest: &Expr<'_>,
+    expr: &Expr<'_>,
+    msrv: &Msrv,
+) -> bool {
+    if msrv.meets(msrvs::MEM_TAKE) && is_expr_used_or_unified(cx.tcx, expr)
+        // disable lint for primitives
+        && let expr_type = cx.typeck_results().expr_ty_adjusted(src)
+        && !is_non_aggregate_primitive_type(expr_type)
+        && is_default_equivalent(cx, src)
+        && !expr.span.in_external_macro(cx.tcx.sess.source_map())
+        && let Some(top_crate) = std_or_core(cx)
+    {
         span_lint_and_then(
             cx,
             MEM_REPLACE_WITH_DEFAULT,
-            expr_span,
+            expr.span,
             format!(
                 "replacing a value of type `T` with `T::default()` is better expressed using `{top_crate}::mem::take`"
             ),
             |diag| {
-                if !expr_span.from_expansion() {
+                if !expr.span.from_expansion() {
                     let suggestion = format!("{top_crate}::mem::take({})", snippet(cx, dest.span, ""));
 
                     diag.span_suggestion(
-                        expr_span,
+                        expr.span,
                         "consider using",
                         suggestion,
                         Applicability::MachineApplicable,
@@ -210,6 +280,9 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<
                 }
             },
         );
+        true
+    } else {
+        false
     }
 }
 
@@ -234,12 +307,12 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
             && cx.tcx.is_diagnostic_item(sym::mem_replace, def_id)
         {
             // Check that second argument is `Option::None`
-            if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) {
-                check_replace_option_with_none(cx, dest, expr.span);
-            } else if self.msrv.meets(msrvs::MEM_TAKE) && is_expr_used_or_unified(cx.tcx, expr) {
-                check_replace_with_default(cx, src, dest, expr.span);
+            if !check_replace_option_with_none(cx, src, dest, expr.span)
+                && !check_replace_option_with_some(cx, src, dest, expr.span, &self.msrv)
+                && !check_replace_with_default(cx, src, dest, expr, &self.msrv)
+            {
+                check_replace_with_uninit(cx, src, dest, expr.span);
             }
-            check_replace_with_uninit(cx, src, dest, expr.span);
         }
     }
     extract_msrv_attr!(LateContext);
diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
index 76bdbe55e2f..18568e3661f 100644
--- a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
+++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -57,14 +57,13 @@ pub(super) fn check<'tcx>(
                     };
 
                     let suggestion_source = reindent_multiline(
-                        format!(
+                        &format!(
                             "std::path::Path::new({})
                                 .extension()
                                 .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))",
                             recv_source,
                             ext_str.strip_prefix('.').unwrap()
-                        )
-                        .into(),
+                        ),
                         true,
                         Some(indent_of(cx, call_span).unwrap_or(0) + 4),
                     );
diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs
index c1653b65e98..15a14c61d2b 100644
--- a/clippy_lints/src/methods/filter_map.rs
+++ b/clippy_lints/src/methods/filter_map.rs
@@ -12,7 +12,6 @@ use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_span::Span;
 use rustc_span::symbol::{Ident, Symbol, sym};
-use std::borrow::Cow;
 
 use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP};
 
@@ -302,7 +301,7 @@ pub(super) fn check(
             filter_span.with_hi(expr.span.hi()),
             "`filter` for `Some` followed by `unwrap`",
             "consider using `flatten` instead",
-            reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, map_span)).into_owned(),
+            reindent_multiline("flatten()", true, indent_of(cx, map_span)),
             Applicability::MachineApplicable,
         );
 
@@ -316,7 +315,7 @@ pub(super) fn check(
             filter_span.with_hi(expr.span.hi()),
             "`filter` for `Ok` followed by `unwrap`",
             "consider using `flatten` instead",
-            reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, map_span)).into_owned(),
+            reindent_multiline("flatten()", true, indent_of(cx, map_span)),
             Applicability::MachineApplicable,
         );
 
diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs
index 129e6925428..d550c145466 100644
--- a/clippy_lints/src/methods/filter_map_bool_then.rs
+++ b/clippy_lints/src/methods/filter_map_bool_then.rs
@@ -6,13 +6,12 @@ use clippy_utils::{is_from_proc_macro, is_trait_method, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Binder;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_span::{Span, sym};
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &Expr<'_>, call_span: Span) {
-    if !in_external_macro(cx.sess(), expr.span)
+    if !expr.span.in_external_macro(cx.sess().source_map())
         && is_trait_method(cx, expr, sym::Iterator)
         && let ExprKind::Closure(closure) = arg.kind
         && let body = cx.tcx.hir().body(closure.body)
diff --git a/clippy_lints/src/methods/is_empty.rs b/clippy_lints/src/methods/is_empty.rs
index a0c21faaa4c..92c81b3c49d 100644
--- a/clippy_lints/src/methods/is_empty.rs
+++ b/clippy_lints/src/methods/is_empty.rs
@@ -4,7 +4,6 @@ use clippy_utils::macros::{is_assert_macro, root_macro_call};
 use clippy_utils::{find_binding_init, get_parent_expr, is_inside_always_const_context, path_to_local};
 use rustc_hir::{Expr, HirId};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_span::sym;
 
 use super::CONST_IS_EMPTY;
@@ -12,7 +11,7 @@ use super::CONST_IS_EMPTY;
 /// Expression whose initialization depend on a constant conditioned by a `#[cfg(…)]` directive will
 /// not trigger the lint.
 pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_>) {
-    if in_external_macro(cx.sess(), expr.span) || !receiver.span.eq_ctxt(expr.span) {
+    if expr.span.in_external_macro(cx.sess().source_map()) || !receiver.span.eq_ctxt(expr.span) {
         return;
     }
     if let Some(parent) = get_parent_expr(cx, expr) {
diff --git a/clippy_lints/src/methods/iter_filter.rs b/clippy_lints/src/methods/iter_filter.rs
index 30387ba62a7..a6308dd9be0 100644
--- a/clippy_lints/src/methods/iter_filter.rs
+++ b/clippy_lints/src/methods/iter_filter.rs
@@ -12,7 +12,6 @@ use rustc_hir as hir;
 use rustc_hir::QPath;
 use rustc_span::Span;
 use rustc_span::symbol::{Ident, Symbol, sym};
-use std::borrow::Cow;
 
 ///
 /// Returns true if the expression is a method call to `method_name`
@@ -181,7 +180,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir
             filter_span.with_hi(expr.span.hi()),
             "`filter` for `is_ok` on iterator over `Result`s",
             "consider using `flatten` instead",
-            reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(),
+            reindent_multiline("flatten()", true, indent_of(cx, filter_span)),
             Applicability::HasPlaceholders,
         ),
         Some(FilterType::IsSome) => span_lint_and_sugg(
@@ -190,7 +189,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir
             filter_span.with_hi(expr.span.hi()),
             "`filter` for `is_some` on iterator over `Option`",
             "consider using `flatten` instead",
-            reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(),
+            reindent_multiline("flatten()", true, indent_of(cx, filter_span)),
             Applicability::HasPlaceholders,
         ),
     }
diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs
index 4321dd6b0e0..8da9c6b3809 100644
--- a/clippy_lints/src/methods/manual_ok_or.rs
+++ b/clippy_lints/src/methods/manual_ok_or.rs
@@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(
         && let Some(err_arg_snippet) = err_arg.span.get_source_text(cx)
         && let Some(indent) = indent_of(cx, expr.span)
     {
-        let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.as_str().into(), true, Some(indent + 4));
+        let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.as_str(), true, Some(indent + 4));
         span_lint_and_sugg(
             cx,
             MANUAL_OK_OR,
diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs
index 4a48d4b547c..a56378b5b73 100644
--- a/clippy_lints/src/methods/manual_try_fold.rs
+++ b/clippy_lints/src/methods/manual_try_fold.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_span::{Span, sym};
 
 use super::MANUAL_TRY_FOLD;
@@ -20,7 +19,7 @@ pub(super) fn check<'tcx>(
     fold_span: Span,
     msrv: &Msrv,
 ) {
-    if !in_external_macro(cx.sess(), fold_span)
+    if !fold_span.in_external_macro(cx.sess().source_map())
         && msrv.meets(msrvs::ITERATOR_TRY_FOLD)
         && is_trait_method(cx, expr, sym::Iterator)
         && let init_ty = cx.typeck_results().expr_ty(init)
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index dd2ab7c10a5..7e9db66ff86 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -82,7 +82,6 @@ mod ok_expect;
 mod open_options;
 mod option_as_ref_cloned;
 mod option_as_ref_deref;
-mod option_map_or_err_ok;
 mod option_map_or_none;
 mod option_map_unwrap_or;
 mod or_fun_call;
@@ -114,6 +113,7 @@ mod suspicious_map;
 mod suspicious_splitn;
 mod suspicious_to_owned;
 mod type_id_on_box;
+mod unbuffered_bytes;
 mod uninit_assumed_init;
 mod unit_hash;
 mod unnecessary_fallible_conversions;
@@ -153,7 +153,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, TraitRef, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, sym};
@@ -2642,7 +2641,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.49.0"]
     pub MANUAL_OK_OR,
-    pedantic,
+    style,
     "finds patterns that can be encoded more concisely with `Option::ok_or`"
 }
 
@@ -3786,31 +3785,6 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of `_.map_or(Err(_), Ok)`.
-    ///
-    /// ### Why is this bad?
-    /// Readability, this can be written more concisely as
-    /// `_.ok_or(_)`.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// # let opt = Some(1);
-    /// opt.map_or(Err("error"), Ok);
-    /// ```
-    ///
-    /// Use instead:
-    /// ```no_run
-    /// # let opt = Some(1);
-    /// opt.ok_or("error");
-    /// ```
-    #[clippy::version = "1.76.0"]
-    pub OPTION_MAP_OR_ERR_OK,
-    style,
-    "using `Option.map_or(Err(_), Ok)`, which is more succinctly expressed as `Option.ok_or(_)`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
     /// Checks for iterators of `Result`s using `.filter(Result::is_ok).map(Result::unwrap)` that may
     /// be replaced with a `.flatten()` call.
     ///
@@ -4433,11 +4407,41 @@ declare_clippy_lint! {
     "using `Option::and_then` or `Result::and_then` to chain a computation that returns an `Option` or a `Result`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `Read::bytes` on types which don't implement `BufRead`.
+    ///
+    /// ### Why is this bad?
+    /// The default implementation calls `read` for each byte, which can be very inefficient for data that’s not in memory, such as `File`.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// use std::io::Read;
+    /// use std::fs::File;
+    /// let file = File::open("./bytes.txt").unwrap();
+    /// file.bytes();
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// use std::io::{BufReader, Read};
+    /// use std::fs::File;
+    /// let file = BufReader::new(std::fs::File::open("./bytes.txt").unwrap());
+    /// file.bytes();
+    /// ```
+    #[clippy::version = "1.86.0"]
+    pub UNBUFFERED_BYTES,
+    perf,
+    "calling .bytes() is very inefficient when data is not in memory"
+}
+
+#[expect(clippy::struct_excessive_bools)]
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
     allow_expect_in_tests: bool,
     allow_unwrap_in_tests: bool,
+    allow_expect_in_consts: bool,
+    allow_unwrap_in_consts: bool,
     allowed_dotfiles: FxHashSet<&'static str>,
     format_args: FormatArgsStorage,
 }
@@ -4452,6 +4456,8 @@ impl Methods {
             msrv: conf.msrv.clone(),
             allow_expect_in_tests: conf.allow_expect_in_tests,
             allow_unwrap_in_tests: conf.allow_unwrap_in_tests,
+            allow_expect_in_consts: conf.allow_expect_in_consts,
+            allow_unwrap_in_consts: conf.allow_unwrap_in_consts,
             allowed_dotfiles,
             format_args,
         }
@@ -4580,7 +4586,6 @@ impl_lint_pass!(Methods => [
     WAKER_CLONE_WAKE,
     UNNECESSARY_FALLIBLE_CONVERSIONS,
     JOIN_ABSOLUTE_PATHS,
-    OPTION_MAP_OR_ERR_OK,
     RESULT_FILTER_MAP,
     ITER_FILTER_IS_SOME,
     ITER_FILTER_IS_OK,
@@ -4603,6 +4608,7 @@ impl_lint_pass!(Methods => [
     MANUAL_REPEAT_N,
     SLICED_STRING_AS_BYTES,
     RETURN_AND_THEN,
+    UNBUFFERED_BYTES,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4667,7 +4673,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 
     #[allow(clippy::too_many_lines)]
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
-        if in_external_macro(cx.sess(), impl_item.span) {
+        if impl_item.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         let name = impl_item.ident.name.as_str();
@@ -4755,7 +4761,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
-        if in_external_macro(cx.tcx.sess, item.span) {
+        if item.span.in_external_macro(cx.tcx.sess.source_map()) {
             return;
         }
 
@@ -4879,6 +4885,7 @@ impl Methods {
                 ("as_ptr", []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, &self.msrv),
                 ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
                 ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
+                ("bytes", []) => unbuffered_bytes::check(cx, expr, recv),
                 ("cloned", []) => {
                     cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv);
                     option_as_ref_cloned::check(cx, recv, span);
@@ -4946,6 +4953,7 @@ impl Methods {
                             expr,
                             recv,
                             false,
+                            self.allow_expect_in_consts,
                             self.allow_expect_in_tests,
                             unwrap_expect_used::Variant::Expect,
                         ),
@@ -4959,6 +4967,7 @@ impl Methods {
                         expr,
                         recv,
                         true,
+                        self.allow_expect_in_consts,
                         self.allow_expect_in_tests,
                         unwrap_expect_used::Variant::Expect,
                     );
@@ -5147,7 +5156,6 @@ impl Methods {
                 ("map_or", [def, map]) => {
                     option_map_or_none::check(cx, expr, recv, def, map);
                     manual_ok_or::check(cx, expr, recv, def, map);
-                    option_map_or_err_ok::check(cx, expr, recv, def, map);
                     unnecessary_map_or::check(cx, expr, recv, def, map, span, &self.msrv);
                 },
                 ("map_or_else", [def, map]) => {
@@ -5333,6 +5341,7 @@ impl Methods {
                         expr,
                         recv,
                         false,
+                        self.allow_unwrap_in_consts,
                         self.allow_unwrap_in_tests,
                         unwrap_expect_used::Variant::Unwrap,
                     );
@@ -5344,6 +5353,7 @@ impl Methods {
                         expr,
                         recv,
                         true,
+                        self.allow_unwrap_in_consts,
                         self.allow_unwrap_in_tests,
                         unwrap_expect_used::Variant::Unwrap,
                     );
@@ -5487,9 +5497,12 @@ impl ShouldImplTraitCase {
     fn lifetime_param_cond(&self, impl_item: &hir::ImplItem<'_>) -> bool {
         self.lint_explicit_lifetime
             || !impl_item.generics.params.iter().any(|p| {
-                matches!(p.kind, hir::GenericParamKind::Lifetime {
-                    kind: hir::LifetimeParamKind::Explicit
-                })
+                matches!(
+                    p.kind,
+                    hir::GenericParamKind::Lifetime {
+                        kind: hir::LifetimeParamKind::Explicit
+                    }
+                )
             })
     }
 }
diff --git a/clippy_lints/src/methods/obfuscated_if_else.rs b/clippy_lints/src/methods/obfuscated_if_else.rs
index b71f79f8482..2272e03ef26 100644
--- a/clippy_lints/src/methods/obfuscated_if_else.rs
+++ b/clippy_lints/src/methods/obfuscated_if_else.rs
@@ -1,6 +1,7 @@
 use super::OBFUSCATED_IF_ELSE;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
+use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use rustc_errors::Applicability;
@@ -41,6 +42,17 @@ pub(super) fn check<'tcx>(
             snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability)
         );
 
+        // To be parsed as an expression, the `if { … } else { … }` as the left operand of a binary operator
+        // requires parentheses.
+        let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr)
+            && let ExprKind::Binary(_, left, _) = parent_expr.kind
+            && left.hir_id == expr.hir_id
+        {
+            format!("({sugg})")
+        } else {
+            sugg
+        };
+
         span_lint_and_sugg(
             cx,
             OBFUSCATED_IF_ELSE,
diff --git a/clippy_lints/src/methods/option_map_or_err_ok.rs b/clippy_lints/src/methods/option_map_or_err_ok.rs
deleted file mode 100644
index 4e424d4c066..00000000000
--- a/clippy_lints/src/methods/option_map_or_err_ok.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_res_lang_ctor, path_res};
-use rustc_errors::Applicability;
-use rustc_hir::LangItem::{ResultErr, ResultOk};
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::LateContext;
-use rustc_span::symbol::sym;
-
-use super::OPTION_MAP_OR_ERR_OK;
-
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'tcx>,
-    recv: &'tcx Expr<'_>,
-    or_expr: &'tcx Expr<'_>,
-    map_expr: &'tcx Expr<'_>,
-) {
-    // We check that it's called on an `Option` type.
-    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option)
-        // We check that first we pass an `Err`.
-        && let ExprKind::Call(call, &[arg]) = or_expr.kind
-        && is_res_lang_ctor(cx, path_res(cx, call), ResultErr)
-        // And finally we check that it is mapped as `Ok`.
-        && is_res_lang_ctor(cx, path_res(cx, map_expr), ResultOk)
-    {
-        let msg = "called `map_or(Err(_), Ok)` on an `Option` value";
-        let self_snippet = snippet(cx, recv.span, "..");
-        let err_snippet = snippet(cx, arg.span, "..");
-        span_lint_and_sugg(
-            cx,
-            OPTION_MAP_OR_ERR_OK,
-            expr.span,
-            msg,
-            "consider using `ok_or`",
-            format!("{self_snippet}.ok_or({err_snippet})"),
-            Applicability::MachineApplicable,
-        );
-    }
-}
diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs
index 6b39b753885..f00e4b87a7d 100644
--- a/clippy_lints/src/methods/or_fun_call.rs
+++ b/clippy_lints/src/methods/or_fun_call.rs
@@ -104,7 +104,7 @@ pub(super) fn check<'tcx>(
         if (is_new(fun) && output_type_implements_default(fun))
             || match call_expr {
                 Some(call_expr) => is_default_equivalent(cx, call_expr),
-                None => is_default_equivalent_call(cx, fun) || closure_body_returns_empty_to_string(cx, fun),
+                None => is_default_equivalent_call(cx, fun, None) || closure_body_returns_empty_to_string(cx, fun),
             }
         {
             span_lint_and_sugg(
diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs
index 2d3007e50b8..38d9c5f1677 100644
--- a/clippy_lints/src/methods/path_buf_push_overwrite.rs
+++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs
@@ -28,7 +28,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
             "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition",
             "try",
             format!("\"{}\"", pushed_path_lit.trim_start_matches(['/', '\\'])),
-            Applicability::MachineApplicable,
+            Applicability::MaybeIncorrect,
         );
     }
 }
diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs
index f4d206c5307..3a5e3217208 100644
--- a/clippy_lints/src/methods/range_zip_with_len.rs
+++ b/clippy_lints/src/methods/range_zip_with_len.rs
@@ -1,6 +1,7 @@
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::{SpanlessEq, higher, is_integer_const, is_trait_method};
+use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
 use rustc_span::sym;
@@ -20,14 +21,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
         && let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind
         && SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments)
     {
-        span_lint(
+        span_lint_and_sugg(
             cx,
             RANGE_ZIP_WITH_LEN,
             expr.span,
-            format!(
-                "it is more idiomatic to use `{}.iter().enumerate()`",
-                snippet(cx, recv.span, "_")
-            ),
+            "using `.zip()` with a range and `.len()`",
+            "try",
+            format!("{}.iter().enumerate()", snippet(cx, recv.span, "_")),
+            Applicability::MachineApplicable,
         );
     }
 }
diff --git a/clippy_lints/src/methods/return_and_then.rs b/clippy_lints/src/methods/return_and_then.rs
index 7b1199ad1e2..3c7b54dd8db 100644
--- a/clippy_lints/src/methods/return_and_then.rs
+++ b/clippy_lints/src/methods/return_and_then.rs
@@ -60,7 +60,7 @@ pub(super) fn check<'tcx>(
         "let {} = {}?;\n{}",
         arg_snip,
         recv_snip,
-        reindent_multiline(inner.into(), false, indent_of(cx, expr.span))
+        reindent_multiline(inner, false, indent_of(cx, expr.span))
     );
 
     span_lint_and_sugg(cx, RETURN_AND_THEN, expr.span, msg, "try", sugg, applicability);
diff --git a/clippy_lints/src/methods/unbuffered_bytes.rs b/clippy_lints/src/methods/unbuffered_bytes.rs
new file mode 100644
index 00000000000..71c23d256ac
--- /dev/null
+++ b/clippy_lints/src/methods/unbuffered_bytes.rs
@@ -0,0 +1,31 @@
+use super::UNBUFFERED_BYTES;
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{get_trait_def_id, is_trait_method, paths};
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
+    let ty = cx.typeck_results().expr_ty_adjusted(recv);
+
+    // If the .bytes() call is a call from the Read trait
+    if is_trait_method(cx, expr, sym::IoRead) {
+        // Retrieve the DefId of the BufRead trait
+        // FIXME: add a diagnostic item for `BufRead`
+        let Some(buf_read) = get_trait_def_id(cx.tcx, &paths::BUF_READ) else {
+            return;
+        };
+        // And the implementor of the trait is not buffered
+        if !implements_trait(cx, ty, buf_read, &[]) {
+            span_lint_and_help(
+                cx,
+                UNBUFFERED_BYTES,
+                expr.span,
+                "calling .bytes() is very inefficient when data is not in memory",
+                None,
+                "consider using `BufReader`",
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs
index c27d1fb4903..e7adf3b43ba 100644
--- a/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/clippy_lints/src/methods/unnecessary_fold.rs
@@ -123,32 +123,60 @@ pub(super) fn check(
     if let hir::ExprKind::Lit(lit) = init.kind {
         match lit.node {
             ast::LitKind::Bool(false) => {
-                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, Replacement {
-                    method_name: "any",
-                    has_args: true,
-                    has_generic_return: false,
-                });
+                check_fold_with_op(
+                    cx,
+                    expr,
+                    acc,
+                    fold_span,
+                    hir::BinOpKind::Or,
+                    Replacement {
+                        method_name: "any",
+                        has_args: true,
+                        has_generic_return: false,
+                    },
+                );
             },
             ast::LitKind::Bool(true) => {
-                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, Replacement {
-                    method_name: "all",
-                    has_args: true,
-                    has_generic_return: false,
-                });
+                check_fold_with_op(
+                    cx,
+                    expr,
+                    acc,
+                    fold_span,
+                    hir::BinOpKind::And,
+                    Replacement {
+                        method_name: "all",
+                        has_args: true,
+                        has_generic_return: false,
+                    },
+                );
             },
             ast::LitKind::Int(Pu128(0), _) => {
-                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, Replacement {
-                    method_name: "sum",
-                    has_args: false,
-                    has_generic_return: needs_turbofish(cx, expr),
-                });
+                check_fold_with_op(
+                    cx,
+                    expr,
+                    acc,
+                    fold_span,
+                    hir::BinOpKind::Add,
+                    Replacement {
+                        method_name: "sum",
+                        has_args: false,
+                        has_generic_return: needs_turbofish(cx, expr),
+                    },
+                );
             },
             ast::LitKind::Int(Pu128(1), _) => {
-                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, Replacement {
-                    method_name: "product",
-                    has_args: false,
-                    has_generic_return: needs_turbofish(cx, expr),
-                });
+                check_fold_with_op(
+                    cx,
+                    expr,
+                    acc,
+                    fold_span,
+                    hir::BinOpKind::Mul,
+                    Replacement {
+                        method_name: "product",
+                        has_args: false,
+                        has_generic_return: needs_turbofish(cx, expr),
+                    },
+                );
             },
             _ => (),
         }
diff --git a/clippy_lints/src/methods/unnecessary_map_or.rs b/clippy_lints/src/methods/unnecessary_map_or.rs
index 6dea1506d0e..c307e8c951d 100644
--- a/clippy_lints/src/methods/unnecessary_map_or.rs
+++ b/clippy_lints/src/methods/unnecessary_map_or.rs
@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::{Sugg, make_binop};
-use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
+use clippy_utils::ty::{get_type_diagnostic_name, implements_trait, is_copy};
 use clippy_utils::visitors::is_local_used;
 use clippy_utils::{get_parent_expr, is_from_proc_macro, path_to_local_id};
 use rustc_ast::LitKind::Bool;
@@ -81,9 +81,11 @@ pub(super) fn check<'a>(
             && (path_to_local_id(l, hir_id) ^ path_to_local_id(r, hir_id))
             && !is_local_used(cx, non_binding_location, hir_id)
             && let typeck_results = cx.typeck_results()
-            && typeck_results.expr_ty(l) == typeck_results.expr_ty(r)
+            && let l_ty = typeck_results.expr_ty(l)
+            && l_ty == typeck_results.expr_ty(r)
             && let Some(partial_eq) = cx.tcx.get_diagnostic_item(sym::PartialEq)
             && implements_trait(cx, recv_ty, partial_eq, &[recv_ty.into()])
+            && is_copy(cx, l_ty)
     {
         let wrap = variant.variant_name();
 
diff --git a/clippy_lints/src/methods/unwrap_expect_used.rs b/clippy_lints/src/methods/unwrap_expect_used.rs
index 5b0bd0f716a..027215e3b4d 100644
--- a/clippy_lints/src/methods/unwrap_expect_used.rs
+++ b/clippy_lints/src/methods/unwrap_expect_used.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::{is_never_like, is_type_diagnostic_item};
-use clippy_utils::{is_in_test, is_lint_allowed};
+use clippy_utils::{is_in_test, is_inside_always_const_context, is_lint_allowed};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, Lint};
 use rustc_middle::ty;
@@ -39,6 +39,7 @@ pub(super) fn check(
     expr: &Expr<'_>,
     recv: &Expr<'_>,
     is_err: bool,
+    allow_unwrap_in_consts: bool,
     allow_unwrap_in_tests: bool,
     variant: Variant,
 ) {
@@ -65,6 +66,10 @@ pub(super) fn check(
         return;
     }
 
+    if allow_unwrap_in_consts && is_inside_always_const_context(cx.tcx, expr.hir_id) {
+        return;
+    }
+
     span_lint_and_then(
         cx,
         variant.lint(),
diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs
index 82313257e5c..6d3da42775f 100644
--- a/clippy_lints/src/methods/useless_asref.rs
+++ b/clippy_lints/src/methods/useless_asref.rs
@@ -55,12 +55,19 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
         let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
         let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
         if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
-            // allow the `as_ref` or `as_mut` if it is followed by another method call
-            if let Some(parent) = get_parent_expr(cx, expr)
-                && let hir::ExprKind::MethodCall(segment, ..) = parent.kind
-                && segment.ident.span != expr.span
-            {
-                return;
+            if let Some(parent) = get_parent_expr(cx, expr) {
+                // allow the `as_ref` or `as_mut` if it is followed by another method call
+                if let hir::ExprKind::MethodCall(segment, ..) = parent.kind
+                    && segment.ident.span != expr.span
+                {
+                    return;
+                }
+
+                // allow the `as_ref` or `as_mut` if they belong to a closure that changes
+                // the number of references
+                if matches!(parent.kind, hir::ExprKind::Closure(..)) && rcv_depth != res_depth {
+                    return;
+                }
             }
 
             let mut applicability = Applicability::MachineApplicable;
diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs
index a99e21d938c..4119b1d1051 100644
--- a/clippy_lints/src/min_ident_chars.rs
+++ b/clippy_lints/src/min_ident_chars.rs
@@ -6,7 +6,6 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{Visitor, walk_item, walk_trait_item};
 use rustc_hir::{GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind, TraitItem, UsePath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use std::borrow::Cow;
@@ -55,7 +54,7 @@ impl MinIdentChars {
 
     #[expect(clippy::cast_possible_truncation)]
     fn is_ident_too_short(&self, cx: &LateContext<'_>, str: &str, span: Span) -> bool {
-        !in_external_macro(cx.sess(), span)
+        !span.in_external_macro(cx.sess().source_map())
             && str.len() <= self.min_ident_chars_threshold as usize
             && !str.starts_with('_')
             && !str.is_empty()
diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs
index 646145997bc..693d1a8dd76 100644
--- a/clippy_lints/src/misc.rs
+++ b/clippy_lints/src/misc.rs
@@ -12,7 +12,6 @@ use rustc_hir::{
     BinOpKind, BindingMode, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
@@ -161,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
             for arg in iter_input_pats(decl, body) {
                 if let PatKind::Binding(BindingMode(ByRef::Yes(_), _), ..) = arg.pat.kind
                     && is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id)
-                    && !in_external_macro(cx.tcx.sess, arg.span)
+                    && !arg.span.in_external_macro(cx.tcx.sess.source_map())
                 {
                     span_lint_hir(
                         cx,
@@ -182,7 +181,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
             && let Some(init) = local.init
             // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue.
             && is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id)
-            && !in_external_macro(cx.tcx.sess, stmt.span)
+            && !stmt.span.in_external_macro(cx.tcx.sess.source_map())
         {
             let ctxt = local.span.ctxt();
             let mut app = Applicability::MachineApplicable;
@@ -238,7 +237,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), expr.span)
+        if expr.span.in_external_macro(cx.sess().source_map())
             || expr.span.desugaring_kind().is_some()
             || in_automatically_derived(cx.tcx, expr.hir_id)
         {
diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs
index 637d6ed3ad2..f880f1f329f 100644
--- a/clippy_lints/src/misc_early/mod.rs
+++ b/clippy_lints/src/misc_early/mod.rs
@@ -14,7 +14,6 @@ use rustc_ast::token;
 use rustc_ast::visit::FnKind;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 
@@ -350,7 +349,7 @@ impl EarlyLintPass for MiscEarlyLints {
     }
 
     fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
-        if in_external_macro(cx.sess(), pat.span) {
+        if pat.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
@@ -387,7 +386,7 @@ impl EarlyLintPass for MiscEarlyLints {
     }
 
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess(), expr.span) {
+        if expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
diff --git a/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs b/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs
index 0c81ee5eced..f2cf93465c0 100644
--- a/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs
+++ b/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs
@@ -2,12 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use rustc_ast::{Pat, PatKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, LintContext};
-use rustc_middle::lint::in_external_macro;
 
 use super::REDUNDANT_AT_REST_PATTERN;
 
 pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
-    if !in_external_macro(cx.sess(), pat.span)
+    if !pat.span.in_external_macro(cx.sess().source_map())
         && let PatKind::Slice(slice) = &pat.kind
         && let [one] = &**slice
         && let PatKind::Ident(annotation, ident, Some(rest)) = &one.kind
diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs
index 2572e186ce6..962d85c6a9d 100644
--- a/clippy_lints/src/missing_const_for_fn.rs
+++ b/clippy_lints/src/missing_const_for_fn.rs
@@ -8,7 +8,6 @@ use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
@@ -106,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
             return;
         }
 
-        if in_external_macro(cx.tcx.sess, span) || is_entrypoint_fn(cx, def_id.to_def_id()) {
+        if span.in_external_macro(cx.tcx.sess.source_map()) || is_entrypoint_fn(cx, def_id.to_def_id()) {
             return;
         }
 
diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs
index bba1b63be27..18385ac9269 100644
--- a/clippy_lints/src/missing_inline.rs
+++ b/clippy_lints/src/missing_inline.rs
@@ -88,7 +88,7 @@ declare_lint_pass!(MissingInline => [MISSING_INLINE_IN_PUBLIC_ITEMS]);
 
 impl<'tcx> LateLintPass<'tcx> for MissingInline {
     fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
-        if rustc_middle::lint::in_external_macro(cx.sess(), it.span) || is_executable_or_proc_macro(cx) {
+        if it.span.in_external_macro(cx.sess().source_map()) || is_executable_or_proc_macro(cx) {
             return;
         }
 
@@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
-        if rustc_middle::lint::in_external_macro(cx.sess(), impl_item.span) || is_executable_or_proc_macro(cx) {
+        if impl_item.span.in_external_macro(cx.sess().source_map()) || is_executable_or_proc_macro(cx) {
             return;
         }
 
diff --git a/clippy_lints/src/multiple_bound_locations.rs b/clippy_lints/src/multiple_bound_locations.rs
index 882ab2dda7a..0e1980a6acb 100644
--- a/clippy_lints/src/multiple_bound_locations.rs
+++ b/clippy_lints/src/multiple_bound_locations.rs
@@ -1,5 +1,5 @@
 use rustc_ast::visit::FnKind;
-use rustc_ast::{NodeId, WherePredicateKind};
+use rustc_ast::{Fn, NodeId, WherePredicateKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
@@ -39,7 +39,7 @@ declare_lint_pass!(MultipleBoundLocations => [MULTIPLE_BOUND_LOCATIONS]);
 
 impl EarlyLintPass for MultipleBoundLocations {
     fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, _: Span, _: NodeId) {
-        if let FnKind::Fn(_, _, _, _, generics, _) = kind
+        if let FnKind::Fn(_, _, _, Fn { generics, .. }) = kind
             && !generics.params.is_empty()
             && !generics.where_clause.predicates.is_empty()
         {
diff --git a/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index aad6ae52a6d..9acede4f32d 100644
--- a/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -6,7 +6,6 @@ use hir::{BlockCheckMode, ExprKind, QPath, UnOp};
 use rustc_ast::Mutability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::{DesugaringKind, Span};
@@ -65,7 +64,7 @@ declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK])
 impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
         if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_))
-            || in_external_macro(cx.tcx.sess, block.span)
+            || block.span.in_external_macro(cx.tcx.sess.source_map())
             || block.span.is_desugaring(DesugaringKind::Await)
         {
             return;
@@ -153,16 +152,19 @@ fn collect_unsafe_exprs<'tcx>(
             ExprKind::AssignOp(_, lhs, rhs) | ExprKind::Assign(lhs, rhs, _) => {
                 if matches!(
                     lhs.kind,
-                    ExprKind::Path(QPath::Resolved(_, hir::Path {
-                        res: Res::Def(
-                            DefKind::Static {
-                                mutability: Mutability::Mut,
-                                ..
-                            },
-                            _
-                        ),
-                        ..
-                    }))
+                    ExprKind::Path(QPath::Resolved(
+                        _,
+                        hir::Path {
+                            res: Res::Def(
+                                DefKind::Static {
+                                    mutability: Mutability::Mut,
+                                    ..
+                                },
+                                _
+                            ),
+                            ..
+                        }
+                    ))
                 ) {
                     unsafe_ops.push(("modification of a mutable static occurs here", expr.span));
                     collect_unsafe_exprs(cx, rhs, unsafe_ops);
diff --git a/clippy_lints/src/mut_mut.rs b/clippy_lints/src/mut_mut.rs
index 0ee851a4cf9..3c4ba5141dd 100644
--- a/clippy_lints/src/mut_mut.rs
+++ b/clippy_lints/src/mut_mut.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_hir};
 use clippy_utils::higher;
 use rustc_hir::{self as hir, AmbigArg, intravisit};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 
@@ -38,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for MutMut {
             && mty.mutbl == hir::Mutability::Mut
             && let hir::TyKind::Ref(_, mty) = mty.ty.kind
             && mty.mutbl == hir::Mutability::Mut
-            && !in_external_macro(cx.sess(), ty.span)
+            && !ty.span.in_external_macro(cx.sess().source_map())
         {
             span_lint(
                 cx,
@@ -56,7 +55,7 @@ pub struct MutVisitor<'a, 'tcx> {
 
 impl<'tcx> intravisit::Visitor<'tcx> for MutVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
-        if in_external_macro(self.cx.sess(), expr.span) {
+        if expr.span.in_external_macro(self.cx.sess().source_map()) {
             return;
         }
 
diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs
index c382fb8fce1..2fd1049f42e 100644
--- a/clippy_lints/src/mut_reference.rs
+++ b/clippy_lints/src/mut_reference.rs
@@ -54,8 +54,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
                     );
                 }
             },
-            ExprKind::MethodCall(path, receiver, arguments, _) => {
-                let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
+            ExprKind::MethodCall(path, receiver, arguments, _)
+                if let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) =>
+            {
                 let args = cx.typeck_results().node_args(e.hir_id);
                 let method_type = cx.tcx.type_of(def_id).instantiate(cx.tcx, args);
                 check_arguments(
diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs
index 05b31fc84b9..b8601f77e24 100644
--- a/clippy_lints/src/needless_continue.rs
+++ b/clippy_lints/src/needless_continue.rs
@@ -356,7 +356,7 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin
         .iter()
         .map(|stmt| {
             let span = cx.sess().source_map().stmt_span(stmt.span, data.loop_block.span);
-            let snip = snippet_block(cx, span, "..", None).into_owned();
+            let snip = snippet_block(cx, span, "..", None);
             snip.lines()
                 .map(|line| format!("{}{line}", " ".repeat(indent)))
                 .collect::<Vec<_>>()
diff --git a/clippy_lints/src/needless_if.rs b/clippy_lints/src/needless_if.rs
index 8e14fbf2f80..7eefb016aca 100644
--- a/clippy_lints/src/needless_if.rs
+++ b/clippy_lints/src/needless_if.rs
@@ -5,7 +5,6 @@ use clippy_utils::source::SpanRangeExt;
 use rustc_errors::Applicability;
 use rustc_hir::{ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -47,7 +46,7 @@ impl LateLintPass<'_> for NeedlessIf {
             && let ExprKind::Block(block, ..) = then.kind
             && block.stmts.is_empty()
             && block.expr.is_none()
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && then.span.check_source_text(cx, |src| {
                 // Ignore
                 // - empty macro expansions
diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs
index 30846fb46ac..2855703b9d5 100644
--- a/clippy_lints/src/needless_pass_by_value.rs
+++ b/clippy_lints/src/needless_pass_by_value.rs
@@ -181,9 +181,14 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                 && !is_copy(cx, ty)
                 && ty.is_sized(cx.tcx, cx.typing_env())
                 && !allowed_traits.iter().any(|&t| {
-                    implements_trait_with_env_from_iter(cx.tcx, cx.typing_env(), ty, t, None, [None::<
-                        ty::GenericArg<'tcx>,
-                    >])
+                    implements_trait_with_env_from_iter(
+                        cx.tcx,
+                        cx.typing_env(),
+                        ty,
+                        t,
+                        None,
+                        [None::<ty::GenericArg<'tcx>>],
+                    )
                 })
                 && !implements_borrow_trait
                 && !all_borrowable_trait
diff --git a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
index fa90ee60612..4f62ba2e58d 100644
--- a/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
+++ b/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::implements_trait;
 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;
 use rustc_span::sym;
 
@@ -48,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
         if let ExprKind::Unary(UnOp::Not, inner) = expr.kind
             && let ExprKind::Binary(ref op, left, _) = inner.kind
             && let BinOpKind::Le | BinOpKind::Ge | BinOpKind::Lt | BinOpKind::Gt = op.node
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
         {
             let ty = cx.typeck_results().expr_ty(left);
 
diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs
index 688374b5676..cc56df3a23d 100644
--- a/clippy_lints/src/new_without_default.rs
+++ b/clippy_lints/src/new_without_default.rs
@@ -6,7 +6,6 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::HirIdSet;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::sym;
 
@@ -69,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
             for assoc_item in *items {
                 if assoc_item.kind == (hir::AssocItemKind::Fn { has_self: false }) {
                     let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
-                    if in_external_macro(cx.sess(), impl_item.span) {
+                    if impl_item.span.in_external_macro(cx.sess().source_map()) {
                         return;
                     }
                     if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs
index ccd50758044..4d3e6aa79d0 100644
--- a/clippy_lints/src/no_effect.rs
+++ b/clippy_lints/src/no_effect.rs
@@ -12,7 +12,6 @@ use rustc_hir::{
 };
 use rustc_infer::infer::TyCtxtInferExt as _;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@@ -268,7 +267,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 
 fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
     if let StmtKind::Semi(expr) = stmt.kind
-        && !in_external_macro(cx.sess(), stmt.span)
+        && !stmt.span.in_external_macro(cx.sess().source_map())
         && let ctxt = stmt.span.ctxt()
         && expr.span.ctxt() == ctxt
         && let Some(reduced) = reduce_expression(cx, expr)
diff --git a/clippy_lints/src/non_canonical_impls.rs b/clippy_lints/src/non_canonical_impls.rs
index 94855c46567..dad1e8a3d6a 100644
--- a/clippy_lints/src/non_canonical_impls.rs
+++ b/clippy_lints/src/non_canonical_impls.rs
@@ -5,7 +5,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::EarlyBinder;
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -129,7 +128,7 @@ impl LateLintPass<'_> for NonCanonicalImpls {
         let ExprKind::Block(block, ..) = body.value.kind else {
             return;
         };
-        if in_external_macro(cx.sess(), block.span) || is_from_proc_macro(cx, impl_item) {
+        if block.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, impl_item) {
             return;
         }
 
diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs
index 147654675ec..0d89b4e8535 100644
--- a/clippy_lints/src/non_copy_const.rs
+++ b/clippy_lints/src/non_copy_const.rs
@@ -215,6 +215,12 @@ impl<'tcx> NonCopyConst<'tcx> {
                 .iter()
                 .zip(tys)
                 .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
+            ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) {
+                Ok(normalized_ty) if ty != normalized_ty => {
+                    Self::is_value_unfrozen_raw_inner(cx, ty::ValTree::Branch(val), normalized_ty)
+                },
+                _ => false,
+            },
             _ => false,
         }
     }
diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs
index 56c4157d6fe..c5873589b26 100644
--- a/clippy_lints/src/non_expressive_names.rs
+++ b/clippy_lints/src/non_expressive_names.rs
@@ -5,7 +5,6 @@ use rustc_ast::ast::{
 };
 use rustc_ast::visit::{Visitor, walk_block, walk_expr, walk_pat};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{Span, sym};
@@ -209,7 +208,8 @@ impl SimilarNamesNameVisitor<'_, '_, '_> {
 
     fn check_ident(&mut self, ident: Ident) {
         let interned_name = ident.name.as_str();
-        if interned_name.chars().any(char::is_uppercase) {
+        // name can be empty if it comes from recovery
+        if interned_name.chars().any(char::is_uppercase) || interned_name.is_empty() {
             return;
         }
         if interned_name.chars().all(|c| c.is_ascii_digit() || c == '_') {
@@ -381,7 +381,7 @@ impl<'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'_, 'tcx> {
 
 impl EarlyLintPass for NonExpressiveNames {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if in_external_macro(cx.sess(), item.span) {
+        if item.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
@@ -396,7 +396,7 @@ impl EarlyLintPass for NonExpressiveNames {
     }
 
     fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) {
-        if in_external_macro(cx.sess(), item.span) {
+        if item.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
diff --git a/clippy_lints/src/non_send_fields_in_send_ty.rs b/clippy_lints/src/non_send_fields_in_send_ty.rs
index 793eb5d9456..9542fed3875 100644
--- a/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -7,7 +7,6 @@ use rustc_ast::ImplPolarity;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{FieldDef, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::sym;
@@ -81,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
         // We start from `Send` impl instead of `check_field_def()` because
         // single `AdtDef` may have multiple `Send` impls due to generic
         // parameters, and the lint is much easier to implement in this way.
-        if !in_external_macro(cx.tcx.sess, item.span)
+        if !item.span.in_external_macro(cx.tcx.sess.source_map())
             && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send)
             && let ItemKind::Impl(hir_impl) = &item.kind
             && let Some(trait_ref) = &hir_impl.of_trait
diff --git a/clippy_lints/src/non_std_lazy_statics.rs b/clippy_lints/src/non_std_lazy_statics.rs
index 312610db042..22116505a1c 100644
--- a/clippy_lints/src/non_std_lazy_statics.rs
+++ b/clippy_lints/src/non_std_lazy_statics.rs
@@ -9,7 +9,6 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::{self as hir, BodyId, Expr, ExprKind, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 
@@ -139,7 +138,7 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic {
             return;
         }
 
-        if in_external_macro(cx.sess(), item.span) {
+        if item.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs
index 2eae9b23746..6e7ee727965 100644
--- a/clippy_lints/src/octal_escapes.rs
+++ b/clippy_lints/src/octal_escapes.rs
@@ -4,7 +4,6 @@ use rustc_ast::token::LitKind;
 use rustc_ast::{Expr, ExprKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::{BytePos, Pos, SpanData};
 
@@ -59,7 +58,7 @@ impl EarlyLintPass for OctalEscapes {
                 LitKind::ByteStr | LitKind::CStr => 2,
                 _ => return,
             })
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
         {
             let s = lit.symbol.as_str();
             let mut iter = s.as_bytes().iter();
diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs
index 6d9e75f51d6..de9f055863c 100644
--- a/clippy_lints/src/option_if_let_else.rs
+++ b/clippy_lints/src/option_if_let_else.rs
@@ -7,7 +7,9 @@ use clippy_utils::{
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::def::Res;
-use rustc_hir::{Arm, BindingMode, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp};
+use rustc_hir::{
+    Arm, BindingMode, Expr, ExprKind, MatchSource, Mutability, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, UnOp,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::SyntaxContext;
@@ -281,7 +283,11 @@ fn try_convert_match<'tcx>(
 
 fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     match arm.pat.kind {
-        PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
+        PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(qpath),
+            hir_id,
+            ..
+        }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
         PatKind::TupleStruct(ref qpath, [first_pat], _) => {
             is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)
                 && matches!(first_pat.kind, PatKind::Wild)
diff --git a/clippy_lints/src/panicking_overflow_checks.rs b/clippy_lints/src/panicking_overflow_checks.rs
index 7f100a746d5..bc1821a48a3 100644
--- a/clippy_lints/src/panicking_overflow_checks.rs
+++ b/clippy_lints/src/panicking_overflow_checks.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint;
 use clippy_utils::eq_expr_value;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 
@@ -72,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for PanickingOverflowChecks {
             && matches!(ty.kind(), ty::Uint(_))
             && ty == typeck.expr_ty(op_rhs)
             && ty == typeck.expr_ty(other)
-            && !in_external_macro(cx.tcx.sess, expr.span)
+            && !expr.span.in_external_macro(cx.tcx.sess.source_map())
             && (eq_expr_value(cx, op_lhs, other) || (commutative && eq_expr_value(cx, op_rhs, other)))
         {
             span_lint(
diff --git a/clippy_lints/src/pathbuf_init_then_push.rs b/clippy_lints/src/pathbuf_init_then_push.rs
index 668f09bbfd5..b653b459b04 100644
--- a/clippy_lints/src/pathbuf_init_then_push.rs
+++ b/clippy_lints/src/pathbuf_init_then_push.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, Symbol, sym};
 
@@ -136,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         if let Some(init_expr) = local.init
             && let PatKind::Binding(BindingMode::MUT, id, name, None) = local.pat.kind
-            && !in_external_macro(cx.sess(), local.span)
+            && !local.span.in_external_macro(cx.sess().source_map())
             && let ty = cx.typeck_results().pat_ty(local.pat)
             && is_type_diagnostic_item(cx, ty, sym::PathBuf)
         {
@@ -157,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> {
             && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind
             && let [name] = &path.segments
             && let Res::Local(id) = path.res
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && let ty = cx.typeck_results().expr_ty(left)
             && is_type_diagnostic_item(cx, ty, sym::PathBuf)
         {
diff --git a/clippy_lints/src/pattern_type_mismatch.rs b/clippy_lints/src/pattern_type_mismatch.rs
index 42fbba8ef6d..8f1a1ee76c6 100644
--- a/clippy_lints/src/pattern_type_mismatch.rs
+++ b/clippy_lints/src/pattern_type_mismatch.rs
@@ -3,7 +3,6 @@ use rustc_hir::{
     Body, Expr, ExprKind, FnDecl, LetExpr, LocalSource, Mutability, Pat, PatKind, Stmt, StmtKind, intravisit,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
@@ -84,7 +83,7 @@ declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);
 impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let StmtKind::Let(local) = stmt.kind {
-            if in_external_macro(cx.sess(), local.pat.span) {
+            if local.pat.span.in_external_macro(cx.sess().source_map()) {
                 return;
             }
             let deref_possible = match local.source {
@@ -171,7 +170,7 @@ fn find_first_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(Span, Mut
         if result.is_some() {
             return false;
         }
-        if in_external_macro(cx.sess(), p.span) {
+        if p.span.in_external_macro(cx.sess().source_map()) {
             return true;
         }
         let adjust_pat = match p.kind {
diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs
index 23d0e768c2f..c6e6e782f9d 100644
--- a/clippy_lints/src/raw_strings.rs
+++ b/clippy_lints/src/raw_strings.rs
@@ -5,7 +5,6 @@ use rustc_ast::ast::{Expr, ExprKind};
 use rustc_ast::token::LitKind;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{BytePos, Pos, Span};
 use std::iter::once;
@@ -72,7 +71,7 @@ impl RawStrings {
 impl EarlyLintPass for RawStrings {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::FormatArgs(format_args) = &expr.kind
-            && !in_external_macro(cx.sess(), format_args.span)
+            && !format_args.span.in_external_macro(cx.sess().source_map())
             && format_args.span.check_source_text(cx, |src| src.starts_with('r'))
             && let Some(str) = snippet_opt(cx.sess(), format_args.span)
             && let count_hash = str.bytes().skip(1).take_while(|b| *b == b'#').count()
@@ -95,7 +94,7 @@ impl EarlyLintPass for RawStrings {
                 LitKind::CStrRaw(max) => ("cr", max),
                 _ => return,
             }
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && expr.span.check_source_text(cx, |src| src.starts_with(prefix))
         {
             self.check_raw_string(cx, lit.symbol.as_str(), expr.span, prefix, max, lit.kind.descr());
diff --git a/clippy_lints/src/redundant_async_block.rs b/clippy_lints/src/redundant_async_block.rs
index 3ade6bcee84..65fd312b3a0 100644
--- a/clippy_lints/src/redundant_async_block.rs
+++ b/clippy_lints/src/redundant_async_block.rs
@@ -10,7 +10,6 @@ use rustc_hir::{
     Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::UpvarCapture;
 use rustc_session::declare_lint_pass;
 
@@ -47,7 +46,7 @@ declare_lint_pass!(RedundantAsyncBlock => [REDUNDANT_ASYNC_BLOCK]);
 impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let span = expr.span;
-        if !in_external_macro(cx.tcx.sess, span) &&
+        if !span.in_external_macro(cx.tcx.sess.source_map()) &&
             let Some(body_expr) = desugar_async_block(cx, expr) &&
             let Some(expr) = desugar_await(peel_blocks(body_expr)) &&
             // The await prefix must not come from a macro as its content could change in the future.
diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs
index b9e0106fc86..fb1bc494bd9 100644
--- a/clippy_lints/src/redundant_clone.rs
+++ b/clippy_lints/src/redundant_clone.rs
@@ -349,10 +349,14 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>,
             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(),
-    })
+    )) = 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 {
diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs
index b4dadef57a3..91d023500ca 100644
--- a/clippy_lints/src/redundant_closure_call.rs
+++ b/clippy_lints/src/redundant_closure_call.rs
@@ -10,7 +10,6 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::ExpnKind;
@@ -138,7 +137,7 @@ fn get_parent_call_exprs<'tcx>(
 
 impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
-        if in_external_macro(cx.sess(), expr.span) {
+        if expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
 
diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs
index 2995cd8d9f7..a3be16ed858 100644
--- a/clippy_lints/src/redundant_else.rs
+++ b/clippy_lints/src/redundant_else.rs
@@ -4,10 +4,8 @@ use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_ast::visit::{Visitor, walk_expr};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
-use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -50,7 +48,7 @@ declare_lint_pass!(RedundantElse => [REDUNDANT_ELSE]);
 
 impl EarlyLintPass for RedundantElse {
     fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) {
-        if in_external_macro(cx.sess(), stmt.span) {
+        if stmt.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         // Only look at expressions that are a whole statement
@@ -164,14 +162,9 @@ fn extract_else_block(mut block: &str) -> String {
     block.trim_end().to_string()
 }
 
-fn make_sugg<'a>(
-    cx: &EarlyContext<'_>,
-    els_span: Span,
-    default: &'a str,
-    indent_relative_to: Option<Span>,
-) -> Cow<'a, str> {
+fn make_sugg(cx: &EarlyContext<'_>, els_span: Span, default: &str, indent_relative_to: Option<Span>) -> String {
     let extracted = extract_else_block(&snippet(cx, els_span, default));
     let indent = indent_relative_to.and_then(|s| indent_of(cx, s));
 
-    reindent_multiline(extracted.into(), false, indent)
+    reindent_multiline(&extracted, false, indent)
 }
diff --git a/clippy_lints/src/redundant_field_names.rs b/clippy_lints/src/redundant_field_names.rs
index 347540e7344..707abc008a8 100644
--- a/clippy_lints/src/redundant_field_names.rs
+++ b/clippy_lints/src/redundant_field_names.rs
@@ -4,7 +4,6 @@ use clippy_utils::msrvs::{self, Msrv};
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
@@ -56,7 +55,7 @@ impl EarlyLintPass for RedundantFieldNames {
             return;
         }
 
-        if in_external_macro(cx.sess(), expr.span) {
+        if expr.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         if let ExprKind::Struct(ref se) = expr.kind {
diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs
index 658d93e634c..ebe3e7c2019 100644
--- a/clippy_lints/src/redundant_locals.rs
+++ b/clippy_lints/src/redundant_locals.rs
@@ -6,7 +6,6 @@ use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, ByRef, ExprKind, HirId, LetStmt, Node, Pat, PatKind, QPath};
 use rustc_hir_typeck::expr_use_visitor::PlaceBase;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::UpvarCapture;
 use rustc_session::declare_lint_pass;
 use rustc_span::DesugaringKind;
@@ -69,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
             // the local does not affect the code's drop behavior
             && !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr))
             // the local is user-controlled
-            && !in_external_macro(cx.sess(), local.span)
+            && !local.span.in_external_macro(cx.sess().source_map())
             && !is_from_proc_macro(cx, expr)
             && !is_by_value_closure_capture(cx, local.hir_id, binding_id)
         {
diff --git a/clippy_lints/src/redundant_pub_crate.rs b/clippy_lints/src/redundant_pub_crate.rs
index 8d6b1c7274d..6a17b83b3d0 100644
--- a/clippy_lints/src/redundant_pub_crate.rs
+++ b/clippy_lints/src/redundant_pub_crate.rs
@@ -4,7 +4,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::CRATE_DEF_ID;
@@ -51,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
             && !cx.effective_visibilities.is_exported(item.owner_id.def_id)
             && self.is_exported.last() == Some(&false)
             && is_not_macro_export(item)
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
         {
             let span = item.span.with_hi(item.ident.span.hi());
             let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id());
diff --git a/clippy_lints/src/reserve_after_initialization.rs b/clippy_lints/src/reserve_after_initialization.rs
index 6157adad059..152d7450f5f 100644
--- a/clippy_lints/src/reserve_after_initialization.rs
+++ b/clippy_lints/src/reserve_after_initialization.rs
@@ -6,7 +6,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 
@@ -72,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         if let Some(init_expr) = local.init
             && let PatKind::Binding(BindingMode::MUT, id, _, None) = local.pat.kind
-            && !in_external_macro(cx.sess(), local.span)
+            && !local.span.in_external_macro(cx.sess().source_map())
             && let Some(init) = get_vec_init_kind(cx, init_expr)
             && !matches!(
                 init,
@@ -101,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
             && let ExprKind::Assign(left, right, _) = expr.kind
             && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind
             && let Res::Local(id) = path.res
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && let Some(init) = get_vec_init_kind(cx, right)
             && !matches!(
                 init,
diff --git a/clippy_lints/src/return_self_not_must_use.rs b/clippy_lints/src/return_self_not_must_use.rs
index 42d9cf2c88c..5a25483c397 100644
--- a/clippy_lints/src/return_self_not_must_use.rs
+++ b/clippy_lints/src/return_self_not_must_use.rs
@@ -5,7 +5,6 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::{Span, sym};
 
@@ -69,7 +68,7 @@ declare_clippy_lint! {
 declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]);
 
 fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, owner_id: OwnerId) {
-    if !in_external_macro(cx.sess(), span)
+    if !span.in_external_macro(cx.sess().source_map())
         // If it comes from an external macro, better ignore it.
         && decl.implicit_self.has_implicit_self()
         // We only show this warning for public exported methods.
diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs
index 664e984fece..0286c9843a9 100644
--- a/clippy_lints/src/returns.rs
+++ b/clippy_lints/src/returns.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::source::{SpanRangeExt, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::visitors::{Descend, for_each_expr};
+use clippy_utils::visitors::for_each_expr;
 use clippy_utils::{
     binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor,
     leaks_droppable_temporary_with_limited_lifetime, path_res, path_to_local_id, span_contains_cfg,
@@ -17,11 +17,11 @@ use rustc_hir::{
     StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass, Level, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
+use rustc_span::edition::Edition;
 use rustc_span::{BytePos, Pos, Span, sym};
 use std::borrow::Cow;
 use std::fmt::Display;
@@ -191,7 +191,7 @@ fn stmt_needs_never_type(cx: &LateContext<'_>, stmt_hir_id: HirId) -> bool {
 
 impl<'tcx> LateLintPass<'tcx> for Return {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
-        if !in_external_macro(cx.sess(), stmt.span)
+        if !stmt.span.in_external_macro(cx.sess().source_map())
             && let StmtKind::Semi(expr) = stmt.kind
             && let ExprKind::Ret(Some(ret)) = expr.kind
             // return Err(...)? desugars to a match
@@ -236,9 +236,9 @@ impl<'tcx> LateLintPass<'tcx> for Return {
             && let Some(initexpr) = &local.init
             && let PatKind::Binding(_, local_id, _, _) = local.pat.kind
             && path_to_local_id(retexpr, local_id)
-            && !last_statement_borrows(cx, initexpr)
-            && !in_external_macro(cx.sess(), initexpr.span)
-            && !in_external_macro(cx.sess(), retexpr.span)
+            && (cx.sess().edition() >= Edition::Edition2024 || !last_statement_borrows(cx, initexpr))
+            && !initexpr.span.in_external_macro(cx.sess().source_map())
+            && !retexpr.span.in_external_macro(cx.sess().source_map())
             && !local.span.from_expansion()
             && !span_contains_cfg(cx, stmt.span.between(retexpr.span))
         {
@@ -484,7 +484,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
         {
             ControlFlow::Break(())
         } else {
-            ControlFlow::Continue(Descend::from(!e.span.from_expansion()))
+            ControlFlow::Continue(())
         }
     })
     .is_some()
diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs
index 8d31641d483..29914d4379f 100644
--- a/clippy_lints/src/same_name_method.rs
+++ b/clippy_lints/src/same_name_method.rs
@@ -62,10 +62,13 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
                 && let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
             {
                 if !map.contains_key(res) {
-                    map.insert(*res, ExistingName {
-                        impl_methods: BTreeMap::new(),
-                        trait_methods: BTreeMap::new(),
-                    });
+                    map.insert(
+                        *res,
+                        ExistingName {
+                            impl_methods: BTreeMap::new(),
+                            trait_methods: BTreeMap::new(),
+                        },
+                    );
                 }
                 let existing_name = map.get_mut(res).unwrap();
 
diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs
index 0176077c70e..fdbccbaa8a5 100644
--- a/clippy_lints/src/single_call_fn.rs
+++ b/clippy_lints/src/single_call_fn.rs
@@ -6,7 +6,6 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{Expr, ExprKind, HirId, Node};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
 
@@ -88,7 +87,7 @@ impl SingleCallFn {
         fn_span: Span,
     ) -> bool {
         (self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id))
-            || in_external_macro(cx.sess(), fn_span)
+            || fn_span.in_external_macro(cx.sess().source_map())
             || cx
                 .tcx
                 .hir()
diff --git a/clippy_lints/src/single_char_lifetime_names.rs b/clippy_lints/src/single_char_lifetime_names.rs
index d92b890950a..50a6ee316c8 100644
--- a/clippy_lints/src/single_char_lifetime_names.rs
+++ b/clippy_lints/src/single_char_lifetime_names.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{GenericParam, GenericParamKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -42,7 +41,7 @@ declare_lint_pass!(SingleCharLifetimeNames => [SINGLE_CHAR_LIFETIME_NAMES]);
 
 impl EarlyLintPass for SingleCharLifetimeNames {
     fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam) {
-        if in_external_macro(ctx.sess(), param.ident.span) {
+        if param.ident.span.in_external_macro(ctx.sess().source_map()) {
             return;
         }
 
diff --git a/clippy_lints/src/single_option_map.rs b/clippy_lints/src/single_option_map.rs
new file mode 100644
index 00000000000..ad8463870a6
--- /dev/null
+++ b/clippy_lints/src/single_option_map.rs
@@ -0,0 +1,91 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{path_res, peel_blocks};
+use rustc_hir::def::Res;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{Body, ExprKind, FnDecl, FnRetTy};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::{Span, sym};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for functions with method calls to `.map(_)` on an arg
+    /// of type `Option` as the outermost expression.
+    ///
+    /// ### Why is this bad?
+    /// Taking and returning an `Option<T>` may require additional
+    /// `Some(_)` and `unwrap` if all you have is a `T`.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// fn double(param: Option<u32>) -> Option<u32> {
+    ///     param.map(|x| x * 2)
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// fn double(param: u32) -> u32 {
+    ///     param * 2
+    /// }
+    /// ```
+    #[clippy::version = "1.86.0"]
+    pub SINGLE_OPTION_MAP,
+    nursery,
+    "Checks for functions with method calls to `.map(_)` on an arg of type `Option` as the outermost expression."
+}
+
+declare_lint_pass!(SingleOptionMap => [SINGLE_OPTION_MAP]);
+
+impl<'tcx> LateLintPass<'tcx> for SingleOptionMap {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        kind: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'tcx>,
+        body: &'tcx Body<'tcx>,
+        span: Span,
+        _fn_def: LocalDefId,
+    ) {
+        if let FnRetTy::Return(_ret) = decl.output
+            && matches!(kind, FnKind::ItemFn(_, _, _) | FnKind::Method(_, _))
+        {
+            let func_body = peel_blocks(body.value);
+            if let ExprKind::MethodCall(method_name, callee, args, _span) = func_body.kind
+                && method_name.ident.name == sym::map
+                && let callee_type = cx.typeck_results().expr_ty(callee)
+                && is_type_diagnostic_item(cx, callee_type, sym::Option)
+                && let ExprKind::Path(_path) = callee.kind
+                && let Res::Local(_id) = path_res(cx, callee)
+                && matches!(path_res(cx, callee), Res::Local(_id))
+                && !matches!(args[0].kind, ExprKind::Path(_))
+            {
+                if let ExprKind::Closure(closure) = args[0].kind {
+                    let Body { params: [..], value } = cx.tcx.hir().body(closure.body);
+                    if let ExprKind::Call(func, f_args) = value.kind
+                        && matches!(func.kind, ExprKind::Path(_))
+                        && f_args.iter().all(|arg| matches!(arg.kind, ExprKind::Path(_)))
+                    {
+                        return;
+                    } else if let ExprKind::MethodCall(_segment, receiver, method_args, _span) = value.kind
+                        && matches!(receiver.kind, ExprKind::Path(_))
+                        && method_args.iter().all(|arg| matches!(arg.kind, ExprKind::Path(_)))
+                        && method_args.iter().all(|arg| matches!(path_res(cx, arg), Res::Local(_)))
+                    {
+                        return;
+                    }
+                }
+
+                span_lint_and_help(
+                    cx,
+                    SINGLE_OPTION_MAP,
+                    span,
+                    "`fn` that only maps over argument",
+                    None,
+                    "move the `.map` to the caller or to an `_opt` function",
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/std_instead_of_core.rs b/clippy_lints/src/std_instead_of_core.rs
index 8ec7bfe9edd..59c13a1e2c5 100644
--- a/clippy_lints/src/std_instead_of_core.rs
+++ b/clippy_lints/src/std_instead_of_core.rs
@@ -8,7 +8,6 @@ use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{HirId, Path, PathSegment};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::kw;
 use rustc_span::{Span, sym};
@@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
         if let Res::Def(_, def_id) = path.res
             && let Some(first_segment) = get_first_segment(path)
             && is_stable(cx, def_id, &self.msrv)
-            && !in_external_macro(cx.sess(), path.span)
+            && !path.span.in_external_macro(cx.sess().source_map())
             && !is_from_proc_macro(cx, &first_segment.ident)
         {
             let (lint, used_mod, replace_with) = match first_segment.ident.name {
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index 2925f355d0b..6164a6191db 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -9,7 +9,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, Node, QPath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::source_map::Spanned;
@@ -147,7 +146,7 @@ declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]);
 
 impl<'tcx> LateLintPass<'tcx> for StringAdd {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if in_external_macro(cx.sess(), e.span) {
+        if e.span.in_external_macro(cx.sess().source_map()) {
             return;
         }
         match e.kind {
@@ -284,7 +283,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
             );
         }
 
-        if !in_external_macro(cx.sess(), e.span)
+        if !e.span.in_external_macro(cx.sess().source_map())
             && let ExprKind::MethodCall(path, receiver, ..) = &e.kind
             && path.ident.name.as_str() == "as_bytes"
             && let ExprKind::Lit(lit) = &receiver.kind
diff --git a/clippy_lints/src/suspicious_xor_used_as_pow.rs b/clippy_lints/src/suspicious_xor_used_as_pow.rs
index d1d822a5532..e55d17818e4 100644
--- a/clippy_lints/src/suspicious_xor_used_as_pow.rs
+++ b/clippy_lints/src/suspicious_xor_used_as_pow.rs
@@ -5,7 +5,6 @@ use rustc_ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
@@ -32,7 +31,7 @@ declare_lint_pass!(ConfusingXorAndPow => [SUSPICIOUS_XOR_USED_AS_POW]);
 
 impl LateLintPass<'_> for ConfusingXorAndPow {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if !in_external_macro(cx.sess(), expr.span)
+        if !expr.span.in_external_macro(cx.sess().source_map())
             && let ExprKind::Binary(op, left, right) = &expr.kind
             && op.node == BinOpKind::BitXor
             && left.span.eq_ctxt(right.span)
diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs
index 9b4c3d275ae..7176d533b61 100644
--- a/clippy_lints/src/swap.rs
+++ b/clippy_lints/src/swap.rs
@@ -12,7 +12,6 @@ use rustc_hir::intravisit::{Visitor, walk_expr};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, LetStmt, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::source_map::Spanned;
@@ -212,7 +211,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
         if let Some((lhs0, rhs0)) = parse(first)
             && let Some((lhs1, rhs1)) = parse(second)
             && first.span.eq_ctxt(second.span)
-			&& !in_external_macro(cx.sess(), first.span)
+			&& !first.span.in_external_macro(cx.sess().source_map())
             && is_same(cx, lhs0, rhs1)
             && is_same(cx, lhs1, rhs0)
 			&& !is_same(cx, lhs1, rhs1) // Ignore a = b; a = a (#10421)
diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs
index 569812d8106..9993e6ae18b 100644
--- a/clippy_lints/src/to_digit_is_some.rs
+++ b/clippy_lints/src/to_digit_is_some.rs
@@ -55,13 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
                     if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind
                         && let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id)
                         && let Some(to_digits_def_id) = to_digits_call_res.opt_def_id()
-                        && match_def_path(cx, to_digits_def_id, &[
-                            "core",
-                            "char",
-                            "methods",
-                            "<impl char>",
-                            "to_digit",
-                        ])
+                        && match_def_path(
+                            cx,
+                            to_digits_def_id,
+                            &["core", "char", "methods", "<impl char>", "to_digit"],
+                        )
                     {
                         Some((false, char_arg, radix_arg))
                     } else {
diff --git a/clippy_lints/src/transmute/missing_transmute_annotations.rs b/clippy_lints/src/transmute/missing_transmute_annotations.rs
index bed4e60ba62..4961dd6b280 100644
--- a/clippy_lints/src/transmute/missing_transmute_annotations.rs
+++ b/clippy_lints/src/transmute/missing_transmute_annotations.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use rustc_errors::Applicability;
 use rustc_hir::{GenericArg, HirId, LetStmt, Node, Path, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Ty;
 
 use crate::transmute::MISSING_TRANSMUTE_ANNOTATIONS;
@@ -44,7 +43,7 @@ pub(super) fn check<'tcx>(
     expr_hir_id: HirId,
 ) -> bool {
     let last = path.segments.last().unwrap();
-    if in_external_macro(cx.tcx.sess, last.ident.span) {
+    if last.ident.span.in_external_macro(cx.tcx.sess.source_map()) {
         // If it comes from a non-local macro, we ignore it.
         return false;
     }
diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs
index 1cb0f837227..7c83a218799 100644
--- a/clippy_lints/src/transmute/mod.rs
+++ b/clippy_lints/src/transmute/mod.rs
@@ -49,7 +49,6 @@ declare_clippy_lint! {
     "transmutes that are confusing at best, undefined behavior at worst and always useless"
 }
 
-// FIXME: Move this to `complexity` again, after #5343 is fixed
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for transmutes to the original type of the object
diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs
index 008e09dd8bd..c7aefc65f70 100644
--- a/clippy_lints/src/tuple_array_conversions.rs
+++ b/clippy_lints/src/tuple_array_conversions.rs
@@ -7,7 +7,6 @@ use itertools::Itertools;
 use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
 use std::iter::once;
@@ -56,7 +55,7 @@ impl TupleArrayConversions {
 
 impl LateLintPass<'_> for TupleArrayConversions {
     fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if in_external_macro(cx.sess(), expr.span) || !self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) {
+        if expr.span.in_external_macro(cx.sess().source_map()) || !self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) {
             return;
         }
 
diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs
index 391c36df492..579cbf447a2 100644
--- a/clippy_lints/src/types/mod.rs
+++ b/clippy_lints/src/types/mod.rs
@@ -386,22 +386,30 @@ impl<'tcx> LateLintPass<'tcx> for Types {
 
         let is_exported = cx.effective_visibilities.is_exported(def_id);
 
-        self.check_fn_decl(cx, decl, CheckTyContext {
-            is_in_trait_impl,
-            in_body: matches!(fn_kind, FnKind::Closure),
-            is_exported,
-            ..CheckTyContext::default()
-        });
+        self.check_fn_decl(
+            cx,
+            decl,
+            CheckTyContext {
+                is_in_trait_impl,
+                in_body: matches!(fn_kind, FnKind::Closure),
+                is_exported,
+                ..CheckTyContext::default()
+            },
+        );
     }
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
 
         match item.kind {
-            ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(cx, ty, CheckTyContext {
-                is_exported,
-                ..CheckTyContext::default()
-            }),
+            ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(
+                cx,
+                ty,
+                CheckTyContext {
+                    is_exported,
+                    ..CheckTyContext::default()
+                },
+            ),
             // functions, enums, structs, impls and traits are covered
             _ => (),
         }
@@ -419,10 +427,14 @@ impl<'tcx> LateLintPass<'tcx> for Types {
                     false
                 };
 
-                self.check_ty(cx, ty, CheckTyContext {
-                    is_in_trait_impl,
-                    ..CheckTyContext::default()
-                });
+                self.check_ty(
+                    cx,
+                    ty,
+                    CheckTyContext {
+                        is_in_trait_impl,
+                        ..CheckTyContext::default()
+                    },
+                );
             },
             // Methods are covered by check_fn.
             // Type aliases are ignored because oftentimes it's impossible to
@@ -438,10 +450,14 @@ impl<'tcx> LateLintPass<'tcx> for Types {
 
         let is_exported = cx.effective_visibilities.is_exported(field.def_id);
 
-        self.check_ty(cx, field.ty, CheckTyContext {
-            is_exported,
-            ..CheckTyContext::default()
-        });
+        self.check_ty(
+            cx,
+            field.ty,
+            CheckTyContext {
+                is_exported,
+                ..CheckTyContext::default()
+            },
+        );
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'tcx>) {
@@ -469,10 +485,14 @@ impl<'tcx> LateLintPass<'tcx> for Types {
 
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
         if let Some(ty) = local.ty {
-            self.check_ty(cx, ty, CheckTyContext {
-                in_body: true,
-                ..CheckTyContext::default()
-            });
+            self.check_ty(
+                cx,
+                ty,
+                CheckTyContext {
+                    in_body: true,
+                    ..CheckTyContext::default()
+                },
+            );
         }
     }
 }
diff --git a/clippy_lints/src/unconditional_recursion.rs b/clippy_lints/src/unconditional_recursion.rs
index 3fc08e8192d..207f2ef4563 100644
--- a/clippy_lints/src/unconditional_recursion.rs
+++ b/clippy_lints/src/unconditional_recursion.rs
@@ -257,10 +257,13 @@ fn is_default_method_on_current_ty<'tcx>(tcx: TyCtxt<'tcx>, qpath: QPath<'tcx>,
             }
             if matches!(
                 ty.kind,
-                TyKind::Path(QPath::Resolved(_, hir::Path {
-                    res: Res::SelfTyAlias { .. },
-                    ..
-                },))
+                TyKind::Path(QPath::Resolved(
+                    _,
+                    hir::Path {
+                        res: Res::SelfTyAlias { .. },
+                        ..
+                    },
+                ))
             ) {
                 return true;
             }
diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs
index 45d730985bb..5e5d6a9e333 100644
--- a/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -11,7 +11,6 @@ use rustc_hir as hir;
 use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{BytePos, Pos, RelativeBytePos, Span, SyntaxContext};
 
@@ -111,7 +110,7 @@ impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECES
 impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
         if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
-            && !in_external_macro(cx.tcx.sess, block.span)
+            && !block.span.in_external_macro(cx.tcx.sess.source_map())
             && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id)
             && !is_unsafe_from_proc_macro(cx, block.span)
             && !block_has_safety_comment(cx, block.span)
@@ -143,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
 
         if let Some(tail) = block.expr
             && !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, tail.hir_id)
-            && !in_external_macro(cx.tcx.sess, tail.span)
+            && !tail.span.in_external_macro(cx.tcx.sess.source_map())
             && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, tail.span, tail.hir_id)
             && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, tail, pos)
         {
@@ -167,7 +166,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
             return;
         };
         if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, stmt.hir_id)
-            && !in_external_macro(cx.tcx.sess, stmt.span)
+            && !stmt.span.in_external_macro(cx.tcx.sess.source_map())
             && let HasSafetyComment::Yes(pos) = stmt_has_safety_comment(cx, stmt.span, stmt.hir_id)
             && let Some(help_span) = expr_has_unnecessary_safety_comment(cx, expr, pos)
         {
@@ -184,7 +183,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
     }
 
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        if in_external_macro(cx.tcx.sess, item.span) {
+        if item.span.in_external_macro(cx.tcx.sess.source_map()) {
             return;
         }
 
diff --git a/clippy_lints/src/uninhabited_references.rs b/clippy_lints/src/uninhabited_references.rs
index ee9ef017253..b342f37f0c5 100644
--- a/clippy_lints/src/uninhabited_references.rs
+++ b/clippy_lints/src/uninhabited_references.rs
@@ -3,7 +3,6 @@ use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnRetTy, TyKind, UnOp};
 use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
@@ -40,7 +39,7 @@ declare_lint_pass!(UninhabitedReferences => [UNINHABITED_REFERENCES]);
 
 impl LateLintPass<'_> for UninhabitedReferences {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
-        if in_external_macro(cx.tcx.sess, expr.span) {
+        if expr.span.in_external_macro(cx.tcx.sess.source_map()) {
             return;
         }
 
@@ -66,7 +65,7 @@ impl LateLintPass<'_> for UninhabitedReferences {
         span: Span,
         _: LocalDefId,
     ) {
-        if in_external_macro(cx.tcx.sess, span) || matches!(kind, FnKind::Closure) {
+        if span.in_external_macro(cx.tcx.sess.source_map()) || matches!(kind, FnKind::Closure) {
             return;
         }
         if let FnRetTy::Return(hir_ty) = fndecl.output
diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs
index 93ed15777e0..7803d5115c9 100644
--- a/clippy_lints/src/uninit_vec.rs
+++ b/clippy_lints/src/uninit_vec.rs
@@ -4,7 +4,6 @@ use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
 use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while};
 use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::{Span, sym};
@@ -64,7 +63,7 @@ declare_lint_pass!(UninitVec => [UNINIT_VEC]);
 // Threads: https://github.com/rust-lang/rust-clippy/pull/7682#discussion_r710998368
 impl<'tcx> LateLintPass<'tcx> for UninitVec {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
-        if !in_external_macro(cx.tcx.sess, block.span) {
+        if !block.span.in_external_macro(cx.tcx.sess.source_map()) {
             for w in block.stmts.windows(2) {
                 if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind {
                     handle_uninit_vec_pair(cx, &w[0], expr);
diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs
index 660bdb9e2be..00b80e827d8 100644
--- a/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/clippy_lints/src/unit_types/let_unit_value.rs
@@ -7,7 +7,6 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{Visitor, walk_body};
 use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, LetStmt, MatchSource, Node, PatKind, QPath, TyKind};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::lint::{in_external_macro, is_from_async_await};
 use rustc_middle::ty;
 
 use super::LET_UNIT_VALUE;
@@ -22,8 +21,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
 
     if let Some(init) = local.init
         && !local.pat.span.from_expansion()
-        && !in_external_macro(cx.sess(), local.span)
-        && !is_from_async_await(local.span)
+        && !local.span.in_external_macro(cx.sess().source_map())
+        && !local.span.is_from_async_await()
         && cx.typeck_results().pat_ty(local.pat).is_unit()
     {
         // skip `let awa = ()`
diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs
index 47d6fe7db76..019ae16ca85 100644
--- a/clippy_lints/src/unit_types/unit_arg.rs
+++ b/clippy_lints/src/unit_types/unit_arg.rs
@@ -177,7 +177,7 @@ fn fmt_stmts_and_call(
     stmts_and_call.push(call_snippet_with_replacements);
     stmts_and_call = stmts_and_call
         .into_iter()
-        .map(|v| reindent_multiline(v.into(), true, Some(call_expr_indent)).into_owned())
+        .map(|v| reindent_multiline(&v, true, Some(call_expr_indent)))
         .collect();
 
     let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent)));
@@ -185,8 +185,7 @@ fn fmt_stmts_and_call(
     let parent_node = cx.tcx.parent_hir_node(call_expr.hir_id);
     if !matches!(parent_node, Node::Block(_)) && !matches!(parent_node, Node::Stmt(_)) {
         let block_indent = call_expr_indent + 4;
-        stmts_and_call_snippet =
-            reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned();
+        stmts_and_call_snippet = reindent_multiline(&stmts_and_call_snippet, true, Some(block_indent));
         stmts_and_call_snippet = format!(
             "{{\n{}{}\n{}}}",
             " ".repeat(block_indent),
diff --git a/clippy_lints/src/unused_result_ok.rs b/clippy_lints/src/unused_result_ok.rs
index 0c0d10eac5b..958f19d1833 100644
--- a/clippy_lints/src/unused_result_ok.rs
+++ b/clippy_lints/src/unused_result_ok.rs
@@ -4,7 +4,6 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
 
@@ -39,7 +38,7 @@ impl LateLintPass<'_> for UnusedResultOk {
             && let ExprKind::MethodCall(ok_path, recv, [], ..) = expr.kind //check is expr.ok() has type Result<T,E>.ok(, _)
             && ok_path.ident.as_str() == "ok"
             && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
-            && !in_external_macro(cx.sess(), stmt.span)
+            && !stmt.span.in_external_macro(cx.sess().source_map())
         {
             let ctxt = expr.span.ctxt();
             let mut applicability = Applicability::MaybeIncorrect;
diff --git a/clippy_lints/src/unused_trait_names.rs b/clippy_lints/src/unused_trait_names.rs
index 17ee5fc20ca..f8341583435 100644
--- a/clippy_lints/src/unused_trait_names.rs
+++ b/clippy_lints/src/unused_trait_names.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Item, ItemKind, UseKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext as _};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Visibility;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::kw;
@@ -63,7 +62,7 @@ impl_lint_pass!(UnusedTraitNames => [UNUSED_TRAIT_NAMES]);
 impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if self.msrv.meets(msrvs::UNDERSCORE_IMPORTS)
-            && !in_external_macro(cx.sess(), item.span)
+            && !item.span.in_external_macro(cx.sess().source_map())
             && let ItemKind::Use(path, UseKind::Single) = item.kind
             // Ignore imports that already use Underscore
             && item.ident.name != kw::Underscore
diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs
index eaa119b045f..6a952c0d97a 100644
--- a/clippy_lints/src/unwrap.rs
+++ b/clippy_lints/src/unwrap.rs
@@ -8,7 +8,6 @@ use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegmen
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::declare_lint_pass;
@@ -292,7 +291,7 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // Shouldn't lint when `expr` is in macro.
-        if in_external_macro(self.cx.tcx.sess, expr.span) {
+        if expr.span.in_external_macro(self.cx.tcx.sess.source_map()) {
             return;
         }
         if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) {
diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs
index c3843279ba2..3449468ef48 100644
--- a/clippy_lints/src/upper_case_acronyms.rs
+++ b/clippy_lints/src/upper_case_acronyms.rs
@@ -4,7 +4,6 @@ use core::mem::replace;
 use rustc_errors::Applicability;
 use rustc_hir::{HirId, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::Ident;
 
@@ -126,7 +125,7 @@ fn check_ident(cx: &LateContext<'_>, ident: &Ident, hir_id: HirId, be_aggressive
 impl LateLintPass<'_> for UpperCaseAcronyms {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
         // do not lint public items or in macros
-        if in_external_macro(cx.sess(), it.span)
+        if it.span.in_external_macro(cx.sess().source_map())
             || (self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(it.owner_id.def_id))
         {
             return;
diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs
index 84b6430294f..569260eda34 100644
--- a/clippy_lints/src/use_self.rs
+++ b/clippy_lints/src/use_self.rs
@@ -2,7 +2,7 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_from_proc_macro;
 use clippy_utils::msrvs::{self, Msrv};
-use clippy_utils::ty::same_type_and_consts;
+use clippy_utils::ty::{same_type_and_consts, ty_from_hir_ty};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -10,9 +10,8 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
 use rustc_hir::{
     self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind,
-    HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
+    HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind,
 };
-use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty as MiddleTy;
 use rustc_session::impl_lint_pass;
@@ -73,7 +72,6 @@ impl UseSelf {
 enum StackItem {
     Check {
         impl_id: LocalDefId,
-        in_body: u32,
         types_to_skip: FxHashSet<HirId>,
     },
     NoCheck,
@@ -96,8 +94,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
                 .as_ref()
                 .is_none_or(|params| params.parenthesized == GenericArgsParentheses::No)
             && !item.span.from_expansion()
+            // expensive, should be last check
             && !is_from_proc_macro(cx, item)
-        // expensive, should be last check
         {
             // Self cannot be used inside const generic parameters
             let types_to_skip = generics
@@ -117,7 +115,6 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
                 .collect();
             StackItem::Check {
                 impl_id: item.owner_id.def_id,
-                in_body: 0,
                 types_to_skip,
             }
         } else {
@@ -131,6 +128,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
+        // Checking items of `impl Self` blocks in which macro expands into.
+        if impl_item.span.from_expansion() {
+            self.stack.push(StackItem::NoCheck);
+            return;
+        }
         // We want to skip types in trait `impl`s that aren't declared as `Self` in the trait
         // declaration. The collection of those types is all this method implementation does.
         if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind
@@ -186,18 +188,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
         }
     }
 
-    fn check_body(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
-        // `lower_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies
-        // we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`.
-        // However the `node_type()` method can *only* be called in bodies.
-        if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() {
-            *in_body = in_body.saturating_add(1);
-        }
-    }
-
-    fn check_body_post(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
-        if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() {
-            *in_body = in_body.saturating_sub(1);
+    fn check_impl_item_post(&mut self, _: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
+        if impl_item.span.from_expansion()
+            && let Some(StackItem::NoCheck) = self.stack.last()
+        {
+            self.stack.pop();
         }
     }
 
@@ -206,7 +201,6 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
             && let Some(&StackItem::Check {
                 impl_id,
-                in_body,
                 ref types_to_skip,
             }) = self.stack.last()
             && let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind
@@ -215,12 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
                 Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _)
             )
             && !types_to_skip.contains(&hir_ty.hir_id)
-            && let ty = if in_body > 0 {
-                cx.typeck_results().node_type(hir_ty.hir_id)
-            } else {
-                // We don't care about ignoring infer vars here
-                lower_ty(cx.tcx, hir_ty.as_unambig_ty())
-            }
+            && let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty())
             && let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity()
             && same_type_and_consts(ty, impl_ty)
             // Ensure the type we encounter and the one from the impl have the same lifetime parameters. It may be that
@@ -258,7 +247,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
             && let Some(&StackItem::Check { impl_id, .. }) = self.stack.last()
             // get the path from the pattern
-            && let PatKind::Path(QPath::Resolved(_, path))
+            && let PatKind::Expr(&PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. })
                  | PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
                  | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind
             && cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).instantiate_identity()
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index 4dcc8ac7fb0..6bad78cf871 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -708,11 +708,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 self.qpath(qpath);
                 self.slice(fields, |pat| self.pat(pat));
             },
-            PatKind::Path(ref qpath) => {
-                bind!(self, qpath);
-                kind!("Path(ref {qpath})");
-                self.qpath(qpath);
-            },
             PatKind::Tuple(fields, skip_pos) => {
                 bind!(self, fields);
                 kind!("Tuple({fields}, {skip_pos:?})");
diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs
index d87d554eb07..3c23662e9d1 100644
--- a/clippy_lints/src/vec_init_then_push.rs
+++ b/clippy_lints/src/vec_init_then_push.rs
@@ -8,7 +8,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, Mutability, PatKind, QPath, Stmt, StmtKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
 use rustc_span::{Span, Symbol};
 
@@ -158,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'tcx>) {
         if let Some(init_expr) = local.init
             && let PatKind::Binding(BindingMode::MUT, id, name, None) = local.pat.kind
-            && !in_external_macro(cx.sess(), local.span)
+            && !local.span.in_external_macro(cx.sess().source_map())
             && let Some(init) = get_vec_init_kind(cx, init_expr)
             && !matches!(init, VecInitKind::WithExprCapacity(_))
         {
@@ -181,7 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
             && let ExprKind::Path(QPath::Resolved(None, path)) = left.kind
             && let [name] = &path.segments
             && let Res::Local(id) = path.res
-            && !in_external_macro(cx.sess(), expr.span)
+            && !expr.span.in_external_macro(cx.sess().source_map())
             && let Some(init) = get_vec_init_kind(cx, right)
             && !matches!(init, VecInitKind::WithExprCapacity(_))
         {
diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs
index 2e5fc5834e2..d17b3df9921 100644
--- a/clippy_lints/src/visibility.rs
+++ b/clippy_lints/src/visibility.rs
@@ -3,7 +3,6 @@ use clippy_utils::source::SpanRangeExt;
 use rustc_ast::ast::{Item, VisibilityKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
 use rustc_span::symbol::kw;
@@ -79,7 +78,7 @@ declare_lint_pass!(Visibility => [NEEDLESS_PUB_SELF, PUB_WITH_SHORTHAND, PUB_WIT
 
 impl EarlyLintPass for Visibility {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if !in_external_macro(cx.sess(), item.span)
+        if !item.span.in_external_macro(cx.sess().source_map())
             && let VisibilityKind::Restricted { path, shorthand, .. } = &item.vis.kind
         {
             if **path == kw::SelfLower && !is_from_proc_macro(cx, item.vis.span) {
diff --git a/clippy_lints/src/zero_sized_map_values.rs b/clippy_lints/src/zero_sized_map_values.rs
index 1221abec1ab..3f64d18e1ad 100644
--- a/clippy_lints/src/zero_sized_map_values.rs
+++ b/clippy_lints/src/zero_sized_map_values.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item};
+use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item, ty_from_hir_ty};
 use rustc_hir::{self as hir, AmbigArg, HirId, ItemKind, Node};
-use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf as _;
-use rustc_middle::ty::{self, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self, TypeVisitableExt};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
 
@@ -82,15 +81,3 @@ fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool {
     }
     false
 }
-
-fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
-    cx.maybe_typeck_results()
-        .and_then(|results| {
-            if results.hir_owner == hir_ty.hir_id.owner {
-                results.node_type_opt(hir_ty.hir_id)
-            } else {
-                None
-            }
-        })
-        .unwrap_or_else(|| lower_ty(cx.tcx, hir_ty))
-}
diff --git a/clippy_utils/README.md b/clippy_utils/README.md
index 251e3dfe41b..41f3b1cbd50 100644
--- a/clippy_utils/README.md
+++ b/clippy_utils/README.md
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2025-01-28
+nightly-2025-02-06
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/clippy_utils/src/ast_utils/mod.rs b/clippy_utils/src/ast_utils/mod.rs
index 2eb09bac8d8..ab5f97199ce 100644
--- a/clippy_utils/src/ast_utils/mod.rs
+++ b/clippy_utils/src/ast_utils/mod.rs
@@ -362,18 +362,21 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
                 defaultness: ld,
                 sig: lf,
                 generics: lg,
+                contract: lc,
                 body: lb,
             }),
             Fn(box ast::Fn {
                 defaultness: rd,
                 sig: rf,
                 generics: rg,
+                contract: rc,
                 body: rb,
             }),
         ) => {
             eq_defaultness(*ld, *rd)
                 && eq_fn_sig(lf, rf)
                 && eq_generics(lg, rg)
+                && eq_opt_fn_contract(lc, rc)
                 && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
         },
         (Mod(lu, lmk), Mod(ru, rmk)) => {
@@ -497,18 +500,21 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
                 defaultness: ld,
                 sig: lf,
                 generics: lg,
+                contract: lc,
                 body: lb,
             }),
             Fn(box ast::Fn {
                 defaultness: rd,
                 sig: rf,
                 generics: rg,
+                contract: rc,
                 body: rb,
             }),
         ) => {
             eq_defaultness(*ld, *rd)
                 && eq_fn_sig(lf, rf)
                 && eq_generics(lg, rg)
+                && eq_opt_fn_contract(lc, rc)
                 && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
         },
         (
@@ -559,18 +565,21 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
                 defaultness: ld,
                 sig: lf,
                 generics: lg,
+                contract: lc,
                 body: lb,
             }),
             Fn(box ast::Fn {
                 defaultness: rd,
                 sig: rf,
                 generics: rg,
+                contract: rc,
                 body: rb,
             }),
         ) => {
             eq_defaultness(*ld, *rd)
                 && eq_fn_sig(lf, rf)
                 && eq_generics(lg, rg)
+                && eq_opt_fn_contract(lc, rc)
                 && both(lb.as_ref(), rb.as_ref(), |l, r| eq_block(l, r))
         },
         (
@@ -653,6 +662,17 @@ pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
         && eq_ext(&l.ext, &r.ext)
 }
 
+#[expect(clippy::ref_option, reason = "This is the type how it is stored in the AST")]
+pub fn eq_opt_fn_contract(l: &Option<P<FnContract>>, r: &Option<P<FnContract>>) -> bool {
+    match (l, r) {
+        (Some(l), Some(r)) => {
+            eq_expr_opt(l.requires.as_ref(), r.requires.as_ref()) && eq_expr_opt(l.ensures.as_ref(), r.ensures.as_ref())
+        },
+        (None, None) => true,
+        (Some(_), None) | (None, Some(_)) => false,
+    }
+}
+
 pub fn eq_generics(l: &Generics, r: &Generics) -> bool {
     over(&l.params, &r.params, eq_generic_param)
         && over(&l.where_clause.predicates, &r.where_clause.predicates, |l, r| {
diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs
index d76231a6eea..4bbf28115a6 100644
--- a/clippy_utils/src/hir_utils.rs
+++ b/clippy_utils/src/hir_utils.rs
@@ -10,7 +10,7 @@ use rustc_hir::{
     AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField,
     ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName,
     Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr,
-    TraitBoundModifiers, Ty, TyKind,
+    TraitBoundModifiers, Ty, TyKind, TyPat, TyPatKind,
 };
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::LateContext;
@@ -524,7 +524,6 @@ impl HirEqInterExpr<'_, '_, '_> {
                 }
                 eq
             },
-            (PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r),
             (&PatKind::Expr(l), &PatKind::Expr(r)) => self.eq_pat_expr(l, r),
             (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
             (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
@@ -1103,6 +1102,22 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         }
     }
 
+    pub fn hash_ty_pat(&mut self, pat: &TyPat<'_>) {
+        std::mem::discriminant(&pat.kind).hash(&mut self.s);
+        match pat.kind {
+            TyPatKind::Range(s, e, i) => {
+                if let Some(s) = s {
+                    self.hash_const_arg(s);
+                }
+                if let Some(e) = e {
+                    self.hash_const_arg(e);
+                }
+                std::mem::discriminant(&i).hash(&mut self.s);
+            },
+            TyPatKind::Err(_) => {},
+        }
+    }
+
     pub fn hash_pat(&mut self, pat: &Pat<'_>) {
         std::mem::discriminant(&pat.kind).hash(&mut self.s);
         match pat.kind {
@@ -1120,7 +1135,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_pat(pat);
                 }
             },
-            PatKind::Path(ref qpath) => self.hash_qpath(qpath),
             PatKind::Range(s, e, i) => {
                 if let Some(s) = s {
                     self.hash_pat_expr(s);
@@ -1249,7 +1263,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             },
             TyKind::Pat(ty, pat) => {
                 self.hash_ty(ty);
-                self.hash_pat(pat);
+                self.hash_ty_pat(pat);
             },
             TyKind::Ptr(mut_ty) => {
                 self.hash_ty(mut_ty.ty);
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 2f5639b686b..0d9502c50db 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -39,6 +39,7 @@ extern crate rustc_data_structures;
 extern crate rustc_driver;
 extern crate rustc_errors;
 extern crate rustc_hir;
+extern crate rustc_hir_analysis;
 extern crate rustc_hir_typeck;
 extern crate rustc_index;
 extern crate rustc_infer;
@@ -106,18 +107,19 @@ use rustc_hir::{
     self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext,
     Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind,
     ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat,
-    PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef,
-    TyKind, UnOp, def,
+    PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
+    TraitItemRef, TraitRef, TyKind, UnOp, def,
 };
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::place::PlaceBase;
+use rustc_middle::mir::{AggregateKind, Operand, RETURN_PLACE, Rvalue, StatementKind, TerminatorKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
     self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgKind, GenericArgsRef, IntTy, Ty,
-    TyCtxt, TypeVisitableExt, UintTy, UpvarCapture,
+    TyCtxt, TypeFlags, TypeVisitableExt, UintTy, UpvarCapture,
 };
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
@@ -341,11 +343,12 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
     matches!(pat.kind, PatKind::Wild)
 }
 
-// Checks if arm has the form `None => _`
+// Checks if arm has the form `None => None`
 pub fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     matches!(
         arm.pat.kind,
-        PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id),OptionNone)
+        PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
+            if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone)
     )
 }
 
@@ -568,7 +571,20 @@ macro_rules! maybe_path {
     };
 }
 maybe_path!(Expr, ExprKind);
-maybe_path!(Pat, PatKind);
+impl<'hir> MaybePath<'hir> for Pat<'hir> {
+    fn hir_id(&self) -> HirId {
+        self.hir_id
+    }
+    fn qpath_opt(&self) -> Option<&QPath<'hir>> {
+        match &self.kind {
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(qpath),
+                ..
+            }) => Some(qpath),
+            _ => None,
+        }
+    }
+}
 maybe_path!(Ty, TyKind);
 
 /// If `maybe_path` is a path node, resolves it, otherwise returns `Res::Err`
@@ -904,22 +920,101 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
 }
 
 /// Returns true if the expr is equal to `Default::default` when evaluated.
-pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) -> bool {
+pub fn is_default_equivalent_call(
+    cx: &LateContext<'_>,
+    repl_func: &Expr<'_>,
+    whole_call_expr: Option<&Expr<'_>>,
+) -> bool {
     if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind
         && let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id()
         && (is_diag_trait_item(cx, repl_def_id, sym::Default)
             || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath))
     {
-        true
-    } else {
-        false
+        return true;
+    }
+
+    // Get the type of the whole method call expression, find the exact method definition, look at
+    // its body and check if it is similar to the corresponding `Default::default()` body.
+    let Some(e) = whole_call_expr else { return false };
+    let Some(default_fn_def_id) = cx.tcx.get_diagnostic_item(sym::default_fn) else {
+        return false;
+    };
+    let Some(ty) = cx.tcx.typeck(e.hir_id.owner.def_id).expr_ty_adjusted_opt(e) else {
+        return false;
+    };
+    let args = rustc_ty::GenericArgs::for_item(cx.tcx, default_fn_def_id, |param, _| {
+        if let rustc_ty::GenericParamDefKind::Lifetime = param.kind {
+            cx.tcx.lifetimes.re_erased.into()
+        } else if param.index == 0 && param.name == kw::SelfUpper {
+            ty.into()
+        } else {
+            param.to_error(cx.tcx)
+        }
+    });
+    let instance = rustc_ty::Instance::try_resolve(cx.tcx, cx.typing_env(), default_fn_def_id, args);
+
+    let Ok(Some(instance)) = instance else { return false };
+    if let rustc_ty::InstanceKind::Item(def) = instance.def
+        && !cx.tcx.is_mir_available(def)
+    {
+        return false;
     }
+    let ExprKind::Path(ref repl_func_qpath) = repl_func.kind else {
+        return false;
+    };
+    let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id() else {
+        return false;
+    };
+
+    // Get the MIR Body for the `<Ty as Default>::default()` function.
+    // If it is a value or call (either fn or ctor), we compare its `DefId` against the one for the
+    // resolution of the expression we had in the path. This lets us identify, for example, that
+    // the body of `<Vec<T> as Default>::default()` is a `Vec::new()`, and the field was being
+    // initialized to `Vec::new()` as well.
+    let body = cx.tcx.instance_mir(instance.def);
+    for block_data in body.basic_blocks.iter() {
+        if block_data.statements.len() == 1
+            && let StatementKind::Assign(assign) = &block_data.statements[0].kind
+            && assign.0.local == RETURN_PLACE
+            && let Rvalue::Aggregate(kind, _places) = &assign.1
+            && let AggregateKind::Adt(did, variant_index, _, _, _) = &**kind
+            && let def = cx.tcx.adt_def(did)
+            && let variant = &def.variant(*variant_index)
+            && variant.fields.is_empty()
+            && let Some((_, did)) = variant.ctor
+            && did == repl_def_id
+        {
+            return true;
+        } else if block_data.statements.is_empty()
+            && let Some(term) = &block_data.terminator
+        {
+            match &term.kind {
+                TerminatorKind::Call {
+                    func: Operand::Constant(c),
+                    ..
+                } if let rustc_ty::FnDef(did, _args) = c.ty().kind()
+                    && *did == repl_def_id =>
+                {
+                    return true;
+                },
+                TerminatorKind::TailCall {
+                    func: Operand::Constant(c),
+                    ..
+                } if let rustc_ty::FnDef(did, _args) = c.ty().kind()
+                    && *did == repl_def_id =>
+                {
+                    return true;
+                },
+                _ => {},
+            }
+        }
+    }
+    false
 }
 
-/// Returns true if the expr is equal to `Default::default()` of it's type when evaluated.
+/// Returns true if the expr is equal to `Default::default()` of its type when evaluated.
 ///
-/// It doesn't cover all cases, for example indirect function calls (some of std
-/// functions are supported) but it is the best we have.
+/// It doesn't cover all cases, like struct literals, but it is a close approximation.
 pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     match &e.kind {
         ExprKind::Lit(lit) => match lit.node {
@@ -940,7 +1035,7 @@ 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, Some(e)),
         ExprKind::Call(from_func, [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([])),
@@ -1760,7 +1855,11 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
         PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
         PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),
         PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
-        PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
+        PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(qpath),
+            hir_id,
+            ..
+        }) => is_enum_variant(cx, qpath, *hir_id),
         PatKind::Or(pats) => {
             // TODO: should be the honest check, that pats is exhaustive set
             are_refutable(cx, pats)
@@ -3489,3 +3588,90 @@ pub fn leaks_droppable_temporary_with_limited_lifetime<'tcx>(cx: &LateContext<'t
     })
     .is_break()
 }
+
+/// Returns true if the specified `expr` requires coercion,
+/// meaning that it either has a coercion or propagates a coercion from one of its sub expressions.
+///
+/// Similar to [`is_adjusted`], this not only checks if an expression's type was adjusted,
+/// but also going through extra steps to see if it fits the description of [coercion sites].
+///
+/// You should used this when you want to avoid suggesting replacing an expression that is currently
+/// a coercion site or coercion propagating expression with one that is not.
+///
+/// [coercion sites]: https://doc.rust-lang.org/stable/reference/type-coercions.html#coercion-sites
+pub fn expr_requires_coercion<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool {
+    let expr_ty_is_adjusted = cx
+        .typeck_results()
+        .expr_adjustments(expr)
+        .iter()
+        // ignore `NeverToAny` adjustments, such as `panic!` call.
+        .any(|adj| !matches!(adj.kind, Adjust::NeverToAny));
+    if expr_ty_is_adjusted {
+        return true;
+    }
+
+    // Identify coercion sites and recursively check if those sites
+    // actually have type adjustments.
+    match expr.kind {
+        ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) if let Some(def_id) = fn_def_id(cx, expr) => {
+            let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity();
+
+            if !fn_sig.output().skip_binder().has_type_flags(TypeFlags::HAS_TY_PARAM) {
+                return false;
+            }
+
+            let self_arg_count = usize::from(matches!(expr.kind, ExprKind::MethodCall(..)));
+            let mut args_with_ty_param = {
+                fn_sig
+                    .inputs()
+                    .skip_binder()
+                    .iter()
+                    .skip(self_arg_count)
+                    .zip(args)
+                    .filter_map(|(arg_ty, arg)| {
+                        if arg_ty.has_type_flags(TypeFlags::HAS_TY_PARAM) {
+                            Some(arg)
+                        } else {
+                            None
+                        }
+                    })
+            };
+            args_with_ty_param.any(|arg| expr_requires_coercion(cx, arg))
+        },
+        // Struct/union initialization.
+        ExprKind::Struct(qpath, _, _) => {
+            let res = cx.typeck_results().qpath_res(qpath, expr.hir_id);
+            if let Some((_, v_def)) = adt_and_variant_of_res(cx, res) {
+                let generic_args = cx.typeck_results().node_args(expr.hir_id);
+                v_def
+                    .fields
+                    .iter()
+                    .any(|field| field.ty(cx.tcx, generic_args).has_type_flags(TypeFlags::HAS_TY_PARAM))
+            } else {
+                false
+            }
+        },
+        // Function results, including the final line of a block or a `return` expression.
+        ExprKind::Block(
+            &Block {
+                expr: Some(ret_expr), ..
+            },
+            _,
+        )
+        | ExprKind::Ret(Some(ret_expr)) => expr_requires_coercion(cx, ret_expr),
+
+        // ===== Coercion-propagation expressions =====
+        ExprKind::Array(elems) | ExprKind::Tup(elems) => elems.iter().any(|elem| expr_requires_coercion(cx, elem)),
+        // Array but with repeating syntax.
+        ExprKind::Repeat(rep_elem, _) => expr_requires_coercion(cx, rep_elem),
+        // Others that may contain coercion sites.
+        ExprKind::If(_, then, maybe_else) => {
+            expr_requires_coercion(cx, then) || maybe_else.is_some_and(|e| expr_requires_coercion(cx, e))
+        },
+        ExprKind::Match(_, arms, _) => arms
+            .iter()
+            .map(|arm| arm.body)
+            .any(|body| expr_requires_coercion(cx, body)),
+        _ => false,
+    }
+}
diff --git a/clippy_utils/src/mir/mod.rs b/clippy_utils/src/mir/mod.rs
index ccbbccd0dbf..85250f81dc4 100644
--- a/clippy_utils/src/mir/mod.rs
+++ b/clippy_utils/src/mir/mod.rs
@@ -112,10 +112,14 @@ pub fn block_in_cycle(body: &Body<'_>, block: BasicBlock) -> bool {
 
 /// Convenience wrapper around `visit_local_usage`.
 pub fn used_exactly_once(mir: &Body<'_>, local: Local) -> Option<bool> {
-    visit_local_usage(&[local], mir, Location {
-        block: START_BLOCK,
-        statement_index: 0,
-    })
+    visit_local_usage(
+        &[local],
+        mir,
+        Location {
+            block: START_BLOCK,
+            statement_index: 0,
+        },
+    )
     .map(|mut vec| {
         let LocalUsage { local_use_locs, .. } = vec.remove(0);
         let mut locations = local_use_locs
diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs
index 24f73b9df26..2e8bcfaa7af 100644
--- a/clippy_utils/src/msrvs.rs
+++ b/clippy_utils/src/msrvs.rs
@@ -37,6 +37,7 @@ msrv_aliases! {
     1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN }
     1,59,0 { THREAD_LOCAL_CONST_INIT }
     1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF }
+    1,57,0 { MAP_WHILE }
     1,56,0 { CONST_FN_UNION }
     1,55,0 { SEEK_REWIND }
     1,54,0 { INTO_KEYS }
@@ -57,6 +58,7 @@ msrv_aliases! {
     1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
     1,34,0 { TRY_FROM }
     1,33,0 { UNDERSCORE_IMPORTS }
+    1,31,0 { OPTION_REPLACE }
     1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
     1,29,0 { ITER_FLATTEN }
     1,28,0 { FROM_BOOL, REPEAT_WITH }
diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs
index f15fffc09e8..74a39235489 100644
--- a/clippy_utils/src/paths.rs
+++ b/clippy_utils/src/paths.rs
@@ -29,6 +29,7 @@ pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]
 
 // Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items.
 pub const ABORT: [&str; 3] = ["std", "process", "abort"];
+pub const BUF_READ: [&str; 3] = ["std", "io", "BufRead"];
 pub const CHILD: [&str; 3] = ["std", "process", "Child"];
 pub const CHILD_ID: [&str; 4] = ["std", "process", "Child", "id"];
 pub const CHILD_KILL: [&str; 4] = ["std", "process", "Child", "kill"];
diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs
index 287bdc9a6fd..c7890f33f27 100644
--- a/clippy_utils/src/qualify_min_const_fn.rs
+++ b/clippy_utils/src/qualify_min_const_fn.rs
@@ -116,6 +116,7 @@ fn check_rvalue<'tcx>(
         Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
         Rvalue::Repeat(operand, _)
         | Rvalue::Use(operand)
+        | Rvalue::WrapUnsafeBinder(operand, _)
         | Rvalue::Cast(
             CastKind::PointerWithExposedProvenance
             | CastKind::IntToInt
@@ -178,7 +179,10 @@ fn check_rvalue<'tcx>(
                 ))
             }
         },
-        Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks, _)
+        Rvalue::NullaryOp(
+            NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_) | NullOp::UbChecks | NullOp::ContractChecks,
+            _,
+        )
         | Rvalue::ShallowInitBox(_, _) => Ok(()),
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
@@ -289,7 +293,8 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B
             | ProjectionElem::Downcast(..)
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Subtype(_)
-            | ProjectionElem::Index(_) => {},
+            | ProjectionElem::Index(_)
+            | ProjectionElem::UnwrapUnsafeBinder(_) => {},
         }
     }
 
diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs
index eecbfb3936a..be1bd5d2e39 100644
--- a/clippy_utils/src/source.rs
+++ b/clippy_utils/src/source.rs
@@ -293,7 +293,7 @@ impl SourceFileRange {
     }
 }
 
-/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
+/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block` with no label.
 pub fn expr_block(
     sess: &impl HasSession,
     expr: &Expr<'_>,
@@ -304,10 +304,10 @@ pub fn expr_block(
 ) -> String {
     let (code, from_macro) = snippet_block_with_context(sess, expr.span, outer, default, indent_relative_to, app);
     if !from_macro
-        && let ExprKind::Block(block, _) = expr.kind
+        && let ExprKind::Block(block, None) = expr.kind
         && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
     {
-        format!("{code}")
+        code
     } else {
         // FIXME: add extra indent for the unsafe blocks:
         //     original code:   unsafe { ... }
@@ -420,11 +420,10 @@ pub fn position_before_rarrow(s: &str) -> Option<usize> {
 }
 
 /// Reindent a multiline string with possibility of ignoring the first line.
-#[expect(clippy::needless_pass_by_value)]
-pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option<usize>) -> Cow<'_, str> {
-    let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' ');
+pub fn reindent_multiline(s: &str, ignore_first: bool, indent: Option<usize>) -> String {
+    let s_space = reindent_multiline_inner(s, ignore_first, indent, ' ');
     let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t');
-    reindent_multiline_inner(&s_tab, ignore_first, indent, ' ').into()
+    reindent_multiline_inner(&s_tab, ignore_first, indent, ' ')
 }
 
 fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option<usize>, ch: char) -> String {
@@ -552,42 +551,37 @@ pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option<String> {
 ///     } // aligned with `if`
 /// ```
 /// Note that the first line of the snippet always has 0 indentation.
-pub fn snippet_block<'a>(
-    sess: &impl HasSession,
-    span: Span,
-    default: &'a str,
-    indent_relative_to: Option<Span>,
-) -> Cow<'a, str> {
+pub fn snippet_block(sess: &impl HasSession, span: Span, default: &str, indent_relative_to: Option<Span>) -> String {
     let snip = snippet(sess, span, default);
     let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
-    reindent_multiline(snip, true, indent)
+    reindent_multiline(&snip, true, indent)
 }
 
 /// Same as `snippet_block`, but adapts the applicability level by the rules of
 /// `snippet_with_applicability`.
-pub fn snippet_block_with_applicability<'a>(
+pub fn snippet_block_with_applicability(
     sess: &impl HasSession,
     span: Span,
-    default: &'a str,
+    default: &str,
     indent_relative_to: Option<Span>,
     applicability: &mut Applicability,
-) -> Cow<'a, str> {
+) -> String {
     let snip = snippet_with_applicability(sess, span, default, applicability);
     let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
-    reindent_multiline(snip, true, indent)
+    reindent_multiline(&snip, true, indent)
 }
 
-pub fn snippet_block_with_context<'a>(
+pub fn snippet_block_with_context(
     sess: &impl HasSession,
     span: Span,
     outer: SyntaxContext,
-    default: &'a str,
+    default: &str,
     indent_relative_to: Option<Span>,
     app: &mut Applicability,
-) -> (Cow<'a, str>, bool) {
+) -> (String, bool) {
     let (snip, from_macro) = snippet_with_context(sess, span, outer, default, app);
     let indent = indent_relative_to.and_then(|s| indent_of(sess, s));
-    (reindent_multiline(snip, true, indent), from_macro)
+    (reindent_multiline(&snip, true, indent), from_macro)
 }
 
 /// Same as `snippet_with_applicability`, but first walks the span up to the given context.
@@ -726,12 +720,15 @@ pub fn str_literal_to_char_literal(
             &snip[1..(snip.len() - 1)]
         };
 
-        let hint = format!("'{}'", match ch {
-            "'" => "\\'",
-            r"\" => "\\\\",
-            "\\\"" => "\"", // no need to escape `"` in `'"'`
-            _ => ch,
-        });
+        let hint = format!(
+            "'{}'",
+            match ch {
+                "'" => "\\'",
+                r"\" => "\\\\",
+                "\\\"" => "\"", // no need to escape `"` in `'"'`
+                _ => ch,
+            }
+        );
 
         Some(hint)
     } else {
@@ -745,11 +742,11 @@ mod test {
 
     #[test]
     fn test_reindent_multiline_single_line() {
-        assert_eq!("", reindent_multiline("".into(), false, None));
-        assert_eq!("...", reindent_multiline("...".into(), false, None));
-        assert_eq!("...", reindent_multiline("    ...".into(), false, None));
-        assert_eq!("...", reindent_multiline("\t...".into(), false, None));
-        assert_eq!("...", reindent_multiline("\t\t...".into(), false, None));
+        assert_eq!("", reindent_multiline("", false, None));
+        assert_eq!("...", reindent_multiline("...", false, None));
+        assert_eq!("...", reindent_multiline("    ...", false, None));
+        assert_eq!("...", reindent_multiline("\t...", false, None));
+        assert_eq!("...", reindent_multiline("\t\t...", false, None));
     }
 
     #[test]
@@ -764,7 +761,7 @@ mod test {
             y
         } else {
             z
-        }".into(), false, None));
+        }", false, None));
         assert_eq!("\
     if x {
     \ty
@@ -774,7 +771,7 @@ mod test {
         \ty
         } else {
         \tz
-        }".into(), false, None));
+        }", false, None));
     }
 
     #[test]
@@ -791,7 +788,7 @@ mod test {
 
         } else {
             z
-        }".into(), false, None));
+        }", false, None));
     }
 
     #[test]
@@ -807,6 +804,6 @@ mod test {
         y
     } else {
         z
-    }".into(), true, Some(8)));
+    }", true, Some(8)));
     }
 }
diff --git a/clippy_utils/src/str_utils.rs b/clippy_utils/src/str_utils.rs
index 1588ee452da..421b25a77fe 100644
--- a/clippy_utils/src/str_utils.rs
+++ b/clippy_utils/src/str_utils.rs
@@ -370,11 +370,9 @@ mod test {
         assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]);
         assert_eq!(camel_case_split("Abc"), vec!["Abc"]);
         assert_eq!(camel_case_split("abcDef"), vec!["abc", "Def"]);
-        assert_eq!(camel_case_split("\u{f6}\u{f6}AabABcd"), vec![
-            "\u{f6}\u{f6}",
-            "Aab",
-            "A",
-            "Bcd"
-        ]);
+        assert_eq!(
+            camel_case_split("\u{f6}\u{f6}AabABcd"),
+            vec!["\u{f6}\u{f6}", "Aab", "A", "Bcd"]
+        );
     }
 }
diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs
index f2bbdda7058..d2510eeeb0a 100644
--- a/clippy_utils/src/ty/mod.rs
+++ b/clippy_utils/src/ty/mod.rs
@@ -10,6 +10,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, FnDecl, LangItem, TyKind};
+use rustc_hir_analysis::lower_ty;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::ConstValue;
@@ -36,6 +37,19 @@ use crate::{def_path_def_ids, match_def_path, path_res};
 mod type_certainty;
 pub use type_certainty::expr_type_is_certain;
 
+/// Lower a [`hir::Ty`] to a [`rustc_middle::Ty`].
+pub fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
+    cx.maybe_typeck_results()
+        .and_then(|results| {
+            if results.hir_owner == hir_ty.hir_id.owner {
+                results.node_type_opt(hir_ty.hir_id)
+            } else {
+                None
+            }
+        })
+        .unwrap_or_else(|| lower_ty(cx.tcx, hir_ty))
+}
+
 /// Checks if the given type implements copy.
 pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     cx.type_is_copy_modulo_regions(ty)
@@ -96,7 +110,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                         return false;
                     }
 
-                    for (predicate, _span) in cx.tcx.explicit_item_super_predicates(def_id).iter_identity_copied() {
+                    for (predicate, _span) in cx.tcx.explicit_item_self_bounds(def_id).iter_identity_copied() {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
                             // and check substitutions to find `U`.
@@ -322,7 +336,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         },
         ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)),
         ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => {
-            for (predicate, _) in cx.tcx.explicit_item_super_predicates(def_id).skip_binder() {
+            for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() {
                 if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
                     if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
                         return true;
@@ -351,20 +365,26 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 /// Checks if `Ty` is normalizable. This function is useful
 /// to avoid crashes on `layout_of`.
 pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
-    is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default())
+    is_normalizable_helper(cx, param_env, ty, 0, &mut FxHashMap::default())
 }
 
 fn is_normalizable_helper<'tcx>(
     cx: &LateContext<'tcx>,
     param_env: ParamEnv<'tcx>,
     ty: Ty<'tcx>,
+    depth: usize,
     cache: &mut FxHashMap<Ty<'tcx>, bool>,
 ) -> bool {
     if let Some(&cached_result) = cache.get(&ty) {
         return cached_result;
     }
-    // prevent recursive loops, false-negative is better than endless loop leading to stack overflow
-    cache.insert(ty, false);
+    if !cx.tcx.recursion_limit().value_within_limit(depth) {
+        return false;
+    }
+    // Prevent recursive loops by answering `true` to recursive requests with the same
+    // type. This will be adjusted when the outermost call analyzes all the type
+    // components.
+    cache.insert(ty, true);
     let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
     let cause = ObligationCause::dummy();
     let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() {
@@ -373,11 +393,11 @@ fn is_normalizable_helper<'tcx>(
                 variant
                     .fields
                     .iter()
-                    .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, args), cache))
+                    .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, args), depth + 1, cache))
             }),
             _ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
                 GenericArgKind::Type(inner_ty) if inner_ty != ty => {
-                    is_normalizable_helper(cx, param_env, inner_ty, cache)
+                    is_normalizable_helper(cx, param_env, inner_ty, depth + 1, cache)
                 },
                 _ => true, // if inner_ty == ty, we've already checked it
             }),
@@ -712,7 +732,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
         ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) => sig_from_bounds(
             cx,
             ty,
-            cx.tcx.item_super_predicates(def_id).iter_instantiated(cx.tcx, args),
+            cx.tcx.item_self_bounds(def_id).iter_instantiated(cx.tcx, args),
             cx.tcx.opt_parent(def_id),
         ),
         ty::FnPtr(sig_tys, hdr) => Some(ExprFnSig::Sig(sig_tys.with(hdr), None)),
@@ -1227,6 +1247,10 @@ impl<'tcx> InteriorMut<'tcx> {
                         .find_map(|f| self.interior_mut_ty_chain(cx, f.ty(cx.tcx, args)))
                 }
             },
+            ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) {
+                Ok(normalized_ty) if ty != normalized_ty => self.interior_mut_ty_chain(cx, normalized_ty),
+                _ => None,
+            },
             _ => None,
         };
 
diff --git a/rust-toolchain b/rust-toolchain
index c15d1fe6cd3..ab760287e83 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2025-01-28"
+channel = "nightly-2025-02-06"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/rustc_tools_util/Cargo.toml b/rustc_tools_util/Cargo.toml
index cba02563948..716b1ed6144 100644
--- a/rustc_tools_util/Cargo.toml
+++ b/rustc_tools_util/Cargo.toml
@@ -1,12 +1,12 @@
 [package]
 name = "rustc_tools_util"
-version = "0.4.0"
+version = "0.4.2"
 description = "small helper to generate version information for git packages"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
 license = "MIT OR Apache-2.0"
 keywords = ["rustc", "tool", "git", "version", "hash"]
 categories = ["development-tools"]
-edition = "2024"
+edition = "2021" # Keep this, for this crate's MSRV to stay low
 
 [dependencies]
diff --git a/rustc_tools_util/README.md b/rustc_tools_util/README.md
index 1b11dfe0619..ff4ca6f830e 100644
--- a/rustc_tools_util/README.md
+++ b/rustc_tools_util/README.md
@@ -13,10 +13,10 @@ build = "build.rs"
 List rustc_tools_util as regular AND build dependency.
 ````toml
 [dependencies]
-rustc_tools_util = "0.4.0"
+rustc_tools_util = "0.4.2"
 
 [build-dependencies]
-rustc_tools_util = "0.4.0"
+rustc_tools_util = "0.4.2"
 ````
 
 In `build.rs`, generate the data in your `main()`
diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs
index 16be02f4a40..423154a69fa 100644
--- a/rustc_tools_util/src/lib.rs
+++ b/rustc_tools_util/src/lib.rs
@@ -28,9 +28,8 @@ macro_rules! get_version_info {
     }};
 }
 
-/// This macro can be used in `build.rs` to automatically set the needed
-/// environment values, namely `GIT_HASH`, `COMMIT_DATE` and
-/// `RUSTC_RELEASE_CHANNEL`
+/// This macro can be used in `build.rs` to automatically set the needed environment values, namely
+/// `GIT_HASH`, `COMMIT_DATE`  and `RUSTC_RELEASE_CHANNEL`
 #[macro_export]
 macro_rules! setup_version_info {
     () => {{
@@ -43,7 +42,11 @@ macro_rules! setup_version_info {
             "cargo:rustc-env=COMMIT_DATE={}",
             $crate::get_commit_date().unwrap_or_default()
         );
-        println!("cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", $crate::get_channel());
+        let compiler_version = $crate::get_compiler_version();
+        println!(
+            "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
+            $crate::get_channel(compiler_version)
+        );
     }};
 }
 
@@ -87,16 +90,17 @@ impl std::fmt::Debug for VersionInfo {
             "VersionInfo {{ crate_name: \"{}\", major: {}, minor: {}, patch: {}",
             self.crate_name, self.major, self.minor, self.patch,
         )?;
-        if self.commit_hash.is_some() {
-            write!(
-                f,
-                ", commit_hash: \"{}\", commit_date: \"{}\" }}",
-                self.commit_hash.clone().unwrap_or_default().trim(),
-                self.commit_date.clone().unwrap_or_default().trim()
-            )?;
-        } else {
-            write!(f, " }}")?;
+        if let Some(ref commit_hash) = self.commit_hash {
+            write!(f, ", commit_hash: \"{}\"", commit_hash.trim(),)?;
+        }
+        if let Some(ref commit_date) = self.commit_date {
+            write!(f, ", commit_date: \"{}\"", commit_date.trim())?;
         }
+        if let Some(ref host_compiler) = self.host_compiler {
+            write!(f, ", host_compiler: \"{}\"", host_compiler.trim())?;
+        }
+
+        write!(f, " }}")?;
 
         Ok(())
     }
@@ -152,22 +156,27 @@ pub fn get_commit_date() -> Option<String> {
 }
 
 #[must_use]
-pub fn get_channel() -> String {
+pub fn get_compiler_version() -> Option<String> {
+    get_output("rustc", &["-V"])
+}
+
+#[must_use]
+pub fn get_channel(compiler_version: Option<String>) -> String {
     if let Ok(channel) = std::env::var("CFG_RELEASE_CHANNEL") {
         return channel;
     }
 
     // if that failed, try to ask rustc -V, do some parsing and find out
-    if let Some(rustc_output) = get_output("rustc", &["-V"]) {
+    if let Some(rustc_output) = compiler_version {
         if rustc_output.contains("beta") {
             return String::from("beta");
-        } else if rustc_output.contains("stable") {
-            return String::from("stable");
+        } else if rustc_output.contains("nightly") {
+            return String::from("nightly");
         }
     }
 
-    // default to nightly
-    String::from("nightly")
+    // default to stable
+    String::from("stable")
 }
 
 #[cfg(test)]
@@ -179,17 +188,19 @@ mod test {
         let vi = get_version_info!();
         assert_eq!(vi.major, 0);
         assert_eq!(vi.minor, 4);
-        assert_eq!(vi.patch, 0);
+        assert_eq!(vi.patch, 2);
         assert_eq!(vi.crate_name, "rustc_tools_util");
         // hard to make positive tests for these since they will always change
         assert!(vi.commit_hash.is_none());
         assert!(vi.commit_date.is_none());
+
+        assert!(vi.host_compiler.is_none());
     }
 
     #[test]
     fn test_display_local() {
         let vi = get_version_info!();
-        assert_eq!(vi.to_string(), "rustc_tools_util 0.4.0");
+        assert_eq!(vi.to_string(), "rustc_tools_util 0.4.2");
     }
 
     #[test]
@@ -198,7 +209,7 @@ mod test {
         let s = format!("{vi:?}");
         assert_eq!(
             s,
-            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 4, patch: 0 }"
+            "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 4, patch: 2 }"
         );
     }
 }
diff --git a/src/driver.rs b/src/driver.rs
index 8201f332d33..e4092bcd105 100644
--- a/src/driver.rs
+++ b/src/driver.rs
@@ -166,6 +166,8 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
         // MIR passes can be enabled / disabled separately, we should figure out, what passes to
         // use for Clippy.
         config.opts.unstable_opts.mir_opt_level = Some(0);
+        config.opts.unstable_opts.mir_enable_passes =
+            vec![("CheckNull".to_owned(), false), ("CheckAlignment".to_owned(), false)];
 
         // Disable flattening and inlining of format_args!(), so the HIR matches with the AST.
         config.opts.unstable_opts.flatten_format_args = false;
@@ -195,7 +197,7 @@ pub fn main() {
     });
 
     exit(rustc_driver::catch_with_exit_code(move || {
-        let mut orig_args = rustc_driver::args::raw_args(&early_dcx)?;
+        let mut orig_args = rustc_driver::args::raw_args(&early_dcx);
 
         let has_sysroot_arg = |args: &mut [String]| -> bool {
             if has_arg(args, "--sysroot") {
@@ -237,7 +239,7 @@ pub fn main() {
             pass_sysroot_env_if_given(&mut args, sys_root_env);
 
             rustc_driver::run_compiler(&args, &mut DefaultCallbacks);
-            return Ok(());
+            return;
         }
 
         if orig_args.iter().any(|a| a == "--version" || a == "-V") {
@@ -299,7 +301,6 @@ pub fn main() {
         } else {
             rustc_driver::run_compiler(&args, &mut RustcCallbacks { clippy_args_var });
         }
-        Ok(())
     }))
 }
 
diff --git a/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.rs b/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr b/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr
new file mode 100644
index 00000000000..86e30409af0
--- /dev/null
+++ b/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr
@@ -0,0 +1,11 @@
+error: error reading Clippy's configuration file: replacement not allowed for this configuration
+  --> $DIR/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml:1:31
+   |
+LL |   await-holding-invalid-types = [
+   |  _______________________________^
+LL | |     { path = "std::string::String", replacement = "std::net::Ipv4Addr" },
+LL | | ]
+   | |_^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml b/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml
new file mode 100644
index 00000000000..f6bc59672ed
--- /dev/null
+++ b/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml
@@ -0,0 +1,3 @@
+await-holding-invalid-types = [
+    { path = "std::string::String", replacement = "std::net::Ipv4Addr" },
+]
diff --git a/tests/ui-toml/expect_used/clippy.toml b/tests/ui-toml/expect_used/clippy.toml
index 6933b816419..895de8357cf 100644
--- a/tests/ui-toml/expect_used/clippy.toml
+++ b/tests/ui-toml/expect_used/clippy.toml
@@ -1 +1,2 @@
+allow-expect-in-consts = false
 allow-expect-in-tests = true
diff --git a/tests/ui-toml/expect_used/expect_used.rs b/tests/ui-toml/expect_used/expect_used.rs
index 206788e19f0..f0b92329f97 100644
--- a/tests/ui-toml/expect_used/expect_used.rs
+++ b/tests/ui-toml/expect_used/expect_used.rs
@@ -1,4 +1,5 @@
 //@compile-flags: --test
+//@no-rustfix
 #![warn(clippy::expect_used)]
 #![allow(clippy::unnecessary_literal_unwrap)]
 
@@ -15,6 +16,14 @@ fn expect_result() {
 fn main() {
     expect_option();
     expect_result();
+
+    const SOME: Option<i32> = Some(3);
+    const UNWRAPPED: i32 = SOME.expect("Not three?");
+    //~^ ERROR: used `expect()` on an `Option` value
+    const {
+        SOME.expect("Still not three?");
+        //~^ ERROR: used `expect()` on an `Option` value
+    }
 }
 
 #[test]
diff --git a/tests/ui-toml/expect_used/expect_used.stderr b/tests/ui-toml/expect_used/expect_used.stderr
index 81691f8ac6c..b28bb7b7e0d 100644
--- a/tests/ui-toml/expect_used/expect_used.stderr
+++ b/tests/ui-toml/expect_used/expect_used.stderr
@@ -1,5 +1,5 @@
 error: used `expect()` on an `Option` value
-  --> tests/ui-toml/expect_used/expect_used.rs:7:13
+  --> tests/ui-toml/expect_used/expect_used.rs:8:13
    |
 LL |     let _ = opt.expect("");
    |             ^^^^^^^^^^^^^^
@@ -9,12 +9,28 @@ LL |     let _ = opt.expect("");
    = help: to override `-D warnings` add `#[allow(clippy::expect_used)]`
 
 error: used `expect()` on a `Result` value
-  --> tests/ui-toml/expect_used/expect_used.rs:12:13
+  --> tests/ui-toml/expect_used/expect_used.rs:13:13
    |
 LL |     let _ = res.expect("");
    |             ^^^^^^^^^^^^^^
    |
    = note: if this value is an `Err`, it will panic
 
-error: aborting due to 2 previous errors
+error: used `expect()` on an `Option` value
+  --> tests/ui-toml/expect_used/expect_used.rs:21:28
+   |
+LL |     const UNWRAPPED: i32 = SOME.expect("Not three?");
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: if this value is `None`, it will panic
+
+error: used `expect()` on an `Option` value
+  --> tests/ui-toml/expect_used/expect_used.rs:24:9
+   |
+LL |         SOME.expect("Still not three?");
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: if this value is `None`, it will panic
+
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui-toml/replaceable_disallowed_types/clippy.toml b/tests/ui-toml/replaceable_disallowed_types/clippy.toml
new file mode 100644
index 00000000000..a08a2f00f50
--- /dev/null
+++ b/tests/ui-toml/replaceable_disallowed_types/clippy.toml
@@ -0,0 +1,3 @@
+disallowed-types = [
+    { path = "std::string::String", replacement = "wrapper::String" },
+]
diff --git a/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.fixed b/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.fixed
new file mode 100644
index 00000000000..6546981bd81
--- /dev/null
+++ b/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.fixed
@@ -0,0 +1,16 @@
+#![warn(clippy::disallowed_types)]
+
+#[allow(clippy::disallowed_types)]
+mod wrapper {
+    pub struct String(std::string::String);
+
+    impl From<&str> for String {
+        fn from(value: &str) -> Self {
+            Self(std::string::String::from(value))
+        }
+    }
+}
+
+fn main() {
+    let _ = wrapper::String::from("x");
+}
diff --git a/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.rs b/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.rs
new file mode 100644
index 00000000000..d76f1af481d
--- /dev/null
+++ b/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.rs
@@ -0,0 +1,16 @@
+#![warn(clippy::disallowed_types)]
+
+#[allow(clippy::disallowed_types)]
+mod wrapper {
+    pub struct String(std::string::String);
+
+    impl From<&str> for String {
+        fn from(value: &str) -> Self {
+            Self(std::string::String::from(value))
+        }
+    }
+}
+
+fn main() {
+    let _ = String::from("x");
+}
diff --git a/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.stderr b/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.stderr
new file mode 100644
index 00000000000..bb63e6970a1
--- /dev/null
+++ b/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.stderr
@@ -0,0 +1,11 @@
+error: use of a disallowed type `std::string::String`
+  --> tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.rs:15:13
+   |
+LL |     let _ = String::from("x");
+   |             ^^^^^^ help: use: `wrapper::String`
+   |
+   = note: `-D clippy::disallowed-types` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::disallowed_types)]`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
index 17fceae0178..0986290bb0e 100644
--- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
+++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
@@ -1,5 +1,3 @@
-//@compile-flags: --crate-name conf_disallowed_methods
-
 #![allow(clippy::needless_raw_strings)]
 #![warn(clippy::disallowed_methods)]
 #![allow(clippy::useless_vec)]
diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
index e77b2b95949..edda35d647a 100644
--- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
+++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
@@ -1,5 +1,5 @@
 error: use of a disallowed method `regex::Regex::new`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:35:14
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:33:14
    |
 LL |     let re = Regex::new(r"ab.*c").unwrap();
    |              ^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     let re = Regex::new(r"ab.*c").unwrap();
    = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]`
 
 error: use of a disallowed method `regex::Regex::is_match`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:8
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:34:8
    |
 LL |     re.is_match("abc");
    |        ^^^^^^^^
@@ -16,73 +16,73 @@ LL |     re.is_match("abc");
    = note: no matching allowed
 
 error: use of a disallowed method `std::iter::Iterator::sum`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:14
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:37:14
    |
 LL |     a.iter().sum::<i32>();
    |              ^^^
 
 error: use of a disallowed method `slice::sort_unstable`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:41:7
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:39:7
    |
 LL |     a.sort_unstable();
    |       ^^^^^^^^^^^^^
 
 error: use of a disallowed method `f32::clamp`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:20
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:42:20
    |
 LL |     let _ = 2.0f32.clamp(3.0f32, 4.0f32);
    |                    ^^^^^
 
 error: use of a disallowed method `regex::Regex::new`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:47:61
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:45:61
    |
 LL |     let indirect: fn(&str) -> Result<Regex, regex::Error> = Regex::new;
    |                                                             ^^^^^^^^^^
 
 error: use of a disallowed method `f32::clamp`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:50:28
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:48:28
    |
 LL |     let in_call = Box::new(f32::clamp);
    |                            ^^^^^^^^^^
 
 error: use of a disallowed method `regex::Regex::new`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:51:53
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:49:53
    |
 LL |     let in_method_call = ["^", "$"].into_iter().map(Regex::new);
    |                                                     ^^^^^^^^^^
 
 error: use of a disallowed method `futures::stream::select_all`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:31
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:52:31
    |
 LL |     let same_name_as_module = select_all(vec![empty::<()>()]);
    |                               ^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::local_fn`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:5
    |
 LL |     local_fn();
    |     ^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::local_mod::f`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57:5
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:55:5
    |
 LL |     local_mod::f();
    |     ^^^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Struct::method`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:7
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57:7
    |
 LL |     s.method();
    |       ^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:7
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:58:7
    |
 LL |     s.provided_method();
    |       ^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method`
-  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:7
+  --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:7
    |
 LL |     s.implemented_method();
    |       ^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui-toml/toml_replaceable_disallowed_methods/clippy.toml b/tests/ui-toml/toml_replaceable_disallowed_methods/clippy.toml
new file mode 100644
index 00000000000..dc393f1355b
--- /dev/null
+++ b/tests/ui-toml/toml_replaceable_disallowed_methods/clippy.toml
@@ -0,0 +1,4 @@
+disallowed-methods = [
+    { path = "replaceable_disallowed_methods::bad", replacement = "good" },
+    { path = "replaceable_disallowed_methods::questionable", replacement = "good", reason = "a better function exists" },
+]
diff --git a/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.fixed b/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.fixed
new file mode 100644
index 00000000000..dae7ce76ba2
--- /dev/null
+++ b/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.fixed
@@ -0,0 +1,8 @@
+fn bad() {}
+fn questionable() {}
+fn good() {}
+
+fn main() {
+    good();
+    good();
+}
diff --git a/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.rs b/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.rs
new file mode 100644
index 00000000000..53678ffdf1c
--- /dev/null
+++ b/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.rs
@@ -0,0 +1,8 @@
+fn bad() {}
+fn questionable() {}
+fn good() {}
+
+fn main() {
+    bad();
+    questionable();
+}
diff --git a/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.stderr b/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.stderr
new file mode 100644
index 00000000000..b8559202942
--- /dev/null
+++ b/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.stderr
@@ -0,0 +1,17 @@
+error: use of a disallowed method `replaceable_disallowed_methods::bad`
+  --> tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.rs:6:5
+   |
+LL |     bad();
+   |     ^^^ help: use: `good`
+   |
+   = note: `-D clippy::disallowed-methods` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]`
+
+error: use of a disallowed method `replaceable_disallowed_methods::questionable`
+  --> tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.rs:7:5
+   |
+LL |     questionable();
+   |     ^^^^^^^^^^^^ help: a better function exists: `good`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 01e9f5c26a3..842059df1e9 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -5,6 +5,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            accept-comment-above-statement
            allow-comparison-to-zero
            allow-dbg-in-tests
+           allow-expect-in-consts
            allow-expect-in-tests
            allow-indexing-slicing-in-tests
            allow-mixed-uninlined-format-args
@@ -13,6 +14,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            allow-print-in-tests
            allow-private-module-inception
            allow-renamed-params-for
+           allow-unwrap-in-consts
            allow-unwrap-in-tests
            allow-useless-vec-in-tests
            allowed-dotfiles
@@ -94,6 +96,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            accept-comment-above-statement
            allow-comparison-to-zero
            allow-dbg-in-tests
+           allow-expect-in-consts
            allow-expect-in-tests
            allow-indexing-slicing-in-tests
            allow-mixed-uninlined-format-args
@@ -102,6 +105,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            allow-print-in-tests
            allow-private-module-inception
            allow-renamed-params-for
+           allow-unwrap-in-consts
            allow-unwrap-in-tests
            allow-useless-vec-in-tests
            allowed-dotfiles
@@ -183,6 +187,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            accept-comment-above-statement
            allow-comparison-to-zero
            allow-dbg-in-tests
+           allow-expect-in-consts
            allow-expect-in-tests
            allow-indexing-slicing-in-tests
            allow-mixed-uninlined-format-args
@@ -191,6 +196,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni
            allow-print-in-tests
            allow-private-module-inception
            allow-renamed-params-for
+           allow-unwrap-in-consts
            allow-unwrap-in-tests
            allow-useless-vec-in-tests
            allowed-dotfiles
diff --git a/tests/ui-toml/unwrap_used/clippy.toml b/tests/ui-toml/unwrap_used/clippy.toml
index 154626ef4e8..6fd1eb6f8d0 100644
--- a/tests/ui-toml/unwrap_used/clippy.toml
+++ b/tests/ui-toml/unwrap_used/clippy.toml
@@ -1 +1,2 @@
+allow-unwrap-in-consts = false
 allow-unwrap-in-tests = true
diff --git a/tests/ui-toml/unwrap_used/unwrap_used_const.rs b/tests/ui-toml/unwrap_used/unwrap_used_const.rs
new file mode 100644
index 00000000000..c7d8e8c1ffb
--- /dev/null
+++ b/tests/ui-toml/unwrap_used/unwrap_used_const.rs
@@ -0,0 +1,11 @@
+#![warn(clippy::unwrap_used)]
+
+fn main() {
+    const SOME: Option<i32> = Some(3);
+    const UNWRAPPED: i32 = SOME.unwrap();
+    //~^ ERROR: used `unwrap()` on an `Option` value
+    const {
+        SOME.unwrap();
+        //~^ ERROR: used `unwrap()` on an `Option` value
+    }
+}
diff --git a/tests/ui-toml/unwrap_used/unwrap_used_const.stderr b/tests/ui-toml/unwrap_used/unwrap_used_const.stderr
new file mode 100644
index 00000000000..362b41bc1bf
--- /dev/null
+++ b/tests/ui-toml/unwrap_used/unwrap_used_const.stderr
@@ -0,0 +1,22 @@
+error: used `unwrap()` on an `Option` value
+  --> tests/ui-toml/unwrap_used/unwrap_used_const.rs:5:28
+   |
+LL |     const UNWRAPPED: i32 = SOME.unwrap();
+   |                            ^^^^^^^^^^^^^
+   |
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
+   = note: `-D clippy::unwrap-used` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]`
+
+error: used `unwrap()` on an `Option` value
+  --> tests/ui-toml/unwrap_used/unwrap_used_const.rs:8:9
+   |
+LL |         SOME.unwrap();
+   |         ^^^^^^^^^^^^^
+   |
+   = note: if this value is `None`, it will panic
+   = help: consider using `expect()` to provide a better panic message
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/borrow_interior_mutable_const/projections.rs b/tests/ui/borrow_interior_mutable_const/projections.rs
new file mode 100644
index 00000000000..bbe5538fbe1
--- /dev/null
+++ b/tests/ui/borrow_interior_mutable_const/projections.rs
@@ -0,0 +1,42 @@
+#![deny(clippy::borrow_interior_mutable_const)]
+#![deny(clippy::declare_interior_mutable_const)]
+
+// Inspired by https://github.com/rust-lang/rust/pull/130543#issuecomment-2364828139
+
+use std::cell::UnsafeCell;
+
+trait Trait {
+    type Assoc;
+}
+
+type Assoc<T> = <T as Trait>::Assoc;
+
+impl Trait for u8 {
+    type Assoc = UnsafeCell<u8>;
+}
+
+impl Trait for () {
+    type Assoc = ();
+}
+
+enum MaybeMutable {
+    Mutable(Assoc<u8>),
+    Immutable(Assoc<()>),
+}
+
+const CELL: Assoc<u8> = UnsafeCell::new(0); //~ ERROR: interior mutable
+const UNIT: Assoc<()> = ();
+const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); //~ ERROR: interior mutable
+const IMMUTABLE: MaybeMutable = MaybeMutable::Immutable(UNIT);
+
+fn print_ref<T>(t: &T) {
+    let p: *const T = t;
+    println!("{p:p}")
+}
+
+fn main() {
+    print_ref(&CELL); //~ ERROR: interior mutability
+    print_ref(&UNIT);
+    print_ref(&MUTABLE); //~ ERROR: interior mutability
+    print_ref(&IMMUTABLE);
+}
diff --git a/tests/ui/borrow_interior_mutable_const/projections.stderr b/tests/ui/borrow_interior_mutable_const/projections.stderr
new file mode 100644
index 00000000000..eabaf66560a
--- /dev/null
+++ b/tests/ui/borrow_interior_mutable_const/projections.stderr
@@ -0,0 +1,44 @@
+error: a `const` item should not be interior mutable
+  --> tests/ui/borrow_interior_mutable_const/projections.rs:27:1
+   |
+LL | const CELL: Assoc<u8> = UnsafeCell::new(0);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
+note: the lint level is defined here
+  --> tests/ui/borrow_interior_mutable_const/projections.rs:2:9
+   |
+LL | #![deny(clippy::declare_interior_mutable_const)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item should not be interior mutable
+  --> tests/ui/borrow_interior_mutable_const/projections.rs:29:1
+   |
+LL | const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
+
+error: a `const` item with interior mutability should not be borrowed
+  --> tests/ui/borrow_interior_mutable_const/projections.rs:38:16
+   |
+LL |     print_ref(&CELL);
+   |                ^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+note: the lint level is defined here
+  --> tests/ui/borrow_interior_mutable_const/projections.rs:1:9
+   |
+LL | #![deny(clippy::borrow_interior_mutable_const)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a `const` item with interior mutability should not be borrowed
+  --> tests/ui/borrow_interior_mutable_const/projections.rs:40:16
+   |
+LL |     print_ref(&MUTABLE);
+   |                ^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/bytes_count_to_len.fixed b/tests/ui/bytes_count_to_len.fixed
index d20af22535a..fb31ceaad7c 100644
--- a/tests/ui/bytes_count_to_len.fixed
+++ b/tests/ui/bytes_count_to_len.fixed
@@ -1,6 +1,6 @@
 #![warn(clippy::bytes_count_to_len)]
 use std::fs::File;
-use std::io::Read;
+use std::io::{BufReader, Read};
 
 fn main() {
     // should fix, because type is String
@@ -26,8 +26,8 @@ fn main() {
     bytes.bytes().count();
 
     // The type is File, so should not fix
-    let _ = File::open("foobar").unwrap().bytes().count();
+    let _ = BufReader::new(File::open("foobar").unwrap()).bytes().count();
 
-    let f = File::open("foobar").unwrap();
+    let f = BufReader::new(File::open("foobar").unwrap());
     let _ = f.bytes().count();
 }
diff --git a/tests/ui/bytes_count_to_len.rs b/tests/ui/bytes_count_to_len.rs
index 340e6b41255..0250059afeb 100644
--- a/tests/ui/bytes_count_to_len.rs
+++ b/tests/ui/bytes_count_to_len.rs
@@ -1,6 +1,6 @@
 #![warn(clippy::bytes_count_to_len)]
 use std::fs::File;
-use std::io::Read;
+use std::io::{BufReader, Read};
 
 fn main() {
     // should fix, because type is String
@@ -26,8 +26,8 @@ fn main() {
     bytes.bytes().count();
 
     // The type is File, so should not fix
-    let _ = File::open("foobar").unwrap().bytes().count();
+    let _ = BufReader::new(File::open("foobar").unwrap()).bytes().count();
 
-    let f = File::open("foobar").unwrap();
+    let f = BufReader::new(File::open("foobar").unwrap());
     let _ = f.bytes().count();
 }
diff --git a/tests/ui/crashes/ice-10508a.rs b/tests/ui/crashes/ice-10508a.rs
new file mode 100644
index 00000000000..f45057217b4
--- /dev/null
+++ b/tests/ui/crashes/ice-10508a.rs
@@ -0,0 +1,19 @@
+// Used to overflow in `is_normalizable`
+
+use std::marker::PhantomData;
+
+struct Node<T: 'static> {
+    m: PhantomData<&'static T>,
+}
+
+struct Digit<T> {
+    elem: T,
+}
+
+enum FingerTree<T: 'static> {
+    Single(T),
+
+    Deep(Digit<T>, Box<FingerTree<Node<T>>>),
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-10508b.rs b/tests/ui/crashes/ice-10508b.rs
new file mode 100644
index 00000000000..41d4f0234b9
--- /dev/null
+++ b/tests/ui/crashes/ice-10508b.rs
@@ -0,0 +1,24 @@
+use std::marker::PhantomData;
+
+struct Digit<T> {
+    elem: T,
+}
+
+struct Node<T: 'static> {
+    m: PhantomData<&'static T>,
+}
+
+enum FingerTree<T: 'static> {
+    Single(T),
+
+    Deep(Digit<T>, Node<FingerTree<Node<T>>>),
+}
+
+enum Wrapper<T: 'static> {
+    Simple,
+    Other(FingerTree<T>),
+}
+
+fn main() {
+    let w = Some(Wrapper::Simple::<u32>);
+}
diff --git a/tests/ui/crashes/ice-10508c.rs b/tests/ui/crashes/ice-10508c.rs
new file mode 100644
index 00000000000..fb84d85fd67
--- /dev/null
+++ b/tests/ui/crashes/ice-10508c.rs
@@ -0,0 +1,7 @@
+#[derive(Debug)]
+struct S<T> {
+    t: T,
+    s: Box<S<fn(u: T)>>,
+}
+
+fn main() {}
diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs
index 5617db90a47..35646e1c239 100644
--- a/tests/ui/deprecated.rs
+++ b/tests/ui/deprecated.rs
@@ -15,5 +15,6 @@
 #![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro`
 #![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names`
 #![warn(clippy::wrong_pub_self_convention)] //~ ERROR: lint `clippy::wrong_pub_self_convention`
+#![warn(clippy::option_map_or_err_ok)] //~ ERROR: lint `clippy::option_map_or_err_ok`
 
 fn main() {}
diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr
index b3e1646c804..d7be1e583b0 100644
--- a/tests/ui/deprecated.stderr
+++ b/tests/ui/deprecated.stderr
@@ -79,5 +79,11 @@ error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong
 LL | #![warn(clippy::wrong_pub_self_convention)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 13 previous errors
+error: lint `clippy::option_map_or_err_ok` has been removed: `clippy::manual_ok_or` covers this case
+  --> tests/ui/deprecated.rs:18:9
+   |
+LL | #![warn(clippy::option_map_or_err_ok)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/derivable_impls.fixed b/tests/ui/derivable_impls.fixed
index c85f384fd6e..65bfded3883 100644
--- a/tests/ui/derivable_impls.fixed
+++ b/tests/ui/derivable_impls.fixed
@@ -144,6 +144,40 @@ impl Default for SpecializedImpl2<String> {
     }
 }
 
+#[derive(Default)]
+pub struct DirectDefaultDefaultCall {
+    v: Vec<i32>,
+}
+
+
+#[derive(Default)]
+pub struct EquivalentToDefaultDefaultCallVec {
+    v: Vec<i32>,
+}
+
+
+pub struct S {
+    x: i32,
+}
+
+impl S {
+    fn new() -> S {
+        S { x: 42 }
+    }
+}
+
+impl Default for S {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+#[derive(Default)]
+pub struct EquivalentToDefaultDefaultCallLocal {
+    v: S,
+}
+
+
 // https://github.com/rust-lang/rust-clippy/issues/7654
 
 pub struct Color {
diff --git a/tests/ui/derivable_impls.rs b/tests/ui/derivable_impls.rs
index 21d73ba8b77..eb9a007bf10 100644
--- a/tests/ui/derivable_impls.rs
+++ b/tests/ui/derivable_impls.rs
@@ -181,6 +181,55 @@ impl Default for SpecializedImpl2<String> {
     }
 }
 
+pub struct DirectDefaultDefaultCall {
+    v: Vec<i32>,
+}
+
+impl Default for DirectDefaultDefaultCall {
+    fn default() -> Self {
+        // When calling `Default::default()` in all fields, we know it is the same as deriving.
+        Self { v: Default::default() }
+    }
+}
+
+pub struct EquivalentToDefaultDefaultCallVec {
+    v: Vec<i32>,
+}
+
+impl Default for EquivalentToDefaultDefaultCallVec {
+    fn default() -> Self {
+        // The body of `<Vec as Default>::default()` is `Vec::new()`, so they are equivalent.
+        Self { v: Vec::new() }
+    }
+}
+
+pub struct S {
+    x: i32,
+}
+
+impl S {
+    fn new() -> S {
+        S { x: 42 }
+    }
+}
+
+impl Default for S {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+pub struct EquivalentToDefaultDefaultCallLocal {
+    v: S,
+}
+
+impl Default for EquivalentToDefaultDefaultCallLocal {
+    fn default() -> Self {
+        // The body of `<S as Default>::default()` is `S::new()`, so they are equivalent.
+        Self { v: S::new() }
+    }
+}
+
 // https://github.com/rust-lang/rust-clippy/issues/7654
 
 pub struct Color {
diff --git a/tests/ui/derivable_impls.stderr b/tests/ui/derivable_impls.stderr
index 0caea892358..a14c0b28c4e 100644
--- a/tests/ui/derivable_impls.stderr
+++ b/tests/ui/derivable_impls.stderr
@@ -98,7 +98,58 @@ LL ~ struct WithoutSelfParan(bool);
    |
 
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:216:1
+  --> tests/ui/derivable_impls.rs:188:1
+   |
+LL | / impl Default for DirectDefaultDefaultCall {
+LL | |     fn default() -> Self {
+LL | |         // When calling `Default::default()` in all fields, we know it is the same as deriving.
+LL | |         Self { v: Default::default() }
+LL | |     }
+LL | | }
+   | |_^
+   |
+help: replace the manual implementation with a derive attribute
+   |
+LL + #[derive(Default)]
+LL ~ pub struct DirectDefaultDefaultCall {
+   |
+
+error: this `impl` can be derived
+  --> tests/ui/derivable_impls.rs:199:1
+   |
+LL | / impl Default for EquivalentToDefaultDefaultCallVec {
+LL | |     fn default() -> Self {
+LL | |         // The body of `<Vec as Default>::default()` is `Vec::new()`, so they are equivalent.
+LL | |         Self { v: Vec::new() }
+LL | |     }
+LL | | }
+   | |_^
+   |
+help: replace the manual implementation with a derive attribute
+   |
+LL + #[derive(Default)]
+LL ~ pub struct EquivalentToDefaultDefaultCallVec {
+   |
+
+error: this `impl` can be derived
+  --> tests/ui/derivable_impls.rs:226:1
+   |
+LL | / impl Default for EquivalentToDefaultDefaultCallLocal {
+LL | |     fn default() -> Self {
+LL | |         // The body of `<S as Default>::default()` is `S::new()`, so they are equivalent.
+LL | |         Self { v: S::new() }
+LL | |     }
+LL | | }
+   | |_^
+   |
+help: replace the manual implementation with a derive attribute
+   |
+LL + #[derive(Default)]
+LL ~ pub struct EquivalentToDefaultDefaultCallLocal {
+   |
+
+error: this `impl` can be derived
+  --> tests/ui/derivable_impls.rs:265:1
    |
 LL | / impl Default for RepeatDefault1 {
 LL | |     fn default() -> Self {
@@ -114,7 +165,7 @@ LL ~ pub struct RepeatDefault1 {
    |
 
 error: this `impl` can be derived
-  --> tests/ui/derivable_impls.rs:250:1
+  --> tests/ui/derivable_impls.rs:299:1
    |
 LL | / impl Default for SimpleEnum {
 LL | |     fn default() -> Self {
@@ -132,5 +183,5 @@ LL ~     #[default]
 LL ~     Bar,
    |
 
-error: aborting due to 8 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/tests/ui/doc/link_adjacent.fixed b/tests/ui/doc/link_adjacent.fixed
new file mode 100644
index 00000000000..0ac297a6b19
--- /dev/null
+++ b/tests/ui/doc/link_adjacent.fixed
@@ -0,0 +1,52 @@
+#![warn(clippy::doc_link_code)]
+
+//! Test case for code links that are adjacent to code text.
+//!
+//! This is not an example: `first``second`
+//!
+//! Neither is this: [`first`](x)
+//!
+//! Neither is this: [`first`](x) `second`
+//!
+//! Neither is this: [first](x)`second`
+//!
+//! This is: <code>[first](x)second</code>
+//~^ ERROR: adjacent
+//!
+//! So is this <code>first[second](x)</code>
+//~^ ERROR: adjacent
+//!
+//! So is this <code>[first](x)[second](x)</code>
+//~^ ERROR: adjacent
+//!
+//! So is this <code>[first](x)[second](x)[third](x)</code>
+//~^ ERROR: adjacent
+//!
+//! So is this <code>[first](x)second[third](x)</code>
+//~^ ERROR: adjacent
+
+/// Test case for code links that are adjacent to code text.
+///
+/// This is not an example: `first``second` arst
+///
+/// Neither is this: [`first`](x) arst
+///
+/// Neither is this: [`first`](x) `second` arst
+///
+/// Neither is this: [first](x)`second` arst
+///
+/// This is: <code>[first](x)second</code> arst
+//~^ ERROR: adjacent
+///
+/// So is this <code>first[second](x)</code> arst
+//~^ ERROR: adjacent
+///
+/// So is this <code>[first](x)[second](x)</code> arst
+//~^ ERROR: adjacent
+///
+/// So is this <code>[first](x)[second](x)[third](x)</code> arst
+//~^ ERROR: adjacent
+///
+/// So is this <code>[first](x)second[third](x)</code> arst
+//~^ ERROR: adjacent
+pub struct WithTrailing;
diff --git a/tests/ui/doc/link_adjacent.rs b/tests/ui/doc/link_adjacent.rs
new file mode 100644
index 00000000000..af6755eeff6
--- /dev/null
+++ b/tests/ui/doc/link_adjacent.rs
@@ -0,0 +1,52 @@
+#![warn(clippy::doc_link_code)]
+
+//! Test case for code links that are adjacent to code text.
+//!
+//! This is not an example: `first``second`
+//!
+//! Neither is this: [`first`](x)
+//!
+//! Neither is this: [`first`](x) `second`
+//!
+//! Neither is this: [first](x)`second`
+//!
+//! This is: [`first`](x)`second`
+//~^ ERROR: adjacent
+//!
+//! So is this `first`[`second`](x)
+//~^ ERROR: adjacent
+//!
+//! So is this [`first`](x)[`second`](x)
+//~^ ERROR: adjacent
+//!
+//! So is this [`first`](x)[`second`](x)[`third`](x)
+//~^ ERROR: adjacent
+//!
+//! So is this [`first`](x)`second`[`third`](x)
+//~^ ERROR: adjacent
+
+/// Test case for code links that are adjacent to code text.
+///
+/// This is not an example: `first``second` arst
+///
+/// Neither is this: [`first`](x) arst
+///
+/// Neither is this: [`first`](x) `second` arst
+///
+/// Neither is this: [first](x)`second` arst
+///
+/// This is: [`first`](x)`second` arst
+//~^ ERROR: adjacent
+///
+/// So is this `first`[`second`](x) arst
+//~^ ERROR: adjacent
+///
+/// So is this [`first`](x)[`second`](x) arst
+//~^ ERROR: adjacent
+///
+/// So is this [`first`](x)[`second`](x)[`third`](x) arst
+//~^ ERROR: adjacent
+///
+/// So is this [`first`](x)`second`[`third`](x) arst
+//~^ ERROR: adjacent
+pub struct WithTrailing;
diff --git a/tests/ui/doc/link_adjacent.stderr b/tests/ui/doc/link_adjacent.stderr
new file mode 100644
index 00000000000..f09762fb6a0
--- /dev/null
+++ b/tests/ui/doc/link_adjacent.stderr
@@ -0,0 +1,124 @@
+error: code link adjacent to code text
+  --> tests/ui/doc/link_adjacent.rs:13:14
+   |
+LL | //! This is: [`first`](x)`second`
+   |              ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: separate code snippets will be shown with a gap
+   = note: `-D clippy::doc-link-code` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::doc_link_code)]`
+help: wrap the entire group in `<code>` tags
+   |
+LL | //! This is: <code>[first](x)second</code>
+   |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: code link adjacent to code text
+  --> tests/ui/doc/link_adjacent.rs:16:16
+   |
+LL | //! So is this `first`[`second`](x)
+   |                ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: separate code snippets will be shown with a gap
+help: wrap the entire group in `<code>` tags
+   |
+LL | //! So is this <code>first[second](x)</code>
+   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: code link adjacent to code text
+  --> tests/ui/doc/link_adjacent.rs:19:16
+   |
+LL | //! So is this [`first`](x)[`second`](x)
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: separate code snippets will be shown with a gap
+help: wrap the entire group in `<code>` tags
+   |
+LL | //! So is this <code>[first](x)[second](x)</code>
+   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: code link adjacent to code text
+  --> tests/ui/doc/link_adjacent.rs:22:16
+   |
+LL | //! So is this [`first`](x)[`second`](x)[`third`](x)
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: separate code snippets will be shown with a gap
+help: wrap the entire group in `<code>` tags
+   |
+LL | //! So is this <code>[first](x)[second](x)[third](x)</code>
+   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: code link adjacent to code text
+  --> tests/ui/doc/link_adjacent.rs:25:16
+   |
+LL | //! So is this [`first`](x)`second`[`third`](x)
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: separate code snippets will be shown with a gap
+help: wrap the entire group in `<code>` tags
+   |
+LL | //! So is this <code>[first](x)second[third](x)</code>
+   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: code link adjacent to code text
+  --> tests/ui/doc/link_adjacent.rs:38:14
+   |
+LL | /// This is: [`first`](x)`second` arst
+   |              ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: separate code snippets will be shown with a gap
+help: wrap the entire group in `<code>` tags
+   |
+LL | /// This is: <code>[first](x)second</code> arst
+   |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: code link adjacent to code text
+  --> tests/ui/doc/link_adjacent.rs:41:16
+   |
+LL | /// So is this `first`[`second`](x) arst
+   |                ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: separate code snippets will be shown with a gap
+help: wrap the entire group in `<code>` tags
+   |
+LL | /// So is this <code>first[second](x)</code> arst
+   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: code link adjacent to code text
+  --> tests/ui/doc/link_adjacent.rs:44:16
+   |
+LL | /// So is this [`first`](x)[`second`](x) arst
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: separate code snippets will be shown with a gap
+help: wrap the entire group in `<code>` tags
+   |
+LL | /// So is this <code>[first](x)[second](x)</code> arst
+   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: code link adjacent to code text
+  --> tests/ui/doc/link_adjacent.rs:47:16
+   |
+LL | /// So is this [`first`](x)[`second`](x)[`third`](x) arst
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: separate code snippets will be shown with a gap
+help: wrap the entire group in `<code>` tags
+   |
+LL | /// So is this <code>[first](x)[second](x)[third](x)</code> arst
+   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: code link adjacent to code text
+  --> tests/ui/doc/link_adjacent.rs:50:16
+   |
+LL | /// So is this [`first`](x)`second`[`third`](x) arst
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: separate code snippets will be shown with a gap
+help: wrap the entire group in `<code>` tags
+   |
+LL | /// So is this <code>[first](x)second[third](x)</code> arst
+   |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/ignored_unit_patterns.fixed b/tests/ui/ignored_unit_patterns.fixed
index fde40437309..118f0b48895 100644
--- a/tests/ui/ignored_unit_patterns.fixed
+++ b/tests/ui/ignored_unit_patterns.fixed
@@ -21,12 +21,15 @@ fn main() {
     let _ = foo().map_err(|()| todo!());
     //~^ ERROR: matching over `()` is more explicit
 
-    println!("{:?}", match foo() {
-        Ok(()) => {},
-        //~^ ERROR: matching over `()` is more explicit
-        Err(()) => {},
-        //~^ ERROR: matching over `()` is more explicit
-    });
+    println!(
+        "{:?}",
+        match foo() {
+            Ok(()) => {},
+            //~^ ERROR: matching over `()` is more explicit
+            Err(()) => {},
+            //~^ ERROR: matching over `()` is more explicit
+        }
+    );
 }
 
 // ignored_unit_patterns in derive macro should be ok
diff --git a/tests/ui/ignored_unit_patterns.rs b/tests/ui/ignored_unit_patterns.rs
index 528844d76e0..92feb9e6c28 100644
--- a/tests/ui/ignored_unit_patterns.rs
+++ b/tests/ui/ignored_unit_patterns.rs
@@ -21,12 +21,15 @@ fn main() {
     let _ = foo().map_err(|_| todo!());
     //~^ ERROR: matching over `()` is more explicit
 
-    println!("{:?}", match foo() {
-        Ok(_) => {},
-        //~^ ERROR: matching over `()` is more explicit
-        Err(_) => {},
-        //~^ ERROR: matching over `()` is more explicit
-    });
+    println!(
+        "{:?}",
+        match foo() {
+            Ok(_) => {},
+            //~^ ERROR: matching over `()` is more explicit
+            Err(_) => {},
+            //~^ ERROR: matching over `()` is more explicit
+        }
+    );
 }
 
 // ignored_unit_patterns in derive macro should be ok
diff --git a/tests/ui/ignored_unit_patterns.stderr b/tests/ui/ignored_unit_patterns.stderr
index 54ff4454d6b..00a254e3919 100644
--- a/tests/ui/ignored_unit_patterns.stderr
+++ b/tests/ui/ignored_unit_patterns.stderr
@@ -26,31 +26,31 @@ LL |     let _ = foo().map_err(|_| todo!());
    |                            ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> tests/ui/ignored_unit_patterns.rs:25:12
+  --> tests/ui/ignored_unit_patterns.rs:27:16
    |
-LL |         Ok(_) => {},
-   |            ^ help: use `()` instead of `_`: `()`
+LL |             Ok(_) => {},
+   |                ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> tests/ui/ignored_unit_patterns.rs:27:13
+  --> tests/ui/ignored_unit_patterns.rs:29:17
    |
-LL |         Err(_) => {},
-   |             ^ help: use `()` instead of `_`: `()`
+LL |             Err(_) => {},
+   |                 ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> tests/ui/ignored_unit_patterns.rs:38:9
+  --> tests/ui/ignored_unit_patterns.rs:41:9
    |
 LL |     let _ = foo().unwrap();
    |         ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> tests/ui/ignored_unit_patterns.rs:47:13
+  --> tests/ui/ignored_unit_patterns.rs:50:13
    |
 LL |         (1, _) => unimplemented!(),
    |             ^ help: use `()` instead of `_`: `()`
 
 error: matching over `()` is more explicit
-  --> tests/ui/ignored_unit_patterns.rs:54:13
+  --> tests/ui/ignored_unit_patterns.rs:57:13
    |
 LL |     for (x, _) in v {
    |             ^ help: use `()` instead of `_`: `()`
diff --git a/tests/ui/large_enum_variant.32bit.stderr b/tests/ui/large_enum_variant.32bit.stderr
index ff4f1a7f312..36f3d930b53 100644
--- a/tests/ui/large_enum_variant.32bit.stderr
+++ b/tests/ui/large_enum_variant.32bit.stderr
@@ -276,5 +276,37 @@ help: consider boxing the large fields to reduce the total size of the enum
 LL |     Error(Box<PossiblyLargeEnumWithConst<256>>),
    |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-error: aborting due to 16 previous errors
+error: large size difference between variants
+  --> tests/ui/large_enum_variant.rs:158:1
+   |
+LL | / enum WithRecursion {
+LL | |     Large([u64; 64]),
+   | |     ---------------- the largest variant contains at least 512 bytes
+LL | |     Recursive(Box<WithRecursion>),
+   | |     ----------------------------- the second-largest variant contains at least 4 bytes
+LL | | }
+   | |_^ the entire enum is at least 516 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Large(Box<[u64; 64]>),
+   |           ~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> tests/ui/large_enum_variant.rs:168:1
+   |
+LL | / enum LargeEnumWithGenericsAndRecursive {
+LL | |     Ok(),
+   | |     ---- the second-largest variant carries no data at all
+LL | |     Error(WithRecursionAndGenerics<u64>),
+   | |     ------------------------------------ the largest variant contains at least 516 bytes
+LL | | }
+   | |_^ the entire enum is at least 516 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Error(Box<WithRecursionAndGenerics<u64>>),
+   |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 18 previous errors
 
diff --git a/tests/ui/large_enum_variant.64bit.stderr b/tests/ui/large_enum_variant.64bit.stderr
index 805cb406f83..31576a5863f 100644
--- a/tests/ui/large_enum_variant.64bit.stderr
+++ b/tests/ui/large_enum_variant.64bit.stderr
@@ -276,5 +276,69 @@ help: consider boxing the large fields to reduce the total size of the enum
 LL |     Error(Box<PossiblyLargeEnumWithConst<256>>),
    |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-error: aborting due to 16 previous errors
+error: large size difference between variants
+  --> tests/ui/large_enum_variant.rs:158:1
+   |
+LL | / enum WithRecursion {
+LL | |     Large([u64; 64]),
+   | |     ---------------- the largest variant contains at least 512 bytes
+LL | |     Recursive(Box<WithRecursion>),
+   | |     ----------------------------- the second-largest variant contains at least 8 bytes
+LL | | }
+   | |_^ the entire enum is at least 520 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Large(Box<[u64; 64]>),
+   |           ~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> tests/ui/large_enum_variant.rs:168:1
+   |
+LL | / enum LargeEnumWithGenericsAndRecursive {
+LL | |     Ok(),
+   | |     ---- the second-largest variant carries no data at all
+LL | |     Error(WithRecursionAndGenerics<u64>),
+   | |     ------------------------------------ the largest variant contains at least 520 bytes
+LL | | }
+   | |_^ the entire enum is at least 520 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |     Error(Box<WithRecursionAndGenerics<u64>>),
+   |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> tests/ui/large_enum_variant.rs:203:5
+   |
+LL | /     enum NoWarnings {
+LL | |         BigBoi(PublishWithBytes),
+   | |         ------------------------ the largest variant contains at least 296 bytes
+LL | |         _SmallBoi(u8),
+   | |         ------------- the second-largest variant contains at least 1 bytes
+LL | |     }
+   | |_____^ the entire enum is at least 296 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |         BigBoi(Box<PublishWithBytes>),
+   |                ~~~~~~~~~~~~~~~~~~~~~
+
+error: large size difference between variants
+  --> tests/ui/large_enum_variant.rs:208:5
+   |
+LL | /     enum MakesClippyAngry {
+LL | |         BigBoi(PublishWithVec),
+   | |         ---------------------- the largest variant contains at least 224 bytes
+LL | |         _SmallBoi(u8),
+   | |         ------------- the second-largest variant contains at least 1 bytes
+LL | |     }
+   | |_____^ the entire enum is at least 224 bytes
+   |
+help: consider boxing the large fields to reduce the total size of the enum
+   |
+LL |         BigBoi(Box<PublishWithVec>),
+   |                ~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 20 previous errors
 
diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs
index 3625c011dbf..57722f63b22 100644
--- a/tests/ui/large_enum_variant.rs
+++ b/tests/ui/large_enum_variant.rs
@@ -155,6 +155,21 @@ enum LargeEnumOfConst {
     Error(PossiblyLargeEnumWithConst<256>),
 }
 
+enum WithRecursion {
+    Large([u64; 64]),
+    Recursive(Box<WithRecursion>),
+}
+
+enum WithRecursionAndGenerics<T> {
+    Large([T; 64]),
+    Recursive(Box<WithRecursionAndGenerics<T>>),
+}
+
+enum LargeEnumWithGenericsAndRecursive {
+    Ok(),
+    Error(WithRecursionAndGenerics<u64>),
+}
+
 fn main() {
     external!(
         enum LargeEnumInMacro {
@@ -163,3 +178,65 @@ fn main() {
         }
     );
 }
+
+mod issue11915 {
+    use std::sync::atomic::AtomicPtr;
+
+    pub struct Bytes {
+        ptr: *const u8,
+        len: usize,
+        // inlined "trait object"
+        data: AtomicPtr<()>,
+        vtable: &'static Vtable,
+    }
+    pub(crate) struct Vtable {
+        /// fn(data, ptr, len)
+        pub clone: unsafe fn(&AtomicPtr<()>, *const u8, usize) -> Bytes,
+        /// fn(data, ptr, len)
+        ///
+        /// takes `Bytes` to value
+        pub to_vec: unsafe fn(&AtomicPtr<()>, *const u8, usize) -> Vec<u8>,
+        /// fn(data, ptr, len)
+        pub drop: unsafe fn(&mut AtomicPtr<()>, *const u8, usize),
+    }
+
+    enum NoWarnings {
+        BigBoi(PublishWithBytes),
+        _SmallBoi(u8),
+    }
+
+    enum MakesClippyAngry {
+        BigBoi(PublishWithVec),
+        _SmallBoi(u8),
+    }
+
+    struct PublishWithBytes {
+        _dup: bool,
+        _retain: bool,
+        _topic: Bytes,
+        __topic: Bytes,
+        ___topic: Bytes,
+        ____topic: Bytes,
+        _pkid: u16,
+        _payload: Bytes,
+        __payload: Bytes,
+        ___payload: Bytes,
+        ____payload: Bytes,
+        _____payload: Bytes,
+    }
+
+    struct PublishWithVec {
+        _dup: bool,
+        _retain: bool,
+        _topic: Vec<u8>,
+        __topic: Vec<u8>,
+        ___topic: Vec<u8>,
+        ____topic: Vec<u8>,
+        _pkid: u16,
+        _payload: Vec<u8>,
+        __payload: Vec<u8>,
+        ___payload: Vec<u8>,
+        ____payload: Vec<u8>,
+        _____payload: Vec<u8>,
+    }
+}
diff --git a/tests/ui/let_and_return.edition2021.fixed b/tests/ui/let_and_return.edition2021.fixed
new file mode 100644
index 00000000000..c160d5df30f
--- /dev/null
+++ b/tests/ui/let_and_return.edition2021.fixed
@@ -0,0 +1,265 @@
+//@revisions: edition2021 edition2024
+//@[edition2021] edition:2021
+//@[edition2024] edition:2024
+
+#![allow(unused)]
+#![warn(clippy::let_and_return)]
+
+use std::cell::RefCell;
+
+fn test() -> i32 {
+    let _y = 0; // no warning
+    
+    5
+    //~^ ERROR: returning the result of a `let` binding from a block
+    //~| NOTE: `-D clippy::let-and-return` implied by `-D warnings`
+}
+
+fn test_inner() -> i32 {
+    if true {
+        
+        5
+        //~^ ERROR: returning the result of a `let` binding from a block
+    } else {
+        0
+    }
+}
+
+fn test_nowarn_1() -> i32 {
+    let mut x = 5;
+    x += 1;
+    x
+}
+
+fn test_nowarn_2() -> i32 {
+    let x = 5;
+    x + 1
+}
+
+fn test_nowarn_3() -> (i32, i32) {
+    // this should technically warn, but we do not compare complex patterns
+    let (x, y) = (5, 9);
+    (x, y)
+}
+
+fn test_nowarn_4() -> i32 {
+    // this should technically warn, but not b/c of clippy::let_and_return, but b/c of useless type
+    let x: i32 = 5;
+    x
+}
+
+fn test_nowarn_5(x: i16) -> u16 {
+    #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
+    let x = x as u16;
+    x
+}
+
+// False positive example
+trait Decode {
+    fn decode<D: std::io::Read>(d: D) -> Result<Self, ()>
+    where
+        Self: Sized;
+}
+
+macro_rules! tuple_encode {
+    ($($x:ident),*) => (
+        impl<$($x: Decode),*> Decode for ($($x),*) {
+            #[inline]
+            #[allow(non_snake_case)]
+            fn decode<D: std::io::Read>(mut d: D) -> Result<Self, ()> {
+                // Shouldn't trigger lint
+                Ok(($({let $x = Decode::decode(&mut d)?; $x }),*))
+            }
+        }
+    );
+}
+
+fn issue_3792() -> String {
+    use std::io::{self, BufRead, Stdin};
+
+    let stdin = io::stdin();
+    // `Stdin::lock` returns `StdinLock<'static>` so `line` doesn't borrow from `stdin`
+    // https://github.com/rust-lang/rust/pull/93965
+    
+    stdin.lock().lines().next().unwrap().unwrap()
+    //~^ ERROR: returning the result of a `let` binding from a block
+}
+
+tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7);
+
+mod no_lint_if_stmt_borrows {
+    use std::cell::RefCell;
+    use std::rc::{Rc, Weak};
+    struct Bar;
+
+    impl Bar {
+        fn new() -> Self {
+            Bar {}
+        }
+        fn baz(&self) -> u32 {
+            0
+        }
+    }
+
+    fn issue_3324(value: Weak<RefCell<Bar>>) -> u32 {
+        let value = value.upgrade().unwrap();
+        let ret = value.borrow().baz();
+        ret
+        //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
+    }
+
+    fn borrows_in_closure(value: Weak<RefCell<Bar>>) -> u32 {
+        fn f(mut x: impl FnMut() -> u32) -> impl FnMut() -> u32 {
+            x
+        }
+
+        let value = value.upgrade().unwrap();
+        let ret = f(|| value.borrow().baz())();
+        ret
+        //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
+    }
+
+    mod free_function {
+        struct Inner;
+
+        struct Foo<'a> {
+            inner: &'a Inner,
+        }
+
+        impl Drop for Foo<'_> {
+            fn drop(&mut self) {}
+        }
+
+        impl<'a> Foo<'a> {
+            fn new(inner: &'a Inner) -> Self {
+                Self { inner }
+            }
+
+            fn value(&self) -> i32 {
+                42
+            }
+        }
+
+        fn some_foo(inner: &Inner) -> Foo<'_> {
+            Foo { inner }
+        }
+
+        fn test() -> i32 {
+            let x = Inner {};
+            let value = some_foo(&x).value();
+            value
+            //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
+        }
+
+        fn test2() -> i32 {
+            let x = Inner {};
+            let value = Foo::new(&x).value();
+            value
+            //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
+        }
+    }
+}
+
+mod issue_5729 {
+    use std::sync::Arc;
+
+    trait Foo {}
+
+    trait FooStorage {
+        fn foo_cloned(&self) -> Arc<dyn Foo>;
+    }
+
+    struct FooStorageImpl<T: Foo> {
+        foo: Arc<T>,
+    }
+
+    impl<T: Foo + 'static> FooStorage for FooStorageImpl<T> {
+        fn foo_cloned(&self) -> Arc<dyn Foo> {
+            
+            (Arc::clone(&self.foo)) as _
+            //~^ ERROR: returning the result of a `let` binding from a block
+        }
+    }
+}
+
+mod issue_11335 {
+    pub enum E<T> {
+        A(T),
+        B(T),
+    }
+
+    impl<T> E<T> {
+        pub fn inner(&self) -> &T {
+            
+
+            (match self {
+                E::A(x) => x,
+                E::B(x) => x,
+            }) as _
+            //~^ ERROR: returning the result of a `let` binding from a block
+        }
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/11167
+macro_rules! fn_in_macro {
+    ($b:block) => {
+        fn f() -> usize $b
+    }
+}
+fn_in_macro!({
+    return 1;
+});
+
+fn issue9150() -> usize {
+    let x = 1;
+    #[cfg(any())]
+    panic!("can't see me");
+    x
+}
+
+fn issue12801() {
+    fn left_is_if() -> String {
+        
+        (if true { "a".to_string() } else { "b".to_string() } + "c")
+        //~^ ERROR: returning the result of a `let` binding from a block
+    }
+
+    fn no_par_needed() -> String {
+        
+        "c".to_string() + if true { "a" } else { "b" }
+        //~^ ERROR: returning the result of a `let` binding from a block
+    }
+
+    fn conjunctive_blocks() -> String {
+        
+        ({ "a".to_string() } + "b" + { "c" } + "d")
+        //~^ ERROR: returning the result of a `let` binding from a block
+    }
+
+    #[allow(clippy::overly_complex_bool_expr)]
+    fn other_ops() {
+        let _ = || {
+            
+            (if true { 2 } else { 3 } << 4)
+            //~^ ERROR: returning the result of a `let` binding from a block
+        };
+        let _ = || {
+            
+            ({ true } || { false } && { 2 <= 3 })
+            //~^ ERROR: returning the result of a `let` binding from a block
+        };
+    }
+}
+
+fn issue14164() -> Result<u32, ()> {
+    let v = std::cell::RefCell::new(Some(vec![1]));
+    let r = match &*v.borrow() {
+        Some(v) => Ok(Ok(v[0])),
+        None => Ok(Ok(0)),
+    }?;
+    r
+    //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
+}
+
+fn main() {}
diff --git a/tests/ui/let_and_return.edition2021.stderr b/tests/ui/let_and_return.edition2021.stderr
new file mode 100644
index 00000000000..105fa7a722d
--- /dev/null
+++ b/tests/ui/let_and_return.edition2021.stderr
@@ -0,0 +1,152 @@
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:13:5
+   |
+LL |     let x = 5;
+   |     ---------- unnecessary `let` binding
+LL |     x
+   |     ^
+   |
+   = note: `-D clippy::let-and-return` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]`
+help: return the expression directly
+   |
+LL ~     
+LL ~     5
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:21:9
+   |
+LL |         let x = 5;
+   |         ---------- unnecessary `let` binding
+LL |         x
+   |         ^
+   |
+help: return the expression directly
+   |
+LL ~         
+LL ~         5
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:84:5
+   |
+LL |     let line = stdin.lock().lines().next().unwrap().unwrap();
+   |     --------------------------------------------------------- unnecessary `let` binding
+LL |     line
+   |     ^^^^
+   |
+help: return the expression directly
+   |
+LL ~     
+LL ~     stdin.lock().lines().next().unwrap().unwrap()
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:179:13
+   |
+LL |             let clone = Arc::clone(&self.foo);
+   |             ---------------------------------- unnecessary `let` binding
+LL |             clone
+   |             ^^^^^
+   |
+help: return the expression directly
+   |
+LL ~             
+LL ~             (Arc::clone(&self.foo)) as _
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:198:13
+   |
+LL | /             let result = match self {
+LL | |                 E::A(x) => x,
+LL | |                 E::B(x) => x,
+LL | |             };
+   | |______________- unnecessary `let` binding
+LL |
+LL |               result
+   |               ^^^^^^
+   |
+help: return the expression directly
+   |
+LL ~             
+LL |
+LL ~             (match self {
+LL +                 E::A(x) => x,
+LL +                 E::B(x) => x,
+LL +             }) as _
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:224:9
+   |
+LL |         let s = if true { "a".to_string() } else { "b".to_string() } + "c";
+   |         ------------------------------------------------------------------- unnecessary `let` binding
+LL |         s
+   |         ^
+   |
+help: return the expression directly
+   |
+LL ~         
+LL ~         (if true { "a".to_string() } else { "b".to_string() } + "c")
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:230:9
+   |
+LL |         let s = "c".to_string() + if true { "a" } else { "b" };
+   |         ------------------------------------------------------- unnecessary `let` binding
+LL |         s
+   |         ^
+   |
+help: return the expression directly
+   |
+LL ~         
+LL ~         "c".to_string() + if true { "a" } else { "b" }
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:236:9
+   |
+LL |         let s = { "a".to_string() } + "b" + { "c" } + "d";
+   |         -------------------------------------------------- unnecessary `let` binding
+LL |         s
+   |         ^
+   |
+help: return the expression directly
+   |
+LL ~         
+LL ~         ({ "a".to_string() } + "b" + { "c" } + "d")
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:244:13
+   |
+LL |             let s = if true { 2 } else { 3 } << 4;
+   |             -------------------------------------- unnecessary `let` binding
+LL |             s
+   |             ^
+   |
+help: return the expression directly
+   |
+LL ~             
+LL ~             (if true { 2 } else { 3 } << 4)
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:249:13
+   |
+LL |             let s = { true } || { false } && { 2 <= 3 };
+   |             -------------------------------------------- unnecessary `let` binding
+LL |             s
+   |             ^
+   |
+help: return the expression directly
+   |
+LL ~             
+LL ~             ({ true } || { false } && { 2 <= 3 })
+   |
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/let_and_return.edition2024.fixed b/tests/ui/let_and_return.edition2024.fixed
new file mode 100644
index 00000000000..f958f70e1dc
--- /dev/null
+++ b/tests/ui/let_and_return.edition2024.fixed
@@ -0,0 +1,265 @@
+//@revisions: edition2021 edition2024
+//@[edition2021] edition:2021
+//@[edition2024] edition:2024
+
+#![allow(unused)]
+#![warn(clippy::let_and_return)]
+
+use std::cell::RefCell;
+
+fn test() -> i32 {
+    let _y = 0; // no warning
+    
+    5
+    //~^ ERROR: returning the result of a `let` binding from a block
+    //~| NOTE: `-D clippy::let-and-return` implied by `-D warnings`
+}
+
+fn test_inner() -> i32 {
+    if true {
+        
+        5
+        //~^ ERROR: returning the result of a `let` binding from a block
+    } else {
+        0
+    }
+}
+
+fn test_nowarn_1() -> i32 {
+    let mut x = 5;
+    x += 1;
+    x
+}
+
+fn test_nowarn_2() -> i32 {
+    let x = 5;
+    x + 1
+}
+
+fn test_nowarn_3() -> (i32, i32) {
+    // this should technically warn, but we do not compare complex patterns
+    let (x, y) = (5, 9);
+    (x, y)
+}
+
+fn test_nowarn_4() -> i32 {
+    // this should technically warn, but not b/c of clippy::let_and_return, but b/c of useless type
+    let x: i32 = 5;
+    x
+}
+
+fn test_nowarn_5(x: i16) -> u16 {
+    #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
+    let x = x as u16;
+    x
+}
+
+// False positive example
+trait Decode {
+    fn decode<D: std::io::Read>(d: D) -> Result<Self, ()>
+    where
+        Self: Sized;
+}
+
+macro_rules! tuple_encode {
+    ($($x:ident),*) => (
+        impl<$($x: Decode),*> Decode for ($($x),*) {
+            #[inline]
+            #[allow(non_snake_case)]
+            fn decode<D: std::io::Read>(mut d: D) -> Result<Self, ()> {
+                // Shouldn't trigger lint
+                Ok(($({let $x = Decode::decode(&mut d)?; $x }),*))
+            }
+        }
+    );
+}
+
+fn issue_3792() -> String {
+    use std::io::{self, BufRead, Stdin};
+
+    let stdin = io::stdin();
+    // `Stdin::lock` returns `StdinLock<'static>` so `line` doesn't borrow from `stdin`
+    // https://github.com/rust-lang/rust/pull/93965
+    
+    stdin.lock().lines().next().unwrap().unwrap()
+    //~^ ERROR: returning the result of a `let` binding from a block
+}
+
+tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7);
+
+mod no_lint_if_stmt_borrows {
+    use std::cell::RefCell;
+    use std::rc::{Rc, Weak};
+    struct Bar;
+
+    impl Bar {
+        fn new() -> Self {
+            Bar {}
+        }
+        fn baz(&self) -> u32 {
+            0
+        }
+    }
+
+    fn issue_3324(value: Weak<RefCell<Bar>>) -> u32 {
+        let value = value.upgrade().unwrap();
+        
+        value.borrow().baz()
+        //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
+    }
+
+    fn borrows_in_closure(value: Weak<RefCell<Bar>>) -> u32 {
+        fn f(mut x: impl FnMut() -> u32) -> impl FnMut() -> u32 {
+            x
+        }
+
+        let value = value.upgrade().unwrap();
+        
+        f(|| value.borrow().baz())()
+        //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
+    }
+
+    mod free_function {
+        struct Inner;
+
+        struct Foo<'a> {
+            inner: &'a Inner,
+        }
+
+        impl Drop for Foo<'_> {
+            fn drop(&mut self) {}
+        }
+
+        impl<'a> Foo<'a> {
+            fn new(inner: &'a Inner) -> Self {
+                Self { inner }
+            }
+
+            fn value(&self) -> i32 {
+                42
+            }
+        }
+
+        fn some_foo(inner: &Inner) -> Foo<'_> {
+            Foo { inner }
+        }
+
+        fn test() -> i32 {
+            let x = Inner {};
+            
+            some_foo(&x).value()
+            //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
+        }
+
+        fn test2() -> i32 {
+            let x = Inner {};
+            
+            Foo::new(&x).value()
+            //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
+        }
+    }
+}
+
+mod issue_5729 {
+    use std::sync::Arc;
+
+    trait Foo {}
+
+    trait FooStorage {
+        fn foo_cloned(&self) -> Arc<dyn Foo>;
+    }
+
+    struct FooStorageImpl<T: Foo> {
+        foo: Arc<T>,
+    }
+
+    impl<T: Foo + 'static> FooStorage for FooStorageImpl<T> {
+        fn foo_cloned(&self) -> Arc<dyn Foo> {
+            
+            (Arc::clone(&self.foo)) as _
+            //~^ ERROR: returning the result of a `let` binding from a block
+        }
+    }
+}
+
+mod issue_11335 {
+    pub enum E<T> {
+        A(T),
+        B(T),
+    }
+
+    impl<T> E<T> {
+        pub fn inner(&self) -> &T {
+            
+
+            (match self {
+                E::A(x) => x,
+                E::B(x) => x,
+            }) as _
+            //~^ ERROR: returning the result of a `let` binding from a block
+        }
+    }
+}
+
+// https://github.com/rust-lang/rust-clippy/issues/11167
+macro_rules! fn_in_macro {
+    ($b:block) => {
+        fn f() -> usize $b
+    }
+}
+fn_in_macro!({
+    return 1;
+});
+
+fn issue9150() -> usize {
+    let x = 1;
+    #[cfg(any())]
+    panic!("can't see me");
+    x
+}
+
+fn issue12801() {
+    fn left_is_if() -> String {
+        
+        (if true { "a".to_string() } else { "b".to_string() } + "c")
+        //~^ ERROR: returning the result of a `let` binding from a block
+    }
+
+    fn no_par_needed() -> String {
+        
+        "c".to_string() + if true { "a" } else { "b" }
+        //~^ ERROR: returning the result of a `let` binding from a block
+    }
+
+    fn conjunctive_blocks() -> String {
+        
+        ({ "a".to_string() } + "b" + { "c" } + "d")
+        //~^ ERROR: returning the result of a `let` binding from a block
+    }
+
+    #[allow(clippy::overly_complex_bool_expr)]
+    fn other_ops() {
+        let _ = || {
+            
+            (if true { 2 } else { 3 } << 4)
+            //~^ ERROR: returning the result of a `let` binding from a block
+        };
+        let _ = || {
+            
+            ({ true } || { false } && { 2 <= 3 })
+            //~^ ERROR: returning the result of a `let` binding from a block
+        };
+    }
+}
+
+fn issue14164() -> Result<u32, ()> {
+    let v = std::cell::RefCell::new(Some(vec![1]));
+    
+    match &*v.borrow() {
+        Some(v) => Ok(Ok(v[0])),
+        None => Ok(Ok(0)),
+    }?
+    //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
+}
+
+fn main() {}
diff --git a/tests/ui/let_and_return.edition2024.stderr b/tests/ui/let_and_return.edition2024.stderr
new file mode 100644
index 00000000000..ec87e32b582
--- /dev/null
+++ b/tests/ui/let_and_return.edition2024.stderr
@@ -0,0 +1,228 @@
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:13:5
+   |
+LL |     let x = 5;
+   |     ---------- unnecessary `let` binding
+LL |     x
+   |     ^
+   |
+   = note: `-D clippy::let-and-return` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]`
+help: return the expression directly
+   |
+LL ~     
+LL ~     5
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:21:9
+   |
+LL |         let x = 5;
+   |         ---------- unnecessary `let` binding
+LL |         x
+   |         ^
+   |
+help: return the expression directly
+   |
+LL ~         
+LL ~         5
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:84:5
+   |
+LL |     let line = stdin.lock().lines().next().unwrap().unwrap();
+   |     --------------------------------------------------------- unnecessary `let` binding
+LL |     line
+   |     ^^^^
+   |
+help: return the expression directly
+   |
+LL ~     
+LL ~     stdin.lock().lines().next().unwrap().unwrap()
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:107:9
+   |
+LL |         let ret = value.borrow().baz();
+   |         ------------------------------- unnecessary `let` binding
+LL |         ret
+   |         ^^^
+   |
+help: return the expression directly
+   |
+LL ~         
+LL ~         value.borrow().baz()
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:118:9
+   |
+LL |         let ret = f(|| value.borrow().baz())();
+   |         --------------------------------------- unnecessary `let` binding
+LL |         ret
+   |         ^^^
+   |
+help: return the expression directly
+   |
+LL ~         
+LL ~         f(|| value.borrow().baz())()
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:150:13
+   |
+LL |             let value = some_foo(&x).value();
+   |             --------------------------------- unnecessary `let` binding
+LL |             value
+   |             ^^^^^
+   |
+help: return the expression directly
+   |
+LL ~             
+LL ~             some_foo(&x).value()
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:157:13
+   |
+LL |             let value = Foo::new(&x).value();
+   |             --------------------------------- unnecessary `let` binding
+LL |             value
+   |             ^^^^^
+   |
+help: return the expression directly
+   |
+LL ~             
+LL ~             Foo::new(&x).value()
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:179:13
+   |
+LL |             let clone = Arc::clone(&self.foo);
+   |             ---------------------------------- unnecessary `let` binding
+LL |             clone
+   |             ^^^^^
+   |
+help: return the expression directly
+   |
+LL ~             
+LL ~             (Arc::clone(&self.foo)) as _
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:198:13
+   |
+LL | /             let result = match self {
+LL | |                 E::A(x) => x,
+LL | |                 E::B(x) => x,
+LL | |             };
+   | |______________- unnecessary `let` binding
+LL |
+LL |               result
+   |               ^^^^^^
+   |
+help: return the expression directly
+   |
+LL ~             
+LL |
+LL ~             (match self {
+LL +                 E::A(x) => x,
+LL +                 E::B(x) => x,
+LL +             }) as _
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:224:9
+   |
+LL |         let s = if true { "a".to_string() } else { "b".to_string() } + "c";
+   |         ------------------------------------------------------------------- unnecessary `let` binding
+LL |         s
+   |         ^
+   |
+help: return the expression directly
+   |
+LL ~         
+LL ~         (if true { "a".to_string() } else { "b".to_string() } + "c")
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:230:9
+   |
+LL |         let s = "c".to_string() + if true { "a" } else { "b" };
+   |         ------------------------------------------------------- unnecessary `let` binding
+LL |         s
+   |         ^
+   |
+help: return the expression directly
+   |
+LL ~         
+LL ~         "c".to_string() + if true { "a" } else { "b" }
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:236:9
+   |
+LL |         let s = { "a".to_string() } + "b" + { "c" } + "d";
+   |         -------------------------------------------------- unnecessary `let` binding
+LL |         s
+   |         ^
+   |
+help: return the expression directly
+   |
+LL ~         
+LL ~         ({ "a".to_string() } + "b" + { "c" } + "d")
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:244:13
+   |
+LL |             let s = if true { 2 } else { 3 } << 4;
+   |             -------------------------------------- unnecessary `let` binding
+LL |             s
+   |             ^
+   |
+help: return the expression directly
+   |
+LL ~             
+LL ~             (if true { 2 } else { 3 } << 4)
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:249:13
+   |
+LL |             let s = { true } || { false } && { 2 <= 3 };
+   |             -------------------------------------------- unnecessary `let` binding
+LL |             s
+   |             ^
+   |
+help: return the expression directly
+   |
+LL ~             
+LL ~             ({ true } || { false } && { 2 <= 3 })
+   |
+
+error: returning the result of a `let` binding from a block
+  --> tests/ui/let_and_return.rs:261:5
+   |
+LL | /     let r = match &*v.borrow() {
+LL | |         Some(v) => Ok(Ok(v[0])),
+LL | |         None => Ok(Ok(0)),
+LL | |     }?;
+   | |_______- unnecessary `let` binding
+LL |       r
+   |       ^
+   |
+help: return the expression directly
+   |
+LL ~     
+LL ~     match &*v.borrow() {
+LL +         Some(v) => Ok(Ok(v[0])),
+LL +         None => Ok(Ok(0)),
+LL +     }?
+   |
+
+error: aborting due to 15 previous errors
+
diff --git a/tests/ui/let_and_return.fixed b/tests/ui/let_and_return.fixed
index b68b41cdca2..e22e66eb522 100644
--- a/tests/ui/let_and_return.fixed
+++ b/tests/ui/let_and_return.fixed
@@ -244,4 +244,14 @@ fn issue12801() {
     }
 }
 
+// Do not lint
+fn issue14164() -> Result<u32, ()> {
+    let v = std::cell::RefCell::new(Some(vec![1]));
+    let r = match &*v.borrow() {
+        Some(v) => Ok(Ok(v[0])),
+        None => Ok(Ok(0)),
+    }?;
+    r
+}
+
 fn main() {}
diff --git a/tests/ui/let_and_return.rs b/tests/ui/let_and_return.rs
index 6b9035f9428..0b7a1e26890 100644
--- a/tests/ui/let_and_return.rs
+++ b/tests/ui/let_and_return.rs
@@ -1,3 +1,7 @@
+//@revisions: edition2021 edition2024
+//@[edition2021] edition:2021
+//@[edition2024] edition:2024
+
 #![allow(unused)]
 #![warn(clippy::let_and_return)]
 
@@ -101,6 +105,7 @@ mod no_lint_if_stmt_borrows {
         let value = value.upgrade().unwrap();
         let ret = value.borrow().baz();
         ret
+        //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
     }
 
     fn borrows_in_closure(value: Weak<RefCell<Bar>>) -> u32 {
@@ -111,6 +116,7 @@ mod no_lint_if_stmt_borrows {
         let value = value.upgrade().unwrap();
         let ret = f(|| value.borrow().baz())();
         ret
+        //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
     }
 
     mod free_function {
@@ -142,12 +148,14 @@ mod no_lint_if_stmt_borrows {
             let x = Inner {};
             let value = some_foo(&x).value();
             value
+            //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
         }
 
         fn test2() -> i32 {
             let x = Inner {};
             let value = Foo::new(&x).value();
             value
+            //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
         }
     }
 }
@@ -244,4 +252,14 @@ fn issue12801() {
     }
 }
 
+fn issue14164() -> Result<u32, ()> {
+    let v = std::cell::RefCell::new(Some(vec![1]));
+    let r = match &*v.borrow() {
+        Some(v) => Ok(Ok(v[0])),
+        None => Ok(Ok(0)),
+    }?;
+    r
+    //~[edition2024]^ ERROR: returning the result of a `let` binding from a block
+}
+
 fn main() {}
diff --git a/tests/ui/lines_filter_map_ok.fixed b/tests/ui/lines_filter_map_ok.fixed
index 621115cc132..ae388ec39a1 100644
--- a/tests/ui/lines_filter_map_ok.fixed
+++ b/tests/ui/lines_filter_map_ok.fixed
@@ -31,3 +31,10 @@ fn main() -> io::Result<()> {
     io::stdin().lines().filter_map(|x| x.err()).for_each(|_| ());
     Ok(())
 }
+
+#[clippy::msrv = "1.56"]
+fn msrv_check() {
+    let _lines = BufReader::new(std::fs::File::open("some-path").unwrap())
+        .lines()
+        .filter_map(Result::ok);
+}
diff --git a/tests/ui/lines_filter_map_ok.rs b/tests/ui/lines_filter_map_ok.rs
index a86efbd6686..4f486534e9b 100644
--- a/tests/ui/lines_filter_map_ok.rs
+++ b/tests/ui/lines_filter_map_ok.rs
@@ -31,3 +31,10 @@ fn main() -> io::Result<()> {
     io::stdin().lines().filter_map(|x| x.err()).for_each(|_| ());
     Ok(())
 }
+
+#[clippy::msrv = "1.56"]
+fn msrv_check() {
+    let _lines = BufReader::new(std::fs::File::open("some-path").unwrap())
+        .lines()
+        .filter_map(Result::ok);
+}
diff --git a/tests/ui/literal_string_with_formatting_arg.rs b/tests/ui/literal_string_with_formatting_arg.rs
index f257c66f59d..b9a6654d427 100644
--- a/tests/ui/literal_string_with_formatting_arg.rs
+++ b/tests/ui/literal_string_with_formatting_arg.rs
@@ -1,6 +1,31 @@
 #![warn(clippy::literal_string_with_formatting_args)]
 #![allow(clippy::unnecessary_literal_unwrap)]
 
+// Regression test for <https://github.com/rust-lang/rust-clippy/issues/13885>.
+// It's not supposed to emit the lint in this case (in `assert!` expansion).
+fn compiler_macro() {
+    fn parse(_: &str) -> Result<(), i32> {
+        unimplemented!()
+    }
+
+    assert!(
+        parse(
+            #[allow(clippy::literal_string_with_formatting_args)]
+            "foo {:}"
+        )
+        .is_err()
+    );
+    let value = 0;
+    assert!(format!("{value}").is_ascii());
+}
+
+// Regression test for <https://github.com/rust-lang/rust-clippy/issues/14007>.
+fn regression_14007() {
+    let s = "{и}";
+    let ш = 12;
+    let s = "{ш}"; //~ literal_string_with_formatting_args
+}
+
 fn main() {
     let x: Option<usize> = None;
     let y = "hello";
@@ -13,6 +38,7 @@ fn main() {
     x.expect(r"{y:?}  {y:?} "); //~ literal_string_with_formatting_args
     x.expect(r"{y:?} y:?}"); //~ literal_string_with_formatting_args
     x.expect(r##" {y:?} {y:?} "##); //~ literal_string_with_formatting_args
+    assert!("{y}".is_ascii()); //~ literal_string_with_formatting_args
     // Ensure that it doesn't try to go in the middle of a unicode character.
     x.expect("———{:?}"); //~ literal_string_with_formatting_args
 
diff --git a/tests/ui/literal_string_with_formatting_arg.stderr b/tests/ui/literal_string_with_formatting_arg.stderr
index 32a84f600da..021983056bf 100644
--- a/tests/ui/literal_string_with_formatting_arg.stderr
+++ b/tests/ui/literal_string_with_formatting_arg.stderr
@@ -1,71 +1,83 @@
 error: this looks like a formatting argument but it is not part of a formatting macro
-  --> tests/ui/literal_string_with_formatting_arg.rs:7:15
+  --> tests/ui/literal_string_with_formatting_arg.rs:26:14
    |
-LL |     x.expect("{y} {}");
-   |               ^^^
+LL |     let s = "{ш}";
+   |              ^^^
    |
    = note: `-D clippy::literal-string-with-formatting-args` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::literal_string_with_formatting_args)]`
 
 error: this looks like a formatting argument but it is not part of a formatting macro
-  --> tests/ui/literal_string_with_formatting_arg.rs:8:16
+  --> tests/ui/literal_string_with_formatting_arg.rs:32:15
+   |
+LL |     x.expect("{y} {}");
+   |               ^^^
+
+error: this looks like a formatting argument but it is not part of a formatting macro
+  --> tests/ui/literal_string_with_formatting_arg.rs:33:16
    |
 LL |     x.expect(" {y} bla");
    |                ^^^
 
 error: this looks like a formatting argument but it is not part of a formatting macro
-  --> tests/ui/literal_string_with_formatting_arg.rs:9:15
+  --> tests/ui/literal_string_with_formatting_arg.rs:34:15
    |
 LL |     x.expect("{:?}");
    |               ^^^^
 
 error: this looks like a formatting argument but it is not part of a formatting macro
-  --> tests/ui/literal_string_with_formatting_arg.rs:10:15
+  --> tests/ui/literal_string_with_formatting_arg.rs:35:15
    |
 LL |     x.expect("{y:?}");
    |               ^^^^^
 
 error: these look like formatting arguments but are not part of a formatting macro
-  --> tests/ui/literal_string_with_formatting_arg.rs:11:16
+  --> tests/ui/literal_string_with_formatting_arg.rs:36:16
    |
 LL |     x.expect(" {y:?} {y:?} ");
    |                ^^^^^ ^^^^^
 
 error: this looks like a formatting argument but it is not part of a formatting macro
-  --> tests/ui/literal_string_with_formatting_arg.rs:12:23
+  --> tests/ui/literal_string_with_formatting_arg.rs:37:23
    |
 LL |     x.expect(" {y:..} {y:?} ");
    |                       ^^^^^
 
 error: these look like formatting arguments but are not part of a formatting macro
-  --> tests/ui/literal_string_with_formatting_arg.rs:13:16
+  --> tests/ui/literal_string_with_formatting_arg.rs:38:16
    |
 LL |     x.expect(r"{y:?}  {y:?} ");
    |                ^^^^^  ^^^^^
 
 error: this looks like a formatting argument but it is not part of a formatting macro
-  --> tests/ui/literal_string_with_formatting_arg.rs:14:16
+  --> tests/ui/literal_string_with_formatting_arg.rs:39:16
    |
 LL |     x.expect(r"{y:?} y:?}");
    |                ^^^^^
 
 error: these look like formatting arguments but are not part of a formatting macro
-  --> tests/ui/literal_string_with_formatting_arg.rs:15:19
+  --> tests/ui/literal_string_with_formatting_arg.rs:40:19
    |
 LL |     x.expect(r##" {y:?} {y:?} "##);
    |                   ^^^^^ ^^^^^
 
 error: this looks like a formatting argument but it is not part of a formatting macro
-  --> tests/ui/literal_string_with_formatting_arg.rs:17:18
+  --> tests/ui/literal_string_with_formatting_arg.rs:41:14
+   |
+LL |     assert!("{y}".is_ascii());
+   |              ^^^
+
+error: this looks like a formatting argument but it is not part of a formatting macro
+  --> tests/ui/literal_string_with_formatting_arg.rs:43:18
    |
 LL |     x.expect("———{:?}");
    |                  ^^^^
 
 error: this looks like a formatting argument but it is not part of a formatting macro
-  --> tests/ui/literal_string_with_formatting_arg.rs:27:19
+  --> tests/ui/literal_string_with_formatting_arg.rs:53:19
    |
 LL |     x.expect(r##" {x:?} "##); // `x` doesn't exist so we shoud not lint
    |                   ^^^^^
 
-error: aborting due to 11 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed
index dc1cb8e11fc..ad0266d39e9 100644
--- a/tests/ui/manual_async_fn.fixed
+++ b/tests/ui/manual_async_fn.fixed
@@ -113,4 +113,30 @@ pub(crate) async fn issue_10450_2() -> i32 { 42 }
 
 pub(self) async fn issue_10450_3() -> i32 { 42 }
 
+macro_rules! issue_12407 {
+    (
+        $(
+            $(#[$m:meta])*
+            $v:vis $(override($($overrides:tt),* $(,)?))? fn $name:ident $([$($params:tt)*])? (
+                $($arg_name:ident: $arg_typ:ty),* $(,)?
+            ) $(-> $ret_ty:ty)? = $e:expr;
+        )*
+    ) => {
+        $(
+            $(#[$m])*
+            $v $($($overrides)*)? fn $name$(<$($params)*>)?(
+                $($arg_name: $arg_typ),*
+            ) $(-> $ret_ty)? {
+                $e
+            }
+        )*
+    };
+}
+
+issue_12407! {
+    fn _hello() -> impl Future<Output = ()> = async {};
+    fn non_async() = println!("hello");
+    fn foo() = non_async();
+}
+
 fn main() {}
diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs
index 9ca7654a368..87973222c0b 100644
--- a/tests/ui/manual_async_fn.rs
+++ b/tests/ui/manual_async_fn.rs
@@ -139,4 +139,30 @@ pub(self) fn issue_10450_3() -> impl Future<Output = i32> {
     async { 42 }
 }
 
+macro_rules! issue_12407 {
+    (
+        $(
+            $(#[$m:meta])*
+            $v:vis $(override($($overrides:tt),* $(,)?))? fn $name:ident $([$($params:tt)*])? (
+                $($arg_name:ident: $arg_typ:ty),* $(,)?
+            ) $(-> $ret_ty:ty)? = $e:expr;
+        )*
+    ) => {
+        $(
+            $(#[$m])*
+            $v $($($overrides)*)? fn $name$(<$($params)*>)?(
+                $($arg_name: $arg_typ),*
+            ) $(-> $ret_ty)? {
+                $e
+            }
+        )*
+    };
+}
+
+issue_12407! {
+    fn _hello() -> impl Future<Output = ()> = async {};
+    fn non_async() = println!("hello");
+    fn foo() = non_async();
+}
+
 fn main() {}
diff --git a/tests/ui/manual_map_option.fixed b/tests/ui/manual_map_option.fixed
index 16cee3fd382..3586979ab35 100644
--- a/tests/ui/manual_map_option.fixed
+++ b/tests/ui/manual_map_option.fixed
@@ -113,7 +113,16 @@ fn main() {
     }
 
     // #6811
-    Some(0).map(|x| vec![x]);
+    match Some(0) {
+        Some(x) => Some(vec![x]),
+        None => None,
+    };
+
+    // Don't lint, coercion
+    let x: Option<Vec<&[u8]>> = match Some(()) {
+        Some(_) => Some(vec![b"1234"]),
+        None => None,
+    };
 
     option_env!("").map(String::from);
 
diff --git a/tests/ui/manual_map_option.rs b/tests/ui/manual_map_option.rs
index 4655acf1406..2f21628977c 100644
--- a/tests/ui/manual_map_option.rs
+++ b/tests/ui/manual_map_option.rs
@@ -170,6 +170,12 @@ fn main() {
         None => None,
     };
 
+    // Don't lint, coercion
+    let x: Option<Vec<&[u8]>> = match Some(()) {
+        Some(_) => Some(vec![b"1234"]),
+        None => None,
+    };
+
     match option_env!("") {
         Some(x) => Some(String::from(x)),
         None => None,
diff --git a/tests/ui/manual_map_option.stderr b/tests/ui/manual_map_option.stderr
index 47cc18303ba..c496752e2f6 100644
--- a/tests/ui/manual_map_option.stderr
+++ b/tests/ui/manual_map_option.stderr
@@ -156,16 +156,7 @@ LL | |     };
    | |_____^ help: try: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))`
 
 error: manual implementation of `Option::map`
-  --> tests/ui/manual_map_option.rs:168:5
-   |
-LL | /     match Some(0) {
-LL | |         Some(x) => Some(vec![x]),
-LL | |         None => None,
-LL | |     };
-   | |_____^ help: try: `Some(0).map(|x| vec![x])`
-
-error: manual implementation of `Option::map`
-  --> tests/ui/manual_map_option.rs:173:5
+  --> tests/ui/manual_map_option.rs:179:5
    |
 LL | /     match option_env!("") {
 LL | |         Some(x) => Some(String::from(x)),
@@ -174,7 +165,7 @@ LL | |     };
    | |_____^ help: try: `option_env!("").map(String::from)`
 
 error: manual implementation of `Option::map`
-  --> tests/ui/manual_map_option.rs:193:12
+  --> tests/ui/manual_map_option.rs:199:12
    |
 LL |       } else if let Some(x) = Some(0) {
    |  ____________^
@@ -185,7 +176,7 @@ LL | |     };
    | |_____^ help: try: `{ Some(0).map(|x| x + 1) }`
 
 error: manual implementation of `Option::map`
-  --> tests/ui/manual_map_option.rs:201:12
+  --> tests/ui/manual_map_option.rs:207:12
    |
 LL |       } else if let Some(x) = Some(0) {
    |  ____________^
@@ -195,5 +186,5 @@ LL | |         None
 LL | |     };
    | |_____^ help: try: `{ Some(0).map(|x| x + 1) }`
 
-error: aborting due to 21 previous errors
+error: aborting due to 20 previous errors
 
diff --git a/tests/ui/manual_map_option_2.fixed b/tests/ui/manual_map_option_2.fixed
index f5bb4e0af1b..49b9e77b441 100644
--- a/tests/ui/manual_map_option_2.fixed
+++ b/tests/ui/manual_map_option_2.fixed
@@ -40,9 +40,14 @@ fn main() {
         None => None,
     };
 
-    // Lint. `s` is captured by reference, so no lifetime issues.
     let s = Some(String::new());
+    // Lint. `s` is captured by reference, so no lifetime issues.
     let _ = s.as_ref().map(|x| { if let Some(ref s) = s { (x.clone(), s) } else { panic!() } });
+    // Don't lint this, type of `s` is coercioned from `&String` to `&str`
+    let x: Option<(String, &str)> = match &s {
+        Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+        None => None,
+    };
 
     // Issue #7820
     unsafe fn f(x: u32) -> u32 {
@@ -54,3 +59,89 @@ fn main() {
     let _ = Some(0).map(|x| unsafe { f(x) });
     let _ = Some(0).map(|x| unsafe { f(x) });
 }
+
+// issue #12659
+mod with_type_coercion {
+    trait DummyTrait {}
+
+    fn foo<T: DummyTrait, F: Fn() -> Result<T, ()>>(f: F) {
+        // Don't lint
+        let _: Option<Result<Box<dyn DummyTrait>, ()>> = match Some(0) {
+            Some(_) => Some(match f() {
+                Ok(res) => Ok(Box::new(res)),
+                _ => Err(()),
+            }),
+            None => None,
+        };
+
+        let _: Option<Box<&[u8]>> = match Some(()) {
+            Some(_) => Some(Box::new(b"1234")),
+            None => None,
+        };
+
+        let x = String::new();
+        let _: Option<Box<&str>> = match Some(()) {
+            Some(_) => Some(Box::new(&x)),
+            None => None,
+        };
+
+        let _: Option<&str> = match Some(()) {
+            Some(_) => Some(&x),
+            None => None,
+        };
+
+        //~v ERROR: manual implementation of `Option::map`
+        let _ = Some(0).map(|_| match f() {
+                Ok(res) => Ok(Box::new(res)),
+                _ => Err(()),
+            });
+    }
+
+    #[allow(clippy::redundant_allocation)]
+    fn bar() {
+        fn f(_: Option<Box<&[u8]>>) {}
+        fn g(b: &[u8]) -> Box<&[u8]> {
+            Box::new(b)
+        }
+
+        let x: &[u8; 4] = b"1234";
+        f(match Some(()) {
+            Some(_) => Some(Box::new(x)),
+            None => None,
+        });
+
+        //~v ERROR: manual implementation of `Option::map`
+        let _: Option<Box<&[u8]>> = Some(0).map(|_| g(x));
+    }
+
+    fn with_fn_ret(s: &Option<String>) -> Option<(String, &str)> {
+        // Don't lint, `map` doesn't work as the return type is adjusted.
+        match s {
+            Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+            None => None,
+        }
+    }
+
+    fn with_fn_ret_2(s: &Option<String>) -> Option<(String, &str)> {
+        if true {
+            // Don't lint, `map` doesn't work as the return type is adjusted.
+            return match s {
+                Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+                None => None,
+            };
+        }
+        None
+    }
+
+    #[allow(clippy::needless_late_init)]
+    fn with_fn_ret_3<'a>(s: &'a Option<String>) -> Option<(String, &'a str)> {
+        let x: Option<(String, &'a str)>;
+        x = {
+            match s {
+                Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+                None => None,
+            }
+        };
+        x
+    }
+}
diff --git a/tests/ui/manual_map_option_2.rs b/tests/ui/manual_map_option_2.rs
index cbc2356e0a2..962455daf7b 100644
--- a/tests/ui/manual_map_option_2.rs
+++ b/tests/ui/manual_map_option_2.rs
@@ -43,12 +43,17 @@ fn main() {
         None => None,
     };
 
-    // Lint. `s` is captured by reference, so no lifetime issues.
     let s = Some(String::new());
+    // Lint. `s` is captured by reference, so no lifetime issues.
     let _ = match &s {
         Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
         None => None,
     };
+    // Don't lint this, type of `s` is coercioned from `&String` to `&str`
+    let x: Option<(String, &str)> = match &s {
+        Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+        None => None,
+    };
 
     // Issue #7820
     unsafe fn f(x: u32) -> u32 {
@@ -69,3 +74,95 @@ fn main() {
         None => None,
     };
 }
+
+// issue #12659
+mod with_type_coercion {
+    trait DummyTrait {}
+
+    fn foo<T: DummyTrait, F: Fn() -> Result<T, ()>>(f: F) {
+        // Don't lint
+        let _: Option<Result<Box<dyn DummyTrait>, ()>> = match Some(0) {
+            Some(_) => Some(match f() {
+                Ok(res) => Ok(Box::new(res)),
+                _ => Err(()),
+            }),
+            None => None,
+        };
+
+        let _: Option<Box<&[u8]>> = match Some(()) {
+            Some(_) => Some(Box::new(b"1234")),
+            None => None,
+        };
+
+        let x = String::new();
+        let _: Option<Box<&str>> = match Some(()) {
+            Some(_) => Some(Box::new(&x)),
+            None => None,
+        };
+
+        let _: Option<&str> = match Some(()) {
+            Some(_) => Some(&x),
+            None => None,
+        };
+
+        //~v ERROR: manual implementation of `Option::map`
+        let _ = match Some(0) {
+            Some(_) => Some(match f() {
+                Ok(res) => Ok(Box::new(res)),
+                _ => Err(()),
+            }),
+            None => None,
+        };
+    }
+
+    #[allow(clippy::redundant_allocation)]
+    fn bar() {
+        fn f(_: Option<Box<&[u8]>>) {}
+        fn g(b: &[u8]) -> Box<&[u8]> {
+            Box::new(b)
+        }
+
+        let x: &[u8; 4] = b"1234";
+        f(match Some(()) {
+            Some(_) => Some(Box::new(x)),
+            None => None,
+        });
+
+        //~v ERROR: manual implementation of `Option::map`
+        let _: Option<Box<&[u8]>> = match Some(0) {
+            Some(_) => Some(g(x)),
+            None => None,
+        };
+    }
+
+    fn with_fn_ret(s: &Option<String>) -> Option<(String, &str)> {
+        // Don't lint, `map` doesn't work as the return type is adjusted.
+        match s {
+            Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+            None => None,
+        }
+    }
+
+    fn with_fn_ret_2(s: &Option<String>) -> Option<(String, &str)> {
+        if true {
+            // Don't lint, `map` doesn't work as the return type is adjusted.
+            return match s {
+                Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+                None => None,
+            };
+        }
+        None
+    }
+
+    #[allow(clippy::needless_late_init)]
+    fn with_fn_ret_3<'a>(s: &'a Option<String>) -> Option<(String, &'a str)> {
+        let x: Option<(String, &'a str)>;
+        x = {
+            match s {
+                Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+                None => None,
+            }
+        };
+        x
+    }
+}
diff --git a/tests/ui/manual_map_option_2.stderr b/tests/ui/manual_map_option_2.stderr
index 78e4677544b..db048221db6 100644
--- a/tests/ui/manual_map_option_2.stderr
+++ b/tests/ui/manual_map_option_2.stderr
@@ -32,7 +32,7 @@ LL | |     };
    | |_____^ help: try: `s.as_ref().map(|x| { if let Some(ref s) = s { (x.clone(), s) } else { panic!() } })`
 
 error: manual implementation of `Option::map`
-  --> tests/ui/manual_map_option_2.rs:58:17
+  --> tests/ui/manual_map_option_2.rs:63:17
    |
 LL |           let _ = match Some(0) {
    |  _________________^
@@ -42,7 +42,7 @@ LL | |         };
    | |_________^ help: try: `Some(0).map(|x| f(x))`
 
 error: manual implementation of `Option::map`
-  --> tests/ui/manual_map_option_2.rs:63:13
+  --> tests/ui/manual_map_option_2.rs:68:13
    |
 LL |       let _ = match Some(0) {
    |  _____________^
@@ -52,7 +52,7 @@ LL | |     };
    | |_____^ help: try: `Some(0).map(|x| unsafe { f(x) })`
 
 error: manual implementation of `Option::map`
-  --> tests/ui/manual_map_option_2.rs:67:13
+  --> tests/ui/manual_map_option_2.rs:72:13
    |
 LL |       let _ = match Some(0) {
    |  _____________^
@@ -61,5 +61,36 @@ LL | |         None => None,
 LL | |     };
    | |_____^ help: try: `Some(0).map(|x| unsafe { f(x) })`
 
-error: aborting due to 5 previous errors
+error: manual implementation of `Option::map`
+  --> tests/ui/manual_map_option_2.rs:109:17
+   |
+LL |           let _ = match Some(0) {
+   |  _________________^
+LL | |             Some(_) => Some(match f() {
+LL | |                 Ok(res) => Ok(Box::new(res)),
+LL | |                 _ => Err(()),
+LL | |             }),
+LL | |             None => None,
+LL | |         };
+   | |_________^
+   |
+help: try
+   |
+LL ~         let _ = Some(0).map(|_| match f() {
+LL +                 Ok(res) => Ok(Box::new(res)),
+LL +                 _ => Err(()),
+LL ~             });
+   |
+
+error: manual implementation of `Option::map`
+  --> tests/ui/manual_map_option_2.rs:132:37
+   |
+LL |           let _: Option<Box<&[u8]>> = match Some(0) {
+   |  _____________________________________^
+LL | |             Some(_) => Some(g(x)),
+LL | |             None => None,
+LL | |         };
+   | |_________^ help: try: `Some(0).map(|_| g(x))`
+
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/manual_ok_or.stderr b/tests/ui/manual_ok_or.stderr
index 2441a75b5c4..4722f53580f 100644
--- a/tests/ui/manual_ok_or.stderr
+++ b/tests/ui/manual_ok_or.stderr
@@ -13,15 +13,6 @@ error: this pattern reimplements `Option::ok_or`
 LL |     foo.map_or(Err("error"), Ok);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")`
 
-error: called `map_or(Err(_), Ok)` on an `Option` value
-  --> tests/ui/manual_ok_or.rs:14:5
-   |
-LL |     foo.map_or(Err("error"), Ok);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok_or`: `foo.ok_or("error")`
-   |
-   = note: `-D clippy::option-map-or-err-ok` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::option_map_or_err_ok)]`
-
 error: this pattern reimplements `Option::ok_or`
   --> tests/ui/manual_ok_or.rs:17:5
    |
@@ -47,5 +38,5 @@ LL +         "{}{}{}{}{}{}{}",
 LL ~         "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer"));
    |
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/manual_slice_fill.fixed b/tests/ui/manual_slice_fill.fixed
index 397a156a2dc..80e271117fc 100644
--- a/tests/ui/manual_slice_fill.fixed
+++ b/tests/ui/manual_slice_fill.fixed
@@ -1,5 +1,5 @@
 #![warn(clippy::manual_slice_fill)]
-#![allow(clippy::needless_range_loop)]
+#![allow(clippy::needless_range_loop, clippy::useless_vec)]
 
 macro_rules! assign_element {
     ($slice:ident, $index:expr) => {
@@ -99,3 +99,19 @@ fn should_not_lint() {
         *i = None;
     }
 }
+
+fn issue_14192() {
+    let mut tmp = vec![0; 3];
+
+    for i in 0..tmp.len() {
+        tmp[i] = i;
+    }
+
+    for i in 0..tmp.len() {
+        tmp[i] = 2 + i;
+    }
+
+    for i in 0..tmp.len() {
+        tmp[0] = i;
+    }
+}
diff --git a/tests/ui/manual_slice_fill.rs b/tests/ui/manual_slice_fill.rs
index c25127ca613..75a391f4243 100644
--- a/tests/ui/manual_slice_fill.rs
+++ b/tests/ui/manual_slice_fill.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::manual_slice_fill)]
-#![allow(clippy::needless_range_loop)]
+#![allow(clippy::needless_range_loop, clippy::useless_vec)]
 
 macro_rules! assign_element {
     ($slice:ident, $index:expr) => {
@@ -108,3 +108,19 @@ fn should_not_lint() {
         *i = None;
     }
 }
+
+fn issue_14192() {
+    let mut tmp = vec![0; 3];
+
+    for i in 0..tmp.len() {
+        tmp[i] = i;
+    }
+
+    for i in 0..tmp.len() {
+        tmp[i] = 2 + i;
+    }
+
+    for i in 0..tmp.len() {
+        tmp[0] = i;
+    }
+}
diff --git a/tests/ui/match_bool.fixed b/tests/ui/match_bool.fixed
index 61a8e54fa10..1dfb82db120 100644
--- a/tests/ui/match_bool.fixed
+++ b/tests/ui/match_bool.fixed
@@ -55,4 +55,10 @@ fn match_bool() {
     if !(!test && option == 5) { println!("Hello") };
 }
 
+fn issue14099() {
+    if true { 'a: {
+        break 'a;
+    } }
+}
+
 fn main() {}
diff --git a/tests/ui/match_bool.rs b/tests/ui/match_bool.rs
index 9c81d291786..e77f0304fed 100644
--- a/tests/ui/match_bool.rs
+++ b/tests/ui/match_bool.rs
@@ -103,4 +103,14 @@ fn match_bool() {
     };
 }
 
+fn issue14099() {
+    match true {
+        //~^ ERROR: `match` on a boolean expression
+        true => 'a: {
+            break 'a;
+        },
+        _ => (),
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/match_bool.stderr b/tests/ui/match_bool.stderr
index a4e504a0a82..c05742e5633 100644
--- a/tests/ui/match_bool.stderr
+++ b/tests/ui/match_bool.stderr
@@ -164,5 +164,24 @@ LL | |         _ => println!("Hello"),
 LL | |     };
    | |_____^ help: consider using an `if`/`else` expression: `if !(!test && option == 5) { println!("Hello") }`
 
-error: aborting due to 12 previous errors
+error: `match` on a boolean expression
+  --> tests/ui/match_bool.rs:107:5
+   |
+LL | /     match true {
+LL | |
+LL | |         true => 'a: {
+LL | |             break 'a;
+LL | |         },
+LL | |         _ => (),
+LL | |     }
+   | |_____^
+   |
+help: consider using an `if`/`else` expression
+   |
+LL ~     if true { 'a: {
+LL +         break 'a;
+LL +     } }
+   |
+
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/mem_replace.fixed b/tests/ui/mem_replace.fixed
index 4210dbbe82d..02b0d9c7045 100644
--- a/tests/ui/mem_replace.fixed
+++ b/tests/ui/mem_replace.fixed
@@ -18,10 +18,12 @@ fn replace_option_with_none() {
 fn replace_with_default() {
     let mut s = String::from("foo");
     let _ = std::mem::take(&mut s);
+    let _ = std::mem::take(&mut s);
 
     let s = &mut String::from("foo");
     let _ = std::mem::take(s);
     let _ = std::mem::take(s);
+    let _ = std::mem::take(s);
 
     let mut v = vec![123];
     let _ = std::mem::take(&mut v);
@@ -129,3 +131,25 @@ fn issue9824() {
     // replace with default
     let _ = std::mem::take(&mut b.val);
 }
+
+#[clippy::msrv = "1.31"]
+fn mem_replace_option_with_some() {
+    let mut an_option = Some(0);
+    let replaced = an_option.replace(1);
+    //~^ ERROR: replacing an `Option` with `Some(..)`
+
+    let mut an_option = &mut Some(0);
+    let replaced = an_option.replace(1);
+    //~^ ERROR: replacing an `Option` with `Some(..)`
+
+    let (mut opt1, mut opt2) = (Some(0), Some(0));
+    let b = true;
+    let replaced = (if b { &mut opt1 } else { &mut opt2 }).replace(1);
+    //~^ ERROR: replacing an `Option` with `Some(..)`
+}
+
+#[clippy::msrv = "1.30"]
+fn mem_replace_option_with_some_bad_msrv() {
+    let mut an_option = Some(0);
+    let replaced = mem::replace(&mut an_option, Some(1));
+}
diff --git a/tests/ui/mem_replace.rs b/tests/ui/mem_replace.rs
index bd7ad78b2af..1bb72b5de23 100644
--- a/tests/ui/mem_replace.rs
+++ b/tests/ui/mem_replace.rs
@@ -18,9 +18,11 @@ fn replace_option_with_none() {
 fn replace_with_default() {
     let mut s = String::from("foo");
     let _ = std::mem::replace(&mut s, String::default());
+    let _ = std::mem::replace(&mut s, String::new());
 
     let s = &mut String::from("foo");
     let _ = std::mem::replace(s, String::default());
+    let _ = std::mem::replace(s, String::new());
     let _ = std::mem::replace(s, Default::default());
 
     let mut v = vec![123];
@@ -129,3 +131,25 @@ fn issue9824() {
     // replace with default
     let _ = std::mem::replace(&mut b.val, String::default());
 }
+
+#[clippy::msrv = "1.31"]
+fn mem_replace_option_with_some() {
+    let mut an_option = Some(0);
+    let replaced = mem::replace(&mut an_option, Some(1));
+    //~^ ERROR: replacing an `Option` with `Some(..)`
+
+    let mut an_option = &mut Some(0);
+    let replaced = mem::replace(an_option, Some(1));
+    //~^ ERROR: replacing an `Option` with `Some(..)`
+
+    let (mut opt1, mut opt2) = (Some(0), Some(0));
+    let b = true;
+    let replaced = mem::replace(if b { &mut opt1 } else { &mut opt2 }, Some(1));
+    //~^ ERROR: replacing an `Option` with `Some(..)`
+}
+
+#[clippy::msrv = "1.30"]
+fn mem_replace_option_with_some_bad_msrv() {
+    let mut an_option = Some(0);
+    let replaced = mem::replace(&mut an_option, Some(1));
+}
diff --git a/tests/ui/mem_replace.stderr b/tests/ui/mem_replace.stderr
index c33f80b01b8..42ab546a5d7 100644
--- a/tests/ui/mem_replace.stderr
+++ b/tests/ui/mem_replace.stderr
@@ -23,130 +23,163 @@ LL |     let _ = std::mem::replace(&mut s, String::default());
    = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:23:13
+  --> tests/ui/mem_replace.rs:21:13
+   |
+LL |     let _ = std::mem::replace(&mut s, String::new());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
+
+error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
+  --> tests/ui/mem_replace.rs:24: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`
-  --> tests/ui/mem_replace.rs:24:13
+  --> tests/ui/mem_replace.rs:25:13
+   |
+LL |     let _ = std::mem::replace(s, String::new());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)`
+
+error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
+  --> tests/ui/mem_replace.rs:26: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`
-  --> tests/ui/mem_replace.rs:27:13
+  --> tests/ui/mem_replace.rs:29: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`
-  --> tests/ui/mem_replace.rs:28:13
+  --> tests/ui/mem_replace.rs:30: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`
-  --> tests/ui/mem_replace.rs:29:13
+  --> tests/ui/mem_replace.rs:31: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`
-  --> tests/ui/mem_replace.rs:30:13
+  --> tests/ui/mem_replace.rs:32: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`
-  --> tests/ui/mem_replace.rs:33:13
+  --> tests/ui/mem_replace.rs:35: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`
-  --> tests/ui/mem_replace.rs:36:13
+  --> tests/ui/mem_replace.rs:38: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`
-  --> tests/ui/mem_replace.rs:39:13
+  --> tests/ui/mem_replace.rs:41: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`
-  --> tests/ui/mem_replace.rs:42:13
+  --> tests/ui/mem_replace.rs:44: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`
-  --> tests/ui/mem_replace.rs:45:13
+  --> tests/ui/mem_replace.rs:47: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`
-  --> tests/ui/mem_replace.rs:48:13
+  --> tests/ui/mem_replace.rs:50: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`
-  --> tests/ui/mem_replace.rs:51:13
+  --> tests/ui/mem_replace.rs:53: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`
-  --> tests/ui/mem_replace.rs:54:13
+  --> tests/ui/mem_replace.rs:56: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`
-  --> tests/ui/mem_replace.rs:57:13
+  --> tests/ui/mem_replace.rs:59: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`
-  --> tests/ui/mem_replace.rs:60:13
+  --> tests/ui/mem_replace.rs:62:13
    |
 LL |     let _ = std::mem::replace(&mut slice, &[]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut slice)`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:96:13
+  --> tests/ui/mem_replace.rs:98:13
    |
 LL |     let _ = std::mem::replace(&mut s, String::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)`
 
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace.rs:126:13
+  --> tests/ui/mem_replace.rs:128:13
    |
 LL |     let _ = std::mem::replace(&mut f.0, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()`
 
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace.rs:127:13
+  --> tests/ui/mem_replace.rs:129:13
    |
 LL |     let _ = std::mem::replace(&mut *f, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()`
 
 error: replacing an `Option` with `None`
-  --> tests/ui/mem_replace.rs:128:13
+  --> tests/ui/mem_replace.rs:130:13
    |
 LL |     let _ = std::mem::replace(&mut b.opt, None);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()`
 
 error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take`
-  --> tests/ui/mem_replace.rs:130:13
+  --> tests/ui/mem_replace.rs:132:13
    |
 LL |     let _ = std::mem::replace(&mut b.val, String::default());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut b.val)`
 
-error: aborting due to 24 previous errors
+error: replacing an `Option` with `Some(..)`
+  --> tests/ui/mem_replace.rs:138:20
+   |
+LL |     let replaced = mem::replace(&mut an_option, Some(1));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `an_option.replace(1)`
+   |
+   = note: `-D clippy::mem-replace-option-with-some` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_some)]`
+
+error: replacing an `Option` with `Some(..)`
+  --> tests/ui/mem_replace.rs:142:20
+   |
+LL |     let replaced = mem::replace(an_option, Some(1));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `an_option.replace(1)`
+
+error: replacing an `Option` with `Some(..)`
+  --> tests/ui/mem_replace.rs:147:20
+   |
+LL |     let replaced = mem::replace(if b { &mut opt1 } else { &mut opt2 }, Some(1));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `(if b { &mut opt1 } else { &mut opt2 }).replace(1)`
+
+error: aborting due to 29 previous errors
 
diff --git a/tests/ui/nonminimal_bool.rs b/tests/ui/nonminimal_bool.rs
index 52b0155a762..9d0a475064e 100644
--- a/tests/ui/nonminimal_bool.rs
+++ b/tests/ui/nonminimal_bool.rs
@@ -183,3 +183,9 @@ fn issue_12371(x: usize) -> bool {
 fn many_ops(a: bool, b: bool, c: bool, d: bool, e: bool, f: bool) -> bool {
     (a && c && f) || (!a && b && !d) || (!b && !c && !e) || (d && e && !f)
 }
+
+fn issue14184(a: f32, b: bool) {
+    if !(a < 2.0 && !b) {
+        println!("Hi");
+    }
+}
diff --git a/tests/ui/nonminimal_bool.stderr b/tests/ui/nonminimal_bool.stderr
index 578f918f013..129dadf315e 100644
--- a/tests/ui/nonminimal_bool.stderr
+++ b/tests/ui/nonminimal_bool.stderr
@@ -213,5 +213,11 @@ error: this boolean expression can be simplified
 LL |     if !b != !c {}
    |        ^^^^^^^^ help: try: `b != c`
 
-error: aborting due to 29 previous errors
+error: this boolean expression can be simplified
+  --> tests/ui/nonminimal_bool.rs:188:8
+   |
+LL |     if !(a < 2.0 && !b) {
+   |        ^^^^^^^^^^^^^^^^ help: try: `!(a < 2.0) || b`
+
+error: aborting due to 30 previous errors
 
diff --git a/tests/ui/obfuscated_if_else.fixed b/tests/ui/obfuscated_if_else.fixed
index bfe1c5e10cf..2cdbee90d52 100644
--- a/tests/ui/obfuscated_if_else.fixed
+++ b/tests/ui/obfuscated_if_else.fixed
@@ -3,16 +3,48 @@
 
 fn main() {
     if true { "a" } else { "b" };
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
     if true { "a" } else { "b" };
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
 
     let a = 1;
     if a == 1 { "a" } else { "b" };
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
     if a == 1 { "a" } else { "b" };
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
 
     let partial = (a == 1).then_some("a");
     partial.unwrap_or("b"); // not lint
 
     let mut a = 0;
     if true { a += 1 } else { () };
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
     if true { () } else { a += 2 };
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+}
+
+fn issue11141() {
+    // Parentheses are required around the left side of a binary expression
+    let _ = (if true { 40 } else { 17 }) | 2;
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are required only for the leftmost expression
+    let _ = (if true { 30 } else { 17 }) | if true { 2 } else { 3 } | if true { 10 } else { 1 };
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required around the right side of a binary expression
+    let _ = 2 | if true { 40 } else { 17 };
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required for a cast
+    let _ = if true { 42 } else { 17 } as u8;
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required for a deref
+    let _ = *if true { &42 } else { &17 };
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required for a deref followed by a cast
+    let _ = *if true { &42 } else { &17 } as u8;
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
 }
diff --git a/tests/ui/obfuscated_if_else.rs b/tests/ui/obfuscated_if_else.rs
index 0ded2a2ceed..20c67e72992 100644
--- a/tests/ui/obfuscated_if_else.rs
+++ b/tests/ui/obfuscated_if_else.rs
@@ -3,16 +3,48 @@
 
 fn main() {
     true.then_some("a").unwrap_or("b");
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
     true.then(|| "a").unwrap_or("b");
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
 
     let a = 1;
     (a == 1).then_some("a").unwrap_or("b");
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
     (a == 1).then(|| "a").unwrap_or("b");
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
 
     let partial = (a == 1).then_some("a");
     partial.unwrap_or("b"); // not lint
 
     let mut a = 0;
     true.then_some(a += 1).unwrap_or(());
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
     true.then_some(()).unwrap_or(a += 2);
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+}
+
+fn issue11141() {
+    // Parentheses are required around the left side of a binary expression
+    let _ = true.then_some(40).unwrap_or(17) | 2;
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are required only for the leftmost expression
+    let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required around the right side of a binary expression
+    let _ = 2 | true.then_some(40).unwrap_or(17);
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required for a cast
+    let _ = true.then_some(42).unwrap_or(17) as u8;
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required for a deref
+    let _ = *true.then_some(&42).unwrap_or(&17);
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
+
+    // Parentheses are not required for a deref followed by a cast
+    let _ = *true.then_some(&42).unwrap_or(&17) as u8;
+    //~^ ERROR: this method chain can be written more clearly with `if .. else ..`
 }
diff --git a/tests/ui/obfuscated_if_else.stderr b/tests/ui/obfuscated_if_else.stderr
index 9ce1f475c48..9b1aebb5894 100644
--- a/tests/ui/obfuscated_if_else.stderr
+++ b/tests/ui/obfuscated_if_else.stderr
@@ -8,34 +8,82 @@ LL |     true.then_some("a").unwrap_or("b");
    = help: to override `-D warnings` add `#[allow(clippy::obfuscated_if_else)]`
 
 error: this method chain can be written more clearly with `if .. else ..`
-  --> tests/ui/obfuscated_if_else.rs:6:5
+  --> tests/ui/obfuscated_if_else.rs:7:5
    |
 LL |     true.then(|| "a").unwrap_or("b");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }`
 
 error: this method chain can be written more clearly with `if .. else ..`
-  --> tests/ui/obfuscated_if_else.rs:9:5
+  --> tests/ui/obfuscated_if_else.rs:11:5
    |
 LL |     (a == 1).then_some("a").unwrap_or("b");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if a == 1 { "a" } else { "b" }`
 
 error: this method chain can be written more clearly with `if .. else ..`
-  --> tests/ui/obfuscated_if_else.rs:10:5
+  --> tests/ui/obfuscated_if_else.rs:13:5
    |
 LL |     (a == 1).then(|| "a").unwrap_or("b");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if a == 1 { "a" } else { "b" }`
 
 error: this method chain can be written more clearly with `if .. else ..`
-  --> tests/ui/obfuscated_if_else.rs:16:5
+  --> tests/ui/obfuscated_if_else.rs:20:5
    |
 LL |     true.then_some(a += 1).unwrap_or(());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { a += 1 } else { () }`
 
 error: this method chain can be written more clearly with `if .. else ..`
-  --> tests/ui/obfuscated_if_else.rs:17:5
+  --> tests/ui/obfuscated_if_else.rs:22:5
    |
 LL |     true.then_some(()).unwrap_or(a += 2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { () } else { a += 2 }`
 
-error: aborting due to 6 previous errors
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:28:13
+   |
+LL |     let _ = true.then_some(40).unwrap_or(17) | 2;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(if true { 40 } else { 17 })`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:32:13
+   |
+LL |     let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(if true { 30 } else { 17 })`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:32:48
+   |
+LL |     let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
+   |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 2 } else { 3 }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:32:81
+   |
+LL |     let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
+   |                                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 10 } else { 1 }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:36:17
+   |
+LL |     let _ = 2 | true.then_some(40).unwrap_or(17);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 40 } else { 17 }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:40:13
+   |
+LL |     let _ = true.then_some(42).unwrap_or(17) as u8;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 42 } else { 17 }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:44:14
+   |
+LL |     let _ = *true.then_some(&42).unwrap_or(&17);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+  --> tests/ui/obfuscated_if_else.rs:48:14
+   |
+LL |     let _ = *true.then_some(&42).unwrap_or(&17) as u8;
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }`
+
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/option_map_or_err_ok.fixed b/tests/ui/option_map_or_err_ok.fixed
deleted file mode 100644
index 131f4b2093e..00000000000
--- a/tests/ui/option_map_or_err_ok.fixed
+++ /dev/null
@@ -1,7 +0,0 @@
-#![warn(clippy::option_map_or_err_ok)]
-
-fn main() {
-    let x = Some("a");
-    let _ = x.ok_or("a");
-    //~^ ERROR: called `map_or(Err(_), Ok)` on an `Option` value
-}
diff --git a/tests/ui/option_map_or_err_ok.rs b/tests/ui/option_map_or_err_ok.rs
deleted file mode 100644
index 0f07a592ae5..00000000000
--- a/tests/ui/option_map_or_err_ok.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#![warn(clippy::option_map_or_err_ok)]
-
-fn main() {
-    let x = Some("a");
-    let _ = x.map_or(Err("a"), Ok);
-    //~^ ERROR: called `map_or(Err(_), Ok)` on an `Option` value
-}
diff --git a/tests/ui/option_map_or_err_ok.stderr b/tests/ui/option_map_or_err_ok.stderr
deleted file mode 100644
index 1971af80aa8..00000000000
--- a/tests/ui/option_map_or_err_ok.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: called `map_or(Err(_), Ok)` on an `Option` value
-  --> tests/ui/option_map_or_err_ok.rs:5:13
-   |
-LL |     let _ = x.map_or(Err("a"), Ok);
-   |             ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok_or`: `x.ok_or("a")`
-   |
-   = note: `-D clippy::option-map-or-err-ok` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::option_map_or_err_ok)]`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/range.fixed b/tests/ui/range.fixed
new file mode 100644
index 00000000000..82aa1b5f94f
--- /dev/null
+++ b/tests/ui/range.fixed
@@ -0,0 +1,18 @@
+#![allow(clippy::useless_vec)]
+#[warn(clippy::range_zip_with_len)]
+fn main() {
+    let v1 = vec![1, 2, 3];
+    let v2 = vec![4, 5];
+    let _x = v1.iter().enumerate();
+    //~^ ERROR: using `.zip()` with a range and `.len()`
+    let _y = v1.iter().zip(0..v2.len()); // No error
+}
+
+#[allow(unused)]
+fn no_panic_with_fake_range_types() {
+    struct Range {
+        foo: i32,
+    }
+
+    let _ = Range { foo: 0 };
+}
diff --git a/tests/ui/range.rs b/tests/ui/range.rs
index 9541812b069..a7d5cf38dfb 100644
--- a/tests/ui/range.rs
+++ b/tests/ui/range.rs
@@ -4,8 +4,7 @@ fn main() {
     let v1 = vec![1, 2, 3];
     let v2 = vec![4, 5];
     let _x = v1.iter().zip(0..v1.len());
-    //~^ ERROR: it is more idiomatic to use `v1.iter().enumerate()`
-    //~| NOTE: `-D clippy::range-zip-with-len` implied by `-D warnings`
+    //~^ ERROR: using `.zip()` with a range and `.len()`
     let _y = v1.iter().zip(0..v2.len()); // No error
 }
 
diff --git a/tests/ui/range.stderr b/tests/ui/range.stderr
index 8c71a209700..798ce1842d8 100644
--- a/tests/ui/range.stderr
+++ b/tests/ui/range.stderr
@@ -1,8 +1,8 @@
-error: it is more idiomatic to use `v1.iter().enumerate()`
+error: using `.zip()` with a range and `.len()`
   --> tests/ui/range.rs:6:14
    |
 LL |     let _x = v1.iter().zip(0..v1.len());
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v1.iter().enumerate()`
    |
    = note: `-D clippy::range-zip-with-len` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::range_zip_with_len)]`
diff --git a/tests/ui/single_option_map.rs b/tests/ui/single_option_map.rs
new file mode 100644
index 00000000000..571beec5479
--- /dev/null
+++ b/tests/ui/single_option_map.rs
@@ -0,0 +1,69 @@
+#![warn(clippy::single_option_map)]
+
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+static ATOM: AtomicUsize = AtomicUsize::new(42);
+static MAYBE_ATOMIC: Option<&AtomicUsize> = Some(&ATOM);
+
+fn h(arg: Option<u32>) -> Option<u32> {
+    //~^ ERROR: `fn` that only maps over argument
+    arg.map(|x| x * 2)
+}
+
+fn j(arg: Option<u64>) -> Option<u64> {
+    //~^ ERROR: `fn` that only maps over argument
+    arg.map(|x| x * 2)
+}
+
+fn mul_args(a: String, b: u64) -> String {
+    a
+}
+
+fn mul_args_opt(a: Option<String>, b: u64) -> Option<String> {
+    //~^ ERROR: `fn` that only maps over argument
+    a.map(|val| mul_args(val, b + 1))
+}
+
+// No lint: no `Option` argument argument
+fn maps_static_option() -> Option<usize> {
+    MAYBE_ATOMIC.map(|a| a.load(Ordering::Relaxed))
+}
+
+// No lint: wrapped by another function
+fn manipulate(i: i32) -> i32 {
+    i + 1
+}
+// No lint: wraps another function to do the optional thing
+fn manipulate_opt(opt_i: Option<i32>) -> Option<i32> {
+    opt_i.map(manipulate)
+}
+
+// No lint: maps other than the receiver
+fn map_not_arg(arg: Option<u32>) -> Option<u32> {
+    maps_static_option().map(|_| arg.unwrap())
+}
+
+// No lint: wrapper function with η-expanded form
+#[allow(clippy::redundant_closure)]
+fn manipulate_opt_explicit(opt_i: Option<i32>) -> Option<i32> {
+    opt_i.map(|x| manipulate(x))
+}
+
+// No lint
+fn multi_args(a: String, b: bool, c: u64) -> String {
+    a
+}
+
+// No lint: contains only map of a closure that binds other arguments
+fn multi_args_opt(a: Option<String>, b: bool, c: u64) -> Option<String> {
+    a.map(|a| multi_args(a, b, c))
+}
+
+fn main() {
+    let answer = Some(42u32);
+    let h_result = h(answer);
+
+    let answer = Some(42u64);
+    let j_result = j(answer);
+    maps_static_option();
+}
diff --git a/tests/ui/single_option_map.stderr b/tests/ui/single_option_map.stderr
new file mode 100644
index 00000000000..f7d48eba71e
--- /dev/null
+++ b/tests/ui/single_option_map.stderr
@@ -0,0 +1,37 @@
+error: `fn` that only maps over argument
+  --> tests/ui/single_option_map.rs:8:1
+   |
+LL | / fn h(arg: Option<u32>) -> Option<u32> {
+LL | |
+LL | |     arg.map(|x| x * 2)
+LL | | }
+   | |_^
+   |
+   = help: move the `.map` to the caller or to an `_opt` function
+   = note: `-D clippy::single-option-map` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::single_option_map)]`
+
+error: `fn` that only maps over argument
+  --> tests/ui/single_option_map.rs:13:1
+   |
+LL | / fn j(arg: Option<u64>) -> Option<u64> {
+LL | |
+LL | |     arg.map(|x| x * 2)
+LL | | }
+   | |_^
+   |
+   = help: move the `.map` to the caller or to an `_opt` function
+
+error: `fn` that only maps over argument
+  --> tests/ui/single_option_map.rs:22:1
+   |
+LL | / fn mul_args_opt(a: Option<String>, b: u64) -> Option<String> {
+LL | |
+LL | |     a.map(|val| mul_args(val, b + 1))
+LL | | }
+   | |_^
+   |
+   = help: move the `.map` to the caller or to an `_opt` function
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/string_add.rs b/tests/ui/string_add.rs
index c535f2ebbfc..61c812f16c8 100644
--- a/tests/ui/string_add.rs
+++ b/tests/ui/string_add.rs
@@ -4,7 +4,7 @@ extern crate proc_macros;
 use proc_macros::external;
 
 #[warn(clippy::string_add)]
-#[allow(clippy::string_add_assign, unused)]
+#[allow(clippy::assign_op_pattern, clippy::string_add_assign, unused)]
 fn main() {
     // ignores assignment distinction
     let mut x = String::new();
diff --git a/tests/ui/string_add.stderr b/tests/ui/string_add.stderr
index fe6849b894b..74ff7372e21 100644
--- a/tests/ui/string_add.stderr
+++ b/tests/ui/string_add.stderr
@@ -1,12 +1,3 @@
-error: manual implementation of an assign operation
-  --> tests/ui/string_add.rs:13:9
-   |
-LL |         x = x + ".";
-   |         ^^^^^^^^^^^ help: replace it with: `x += "."`
-   |
-   = note: `-D clippy::assign-op-pattern` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]`
-
 error: you added something to a string. Consider using `String::push_str()` instead
   --> tests/ui/string_add.rs:13:13
    |
@@ -22,11 +13,5 @@ error: you added something to a string. Consider using `String::push_str()` inst
 LL |     let z = y + "...";
    |             ^^^^^^^^^
 
-error: manual implementation of an assign operation
-  --> tests/ui/string_add.rs:22:5
-   |
-LL |     x = x + 1;
-   |     ^^^^^^^^^ help: replace it with: `x += 1`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed b/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed
new file mode 100644
index 00000000000..5e5821a140d
--- /dev/null
+++ b/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed
@@ -0,0 +1,8 @@
+// https://github.com/rust-lang/rust-clippy/issues/12302
+use std::marker::PhantomData;
+
+pub struct Aa<T>(PhantomData<T>);
+
+fn aa(a: Aa<String>) {
+
+}
diff --git a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs b/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs
new file mode 100644
index 00000000000..d6e1da0e089
--- /dev/null
+++ b/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs
@@ -0,0 +1,8 @@
+// https://github.com/rust-lang/rust-clippy/issues/12302
+use std::marker::PhantomData;
+
+pub struct Aa<T>(PhantomData<T>);
+
+fn aa(a: Aa<String) {
+
+}
diff --git a/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr b/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr
new file mode 100644
index 00000000000..e334ca5241e
--- /dev/null
+++ b/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.stderr
@@ -0,0 +1,13 @@
+error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)`
+  --> tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs:6:19
+   |
+LL | fn aa(a: Aa<String) {
+   |                   ^ expected one of 7 possible tokens
+   |
+help: you might have meant to end the type parameters here
+   |
+LL | fn aa(a: Aa<String>) {
+   |                   +
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/unbuffered_bytes.rs b/tests/ui/unbuffered_bytes.rs
new file mode 100644
index 00000000000..82c8839e839
--- /dev/null
+++ b/tests/ui/unbuffered_bytes.rs
@@ -0,0 +1,37 @@
+#![warn(clippy::unbuffered_bytes)]
+
+use std::fs::File;
+use std::io::{BufReader, Cursor, Read, Stdin, stdin};
+use std::net::TcpStream;
+
+fn main() {
+    // File is not buffered, should complain
+    let file = File::open("./bytes.txt").unwrap();
+    file.bytes();
+
+    // TcpStream is not buffered, should complain
+    let tcp_stream: TcpStream = TcpStream::connect("127.0.0.1:80").unwrap();
+    tcp_stream.bytes();
+
+    // BufReader<File> is buffered, should not complain
+    let file = BufReader::new(File::open("./bytes.txt").unwrap());
+    file.bytes();
+
+    // Cursor is buffered, should not complain
+    let cursor = Cursor::new(Vec::new());
+    cursor.bytes();
+
+    // Stdio would acquire the lock for every byte, should complain
+    let s: Stdin = stdin();
+    s.bytes();
+
+    // But when locking stdin, this is fine so should not complain
+    let s: Stdin = stdin();
+    let s = s.lock();
+    s.bytes();
+}
+
+fn use_read<R: Read>(r: R) {
+    // Callers of `use_read` may choose a `R` that is not buffered
+    r.bytes();
+}
diff --git a/tests/ui/unbuffered_bytes.stderr b/tests/ui/unbuffered_bytes.stderr
new file mode 100644
index 00000000000..3303d579fed
--- /dev/null
+++ b/tests/ui/unbuffered_bytes.stderr
@@ -0,0 +1,36 @@
+error: calling .bytes() is very inefficient when data is not in memory
+  --> tests/ui/unbuffered_bytes.rs:10:5
+   |
+LL |     file.bytes();
+   |     ^^^^^^^^^^^^
+   |
+   = help: consider using `BufReader`
+   = note: `-D clippy::unbuffered-bytes` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unbuffered_bytes)]`
+
+error: calling .bytes() is very inefficient when data is not in memory
+  --> tests/ui/unbuffered_bytes.rs:14:5
+   |
+LL |     tcp_stream.bytes();
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using `BufReader`
+
+error: calling .bytes() is very inefficient when data is not in memory
+  --> tests/ui/unbuffered_bytes.rs:26:5
+   |
+LL |     s.bytes();
+   |     ^^^^^^^^^
+   |
+   = help: consider using `BufReader`
+
+error: calling .bytes() is very inefficient when data is not in memory
+  --> tests/ui/unbuffered_bytes.rs:36:5
+   |
+LL |     r.bytes();
+   |     ^^^^^^^^^
+   |
+   = help: consider using `BufReader`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/unnecessary_map_or.fixed b/tests/ui/unnecessary_map_or.fixed
index 5a6e77a06b8..27532373a7b 100644
--- a/tests/ui/unnecessary_map_or.fixed
+++ b/tests/ui/unnecessary_map_or.fixed
@@ -99,3 +99,9 @@ impl std::ops::Deref for S {
 fn with_deref(o: &S) -> bool {
     o.is_none_or(|n| n > 5)
 }
+
+fn issue14201(a: Option<String>, b: Option<String>, s: &String) -> bool {
+    let x = a.is_some_and(|a| a == *s);
+    let y = b.is_none_or(|b| b == *s);
+    x && y
+}
diff --git a/tests/ui/unnecessary_map_or.rs b/tests/ui/unnecessary_map_or.rs
index 5ba63121659..6496defe130 100644
--- a/tests/ui/unnecessary_map_or.rs
+++ b/tests/ui/unnecessary_map_or.rs
@@ -102,3 +102,9 @@ impl std::ops::Deref for S {
 fn with_deref(o: &S) -> bool {
     o.map_or(true, |n| n > 5)
 }
+
+fn issue14201(a: Option<String>, b: Option<String>, s: &String) -> bool {
+    let x = a.map_or(false, |a| a == *s);
+    let y = b.map_or(true, |b| b == *s);
+    x && y
+}
diff --git a/tests/ui/unnecessary_map_or.stderr b/tests/ui/unnecessary_map_or.stderr
index 2ae327f0bf8..f672f55dd04 100644
--- a/tests/ui/unnecessary_map_or.stderr
+++ b/tests/ui/unnecessary_map_or.stderr
@@ -287,5 +287,29 @@ LL -     o.map_or(true, |n| n > 5)
 LL +     o.is_none_or(|n| n > 5)
    |
 
-error: aborting due to 24 previous errors
+error: this `map_or` can be simplified
+  --> tests/ui/unnecessary_map_or.rs:107:13
+   |
+LL |     let x = a.map_or(false, |a| a == *s);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use is_some_and instead
+   |
+LL -     let x = a.map_or(false, |a| a == *s);
+LL +     let x = a.is_some_and(|a| a == *s);
+   |
+
+error: this `map_or` can be simplified
+  --> tests/ui/unnecessary_map_or.rs:108:13
+   |
+LL |     let y = b.map_or(true, |b| b == *s);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use is_none_or instead
+   |
+LL -     let y = b.map_or(true, |b| b == *s);
+LL +     let y = b.is_none_or(|b| b == *s);
+   |
+
+error: aborting due to 26 previous errors
 
diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs
index a56bd0a8d07..bab99f2ffbd 100644
--- a/tests/ui/unwrap_expect_used.rs
+++ b/tests/ui/unwrap_expect_used.rs
@@ -50,4 +50,15 @@ fn main() {
     //~^ ERROR: used `unwrap_err()` on a `Result` value
     a.expect_err("Hello error!");
     //~^ ERROR: used `expect_err()` on a `Result` value
+
+    // Don't trigger in compile time contexts by default
+    const SOME: Option<i32> = Some(3);
+    const UNWRAPPED: i32 = SOME.unwrap();
+    const EXPECTED: i32 = SOME.expect("Not three?");
+    const {
+        SOME.unwrap();
+    }
+    const {
+        SOME.expect("Still not three?");
+    }
 }
diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed
index ffc5b74d7bd..b44840d440b 100644
--- a/tests/ui/use_self.fixed
+++ b/tests/ui/use_self.fixed
@@ -667,3 +667,48 @@ mod issue_10371 {
         }
     }
 }
+
+mod issue_13092 {
+    use std::cell::RefCell;
+    macro_rules! macro_inner_item {
+        ($ty:ty) => {
+            fn foo(_: $ty) {
+                fn inner(_: $ty) {}
+            }
+        };
+    }
+
+    #[derive(Default)]
+    struct MyStruct;
+
+    impl MyStruct {
+        macro_inner_item!(MyStruct);
+    }
+
+    impl MyStruct {
+        thread_local! {
+            static SPECIAL: RefCell<MyStruct> = RefCell::default();
+        }
+    }
+}
+
+mod crash_check_13128 {
+    struct A;
+
+    impl A {
+        fn a() {
+            struct B;
+
+            // pushes a NoCheck
+            impl Iterator for &B {
+                // Pops the NoCheck
+                type Item = A;
+
+                // Lints A -> Self
+                fn next(&mut self) -> Option<A> {
+                    Some(A)
+                }
+            }
+        }
+    }
+}
diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs
index eb9d96168bc..342c724c8e4 100644
--- a/tests/ui/use_self.rs
+++ b/tests/ui/use_self.rs
@@ -667,3 +667,48 @@ mod issue_10371 {
         }
     }
 }
+
+mod issue_13092 {
+    use std::cell::RefCell;
+    macro_rules! macro_inner_item {
+        ($ty:ty) => {
+            fn foo(_: $ty) {
+                fn inner(_: $ty) {}
+            }
+        };
+    }
+
+    #[derive(Default)]
+    struct MyStruct;
+
+    impl MyStruct {
+        macro_inner_item!(MyStruct);
+    }
+
+    impl MyStruct {
+        thread_local! {
+            static SPECIAL: RefCell<MyStruct> = RefCell::default();
+        }
+    }
+}
+
+mod crash_check_13128 {
+    struct A;
+
+    impl A {
+        fn a() {
+            struct B;
+
+            // pushes a NoCheck
+            impl Iterator for &B {
+                // Pops the NoCheck
+                type Item = A;
+
+                // Lints A -> Self
+                fn next(&mut self) -> Option<A> {
+                    Some(A)
+                }
+            }
+        }
+    }
+}
diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed
index ddbb9255b46..2f179200bb3 100644
--- a/tests/ui/useless_asref.fixed
+++ b/tests/ui/useless_asref.fixed
@@ -198,6 +198,11 @@ fn issue_12528() {
     let _ = opt.as_ref().map(RcWeak::clone);
 }
 
+fn issue_14088() {
+    let s = Some("foo");
+    let _: Option<&str> = s.as_ref().map(|x| x.as_ref());
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs
index b0405e930a2..9851a0caac4 100644
--- a/tests/ui/useless_asref.rs
+++ b/tests/ui/useless_asref.rs
@@ -198,6 +198,11 @@ fn issue_12528() {
     let _ = opt.as_ref().map(RcWeak::clone);
 }
 
+fn issue_14088() {
+    let s = Some("foo");
+    let _: Option<&str> = s.as_ref().map(|x| x.as_ref());
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/tests/ui/{literal_string_with_formatting_args}.rs b/tests/ui/{literal_string_with_formatting_args}.rs
new file mode 100644
index 00000000000..0f5b36e6750
--- /dev/null
+++ b/tests/ui/{literal_string_with_formatting_args}.rs
@@ -0,0 +1,46 @@
+// Regression test for <https://github.com/rust-lang/rust-clippy/issues/13885>.
+// The `dbg` macro generates a literal with the name of the current file, so
+// we need to ensure the lint is not emitted in this case.
+
+// Clippy sets `-Zflatten_format_args=no`, which changes the default behavior of how format args
+// are lowered and only that one has this non-macro span. Adding the flag makes it repro on
+// godbolt and shows a root context span for the file name string.
+//
+// So instead of having:
+//
+// ```
+// Lit(
+//     Spanned {
+//         node: Str(
+//             "[/app/example.rs:2:5] \"something\" = ",
+//             Cooked,
+//         ),
+//         span: /rustc/eb54a50837ad4bcc9842924f27e7287ca66e294c/library/std/src/macros.rs:365:35: 365:58 (#4),
+//     },
+// ),
+// ```
+//
+// We get:
+//
+// ```
+// Lit(
+//     Spanned {
+//         node: Str(
+//             "/app/example.rs",
+//             Cooked,
+//         ),
+//         span: /app/example.rs:2:5: 2:22 (#0),
+//     },
+// )
+// ```
+
+#![crate_name = "foo"]
+#![allow(unused)]
+#![warn(clippy::literal_string_with_formatting_args)]
+
+fn another_bad() {
+    let literal_string_with_formatting_args = 0;
+    dbg!("something");
+}
+
+fn main() {}
diff --git a/tests/versioncheck.rs b/tests/versioncheck.rs
index ed357137095..ea540d48a2b 100644
--- a/tests/versioncheck.rs
+++ b/tests/versioncheck.rs
@@ -90,3 +90,9 @@ fn check_that_clippy_has_the_same_major_version_as_rustc() {
         },
     }
 }
+
+#[test]
+fn check_host_compiler() {
+    let version = rustc_tools_util::get_version_info!();
+    assert_eq!(version.host_compiler, Some("nightly".to_string()));
+}