about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml29
-rw-r--r--src/tools/clippy/CHANGELOG.md14
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md21
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/absolute_paths.rs100
-rw-r--r--src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs1018
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs48
-rw-r--r--src/tools/clippy/clippy_lints/src/error_impl_error.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs334
-rw-r--r--src/tools/clippy/clippy_lints/src/four_forward_slashes.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/incorrect_impls.rs72
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs190
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs320
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/format_collect.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs220
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs122
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/min_ident_chars.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs205
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/option_env_unwrap.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs103
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs80
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs113
-rw-r--r--src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs316
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs108
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs25
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs282
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_origin.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs198
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/certainty.rs122
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs320
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs49
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs10
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs2
-rw-r--r--src/tools/clippy/src/main.rs3
-rw-r--r--src/tools/clippy/tests/compile-test.rs40
-rw-r--r--src/tools/clippy/tests/integration.rs24
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr28
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr70
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs97
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml2
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs11
-rw-r--r--src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr4
-rw-r--r--src/tools/clippy/tests/ui/arc_with_non_send_sync.rs30
-rw-r--r--src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr6
-rw-r--r--src/tools/clippy/tests/ui/arithmetic_side_effects.rs7
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.fixed12
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.rs12
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.stderr40
-rw-r--r--src/tools/clippy/tests/ui/error_impl_error.rs90
-rw-r--r--src/tools/clippy/tests/ui/error_impl_error.stderr45
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed55
-rw-r--r--src/tools/clippy/tests/ui/eta.rs55
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr8
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then.fixed44
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then.rs44
-rw-r--r--src/tools/clippy/tests/ui/filter_map_bool_then.stderr34
-rw-r--r--src/tools/clippy/tests/ui/format_collect.rs31
-rw-r--r--src/tools/clippy/tests/ui/format_collect.stderr62
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes.fixed48
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes.rs48
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes.stderr68
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed7
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs7
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr15
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.rs41
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.stderr20
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.rs4
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.stderr4
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed33
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs33
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr4
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs51
-rw-r--r--src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr31
-rw-r--r--src/tools/clippy/tests/ui/infinite_loop.stderr16
-rw-r--r--src/tools/clippy/tests/ui/inherent_to_string.rs26
-rw-r--r--src/tools/clippy/tests/ui/inherent_to_string.stderr10
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_zero.fixed25
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_zero.rs25
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_zero.stderr43
-rw-r--r--src/tools/clippy/tests/ui/let_and_return.rs10
-rw-r--r--src/tools/clippy/tests/ui/let_underscore_future.stderr16
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.fixed24
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.rs28
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.stderr73
-rw-r--r--src/tools/clippy/tests/ui/manual_find_map.stderr53
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed3
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs3
-rw-r--r--src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr28
-rw-r--r--src/tools/clippy/tests/ui/min_ident_chars.rs4
-rw-r--r--src/tools/clippy/tests/ui/mut_key.stderr16
-rw-r--r--src/tools/clippy/tests/ui/mut_reference.stderr24
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs120
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr72
-rw-r--r--src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed40
-rw-r--r--src/tools/clippy/tests/ui/needless_return_with_question_mark.rs40
-rw-r--r--src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr10
-rw-r--r--src/tools/clippy/tests/ui/option_env_unwrap.rs1
-rw-r--r--src/tools/clippy/tests/ui/option_env_unwrap.stderr18
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed3
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs3
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr46
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed63
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs55
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr90
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs13
-rw-r--r--src/tools/clippy/tests/ui/read_zero_byte_vec.rs6
-rw-r--r--src/tools/clippy/tests/ui/read_zero_byte_vec.stderr20
-rw-r--r--src/tools/clippy/tests/ui/readonly_write_lock.rs42
-rw-r--r--src/tools/clippy/tests/ui/readonly_write_lock.stderr16
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.fixed133
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.rs133
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.stderr98
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.rs111
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.stderr136
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed14
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs14
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr74
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed2
-rw-r--r--src/tools/clippy/tests/ui/rename.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr114
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed123
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs3
-rw-r--r--src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr10
-rw-r--r--src/tools/clippy/tests/ui/shadow.rs7
-rw-r--r--src/tools/clippy/tests/ui/shadow.stderr92
-rw-r--r--src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr18
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.fixed27
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.rs27
-rw-r--r--src/tools/clippy/tests/ui/significant_drop_tightening.stderr6
-rw-r--r--src/tools/clippy/tests/ui/single_match.fixed1
-rw-r--r--src/tools/clippy/tests/ui/single_match.rs1
-rw-r--r--src/tools/clippy/tests/ui/single_match.stderr36
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.rs16
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.stderr64
-rw-r--r--src/tools/clippy/tests/ui/string_lit_chars_any.fixed50
-rw-r--r--src/tools/clippy/tests/ui/string_lit_chars_any.rs50
-rw-r--r--src/tools/clippy/tests/ui/string_lit_chars_any.stderr58
-rw-r--r--src/tools/clippy/tests/ui/swap.fixed3
-rw-r--r--src/tools/clippy/tests/ui/swap.rs3
-rw-r--r--src/tools/clippy/tests/ui/swap.stderr34
-rw-r--r--src/tools/clippy/tests/ui/try_err.fixed6
-rw-r--r--src/tools/clippy/tests/ui/try_err.rs6
-rw-r--r--src/tools/clippy/tests/ui/try_err.stderr22
-rw-r--r--src/tools/clippy/tests/ui/tuple_array_conversions.rs30
-rw-r--r--src/tools/clippy/tests/ui/tuple_array_conversions.stderr36
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.fixed17
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.rs17
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.stderr88
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_filter_map.rs6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_filter_map.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_find_map.rs6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_find_map.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed11
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs11
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr188
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr182
-rw-r--r--src/tools/clippy/tests/ui/unused_async.rs17
-rw-r--r--src/tools/clippy/tests/ui/unused_async.stderr14
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or_else_default.fixed62
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or_else_default.rs62
-rw-r--r--src/tools/clippy/tests/ui/unwrap_or_else_default.stderr100
-rw-r--r--src/tools/clippy/triagebot.toml5
215 files changed, 7968 insertions, 2143 deletions
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 4eb11a3ac85..5c69714bc1e 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -187,16 +187,14 @@ jobs:
     - name: Extract Binaries
       run: |
         DIR=$CARGO_TARGET_DIR/debug
-        rm $DIR/deps/integration-*.d
-        mv $DIR/deps/integration-* $DIR/integration
+        find $DIR/deps/integration-* -executable ! -type d | xargs -I {} mv {} $DIR/integration
         find $DIR ! -executable -o -type d ! -path $DIR | xargs rm -rf
-        rm -rf $CARGO_TARGET_DIR/release
 
     - name: Upload Binaries
-      uses: actions/upload-artifact@v1
+      uses: actions/upload-artifact@v3
       with:
-        name: target
-        path: target
+        name: binaries
+        path: target/debug
 
   integration:
     needs: integration_build
@@ -206,22 +204,20 @@ jobs:
       matrix:
         integration:
         - 'rust-lang/cargo'
-        # FIXME: re-enable once fmt_macros is renamed in RLS
-        # - 'rust-lang/rls'
         - 'rust-lang/chalk'
         - 'rust-lang/rustfmt'
         - 'Marwes/combine'
         - 'Geal/nom'
         - 'rust-lang/stdarch'
         - 'serde-rs/serde'
-        # FIXME: chrono currently cannot be compiled with `--all-targets`
-        # - 'chronotope/chrono'
+        - 'chronotope/chrono'
         - 'hyperium/hyper'
         - 'rust-random/rand'
         - 'rust-lang/futures-rs'
         - 'rust-itertools/itertools'
         - 'rust-lang-nursery/failure'
         - 'rust-lang/log'
+        - 'matthiaskrgr/clippy_ci_panic_test'
 
     runs-on: ubuntu-latest
 
@@ -237,12 +233,17 @@ jobs:
     - name: Install toolchain
       run: rustup show active-toolchain
 
+    - name: Set LD_LIBRARY_PATH
+      run: |
+        SYSROOT=$(rustc --print sysroot)
+        echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV
+
     # Download
     - name: Download target dir
-      uses: actions/download-artifact@v1
+      uses: actions/download-artifact@v3
       with:
-        name: target
-        path: target
+        name: binaries
+        path: target/debug
 
     - name: Make Binaries Executable
       run: chmod +x $CARGO_TARGET_DIR/debug/*
@@ -251,7 +252,7 @@ jobs:
     - name: Test ${{ matrix.integration }}
       run: |
         RUSTUP_TOOLCHAIN="$(rustup show active-toolchain | grep -o -E "nightly-[0-9]{4}-[0-9]{2}-[0-9]{2}")" \
-          $CARGO_TARGET_DIR/debug/integration
+          $CARGO_TARGET_DIR/debug/integration --show-output
       env:
         INTEGRATION: ${{ matrix.integration }}
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index b3b6e3b865f..2655d93599e 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -4680,6 +4680,7 @@ Released 2018-09-13
 
 <!-- lint disable no-unused-definitions -->
 <!-- begin autogenerated links to lint list -->
+[`absolute_paths`]: https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths
 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
 [`alloc_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#alloc_instead_of_core
 [`allow_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes
@@ -4819,6 +4820,7 @@ Released 2018-09-13
 [`equatable_if_let`]: https://rust-lang.github.io/rust-clippy/master/index.html#equatable_if_let
 [`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
 [`err_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#err_expect
+[`error_impl_error`]: https://rust-lang.github.io/rust-clippy/master/index.html#error_impl_error
 [`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
 [`excessive_nesting`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting
 [`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
@@ -4842,6 +4844,7 @@ Released 2018-09-13
 [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
 [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
 [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map
+[`filter_map_bool_then`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_bool_then
 [`filter_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_identity
 [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next
 [`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next
@@ -4865,8 +4868,10 @@ Released 2018-09-13
 [`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
 [`forget_non_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_non_drop
 [`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
+[`format_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_collect
 [`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args
 [`format_push_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_push_string
+[`four_forward_slashes`]: https://rust-lang.github.io/rust-clippy/master/index.html#four_forward_slashes
 [`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
 [`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
 [`from_raw_with_void_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_raw_with_void_ptr
@@ -4937,6 +4942,7 @@ Released 2018-09-13
 [`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items
 [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
 [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
+[`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero
 [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
 [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
 [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
@@ -5092,6 +5098,7 @@ Released 2018-09-13
 [`needless_raw_string_hashes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_string_hashes
 [`needless_raw_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_strings
 [`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
+[`needless_return_with_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return_with_question_mark
 [`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn
 [`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
 [`neg_cmp_op_on_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#neg_cmp_op_on_partial_ord
@@ -5174,6 +5181,7 @@ Released 2018-09-13
 [`rc_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex
 [`read_line_without_trim`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_line_without_trim
 [`read_zero_byte_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_zero_byte_vec
+[`readonly_write_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#readonly_write_lock
 [`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl
 [`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
 [`redundant_async_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_async_block
@@ -5185,6 +5193,8 @@ Released 2018-09-13
 [`redundant_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_else
 [`redundant_feature_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_feature_names
 [`redundant_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names
+[`redundant_guards`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_guards
+[`redundant_locals`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_locals
 [`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
 [`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
@@ -5254,6 +5264,7 @@ Released 2018-09-13
 [`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
 [`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
 [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
+[`string_lit_chars_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_chars_any
 [`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice
 [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
 [`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
@@ -5362,6 +5373,7 @@ Released 2018-09-13
 [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
 [`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
 [`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
+[`unwrap_or_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_default
 [`unwrap_or_else_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_or_else_default
 [`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
 [`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms
@@ -5462,4 +5474,6 @@ Released 2018-09-13
 [`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement
 [`accept-comment-above-attributes`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-attributes
 [`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings
+[`absolute-paths-max-segments`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-max-segments
+[`absolute-paths-allowed-crates`]: https://doc.rust-lang.org/clippy/lint_configuration.html#absolute-paths-allowed-crates
 <!-- end autogenerated links to configuration documentation -->
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index f8073dac330..caaad6d1173 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -730,3 +730,24 @@ Whether to allow `r#""#` when `r""` can be used
 * [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes)
 
 
+## `absolute-paths-max-segments`
+The maximum number of segments a path can have before being linted, anything above this will
+be linted.
+
+**Default Value:** `2` (`u64`)
+
+---
+**Affected lints:**
+* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths)
+
+
+## `absolute-paths-allowed-crates`
+Which crates to allow absolute paths from
+
+**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+
+---
+**Affected lints:**
+* [`absolute_paths`](https://rust-lang.github.io/rust-clippy/master/index.html#absolute_paths)
+
+
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 4624451cff4..c4ae4f0e2bd 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -51,7 +51,7 @@ pub fn clippy_project_root() -> PathBuf {
     for path in current_dir.ancestors() {
         let result = std::fs::read_to_string(path.join("Cargo.toml"));
         if let Err(err) = &result {
-            if err.kind() == std::io::ErrorKind::NotFound {
+            if err.kind() == io::ErrorKind::NotFound {
                 continue;
             }
         }
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index f39bc06e6d7..e64cf2c8749 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -96,8 +96,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
 
         path.push("src");
         fs::create_dir(&path)?;
-        let header = format!("//@compile-flags: --crate-name={lint_name}");
-        write_file(path.join("main.rs"), get_test_file_contents(lint_name, Some(&header)))?;
+        write_file(path.join("main.rs"), get_test_file_contents(lint_name))?;
 
         Ok(())
     }
@@ -113,7 +112,7 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
         println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`");
     } else {
         let test_path = format!("tests/ui/{}.rs", lint.name);
-        let test_contents = get_test_file_contents(lint.name, None);
+        let test_contents = get_test_file_contents(lint.name);
         write_file(lint.project_root.join(&test_path), test_contents)?;
 
         println!("Generated test file: `{test_path}`");
@@ -195,23 +194,16 @@ pub(crate) fn get_stabilization_version() -> String {
     parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
 }
 
-fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
-    let mut contents = formatdoc!(
+fn get_test_file_contents(lint_name: &str) -> String {
+    formatdoc!(
         r#"
-        #![allow(unused)]
         #![warn(clippy::{lint_name})]
 
         fn main() {{
             // test code goes here
         }}
     "#
-    );
-
-    if let Some(header) = header_commands {
-        contents = format!("{header}\n{contents}");
-    }
-
-    contents
+    )
 }
 
 fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
diff --git a/src/tools/clippy/clippy_lints/src/absolute_paths.rs b/src/tools/clippy/clippy_lints/src/absolute_paths.rs
new file mode 100644
index 00000000000..04417c4c460
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/absolute_paths.rs
@@ -0,0 +1,100 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::source::snippet_opt;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_hir::{HirId, ItemKind, Node, Path};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::kw;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of items through absolute paths, like `std::env::current_dir`.
+    ///
+    /// ### Why is this bad?
+    /// Many codebases have their own style when it comes to importing, but one that is seldom used
+    /// is using absolute paths *everywhere*. This is generally considered unidiomatic, and you
+    /// should add a `use` statement.
+    ///
+    /// The default maximum segments (2) is pretty strict, you may want to increase this in
+    /// `clippy.toml`.
+    ///
+    /// Note: One exception to this is code from macro expansion - this does not lint such cases, as
+    /// using absolute paths is the proper way of referencing items in one.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x = std::f64::consts::PI;
+    /// ```
+    /// Use any of the below instead, or anything else:
+    /// ```rust
+    /// use std::f64;
+    /// use std::f64::consts;
+    /// use std::f64::consts::PI;
+    /// let x = f64::consts::PI;
+    /// let x = consts::PI;
+    /// let x = PI;
+    /// use std::f64::consts as f64_consts;
+    /// let x = f64_consts::PI;
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub ABSOLUTE_PATHS,
+    restriction,
+    "checks for usage of an item without a `use` statement"
+}
+impl_lint_pass!(AbsolutePaths => [ABSOLUTE_PATHS]);
+
+pub struct AbsolutePaths {
+    pub absolute_paths_max_segments: u64,
+    pub absolute_paths_allowed_crates: FxHashSet<String>,
+}
+
+impl LateLintPass<'_> for AbsolutePaths {
+    // We should only lint `QPath::Resolved`s, but since `Path` is only used in `Resolved` and `UsePath`
+    // we don't need to use a visitor or anything as we can just check if the `Node` for `hir_id` isn't
+    // a `Use`
+    #[expect(clippy::cast_possible_truncation)]
+    fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
+        let Self {
+            absolute_paths_max_segments,
+            absolute_paths_allowed_crates,
+        } = self;
+
+        if !path.span.from_expansion()
+            && let Some(node) = cx.tcx.hir().find(hir_id)
+            && !matches!(node, Node::Item(item) if matches!(item.kind, ItemKind::Use(_, _)))
+            && let [first, rest @ ..] = path.segments
+            // Handle `::std`
+            && let (segment, len) = if first.ident.name == kw::PathRoot {
+                // Indexing is fine as `PathRoot` must be followed by another segment. `len() - 1`
+                // is fine here for the same reason
+                (&rest[0], path.segments.len() - 1)
+            } else {
+                (first, path.segments.len())
+            }
+            && len > *absolute_paths_max_segments as usize
+            && let Some(segment_snippet) = snippet_opt(cx, segment.ident.span)
+            && segment_snippet == segment.ident.as_str()
+        {
+            let is_abs_external =
+                matches!(segment.res, Res::Def(DefKind::Mod, DefId { index, .. }) if index == CRATE_DEF_INDEX);
+            let is_abs_crate = segment.ident.name == kw::Crate;
+
+            if is_abs_external && absolute_paths_allowed_crates.contains(segment.ident.name.as_str())
+                || is_abs_crate && absolute_paths_allowed_crates.contains("crate")
+            {
+                return;
+            }
+
+            if is_abs_external || is_abs_crate {
+                span_lint(
+                    cx,
+                    ABSOLUTE_PATHS,
+                    path.span,
+                    "consider bringing this path into scope with the `use` keyword",
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
index 7adcd9ad055..35a04b5e44a 100644
--- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
+++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::last_path_segment;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::{is_from_proc_macro, last_path_segment};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
@@ -38,10 +38,11 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]);
 
-impl LateLintPass<'_> for ArcWithNonSendSync {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        let ty = cx.typeck_results().expr_ty(expr);
-        if is_type_diagnostic_item(cx, ty, sym::Arc)
+impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if !expr.span.from_expansion()
+            && let ty = cx.typeck_results().expr_ty(expr)
+            && is_type_diagnostic_item(cx, ty, sym::Arc)
             && let ExprKind::Call(func, [arg]) = expr.kind
             && let ExprKind::Path(func_path) = func.kind
             && last_path_segment(&func_path).ident.name == sym::new
@@ -54,6 +55,7 @@ impl LateLintPass<'_> for ArcWithNonSendSync {
             && let Some(sync) = cx.tcx.lang_items().sync_trait()
             && let [is_send, is_sync] = [send, sync].map(|id| implements_trait(cx, arg_ty, id, &[]))
             && !(is_send && is_sync)
+            && !is_from_proc_macro(cx, expr)
         {
             span_lint_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index 0ac6ef6496a..d34de305f5d 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -181,6 +181,14 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// It's just unnecessary.
     ///
+    /// ### Known problems
+    /// When the expression on the left is a function call, the lint considers the return type to be
+    /// a type alias if it's aliased through a `use` statement
+    /// (like `use std::io::Result as IoResult`). It will not lint such cases.
+    ///
+    /// This check is also rather primitive. It will only work on primitive types without any
+    /// intermediate references, raw pointers and trait objects may or may not work.
+    ///
     /// ### Example
     /// ```rust
     /// let _ = 2i32 as i32;
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index ae56f38d9ad..86057bb74ee 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -85,11 +85,6 @@ pub(super) fn check<'tcx>(
         }
     }
 
-    // skip cast of fn call that returns type alias
-    if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) {
-        return false;
-    }
-
     // skip cast to non-primitive type
     if_chain! {
         if let ExprKind::Cast(_, cast_to) = expr.kind;
@@ -101,6 +96,11 @@ pub(super) fn check<'tcx>(
         }
     }
 
+    // skip cast of fn call that returns type alias
+    if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) {
+        return false;
+    }
+
     if let Some(lit) = get_numeric_literal(cast_expr) {
         let literal_str = &cast_str;
 
@@ -254,14 +254,12 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
                 // function's declaration snippet is exactly equal to the `Ty`. That way, we can
                 // see whether it's a type alias.
                 //
-                // Will this work for more complex types? Probably not!
+                // FIXME: This won't work if the type is given an alias through `use`, should we
+                // consider this a type alias as well?
                 if !snippet
                     .split("->")
-                    .skip(0)
-                    .map(|s| {
-                        s.trim() == cast_from.to_string()
-                            || s.split("where").any(|ty| ty.trim() == cast_from.to_string())
-                    })
+                    .skip(1)
+                    .map(|s| snippet_eq_ty(s, cast_from) || s.split("where").any(|ty| snippet_eq_ty(ty, cast_from)))
                     .any(|a| a)
                 {
                     return ControlFlow::Break(());
@@ -288,3 +286,7 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
     })
     .is_some()
 }
+
+fn snippet_eq_ty(snippet: &str, ty: Ty<'_>) -> bool {
+    snippet.trim() == ty.to_string() || snippet.trim().contains(&format!("::{ty}"))
+}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 498d657b31f..d4e0d286334 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -37,6 +37,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
+    crate::absolute_paths::ABSOLUTE_PATHS_INFO,
     crate::allow_attributes::ALLOW_ATTRIBUTES_INFO,
     crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
     crate::approx_const::APPROX_CONSTANT_INFO,
@@ -155,6 +156,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::enum_variants::MODULE_INCEPTION_INFO,
     crate::enum_variants::MODULE_NAME_REPETITIONS_INFO,
     crate::equatable_if_let::EQUATABLE_IF_LET_INFO,
+    crate::error_impl_error::ERROR_IMPL_ERROR_INFO,
     crate::escape::BOXED_LOCAL_INFO,
     crate::eta_reduction::REDUNDANT_CLOSURE_INFO,
     crate::eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS_INFO,
@@ -183,6 +185,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING_INFO,
     crate::formatting::SUSPICIOUS_ELSE_FORMATTING_INFO,
     crate::formatting::SUSPICIOUS_UNARY_OP_FORMATTING_INFO,
+    crate::four_forward_slashes::FOUR_FORWARD_SLASHES_INFO,
     crate::from_over_into::FROM_OVER_INTO_INFO,
     crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO,
     crate::from_str_radix_10::FROM_STR_RADIX_10_INFO,
@@ -305,6 +308,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS_INFO,
     crate::matches::MATCH_WILD_ERR_ARM_INFO,
     crate::matches::NEEDLESS_MATCH_INFO,
+    crate::matches::REDUNDANT_GUARDS_INFO,
     crate::matches::REDUNDANT_PATTERN_MATCHING_INFO,
     crate::matches::REST_PAT_IN_FULLY_BOUND_STRUCTS_INFO,
     crate::matches::SIGNIFICANT_DROP_IN_SCRUTINEE_INFO,
@@ -333,11 +337,13 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::EXPECT_USED_INFO,
     crate::methods::EXTEND_WITH_DRAIN_INFO,
     crate::methods::FILETYPE_IS_FILE_INFO,
+    crate::methods::FILTER_MAP_BOOL_THEN_INFO,
     crate::methods::FILTER_MAP_IDENTITY_INFO,
     crate::methods::FILTER_MAP_NEXT_INFO,
     crate::methods::FILTER_NEXT_INFO,
     crate::methods::FLAT_MAP_IDENTITY_INFO,
     crate::methods::FLAT_MAP_OPTION_INFO,
+    crate::methods::FORMAT_COLLECT_INFO,
     crate::methods::FROM_ITER_INSTEAD_OF_COLLECT_INFO,
     crate::methods::GET_FIRST_INFO,
     crate::methods::GET_LAST_WITH_LEN_INFO,
@@ -358,6 +364,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::ITER_ON_SINGLE_ITEMS_INFO,
     crate::methods::ITER_OVEREAGER_CLONED_INFO,
     crate::methods::ITER_SKIP_NEXT_INFO,
+    crate::methods::ITER_SKIP_ZERO_INFO,
     crate::methods::ITER_WITH_DRAIN_INFO,
     crate::methods::MANUAL_FILTER_MAP_INFO,
     crate::methods::MANUAL_FIND_MAP_INFO,
@@ -391,6 +398,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::OR_THEN_UNWRAP_INFO,
     crate::methods::PATH_BUF_PUSH_OVERWRITE_INFO,
     crate::methods::RANGE_ZIP_WITH_LEN_INFO,
+    crate::methods::READONLY_WRITE_LOCK_INFO,
     crate::methods::READ_LINE_WITHOUT_TRIM_INFO,
     crate::methods::REPEAT_ONCE_INFO,
     crate::methods::RESULT_MAP_OR_INTO_OPTION_INFO,
@@ -403,6 +411,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::SKIP_WHILE_NEXT_INFO,
     crate::methods::STABLE_SORT_PRIMITIVE_INFO,
     crate::methods::STRING_EXTEND_CHARS_INFO,
+    crate::methods::STRING_LIT_CHARS_ANY_INFO,
     crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO,
     crate::methods::SUSPICIOUS_MAP_INFO,
     crate::methods::SUSPICIOUS_SPLITN_INFO,
@@ -418,7 +427,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
     crate::methods::UNNECESSARY_SORT_BY_INFO,
     crate::methods::UNNECESSARY_TO_OWNED_INFO,
-    crate::methods::UNWRAP_OR_ELSE_DEFAULT_INFO,
+    crate::methods::UNWRAP_OR_DEFAULT_INFO,
     crate::methods::UNWRAP_USED_INFO,
     crate::methods::USELESS_ASREF_INFO,
     crate::methods::VEC_RESIZE_TO_ZERO_INFO,
@@ -555,6 +564,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::redundant_closure_call::REDUNDANT_CLOSURE_CALL_INFO,
     crate::redundant_else::REDUNDANT_ELSE_INFO,
     crate::redundant_field_names::REDUNDANT_FIELD_NAMES_INFO,
+    crate::redundant_locals::REDUNDANT_LOCALS_INFO,
     crate::redundant_pub_crate::REDUNDANT_PUB_CRATE_INFO,
     crate::redundant_slicing::DEREF_BY_SLICING_INFO,
     crate::redundant_slicing::REDUNDANT_SLICING_INFO,
@@ -568,6 +578,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
     crate::returns::LET_AND_RETURN_INFO,
     crate::returns::NEEDLESS_RETURN_INFO,
+    crate::returns::NEEDLESS_RETURN_WITH_QUESTION_MARK_INFO,
     crate::same_name_method::SAME_NAME_METHOD_INFO,
     crate::self_named_constructors::SELF_NAMED_CONSTRUCTORS_INFO,
     crate::semicolon_block::SEMICOLON_INSIDE_BLOCK_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 8a9d978a106..a5ec979ccd9 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -3,21 +3,23 @@ use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exact
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{adt_and_variant_of_res, expr_sig, is_copy, peel_mid_ty_refs, ty_sig};
+use clippy_utils::ty::{is_copy, peel_mid_ty_refs};
 use clippy_utils::{
-    fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage,
+    expr_use_ctxt, get_parent_expr, get_parent_node, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
 };
 
+use hir::def::DefKind;
+use hir::MatchSource;
 use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::graph::iterate::{CycleDetector, TriColorDepthFirstSearch};
 use rustc_errors::Applicability;
+use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{
-    self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId,
-    ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem,
-    TraitItemKind, TyKind, UnOp,
+    self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind,
+    Path, QPath, TyKind, UnOp,
 };
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -25,8 +27,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::{Rvalue, StatementKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{
-    self, Binder, BoundVariableKind, ClauseKind, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy,
-    ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
+    self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, List, ParamEnv, ParamTy, ProjectionPredicate, Ty,
+    TyCtxt, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::sym;
@@ -163,7 +165,7 @@ impl_lint_pass!(Dereferencing<'_> => [
 
 #[derive(Default)]
 pub struct Dereferencing<'tcx> {
-    state: Option<(State, StateData)>,
+    state: Option<(State, StateData<'tcx>)>,
 
     // While parsing a `deref` method call in ufcs form, the path to the function is itself an
     // expression. This is to store the id of that expression so it can be skipped when
@@ -203,29 +205,28 @@ impl<'tcx> Dereferencing<'tcx> {
 }
 
 #[derive(Debug)]
-struct StateData {
+struct StateData<'tcx> {
     /// Span of the top level expression
     span: Span,
     hir_id: HirId,
-    position: Position,
+    adjusted_ty: Ty<'tcx>,
 }
 
-#[derive(Debug)]
 struct DerefedBorrow {
     count: usize,
     msg: &'static str,
-    snip_expr: Option<HirId>,
+    stability: TyCoercionStability,
+    for_field_access: Option<Symbol>,
 }
 
-#[derive(Debug)]
 enum State {
     // Any number of deref method calls.
     DerefMethod {
         // The number of calls in a sequence which changed the referenced type
         ty_changed_count: usize,
-        is_final_ufcs: bool,
+        is_ufcs: bool,
         /// The required mutability
-        target_mut: Mutability,
+        mutbl: Mutability,
     },
     DerefedBorrow(DerefedBorrow),
     ExplicitDeref {
@@ -244,7 +245,7 @@ enum State {
 
 // A reference operation considered by this lint pass
 enum RefOp {
-    Method(Mutability),
+    Method { mutbl: Mutability, is_ufcs: bool },
     Deref,
     AddrOf(Mutability),
 }
@@ -294,48 +295,115 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
         match (self.state.take(), kind) {
             (None, kind) => {
                 let expr_ty = typeck.expr_ty(expr);
-                let (position, adjustments) = walk_parents(cx, &mut self.possible_borrowers, expr, &self.msrv);
-                match kind {
-                    RefOp::Deref => {
+                let use_cx = expr_use_ctxt(cx, expr);
+                let adjusted_ty = match &use_cx {
+                    Some(use_cx) => match use_cx.adjustments {
+                        [.., a] => a.target,
+                        _ => expr_ty,
+                    },
+                    _ => typeck.expr_ty_adjusted(expr),
+                };
+
+                match (use_cx, kind) {
+                    (Some(use_cx), RefOp::Deref) => {
                         let sub_ty = typeck.expr_ty(sub_expr);
-                        if let Position::FieldAccess {
-                            name,
-                            of_union: false,
-                        } = position
-                            && !ty_contains_field(sub_ty, name)
+                        if let ExprUseNode::FieldAccess(name) = use_cx.node
+                            && adjusted_ty.ty_adt_def().map_or(true, |adt| !adt.is_union())
+                            && !ty_contains_field(sub_ty, name.name)
                         {
                             self.state = Some((
-                                State::ExplicitDerefField { name },
-                                StateData { span: expr.span, hir_id: expr.hir_id, position },
+                                State::ExplicitDerefField { name: name.name },
+                                StateData {
+                                    span: expr.span,
+                                    hir_id: expr.hir_id,
+                                    adjusted_ty,
+                                },
                             ));
-                        } else if position.is_deref_stable() && sub_ty.is_ref() {
+                        } else if sub_ty.is_ref()
+                            // Linting method receivers would require verifying that name lookup
+                            // would resolve the same way. This is complicated by trait methods.
+                            && !use_cx.node.is_recv()
+                            && let Some(ty) = use_cx.node.defined_ty(cx)
+                            && TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return()).is_deref_stable()
+                        {
                             self.state = Some((
                                 State::ExplicitDeref { mutability: None },
-                                StateData { span: expr.span, hir_id: expr.hir_id, position },
+                                StateData {
+                                    span: expr.span,
+                                    hir_id: expr.hir_id,
+                                    adjusted_ty,
+                                },
                             ));
                         }
                     },
-                    RefOp::Method(target_mut)
+                    (_, RefOp::Method { mutbl, is_ufcs })
                         if !is_lint_allowed(cx, EXPLICIT_DEREF_METHODS, expr.hir_id)
-                            && position.lint_explicit_deref() =>
+                            // Allow explicit deref in method chains. e.g. `foo.deref().bar()`
+                            && (is_ufcs || !in_postfix_position(cx, expr)) =>
                     {
                         let ty_changed_count = usize::from(!deref_method_same_type(expr_ty, typeck.expr_ty(sub_expr)));
                         self.state = Some((
                             State::DerefMethod {
                                 ty_changed_count,
-                                is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
-                                target_mut,
+                                is_ufcs,
+                                mutbl,
                             },
                             StateData {
                                 span: expr.span,
                                 hir_id: expr.hir_id,
-                                position,
+                                adjusted_ty,
                             },
                         ));
                     },
-                    RefOp::AddrOf(mutability) => {
+                    (Some(use_cx), RefOp::AddrOf(mutability)) => {
+                        let defined_ty = use_cx.node.defined_ty(cx);
+
+                        // Check needless_borrow for generic arguments.
+                        if !use_cx.is_ty_unified
+                            && let Some(DefinedTy::Mir(ty)) = defined_ty
+                            && let ty::Param(ty) = *ty.value.skip_binder().kind()
+                            && let Some((hir_id, fn_id, i)) = match use_cx.node {
+                                ExprUseNode::MethodArg(_, _, 0) => None,
+                                ExprUseNode::MethodArg(hir_id, None, i) => {
+                                    typeck.type_dependent_def_id(hir_id).map(|id| (hir_id, id, i))
+                                },
+                                ExprUseNode::FnArg(&Expr { kind: ExprKind::Path(ref p), hir_id, .. }, i)
+                                if !path_has_args(p) => match typeck.qpath_res(p, hir_id) {
+                                    Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) => {
+                                        Some((hir_id, id, i))
+                                    },
+                                    _ => None,
+                                },
+                                _ => None,
+                            } && let count = needless_borrow_generic_arg_count(
+                                cx,
+                                &mut self.possible_borrowers,
+                                fn_id,
+                                typeck.node_args(hir_id),
+                                i,
+                                ty,
+                                expr,
+                                &self.msrv,
+                            ) && count != 0
+                        {
+                            self.state = Some((
+                                State::DerefedBorrow(DerefedBorrow {
+                                    count: count - 1,
+                                    msg: "the borrowed expression implements the required traits",
+                                    stability: TyCoercionStability::None,
+                                    for_field_access: None,
+                                }),
+                                StateData {
+                                    span: expr.span,
+                                    hir_id: expr.hir_id,
+                                    adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
+                                },
+                            ));
+                            return;
+                        }
+
                         // Find the number of times the borrow is auto-derefed.
-                        let mut iter = adjustments.iter();
+                        let mut iter = use_cx.adjustments.iter();
                         let mut deref_count = 0usize;
                         let next_adjust = loop {
                             match iter.next() {
@@ -352,6 +420,58 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                             };
                         };
 
+                        let stability = defined_ty.map_or(TyCoercionStability::None, |ty| {
+                            TyCoercionStability::for_defined_ty(cx, ty, use_cx.node.is_return())
+                        });
+                        let can_auto_borrow = match use_cx.node {
+                            ExprUseNode::Callee => true,
+                            ExprUseNode::FieldAccess(_) => adjusted_ty.ty_adt_def().map_or(true, |adt| !adt.is_union()),
+                            ExprUseNode::MethodArg(hir_id, _, 0) if !use_cx.moved_before_use => {
+                                // Check for calls to trait methods where the trait is implemented
+                                // on a reference.
+                                // Two cases need to be handled:
+                                // * `self` methods on `&T` will never have auto-borrow
+                                // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
+                                //   priority.
+                                if let Some(fn_id) = typeck.type_dependent_def_id(hir_id)
+                                    && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+                                    && let arg_ty
+                                        = cx.tcx.erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target))
+                                    && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
+                                    && let args = cx
+                                        .typeck_results()
+                                        .node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default()
+                                    && let impl_ty = if cx.tcx.fn_sig(fn_id)
+                                        .instantiate_identity()
+                                        .skip_binder()
+                                        .inputs()[0].is_ref()
+                                    {
+                                        // Trait methods taking `&self`
+                                        sub_ty
+                                    } else {
+                                        // Trait methods taking `self`
+                                        arg_ty
+                                    } && impl_ty.is_ref()
+                                    && cx.tcx.infer_ctxt().build()
+                                        .type_implements_trait(
+                                            trait_id,
+                                            [impl_ty.into()].into_iter().chain(args.iter().copied()),
+                                            cx.param_env,
+                                        )
+                                        .must_apply_modulo_regions()
+                                {
+                                    false
+                                } else {
+                                    true
+                                }
+                            },
+                            _ => false,
+                        };
+
+                        let deref_msg =
+                            "this expression creates a reference which is immediately dereferenced by the compiler";
+                        let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
+
                         // Determine the required number of references before any can be removed. In all cases the
                         // reference made by the current expression will be removed. After that there are four cases to
                         // handle.
@@ -374,26 +494,18 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                         //        };
                         //    }
                         //    ```
-                        let deref_msg =
-                            "this expression creates a reference which is immediately dereferenced by the compiler";
-                        let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
-                        let impl_msg = "the borrowed expression implements the required traits";
-
-                        let (required_refs, msg, snip_expr) = if position.can_auto_borrow() {
-                            (1, if deref_count == 1 { borrow_msg } else { deref_msg }, None)
-                        } else if let Position::ImplArg(hir_id) = position {
-                            (0, impl_msg, Some(hir_id))
-                        } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) =
-                            next_adjust.map(|a| &a.kind)
+                        let (required_refs, msg) = if can_auto_borrow {
+                            (1, if deref_count == 1 { borrow_msg } else { deref_msg })
+                        } else if let Some(&Adjustment {
+                                kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)),
+                                ..
+                            }) = next_adjust
+                            && matches!(mutability, AutoBorrowMutability::Mut { .. })
+                            && !stability.is_reborrow_stable()
                         {
-                            if matches!(mutability, AutoBorrowMutability::Mut { .. }) && !position.is_reborrow_stable()
-                            {
-                                (3, deref_msg, None)
-                            } else {
-                                (2, deref_msg, None)
-                            }
+                            (3, deref_msg)
                         } else {
-                            (2, deref_msg, None)
+                            (2, deref_msg)
                         };
 
                         if deref_count >= required_refs {
@@ -403,15 +515,19 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                                     // can't be removed without breaking the code. See earlier comment.
                                     count: deref_count - required_refs,
                                     msg,
-                                    snip_expr,
+                                    stability,
+                                    for_field_access: match use_cx.node {
+                                        ExprUseNode::FieldAccess(name) => Some(name.name),
+                                        _ => None,
+                                    },
                                 }),
                                 StateData {
                                     span: expr.span,
                                     hir_id: expr.hir_id,
-                                    position,
+                                    adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
                                 },
                             ));
-                        } else if position.is_deref_stable()
+                        } else if stability.is_deref_stable()
                             // Auto-deref doesn't combine with other adjustments
                             && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
                             && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
@@ -421,24 +537,24 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                                 StateData {
                                     span: expr.span,
                                     hir_id: expr.hir_id,
-                                    position,
+                                    adjusted_ty: use_cx.adjustments.last().map_or(expr_ty, |a| a.target),
                                 },
                             ));
                         }
                     },
-                    RefOp::Method(..) => (),
+                    (None, _) | (_, RefOp::Method { .. }) => (),
                 }
             },
             (
                 Some((
                     State::DerefMethod {
-                        target_mut,
+                        mutbl,
                         ty_changed_count,
                         ..
                     },
                     data,
                 )),
-                RefOp::Method(_),
+                RefOp::Method { is_ufcs, .. },
             ) => {
                 self.state = Some((
                     State::DerefMethod {
@@ -447,8 +563,8 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                         } else {
                             ty_changed_count + 1
                         },
-                        is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
-                        target_mut,
+                        is_ufcs,
+                        mutbl,
                     },
                     data,
                 ));
@@ -463,33 +579,44 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                 ));
             },
             (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => {
-                let position = data.position;
+                let adjusted_ty = data.adjusted_ty;
+                let stability = state.stability;
                 report(cx, expr, State::DerefedBorrow(state), data);
-                if position.is_deref_stable() {
+                if stability.is_deref_stable() {
                     self.state = Some((
                         State::Borrow { mutability },
                         StateData {
                             span: expr.span,
                             hir_id: expr.hir_id,
-                            position,
+                            adjusted_ty,
                         },
                     ));
                 }
             },
             (Some((State::DerefedBorrow(state), data)), RefOp::Deref) => {
-                let position = data.position;
+                let adjusted_ty = data.adjusted_ty;
+                let stability = state.stability;
+                let for_field_access = state.for_field_access;
                 report(cx, expr, State::DerefedBorrow(state), data);
-                if let Position::FieldAccess{name, ..} = position
+                if let Some(name) = for_field_access
                     && !ty_contains_field(typeck.expr_ty(sub_expr), name)
                 {
                     self.state = Some((
                         State::ExplicitDerefField { name },
-                        StateData { span: expr.span, hir_id: expr.hir_id, position },
+                        StateData {
+                            span: expr.span,
+                            hir_id: expr.hir_id,
+                            adjusted_ty,
+                        },
                     ));
-                } else if position.is_deref_stable() {
+                } else if stability.is_deref_stable() {
                     self.state = Some((
                         State::ExplicitDeref { mutability: None },
-                        StateData { span: expr.span, hir_id: expr.hir_id, position },
+                        StateData {
+                            span: expr.span,
+                            hir_id: expr.hir_id,
+                            adjusted_ty,
+                        },
                     ));
                 }
             },
@@ -611,8 +738,8 @@ fn try_parse_ref_op<'tcx>(
     typeck: &'tcx TypeckResults<'_>,
     expr: &'tcx Expr<'_>,
 ) -> Option<(RefOp, &'tcx Expr<'tcx>)> {
-    let (def_id, arg) = match expr.kind {
-        ExprKind::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg),
+    let (is_ufcs, def_id, arg) = match expr.kind {
+        ExprKind::MethodCall(_, arg, [], _) => (false, typeck.type_dependent_def_id(expr.hir_id)?, arg),
         ExprKind::Call(
             Expr {
                 kind: ExprKind::Path(path),
@@ -620,7 +747,7 @@ fn try_parse_ref_op<'tcx>(
                 ..
             },
             [arg],
-        ) => (typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
+        ) => (true, typeck.qpath_res(path, *hir_id).opt_def_id()?, arg),
         ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => {
             return Some((RefOp::Deref, sub_expr));
         },
@@ -628,9 +755,21 @@ fn try_parse_ref_op<'tcx>(
         _ => return None,
     };
     if tcx.is_diagnostic_item(sym::deref_method, def_id) {
-        Some((RefOp::Method(Mutability::Not), arg))
+        Some((
+            RefOp::Method {
+                mutbl: Mutability::Not,
+                is_ufcs,
+            },
+            arg,
+        ))
     } else if tcx.trait_of_item(def_id)? == tcx.lang_items().deref_mut_trait()? {
-        Some((RefOp::Method(Mutability::Mut), arg))
+        Some((
+            RefOp::Method {
+                mutbl: Mutability::Mut,
+                is_ufcs,
+            },
+            arg,
+        ))
     } else {
         None
     }
@@ -649,420 +788,164 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
     }
 }
 
-/// The position of an expression relative to it's parent.
-#[derive(Clone, Copy, Debug)]
-enum Position {
-    MethodReceiver,
-    /// The method is defined on a reference type. e.g. `impl Foo for &T`
-    MethodReceiverRefImpl,
-    Callee,
-    ImplArg(HirId),
-    FieldAccess {
-        name: Symbol,
-        of_union: bool,
-    }, // union fields cannot be auto borrowed
-    Postfix,
-    Deref,
-    /// Any other location which will trigger auto-deref to a specific time.
-    /// Contains the precedence of the parent expression and whether the target type is sized.
-    DerefStable(i8, bool),
-    /// Any other location which will trigger auto-reborrowing.
-    /// Contains the precedence of the parent expression.
-    ReborrowStable(i8),
-    /// Contains the precedence of the parent expression.
-    Other(i8),
-}
-impl Position {
-    fn is_deref_stable(self) -> bool {
-        matches!(self, Self::DerefStable(..))
+fn path_has_args(p: &QPath<'_>) -> bool {
+    match *p {
+        QPath::Resolved(_, Path { segments: [.., s], .. }) | QPath::TypeRelative(_, s) => s.args.is_some(),
+        _ => false,
     }
+}
 
-    fn is_reborrow_stable(self) -> bool {
-        matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_))
+fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
+    if let Some(parent) = get_parent_expr(cx, e)
+        && parent.span.ctxt() == e.span.ctxt()
+    {
+        match parent.kind {
+            ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _)
+                if child.hir_id == e.hir_id => true,
+            ExprKind::Field(_, _) | ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) => true,
+            _ => false,
+        }
+    } else {
+        false
     }
+}
 
-    fn can_auto_borrow(self) -> bool {
-        matches!(
-            self,
-            Self::MethodReceiver | Self::FieldAccess { of_union: false, .. } | Self::Callee
-        )
+#[derive(Clone, Copy)]
+enum TyCoercionStability {
+    Deref,
+    Reborrow,
+    None,
+}
+impl TyCoercionStability {
+    fn is_deref_stable(self) -> bool {
+        matches!(self, Self::Deref)
     }
 
-    fn lint_explicit_deref(self) -> bool {
-        matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_))
+    fn is_reborrow_stable(self) -> bool {
+        matches!(self, Self::Deref | Self::Reborrow)
     }
 
-    fn precedence(self) -> i8 {
-        match self {
-            Self::MethodReceiver
-            | Self::MethodReceiverRefImpl
-            | Self::Callee
-            | Self::FieldAccess { .. }
-            | Self::Postfix => PREC_POSTFIX,
-            Self::ImplArg(_) | Self::Deref => PREC_PREFIX,
-            Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
+    fn for_defined_ty<'tcx>(cx: &LateContext<'tcx>, ty: DefinedTy<'tcx>, for_return: bool) -> Self {
+        match ty {
+            DefinedTy::Hir(ty) => Self::for_hir_ty(ty),
+            DefinedTy::Mir(ty) => Self::for_mir_ty(
+                cx.tcx,
+                ty.param_env,
+                cx.tcx.erase_late_bound_regions(ty.value),
+                for_return,
+            ),
         }
     }
-}
-
-/// Walks up the parent expressions attempting to determine both how stable the auto-deref result
-/// is, and which adjustments will be applied to it. Note this will not consider auto-borrow
-/// locations as those follow different rules.
-#[expect(clippy::too_many_lines)]
-fn walk_parents<'tcx>(
-    cx: &LateContext<'tcx>,
-    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
-    e: &'tcx Expr<'_>,
-    msrv: &Msrv,
-) -> (Position, &'tcx [Adjustment<'tcx>]) {
-    let mut adjustments = [].as_slice();
-    let mut precedence = 0i8;
-    let ctxt = e.span.ctxt();
-    let position = walk_to_expr_usage(cx, e, &mut |parent, child_id| {
-        // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead.
-        if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) {
-            adjustments = cx.typeck_results().expr_adjustments(e);
-        }
-        match parent {
-            Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => {
-                Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty()))
-            },
-            Node::Item(&Item {
-                kind: ItemKind::Static(..) | ItemKind::Const(..),
-                owner_id,
-                span,
-                ..
-            })
-            | Node::TraitItem(&TraitItem {
-                kind: TraitItemKind::Const(..),
-                owner_id,
-                span,
-                ..
-            })
-            | Node::ImplItem(&ImplItem {
-                kind: ImplItemKind::Const(..),
-                owner_id,
-                span,
-                ..
-            }) if span.ctxt() == ctxt => {
-                let ty = cx.tcx.type_of(owner_id.def_id).instantiate_identity();
-                Some(ty_auto_deref_stability(cx.tcx, cx.param_env, ty, precedence).position_for_result(cx))
-            },
 
-            Node::Item(&Item {
-                kind: ItemKind::Fn(..),
-                owner_id,
-                span,
-                ..
-            })
-            | Node::TraitItem(&TraitItem {
-                kind: TraitItemKind::Fn(..),
-                owner_id,
-                span,
-                ..
-            })
-            | Node::ImplItem(&ImplItem {
-                kind: ImplItemKind::Fn(..),
-                owner_id,
-                span,
-                ..
-            }) if span.ctxt() == ctxt => {
-                let output = cx
-                    .tcx
-                    .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).instantiate_identity().output());
-                Some(ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx))
-            },
-
-            Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) {
-                Some(Expr {
-                    hir_id,
-                    kind: ExprKind::Struct(path, ..),
-                    ..
-                }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
-                    .and_then(|(adt, variant)| {
-                        variant
-                            .fields
-                            .iter()
-                            .find(|f| f.name == field.ident.name)
-                            .map(|f| (adt, f))
-                    })
-                    .map(|(adt, field_def)| {
-                        ty_auto_deref_stability(
-                            cx.tcx,
-                            // Use the param_env of the target type.
-                            cx.tcx.param_env(adt.did()),
-                            cx.tcx.type_of(field_def.did).instantiate_identity(),
-                            precedence,
-                        )
-                        .position_for_arg()
-                    }),
-                _ => None,
-            },
+    // Checks the stability of type coercions when assigned to a binding with the given explicit type.
+    //
+    // e.g.
+    // let x = Box::new(Box::new(0u32));
+    // let y1: &Box<_> = x.deref();
+    // let y2: &Box<_> = &x;
+    //
+    // Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
+    // switching to auto-dereferencing.
+    fn for_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Self {
+        let TyKind::Ref(_, ty) = &ty.kind else {
+            return Self::None;
+        };
+        let mut ty = ty;
 
-            Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
-                ExprKind::Ret(_) => {
-                    let owner_id = cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap());
-                    Some(
-                        if let Node::Expr(
-                            closure_expr @ Expr {
-                                kind: ExprKind::Closure(closure),
-                                ..
-                            },
-                        ) = cx.tcx.hir().get_by_def_id(owner_id)
-                        {
-                            closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
-                        } else {
-                            let output = cx
-                                .tcx
-                                .erase_late_bound_regions(cx.tcx.fn_sig(owner_id).instantiate_identity().output());
-                            ty_auto_deref_stability(cx.tcx, cx.param_env, output, precedence).position_for_result(cx)
-                        },
-                    )
-                },
-                ExprKind::Closure(closure) => Some(closure_result_position(
-                    cx,
-                    closure,
-                    cx.typeck_results().expr_ty(parent),
-                    precedence,
-                )),
-                ExprKind::Call(func, _) if func.hir_id == child_id => {
-                    (child_id == e.hir_id).then_some(Position::Callee)
+        loop {
+            break match ty.ty.kind {
+                TyKind::Ref(_, ref ref_ty) => {
+                    ty = ref_ty;
+                    continue;
                 },
-                ExprKind::Call(func, args) => args
-                    .iter()
-                    .position(|arg| arg.hir_id == child_id)
-                    .zip(expr_sig(cx, func))
-                    .and_then(|(i, sig)| {
-                        sig.input_with_hir(i).map(|(hir_ty, ty)| {
-                            match hir_ty {
-                                // Type inference for closures can depend on how they're called. Only go by the explicit
-                                // types here.
-                                Some(hir_ty) => {
-                                    binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars())
-                                },
-                                None => {
-                                    // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
-                                    // `!call_is_qualified(func)` for https://github.com/rust-lang/rust-clippy/issues/9782
-                                    if e.hir_id == child_id
-                                        && !call_is_qualified(func)
-                                        && let ty::Param(param_ty) = ty.skip_binder().kind()
-                                    {
-                                        needless_borrow_impl_arg_position(
-                                            cx,
-                                            possible_borrowers,
-                                            parent,
-                                            i,
-                                            *param_ty,
-                                            e,
-                                            precedence,
-                                            msrv,
-                                        )
-                                    } else {
-                                        ty_auto_deref_stability(
-                                            cx.tcx,
-                                            // Use the param_env of the target function.
-                                            sig.predicates_id().map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id)),
-                                            cx.tcx.erase_late_bound_regions(ty),
-                                            precedence
-                                        ).position_for_arg()
-                                    }
-                                },
-                            }
+                TyKind::Path(
+                    QPath::TypeRelative(_, path)
+                    | QPath::Resolved(
+                        _,
+                        Path {
+                            segments: [.., path], ..
+                        },
+                    ),
+                ) => {
+                    if let Some(args) = path.args
+                        && args.args.iter().any(|arg| match arg {
+                            hir::GenericArg::Infer(_) => true,
+                            hir::GenericArg::Type(ty) => ty_contains_infer(ty),
+                            _ => false,
                         })
-                    }),
-                ExprKind::MethodCall(method, receiver, args, _) => {
-                    let fn_id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
-                    if receiver.hir_id == child_id {
-                        // Check for calls to trait methods where the trait is implemented on a reference.
-                        // Two cases need to be handled:
-                        // * `self` methods on `&T` will never have auto-borrow
-                        // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take
-                        //   priority.
-                        if e.hir_id != child_id {
-                            return Some(Position::ReborrowStable(precedence))
-                        } else if let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
-                            && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e))
-                            && let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
-                            && let subs = cx
-                                .typeck_results()
-                                .node_args_opt(parent.hir_id).map(|subs| &subs[1..]).unwrap_or_default()
-                            && let impl_ty = if cx.tcx.fn_sig(fn_id)
-                                .instantiate_identity()
-                                .skip_binder()
-                                .inputs()[0].is_ref()
-                            {
-                                // Trait methods taking `&self`
-                                sub_ty
-                            } else {
-                                // Trait methods taking `self`
-                                arg_ty
-                            } && impl_ty.is_ref()
-                            && let infcx = cx.tcx.infer_ctxt().build()
-                            && infcx
-                                .type_implements_trait(
-                                    trait_id,
-                                    [impl_ty.into()].into_iter().chain(subs.iter().copied()),
-                                    cx.param_env,
-                                )
-                                .must_apply_modulo_regions()
-                        {
-                            return Some(Position::MethodReceiverRefImpl)
-                        }
-                        return Some(Position::MethodReceiver);
+                    {
+                        Self::Reborrow
+                    } else {
+                        Self::Deref
                     }
-                    args.iter().position(|arg| arg.hir_id == child_id).map(|i| {
-                        let ty = cx.tcx.fn_sig(fn_id).instantiate_identity().input(i + 1);
-                        // `e.hir_id == child_id` for https://github.com/rust-lang/rust-clippy/issues/9739
-                        // `method.args.is_none()` for https://github.com/rust-lang/rust-clippy/issues/9782
-                        if e.hir_id == child_id
-                            && method.args.is_none()
-                            && let ty::Param(param_ty) = ty.skip_binder().kind()
-                        {
-                            needless_borrow_impl_arg_position(
-                                cx,
-                                possible_borrowers,
-                                parent,
-                                i + 1,
-                                *param_ty,
-                                e,
-                                precedence,
-                                msrv,
-                            )
-                        } else {
-                            ty_auto_deref_stability(
-                                cx.tcx,
-                                // Use the param_env of the target function.
-                                cx.tcx.param_env(fn_id),
-                                cx.tcx.erase_late_bound_regions(ty),
-                                precedence,
-                            )
-                            .position_for_arg()
-                        }
-                    })
-                },
-                ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess {
-                    name: name.name,
-                    of_union: is_union(cx.typeck_results(), child),
-                }),
-                ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
-                ExprKind::Match(child, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
-                | ExprKind::Index(child, _)
-                    if child.hir_id == e.hir_id =>
-                {
-                    Some(Position::Postfix)
-                },
-                _ if child_id == e.hir_id => {
-                    precedence = parent.precedence().order();
-                    None
                 },
-                _ => None,
-            },
-            _ => None,
+                TyKind::Slice(_)
+                | TyKind::Array(..)
+                | TyKind::Ptr(_)
+                | TyKind::BareFn(_)
+                | TyKind::Never
+                | TyKind::Tup(_)
+                | TyKind::Path(_) => Self::Deref,
+                TyKind::OpaqueDef(..)
+                | TyKind::Infer
+                | TyKind::Typeof(..)
+                | TyKind::TraitObject(..)
+                | TyKind::Err(_) => Self::Reborrow,
+            };
         }
-    })
-    .unwrap_or(Position::Other(precedence));
-    (position, adjustments)
-}
-
-fn is_union<'tcx>(typeck: &'tcx TypeckResults<'_>, path_expr: &'tcx Expr<'_>) -> bool {
-    typeck
-        .expr_ty_adjusted(path_expr)
-        .ty_adt_def()
-        .map_or(false, rustc_middle::ty::AdtDef::is_union)
-}
-
-fn closure_result_position<'tcx>(
-    cx: &LateContext<'tcx>,
-    closure: &'tcx Closure<'_>,
-    ty: Ty<'tcx>,
-    precedence: i8,
-) -> Position {
-    match closure.fn_decl.output {
-        FnRetTy::Return(hir_ty) => {
-            if let Some(sig) = ty_sig(cx, ty)
-                && let Some(output) = sig.output()
-            {
-                binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars())
-            } else {
-                Position::Other(precedence)
-            }
-        },
-        FnRetTy::DefaultReturn(_) => Position::Other(precedence),
     }
-}
 
-// Checks the stability of auto-deref when assigned to a binding with the given explicit type.
-//
-// e.g.
-// let x = Box::new(Box::new(0u32));
-// let y1: &Box<_> = x.deref();
-// let y2: &Box<_> = &x;
-//
-// Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
-// switching to auto-dereferencing.
-fn binding_ty_auto_deref_stability<'tcx>(
-    cx: &LateContext<'tcx>,
-    ty: &'tcx hir::Ty<'_>,
-    precedence: i8,
-    binder_args: &'tcx List<BoundVariableKind>,
-) -> Position {
-    let TyKind::Ref(_, ty) = &ty.kind else {
-        return Position::Other(precedence);
-    };
-    let mut ty = ty;
+    fn for_mir_ty<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, for_return: bool) -> Self {
+        let ty::Ref(_, mut ty, _) = *ty.kind() else {
+            return Self::None;
+        };
 
-    loop {
-        break match ty.ty.kind {
-            TyKind::Ref(_, ref ref_ty) => {
-                ty = ref_ty;
-                continue;
-            },
-            TyKind::Path(
-                QPath::TypeRelative(_, path)
-                | QPath::Resolved(
-                    _,
-                    Path {
-                        segments: [.., path], ..
-                    },
-                ),
-            ) => {
-                if let Some(args) = path.args
-                    && args.args.iter().any(|arg| match arg {
-                        GenericArg::Infer(_) => true,
-                        GenericArg::Type(ty) => ty_contains_infer(ty),
-                        _ => false,
-                    })
+        ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
+        loop {
+            break match *ty.kind() {
+                ty::Ref(_, ref_ty, _) => {
+                    ty = ref_ty;
+                    continue;
+                },
+                ty::Param(_) if for_return => Self::Deref,
+                ty::Alias(ty::Weak | ty::Inherent, _) => unreachable!("should have been normalized away above"),
+                ty::Alias(ty::Projection, _) if !for_return && ty.has_non_region_param() => Self::Reborrow,
+                ty::Infer(_)
+                | ty::Error(_)
+                | ty::Bound(..)
+                | ty::Alias(ty::Opaque, ..)
+                | ty::Placeholder(_)
+                | ty::Dynamic(..)
+                | ty::Param(_) => Self::Reborrow,
+                ty::Adt(_, args)
+                    if ty.has_placeholders()
+                        || ty.has_opaque_types()
+                        || (!for_return && args.has_non_region_param()) =>
                 {
-                    Position::ReborrowStable(precedence)
-                } else {
-                    Position::DerefStable(
-                        precedence,
-                        cx.tcx
-                            .erase_late_bound_regions(Binder::bind_with_vars(
-                                cx.typeck_results().node_type(ty.ty.hir_id),
-                                binder_args,
-                            ))
-                            .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
-                    )
-                }
-            },
-            TyKind::Slice(_) => Position::DerefStable(precedence, false),
-            TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true),
-            TyKind::Never
-            | TyKind::Tup(_)
-            | TyKind::Path(_) => Position::DerefStable(
-                precedence,
-                cx.tcx
-                    .erase_late_bound_regions(Binder::bind_with_vars(
-                        cx.typeck_results().node_type(ty.ty.hir_id),
-                        binder_args,
-                    ))
-                    .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
-            ),
-            TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err(_) => {
-                Position::ReborrowStable(precedence)
-            },
-        };
+                    Self::Reborrow
+                },
+                ty::Bool
+                | ty::Char
+                | ty::Int(_)
+                | ty::Uint(_)
+                | ty::Array(..)
+                | ty::Float(_)
+                | ty::RawPtr(..)
+                | ty::FnPtr(_)
+                | ty::Str
+                | ty::Slice(..)
+                | ty::Adt(..)
+                | ty::Foreign(_)
+                | ty::FnDef(..)
+                | ty::Generator(..)
+                | ty::GeneratorWitness(..)
+                | ty::GeneratorWitnessMIR(..)
+                | ty::Closure(..)
+                | ty::Never
+                | ty::Tuple(_)
+                | ty::Alias(ty::Projection, _) => Self::Deref,
+            };
+        }
     }
 }
 
@@ -1084,10 +967,10 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
             }
         }
 
-        fn visit_generic_arg(&mut self, arg: &GenericArg<'_>) {
-            if self.0 || matches!(arg, GenericArg::Infer(_)) {
+        fn visit_generic_arg(&mut self, arg: &hir::GenericArg<'_>) {
+            if self.0 || matches!(arg, hir::GenericArg::Infer(_)) {
                 self.0 = true;
-            } else if let GenericArg::Type(ty) = arg {
+            } else if let hir::GenericArg::Type(ty) = arg {
                 self.visit_ty(ty);
             }
         }
@@ -1097,51 +980,29 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
     v.0
 }
 
-fn call_is_qualified(expr: &Expr<'_>) -> bool {
-    if let ExprKind::Path(path) = &expr.kind {
-        match path {
-            QPath::Resolved(_, path) => path.segments.last().map_or(false, |segment| segment.args.is_some()),
-            QPath::TypeRelative(_, segment) => segment.args.is_some(),
-            QPath::LangItem(..) => false,
-        }
-    } else {
-        false
-    }
-}
-
-// Checks whether:
-// * child is an expression of the form `&e` in an argument position requiring an `impl Trait`
-// * `e`'s type implements `Trait` and is copyable
-// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`.
-//   The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to
-// be moved, but it cannot be.
-#[expect(clippy::too_many_arguments, clippy::too_many_lines)]
-fn needless_borrow_impl_arg_position<'tcx>(
+/// Checks for the number of borrow expressions which can be removed from the given expression
+/// where the expression is used as an argument to a function expecting a generic type.
+///
+/// The following constraints will be checked:
+/// * The borrowed expression meets all the generic type's constraints.
+/// * The generic type appears only once in the functions signature.
+/// * The borrowed value will not be moved if it is used later in the function.
+#[expect(clippy::too_many_arguments)]
+fn needless_borrow_generic_arg_count<'tcx>(
     cx: &LateContext<'tcx>,
     possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
-    parent: &Expr<'tcx>,
+    fn_id: DefId,
+    callee_args: &'tcx List<GenericArg<'tcx>>,
     arg_index: usize,
     param_ty: ParamTy,
     mut expr: &Expr<'tcx>,
-    precedence: i8,
     msrv: &Msrv,
-) -> Position {
+) -> usize {
     let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
     let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
 
-    let Some(callee_def_id) = fn_def_id(cx, parent) else {
-        return Position::Other(precedence);
-    };
-    let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder();
-    let args_with_expr_ty = cx
-        .typeck_results()
-        .node_args(if let ExprKind::Call(callee, _) = parent.kind {
-            callee.hir_id
-        } else {
-            parent.hir_id
-        });
-
-    let predicates = cx.tcx.param_env(callee_def_id).caller_bounds();
+    let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder();
+    let predicates = cx.tcx.param_env(fn_id).caller_bounds();
     let projection_predicates = predicates
         .iter()
         .filter_map(|predicate| {
@@ -1176,7 +1037,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
                 || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id)
         })
     {
-        return Position::Other(precedence);
+        return 0;
     }
 
     // See:
@@ -1184,14 +1045,14 @@ fn needless_borrow_impl_arg_position<'tcx>(
     // - https://github.com/rust-lang/rust-clippy/pull/9674#issuecomment-1292225232
     if projection_predicates
         .iter()
-        .any(|projection_predicate| is_mixed_projection_predicate(cx, callee_def_id, projection_predicate))
+        .any(|projection_predicate| is_mixed_projection_predicate(cx, fn_id, projection_predicate))
     {
-        return Position::Other(precedence);
+        return 0;
     }
 
     // `args_with_referent_ty` can be constructed outside of `check_referent` because the same
     // elements are modified each time `check_referent` is called.
-    let mut args_with_referent_ty = args_with_expr_ty.to_vec();
+    let mut args_with_referent_ty = callee_args.to_vec();
 
     let mut check_reference_and_referent = |reference, referent| {
         let referent_ty = cx.typeck_results().expr_ty(referent);
@@ -1238,20 +1099,15 @@ fn needless_borrow_impl_arg_position<'tcx>(
         })
     };
 
-    let mut needless_borrow = false;
+    let mut count = 0;
     while let ExprKind::AddrOf(_, _, referent) = expr.kind {
         if !check_reference_and_referent(expr, referent) {
             break;
         }
         expr = referent;
-        needless_borrow = true;
-    }
-
-    if needless_borrow {
-        Position::ImplArg(expr.hir_id)
-    } else {
-        Position::Other(precedence)
+        count += 1;
     }
+    count
 }
 
 fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
@@ -1392,93 +1248,6 @@ fn replace_types<'tcx>(
     true
 }
 
-struct TyPosition<'tcx> {
-    position: Position,
-    ty: Option<Ty<'tcx>>,
-}
-impl From<Position> for TyPosition<'_> {
-    fn from(position: Position) -> Self {
-        Self { position, ty: None }
-    }
-}
-impl<'tcx> TyPosition<'tcx> {
-    fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self {
-        Self {
-            position: Position::ReborrowStable(precedence),
-            ty: Some(ty),
-        }
-    }
-    fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
-        match (self.position, self.ty) {
-            (Position::ReborrowStable(precedence), Some(ty)) => {
-                Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env))
-            },
-            (position, _) => position,
-        }
-    }
-    fn position_for_arg(self) -> Position {
-        self.position
-    }
-}
-
-// Checks whether a type is stable when switching to auto dereferencing,
-fn ty_auto_deref_stability<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
-    precedence: i8,
-) -> TyPosition<'tcx> {
-    let ty::Ref(_, mut ty, _) = *ty.kind() else {
-        return Position::Other(precedence).into();
-    };
-
-    ty = tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
-
-    loop {
-        break match *ty.kind() {
-            ty::Ref(_, ref_ty, _) => {
-                ty = ref_ty;
-                continue;
-            },
-            ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
-            ty::Alias(ty::Weak, _) => unreachable!("should have been normalized away above"),
-            ty::Alias(ty::Inherent, _) => unreachable!("inherent projection should have been normalized away above"),
-            ty::Alias(ty::Projection, _) if ty.has_non_region_param() => {
-                TyPosition::new_deref_stable_for_result(precedence, ty)
-            },
-            ty::Infer(_)
-            | ty::Error(_)
-            | ty::Bound(..)
-            | ty::Alias(ty::Opaque, ..)
-            | ty::Placeholder(_)
-            | ty::Dynamic(..) => Position::ReborrowStable(precedence).into(),
-            ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
-                Position::ReborrowStable(precedence).into()
-            },
-            ty::Adt(_, args) if args.has_non_region_param() => TyPosition::new_deref_stable_for_result(precedence, ty),
-            ty::Bool
-            | ty::Char
-            | ty::Int(_)
-            | ty::Uint(_)
-            | ty::Array(..)
-            | ty::Float(_)
-            | ty::RawPtr(..)
-            | ty::FnPtr(_) => Position::DerefStable(precedence, true).into(),
-            ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(),
-            ty::Adt(..)
-            | ty::Foreign(_)
-            | ty::FnDef(..)
-            | ty::Generator(..)
-            | ty::GeneratorWitness(..)
-            | ty::GeneratorWitnessMIR(..)
-            | ty::Closure(..)
-            | ty::Never
-            | ty::Tuple(_)
-            | ty::Alias(ty::Projection, _) => Position::DerefStable(precedence, ty.is_sized(tcx, param_env)).into(),
-        };
-    }
-}
-
 fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool {
     if let ty::Adt(adt, _) = *ty.kind() {
         adt.is_struct() && adt.all_fields().any(|f| f.name == name)
@@ -1488,12 +1257,12 @@ fn ty_contains_field(ty: Ty<'_>, name: Symbol) -> bool {
 }
 
 #[expect(clippy::needless_pass_by_value, clippy::too_many_lines)]
-fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
+fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData<'tcx>) {
     match state {
         State::DerefMethod {
             ty_changed_count,
-            is_final_ufcs,
-            target_mut,
+            is_ufcs,
+            mutbl,
         } => {
             let mut app = Applicability::MachineApplicable;
             let (expr_str, _expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
@@ -1508,12 +1277,12 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
             };
             let addr_of_str = if ty_changed_count < ref_count {
                 // Check if a reborrow from &mut T -> &T is required.
-                if target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
+                if mutbl == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
                     "&*"
                 } else {
                     ""
                 }
-            } else if target_mut == Mutability::Mut {
+            } else if mutbl == Mutability::Mut {
                 "&mut "
             } else {
                 "&"
@@ -1530,7 +1299,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
             */
 
             // Fix #10850, do not lint if it's `Foo::deref` instead of `foo.deref()`.
-            if is_final_ufcs {
+            if is_ufcs {
                 return;
             }
 
@@ -1538,7 +1307,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                 cx,
                 EXPLICIT_DEREF_METHODS,
                 data.span,
-                match target_mut {
+                match mutbl {
                     Mutability::Not => "explicit `deref` method call",
                     Mutability::Mut => "explicit `deref_mut` method call",
                 },
@@ -1549,13 +1318,19 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
         },
         State::DerefedBorrow(state) => {
             let mut app = Applicability::MachineApplicable;
-            let snip_expr = state.snip_expr.map_or(expr, |hir_id| cx.tcx.hir().expect_expr(hir_id));
-            let (snip, snip_is_macro) = snippet_with_context(cx, snip_expr.span, data.span.ctxt(), "..", &mut app);
+            let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
             span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| {
-                let calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee);
+                let (precedence, calls_field) = match get_parent_node(cx.tcx, data.hir_id) {
+                    Some(Node::Expr(e)) => match e.kind {
+                        ExprKind::Call(callee, _) if callee.hir_id != data.hir_id => (0, false),
+                        ExprKind::Call(..) => (PREC_POSTFIX, matches!(expr.kind, ExprKind::Field(..))),
+                        _ => (e.precedence().order(), false),
+                    },
+                    _ => (0, false),
+                };
                 let sugg = if !snip_is_macro
+                    && (calls_field || expr.precedence().order() < precedence)
                     && !has_enclosing_paren(&snip)
-                    && (expr.precedence().order() < data.position.precedence() || calls_field)
                 {
                     format!("({snip})")
                 } else {
@@ -1572,7 +1347,8 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                     | ExprKind::If(..)
                     | ExprKind::Loop(..)
                     | ExprKind::Match(..)
-            ) && matches!(data.position, Position::DerefStable(_, true))
+            ) && let ty::Ref(_, ty, _) = data.adjusted_ty.kind()
+                && ty.is_sized(cx.tcx, cx.param_env)
             {
                 // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
                 return;
@@ -1585,9 +1361,9 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                     Mutability::Not => "&",
                     Mutability::Mut => "&mut ",
                 };
-                (prefix, 0)
+                (prefix, PREC_PREFIX)
             } else {
-                ("", data.position.precedence())
+                ("", 0)
             };
             span_lint_hir_and_then(
                 cx,
@@ -1616,7 +1392,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                     | ExprKind::If(..)
                     | ExprKind::Loop(..)
                     | ExprKind::Match(..)
-            ) && matches!(data.position, Position::DerefStable(_, true))
+            ) && data.adjusted_ty.is_sized(cx.tcx, cx.param_env)
             {
                 // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
                 return;
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 91bc30ab577..e3f2026cfe9 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -1,4 +1,6 @@
-use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::{
+    span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
+};
 use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
 use clippy_utils::{is_lint_allowed, match_def_path, paths};
 use if_chain::if_chain;
@@ -6,15 +8,15 @@ use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
 use rustc_hir::{
-    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource,
-    Unsafety,
+    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind,
+    UnsafeSource, Unsafety,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate,
-    TraitPredicate, Ty, TyCtxt,
+    self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv,
+    ToPredicate, TraitPredicate, Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
@@ -205,13 +207,10 @@ declare_lint_pass!(Derive => [
 
 impl<'tcx> LateLintPass<'tcx> for Derive {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let ItemKind::Impl(Impl {
-            of_trait: Some(ref trait_ref),
-            ..
-        }) = item.kind
-        {
+        if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), .. }) = item.kind {
             let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
-            let is_automatically_derived = cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
+            let is_automatically_derived =
+                cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
 
             check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
             check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
@@ -328,7 +327,12 @@ fn check_ord_partial_ord<'tcx>(
 }
 
 /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
-fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
+fn check_copy_clone<'tcx>(
+    cx: &LateContext<'tcx>,
+    item: &Item<'_>,
+    trait_ref: &hir::TraitRef<'_>,
+    ty: Ty<'tcx>,
+) {
     let clone_id = match cx.tcx.lang_items().clone_trait() {
         Some(id) if trait_ref.trait_def_id() == Some(id) => id,
         _ => return,
@@ -427,7 +431,14 @@ struct UnsafeVisitor<'a, 'tcx> {
 impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, _: Span, id: LocalDefId) {
+    fn visit_fn(
+        &mut self,
+        kind: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'_>,
+        body_id: BodyId,
+        _: Span,
+        id: LocalDefId,
+    ) {
         if self.has_unsafe {
             return;
         }
@@ -463,7 +474,12 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
 }
 
 /// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
-fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
+fn check_partial_eq_without_eq<'tcx>(
+    cx: &LateContext<'tcx>,
+    span: Span,
+    trait_ref: &hir::TraitRef<'_>,
+    ty: Ty<'tcx>,
+) {
     if_chain! {
         if let ty::Adt(adt, args) = ty.kind();
         if cx.tcx.visibility(adt.did()).is_public();
@@ -471,12 +487,12 @@ fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_r
         if let Some(def_id) = trait_ref.trait_def_id();
         if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id);
         let param_env = param_env_for_derived_eq(cx.tcx, adt.did(), eq_trait_def_id);
-        if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, []);
+        if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]);
         // If all of our fields implement `Eq`, we can implement `Eq` too
         if adt
             .all_fields()
             .map(|f| f.ty(cx.tcx, args))
-            .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, []));
+            .all(|ty| implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, &[]));
         then {
             span_lint_and_sugg(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/error_impl_error.rs b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
new file mode 100644
index 00000000000..379af9b2234
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
@@ -0,0 +1,87 @@
+use clippy_utils::diagnostics::{span_lint, span_lint_hir_and_then};
+use clippy_utils::path_res;
+use clippy_utils::ty::implements_trait;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{Item, ItemKind};
+use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Visibility;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for types named `Error` that implement `Error`.
+    ///
+    /// ### Why is this bad?
+    /// It can become confusing when a codebase has 20 types all named `Error`, requiring either
+    /// aliasing them in the `use` statement or qualifying them like `my_module::Error`. This
+    /// hinders comprehension, as it requires you to memorize every variation of importing `Error`
+    /// used across a codebase.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// #[derive(Debug)]
+    /// pub enum Error { ... }
+    ///
+    /// impl std::fmt::Display for Error { ... }
+    ///
+    /// impl std::error::Error for Error { ... }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub ERROR_IMPL_ERROR,
+    restriction,
+    "exported types named `Error` that implement `Error`"
+}
+declare_lint_pass!(ErrorImplError => [ERROR_IMPL_ERROR]);
+
+impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error) else {
+            return;
+        };
+
+        match item.kind {
+            ItemKind::TyAlias(ty, _) if implements_trait(cx, hir_ty_to_ty(cx.tcx, ty), error_def_id, &[])
+                && item.ident.name == sym::Error
+                && is_visible_outside_module(cx, item.owner_id.def_id) =>
+            {
+                span_lint(
+                    cx,
+                    ERROR_IMPL_ERROR,
+                    item.ident.span,
+                    "exported type alias named `Error` that implements `Error`",
+                );
+            },
+            ItemKind::Impl(imp) if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
+                && error_def_id == trait_def_id
+                && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
+                && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id)
+                && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
+                && ident.name == sym::Error
+                && is_visible_outside_module(cx, def_id) =>
+            {
+                span_lint_hir_and_then(
+                    cx,
+                    ERROR_IMPL_ERROR,
+                    hir_id,
+                    ident.span,
+                    "exported type named `Error` that implements `Error`",
+                    |diag| {
+                        diag.span_note(item.span, "`Error` was implemented here");
+                    }
+                );
+            }
+            _ => {},
+        }
+    }
+}
+
+/// Do not lint private `Error`s, i.e., ones without any `pub` (minus `pub(self)` of course) and
+/// which aren't reexported
+fn is_visible_outside_module(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
+    !matches!(
+        cx.tcx.visibility(def_id),
+        Visibility::Restricted(mod_def_id) if cx.tcx.parent_module_from_def_id(def_id).to_def_id() == mod_def_id
+    )
+}
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 22e10accd35..8d6fb8438b6 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -1,19 +1,22 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::higher::VecArgs;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::usage::local_used_after_expr;
+use clippy_utils::ty::type_diagnostic_name;
+use clippy_utils::usage::{local_used_after_expr, local_used_in};
 use clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id};
-use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Closure, Expr, ExprKind, Param, PatKind, Unsafety};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety};
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
-use rustc_middle::ty::binding::BindingMode;
-use rustc_middle::ty::{self, EarlyBinder, GenericArgsRef, Ty, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, Binder, BoundConstness, ClosureArgs, ClosureKind, EarlyBinder, FnSig, GenericArg, GenericArgKind,
+    GenericArgsRef, ImplPolarity, List, Region, RegionKind, Ty, TypeVisitableExt, TypeckResults,
+};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
+use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -72,14 +75,18 @@ declare_clippy_lint! {
 declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_METHOD_CALLS]);
 
 impl<'tcx> LateLintPass<'tcx> for EtaReduction {
+    #[allow(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if expr.span.from_expansion() {
+        let body = if let ExprKind::Closure(c) = expr.kind
+            && c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer))
+            && matches!(c.fn_decl.output, FnRetTy::DefaultReturn(_))
+            && !expr.span.from_expansion()
+        {
+            cx.tcx.hir().body(c.body)
+        } else {
             return;
-        }
-        let body = match expr.kind {
-            ExprKind::Closure(&Closure { body, .. }) => cx.tcx.hir().body(body),
-            _ => return,
         };
+
         if body.value.span.from_expansion() {
             if body.params.is_empty() {
                 if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, body.value) {
@@ -99,140 +106,209 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
             return;
         }
 
-        let closure_ty = cx.typeck_results().expr_ty(expr);
+        let typeck = cx.typeck_results();
+        let closure = if let ty::Closure(_, closure_subs) = typeck.expr_ty(expr).kind() {
+            closure_subs.as_closure()
+        } else {
+            return;
+        };
 
-        if_chain!(
-            if !is_adjusted(cx, body.value);
-            if let ExprKind::Call(callee, args) = body.value.kind;
-            if let ExprKind::Path(_) = callee.kind;
-            if check_inputs(cx, body.params, None, args);
-            let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
-            let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
-                .map_or(callee_ty, |id| cx.tcx.type_of(id).instantiate_identity());
-            if check_sig(cx, closure_ty, call_ty);
-            let args = cx.typeck_results().node_args(callee.hir_id);
-            // This fixes some false positives that I don't entirely understand
-            if args.is_empty() || !cx.typeck_results().expr_ty(expr).has_late_bound_regions();
-            // A type param function ref like `T::f` is not 'static, however
-            // it is if cast like `T::f as fn()`. This seems like a rustc bug.
-            if !args.types().any(|t| matches!(t.kind(), ty::Param(_)));
-            let callee_ty_unadjusted = cx.typeck_results().expr_ty(callee).peel_refs();
-            if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Arc);
-            if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Rc);
-            if let ty::Closure(_, args) = *closure_ty.kind();
-            // Don't lint if this is an inclusive range expression.
-            // They desugar to a call to `RangeInclusiveNew` which would have odd suggestions. (#10684)
-            if !matches!(higher::Range::hir(body.value), Some(higher::Range {
-                start: Some(_),
-                end: Some(_),
-                limits: rustc_ast::RangeLimits::Closed
-            }));
-            then {
-                span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
-                    if let Some(mut snippet) = snippet_opt(cx, callee.span) {
-                        if let Some(fn_mut_id) = cx.tcx.lang_items().fn_mut_trait()
-                            && let args = cx.tcx.erase_late_bound_regions(args.as_closure().sig()).inputs()
-                            && implements_trait(
-                                   cx,
-                                   callee_ty.peel_refs(),
-                                   fn_mut_id,
-                                   &args.iter().copied().map(Into::into).collect::<Vec<_>>(),
-                               )
-                            && path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr))
-                        {
-                                // Mutable closure is used after current expr; we cannot consume it.
-                                snippet = format!("&mut {snippet}");
-                        }
+        if is_adjusted(cx, body.value) {
+            return;
+        }
 
-                        diag.span_suggestion(
-                            expr.span,
-                            "replace the closure with the function itself",
-                            snippet,
-                            Applicability::MachineApplicable,
-                        );
-                    }
-                });
-            }
-        );
+        match body.value.kind {
+            ExprKind::Call(callee, args)
+                if matches!(callee.kind, ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))) =>
+            {
+                let callee_ty = typeck.expr_ty(callee).peel_refs();
+                if matches!(
+                    type_diagnostic_name(cx, callee_ty),
+                    Some(sym::Arc | sym::Rc)
+                ) || !check_inputs(typeck, body.params, None, args) {
+                    return;
+                }
+                let callee_ty_adjusted = typeck.expr_adjustments(callee).last().map_or(
+                    callee_ty,
+                    |a| a.target.peel_refs(),
+                );
 
-        if_chain!(
-            if !is_adjusted(cx, body.value);
-            if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind;
-            if check_inputs(cx, body.params, Some(receiver), args);
-            let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
-            let args = cx.typeck_results().node_args(body.value.hir_id);
-            let call_ty = cx.tcx.type_of(method_def_id).instantiate(cx.tcx, args);
-            if check_sig(cx, closure_ty, call_ty);
-            then {
-                span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| {
-                    let name = get_ufcs_type_name(cx, method_def_id, args);
-                    diag.span_suggestion(
+                let sig = match callee_ty_adjusted.kind() {
+                    ty::FnDef(def, _) => cx.tcx.fn_sig(def).skip_binder().skip_binder(),
+                    ty::FnPtr(sig) => sig.skip_binder(),
+                    ty::Closure(_, subs) => cx
+                        .tcx
+                        .signature_unclosure(subs.as_closure().sig(), Unsafety::Normal)
+                        .skip_binder(),
+                    _ => {
+                        if typeck.type_dependent_def_id(body.value.hir_id).is_some()
+                            && let subs = typeck.node_args(body.value.hir_id)
+                            && let output = typeck.expr_ty(body.value)
+                            && let ty::Tuple(tys) = *subs.type_at(1).kind()
+                        {
+                            cx.tcx.mk_fn_sig(tys, output, false, Unsafety::Normal, Abi::Rust)
+                        } else {
+                            return;
+                        }
+                    },
+                };
+                if check_sig(cx, closure, sig)
+                    && let generic_args = typeck.node_args(callee.hir_id)
+                    // Given some trait fn `fn f() -> ()` and some type `T: Trait`, `T::f` is not
+                    // `'static` unless `T: 'static`. The cast `T::f as fn()` will, however, result
+                    // in a type which is `'static`.
+                    // For now ignore all callee types which reference a type parameter.
+                    && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
+                {
+                    span_lint_and_then(
+                        cx,
+                        REDUNDANT_CLOSURE,
                         expr.span,
-                        "replace the closure with the method itself",
-                        format!("{name}::{}", path.ident.name),
-                        Applicability::MachineApplicable,
+                        "redundant closure",
+                        |diag| {
+                            if let Some(mut snippet) = snippet_opt(cx, callee.span) {
+                                if let Ok((ClosureKind::FnMut, _))
+                                    = cx.tcx.infer_ctxt().build().type_implements_fn_trait(
+                                        cx.param_env,
+                                        Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
+                                        BoundConstness::NotConst,
+                                        ImplPolarity::Positive,
+                                    ) && path_to_local(callee)
+                                        .map_or(
+                                            false,
+                                            |l| local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr),
+                                        )
+                                {
+                                    // Mutable closure is used after current expr; we cannot consume it.
+                                    snippet = format!("&mut {snippet}");
+                                }
+                                diag.span_suggestion(
+                                    expr.span,
+                                    "replace the closure with the function itself",
+                                    snippet,
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                        }
                     );
-                })
-            }
-        );
+                }
+            },
+            ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
+                if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
+                    && check_sig(cx, closure, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
+                {
+                    span_lint_and_then(
+                        cx,
+                        REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
+                        expr.span,
+                        "redundant closure",
+                        |diag| {
+                            let args = typeck.node_args(body.value.hir_id);
+                            let name = get_ufcs_type_name(cx, method_def_id, args);
+                            diag.span_suggestion(
+                                expr.span,
+                                "replace the closure with the method itself",
+                                format!("{}::{}", name, path.ident.name),
+                                Applicability::MachineApplicable,
+                            );
+                        },
+                    );
+                }
+            },
+            _ => (),
+        }
     }
 }
 
 fn check_inputs(
-    cx: &LateContext<'_>,
+    typeck: &TypeckResults<'_>,
     params: &[Param<'_>],
-    receiver: Option<&Expr<'_>>,
-    call_args: &[Expr<'_>],
+    self_arg: Option<&Expr<'_>>,
+    args: &[Expr<'_>],
 ) -> bool {
-    if receiver.map_or(params.len() != call_args.len(), |_| params.len() != call_args.len() + 1) {
-        return false;
+    params.len() == self_arg.map_or(0, |_| 1) + args.len()
+        && params.iter().zip(self_arg.into_iter().chain(args)).all(|(p, arg)| {
+            matches!(
+                p.pat.kind,PatKind::Binding(BindingAnnotation::NONE, id, _, None)
+                if path_to_local_id(arg, id)
+            )
+            // Only allow adjustments which change regions (i.e. re-borrowing).
+            && typeck
+                .expr_adjustments(arg)
+                .last()
+                .map_or(true, |a| a.target == typeck.expr_ty(arg))
+        })
+}
+
+fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<'tcx>, call_sig: FnSig<'_>) -> bool {
+    call_sig.unsafety == Unsafety::Normal
+        && !has_late_bound_to_non_late_bound_regions(
+            cx.tcx
+                .signature_unclosure(closure.sig(), Unsafety::Normal)
+                .skip_binder(),
+            call_sig,
+        )
+}
+
+/// This walks through both signatures and checks for any time a late-bound region is expected by an
+/// `impl Fn` type, but the target signature does not have a late-bound region in the same position.
+///
+/// This is needed because rustc is unable to late bind early-bound regions in a function signature.
+fn has_late_bound_to_non_late_bound_regions(from_sig: FnSig<'_>, to_sig: FnSig<'_>) -> bool {
+    fn check_region(from_region: Region<'_>, to_region: Region<'_>) -> bool {
+        matches!(from_region.kind(), RegionKind::ReLateBound(..))
+            && !matches!(to_region.kind(), RegionKind::ReLateBound(..))
     }
-    let binding_modes = cx.typeck_results().pat_binding_modes();
-    let check_inputs = |param: &Param<'_>, arg| {
-        match param.pat.kind {
-            PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
-            _ => return false,
-        }
-        // checks that parameters are not bound as `ref` or `ref mut`
-        if let Some(BindingMode::BindByReference(_)) = binding_modes.get(param.pat.hir_id) {
-            return false;
-        }
 
-        match *cx.typeck_results().expr_adjustments(arg) {
-            [] => true,
-            [
-                Adjustment {
-                    kind: Adjust::Deref(None),
-                    ..
+    fn check_subs(from_subs: &[GenericArg<'_>], to_subs: &[GenericArg<'_>]) -> bool {
+        if from_subs.len() != to_subs.len() {
+            return true;
+        }
+        for (from_arg, to_arg) in to_subs.iter().zip(from_subs) {
+            match (from_arg.unpack(), to_arg.unpack()) {
+                (GenericArgKind::Lifetime(from_region), GenericArgKind::Lifetime(to_region)) => {
+                    if check_region(from_region, to_region) {
+                        return true;
+                    }
                 },
-                Adjustment {
-                    kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
-                    ..
+                (GenericArgKind::Type(from_ty), GenericArgKind::Type(to_ty)) => {
+                    if check_ty(from_ty, to_ty) {
+                        return true;
+                    }
                 },
-            ] => {
-                // re-borrow with the same mutability is allowed
-                let ty = cx.typeck_results().expr_ty(arg);
-                matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())
-            },
-            _ => false,
+                (GenericArgKind::Const(_), GenericArgKind::Const(_)) => (),
+                _ => return true,
+            }
         }
-    };
-    std::iter::zip(params, receiver.into_iter().chain(call_args.iter())).all(|(param, arg)| check_inputs(param, arg))
-}
-
-fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
-    let call_sig = call_ty.fn_sig(cx.tcx);
-    if call_sig.unsafety() == Unsafety::Unsafe {
-        return false;
+        false
     }
-    if !closure_ty.has_late_bound_regions() {
-        return true;
+
+    fn check_ty(from_ty: Ty<'_>, to_ty: Ty<'_>) -> bool {
+        match (from_ty.kind(), to_ty.kind()) {
+            (&ty::Adt(_, from_subs), &ty::Adt(_, to_subs)) => check_subs(from_subs, to_subs),
+            (&ty::Array(from_ty, _), &ty::Array(to_ty, _)) | (&ty::Slice(from_ty), &ty::Slice(to_ty)) => {
+                check_ty(from_ty, to_ty)
+            },
+            (&ty::Ref(from_region, from_ty, _), &ty::Ref(to_region, to_ty, _)) => {
+                check_region(from_region, to_region) || check_ty(from_ty, to_ty)
+            },
+            (&ty::Tuple(from_tys), &ty::Tuple(to_tys)) => {
+                from_tys.len() != to_tys.len()
+                    || from_tys
+                        .iter()
+                        .zip(to_tys)
+                        .any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
+            },
+            _ => from_ty.has_late_bound_regions(),
+        }
     }
-    let ty::Closure(_, args) = closure_ty.kind() else {
-        return false;
-    };
-    let closure_sig = cx.tcx.signature_unclosure(args.as_closure().sig(), Unsafety::Normal);
-    cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig)
+
+    assert!(from_sig.inputs_and_output.len() == to_sig.inputs_and_output.len());
+    from_sig
+        .inputs_and_output
+        .iter()
+        .zip(to_sig.inputs_and_output)
+        .any(|(from_ty, to_ty)| check_ty(from_ty, to_ty))
 }
 
 fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, args: GenericArgsRef<'tcx>) -> String {
@@ -241,7 +317,7 @@ fn get_ufcs_type_name<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId, args:
     match assoc_item.container {
         ty::TraitContainer => cx.tcx.def_path_str(def_id),
         ty::ImplContainer => {
-            let ty = cx.tcx.type_of(def_id).skip_binder();
+            let ty = cx.tcx.type_of(def_id).instantiate_identity();
             match ty.kind() {
                 ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
                 ty::Array(..)
diff --git a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
new file mode 100644
index 00000000000..419c7734344
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
@@ -0,0 +1,99 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_errors::Applicability;
+use rustc_hir::Item;
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for outer doc comments written with 4 forward slashes (`////`).
+    ///
+    /// ### Why is this bad?
+    /// This is (probably) a typo, and results in it not being a doc comment; just a regular
+    /// comment.
+    ///
+    /// ### Example
+    /// ```rust
+    /// //// My amazing data structure
+    /// pub struct Foo {
+    ///     // ...
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// /// My amazing data structure
+    /// pub struct Foo {
+    ///     // ...
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub FOUR_FORWARD_SLASHES,
+    suspicious,
+    "comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)"
+}
+declare_lint_pass!(FourForwardSlashes => [FOUR_FORWARD_SLASHES]);
+
+impl<'tcx> LateLintPass<'tcx> for FourForwardSlashes {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if item.span.from_expansion() {
+            return;
+        }
+        let sm = cx.sess().source_map();
+        let mut span = cx
+            .tcx
+            .hir()
+            .attrs(item.hir_id())
+            .iter()
+            .fold(item.span.shrink_to_lo(), |span, attr| span.to(attr.span));
+        let (Some(file), _, _, end_line, _) = sm.span_to_location_info(span) else {
+            return;
+        };
+        let mut bad_comments = vec![];
+        for line in (0..end_line.saturating_sub(1)).rev() {
+            let Some(contents) = file.get_line(line).map(|c| c.trim().to_owned()) else {
+                return;
+            };
+            // Keep searching until we find the next item
+            if !contents.is_empty() && !contents.starts_with("//") && !contents.starts_with("#[") {
+                break;
+            }
+
+            if contents.starts_with("////") && !matches!(contents.chars().nth(4), Some('/' | '!')) {
+                let bounds = file.line_bounds(line);
+                let line_span = Span::with_root_ctxt(bounds.start, bounds.end);
+                span = line_span.to(span);
+                bad_comments.push((line_span, contents));
+            }
+        }
+
+        if !bad_comments.is_empty() {
+            span_lint_and_then(
+                cx,
+                FOUR_FORWARD_SLASHES,
+                span,
+                "this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't",
+                |diag| {
+                    let msg = if bad_comments.len() == 1 {
+                        "make this a doc comment by removing one `/`"
+                    } else {
+                        "turn these into doc comments by removing one `/`"
+                    };
+
+                    diag.multipart_suggestion(
+                        msg,
+                        bad_comments
+                            .into_iter()
+                            // It's a little unfortunate but the span includes the `\n` yet the contents
+                            // do not, so we must add it back. If some codebase uses `\r\n` instead they
+                            // will need normalization but it should be fine
+                            .map(|(span, c)| (span, c.replacen("////", "///", 1) + "\n"))
+                            .collect(),
+                        Applicability::MachineApplicable,
+                    );
+                },
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/incorrect_impls.rs b/src/tools/clippy/clippy_lints/src/incorrect_impls.rs
index e6c42ebb832..3c59b839a39 100644
--- a/src/tools/clippy/clippy_lints/src/incorrect_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/incorrect_impls.rs
@@ -1,8 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::paths::ORD_CMP;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, path_res};
+use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, match_def_path, path_res, std_or_core};
 use rustc_errors::Applicability;
-use rustc_hir::def::Res;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, ItemKind, LangItem, Node, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::EarlyBinder;
@@ -59,6 +60,10 @@ declare_clippy_lint! {
     /// wrapping the result of `cmp` in `Some` for `partial_cmp`. Not doing this may silently
     /// introduce an error upon refactoring.
     ///
+    /// ### Known issues
+    /// Code that calls the `.into()` method instead will be flagged as incorrect, despite `.into()`
+    /// wrapping it in `Some`.
+    ///
     /// ### Limitations
     /// Will not lint if `Self` and `Rhs` do not have the same type.
     ///
@@ -190,6 +195,11 @@ impl LateLintPass<'_> for IncorrectImpls {
                     &[],
                 )
         {
+            // If the `cmp` call likely needs to be fully qualified in the suggestion
+            // (like `std::cmp::Ord::cmp`). It's unfortunate we must put this here but we can't
+            // access `cmp_expr` in the suggestion without major changes, as we lint in `else`.
+            let mut needs_fully_qualified = false;
+
             if block.stmts.is_empty()
                 && let Some(expr) = block.expr
                 && let ExprKind::Call(
@@ -201,9 +211,8 @@ impl LateLintPass<'_> for IncorrectImpls {
                         [cmp_expr],
                     ) = expr.kind
                 && is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome)
-                && let ExprKind::MethodCall(cmp_path, _, [other_expr], ..) = cmp_expr.kind
-                && cmp_path.ident.name == sym::cmp
-                && let Res::Local(..) = path_res(cx, other_expr)
+                // Fix #11178, allow `Self::cmp(self, ..)` too
+                && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, &mut needs_fully_qualified)
             {} else {
                 // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
                 // suggestion tons more complex.
@@ -220,14 +229,29 @@ impl LateLintPass<'_> for IncorrectImpls {
                         let [_, other] = body.params else {
                             return;
                         };
+                        let Some(std_or_core) = std_or_core(cx) else {
+                            return;
+                        };
 
-                        let suggs = if let Some(other_ident) = other.pat.simple_ident() {
-                            vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
-                        } else {
-                            vec![
+                        let suggs = match (other.pat.simple_ident(), needs_fully_qualified) {
+                            (Some(other_ident), true) => vec![(
+                                block.span,
+                                format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, {})) }}", other_ident.name),
+                            )],
+                            (Some(other_ident), false) => {
+                                vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
+                            },
+                            (None, true) => vec![
+                                (
+                                    block.span,
+                                    format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, other)) }}"),
+                                ),
+                                (other.pat.span, "other".to_owned()),
+                            ],
+                            (None, false) => vec![
                                 (block.span, "{ Some(self.cmp(other)) }".to_owned()),
                                 (other.pat.span, "other".to_owned()),
-                            ]
+                            ],
                         };
 
                         diag.multipart_suggestion(
@@ -241,3 +265,31 @@ impl LateLintPass<'_> for IncorrectImpls {
         }
     }
 }
+
+/// Returns whether this is any of `self.cmp(..)`, `Self::cmp(self, ..)` or `Ord::cmp(self, ..)`.
+fn self_cmp_call<'tcx>(
+    cx: &LateContext<'tcx>,
+    cmp_expr: &'tcx Expr<'tcx>,
+    def_id: LocalDefId,
+    needs_fully_qualified: &mut bool,
+) -> bool {
+    match cmp_expr.kind {
+        ExprKind::Call(path, [_self, _other]) => path_res(cx, path)
+            .opt_def_id()
+            .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP)),
+        ExprKind::MethodCall(_, _, [_other], ..) => {
+            // We can set this to true here no matter what as if it's a `MethodCall` and goes to the
+            // `else` branch, it must be a method named `cmp` that isn't `Ord::cmp`
+            *needs_fully_qualified = true;
+
+            // It's a bit annoying but `typeck_results` only gives us the CURRENT body, which we
+            // have none, not of any `LocalDefId` we want, so we must call the query itself to avoid
+            // an immediate ICE
+            cx.tcx
+                .typeck(def_id)
+                .type_dependent_def_id(cmp_expr.hir_id)
+                .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP))
+        },
+        _ => false,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index d43e5cc9b2c..bc4ec33b733 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::{implements_trait, is_type_lang_item};
 use clippy_utils::{return_ty, trait_ref_of_method};
-use if_chain::if_chain;
-use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem};
+use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Unsafety};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
+use rustc_target::spec::abi::Abi;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -95,24 +95,23 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             return;
         }
 
-        if_chain! {
-            // Check if item is a method, called to_string and has a parameter 'self'
-            if let ImplItemKind::Fn(ref signature, _) = impl_item.kind;
-            if impl_item.ident.name == sym::to_string;
-            let decl = &signature.decl;
-            if decl.implicit_self.has_implicit_self();
-            if decl.inputs.len() == 1;
-            if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }));
-
+        // Check if item is a method called `to_string` and has a parameter 'self'
+        if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
+            // #11201
+            && let header = signature.header
+            && header.unsafety == Unsafety::Normal
+            && header.abi == Abi::Rust
+            && impl_item.ident.name == sym::to_string
+            && let decl = signature.decl
+            && decl.implicit_self.has_implicit_self()
+            && decl.inputs.len() == 1
+            && impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
             // Check if return type is String
-            if is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String);
-
+            && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
             // Filters instances of to_string which are required by a trait
-            if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none();
-
-            then {
-                show_lint(cx, impl_item);
-            }
+            && trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none()
+        {
+            show_lint(cx, impl_item);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 50c433d3161..deba232bdd2 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -7,11 +7,10 @@ use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, DefIdSet};
-use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
     AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
-    ImplicitSelfKind, Item, ItemKind, Mutability, Node, PathSegment, PrimTy, QPath, TraitItemRef, TyKind,
-    TypeBindingKind,
+    ImplicitSelfKind, Item, ItemKind, LangItem, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef,
+    TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
@@ -171,6 +170,31 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             return;
         }
 
+        if let ExprKind::Let(lt) = expr.kind
+            && has_is_empty(cx, lt.init)
+            && match lt.pat.kind {
+                PatKind::Slice([], None, []) => true,
+                PatKind::Lit(lit) if is_empty_string(lit) => true,
+                _ => false,
+            }
+        {
+            let mut applicability = Applicability::MachineApplicable;
+
+            let lit1 = peel_ref_operators(cx, lt.init);
+            let lit_str =
+                Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par();
+
+            span_lint_and_sugg(
+                cx,
+                COMPARISON_TO_EMPTY,
+                lt.span,
+                "comparison to empty slice using `if let`",
+                "using `is_empty` is clearer and more explicit",
+                format!("{lit_str}.is_empty()"),
+                applicability,
+            );
+        }
+
         if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
             // expr.span might contains parenthesis, see issue #10529
             let actual_span = left.span.with_hi(right.span.hi());
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 5e62cfd70ec..9d6096ccb2a 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -65,6 +65,7 @@ mod declared_lints;
 mod renamed_lints;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
+mod absolute_paths;
 mod allow_attributes;
 mod almost_complete_range;
 mod approx_const;
@@ -120,6 +121,7 @@ mod entry;
 mod enum_clike;
 mod enum_variants;
 mod equatable_if_let;
+mod error_impl_error;
 mod escape;
 mod eta_reduction;
 mod excessive_bools;
@@ -136,6 +138,7 @@ mod format_args;
 mod format_impl;
 mod format_push_string;
 mod formatting;
+mod four_forward_slashes;
 mod from_over_into;
 mod from_raw_with_void_ptr;
 mod from_str_radix_10;
@@ -272,6 +275,7 @@ mod redundant_clone;
 mod redundant_closure_call;
 mod redundant_else;
 mod redundant_field_names;
+mod redundant_locals;
 mod redundant_pub_crate;
 mod redundant_slicing;
 mod redundant_static_lifetimes;
@@ -909,7 +913,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv())));
     store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison));
     store.register_early_pass(move || Box::new(module_style::ModStyle));
-    store.register_late_pass(|_| Box::new(unused_async::UnusedAsync));
+    store.register_late_pass(|_| Box::<unused_async::UnusedAsync>::default());
     let disallowed_types = conf.disallowed_types.clone();
     store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone())));
     let import_renames = conf.enforced_import_renames.clone();
@@ -1078,6 +1082,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| Box::new(visibility::Visibility));
     store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() }));
     store.register_late_pass(|_| Box::new(manual_float_methods::ManualFloatMethods));
+    store.register_late_pass(|_| Box::new(four_forward_slashes::FourForwardSlashes));
+    store.register_late_pass(|_| Box::new(error_impl_error::ErrorImplError));
+    let absolute_paths_max_segments = conf.absolute_paths_max_segments;
+    let absolute_paths_allowed_crates = conf.absolute_paths_allowed_crates.clone();
+    store.register_late_pass(move |_| {
+        Box::new(absolute_paths::AbsolutePaths {
+            absolute_paths_max_segments,
+            absolute_paths_allowed_crates: absolute_paths_allowed_crates.clone(),
+        })
+    });
+    store.register_late_pass(|_| Box::new(redundant_locals::RedundantLocals));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 852f6736585..0004a150d51 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -15,6 +15,7 @@ use rustc_hir::{
     PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
 };
 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::{declare_lint_pass, declare_tool_lint};
@@ -620,7 +621,7 @@ impl<'cx, 'tcx, F> Visitor<'tcx> for LifetimeChecker<'cx, 'tcx, F>
 where
     F: NestedFilter<'tcx>,
 {
-    type Map = rustc_middle::hir::map::Map<'tcx>;
+    type Map = Map<'tcx>;
     type NestedFilter = F;
 
     // for lifetimes as parameters of generics
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index a84a0a6eeb8..7b8c88235a9 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -109,7 +109,7 @@ fn is_ref_iterable<'tcx>(
         && let sig = cx.tcx.liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder())
         && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output
         && let param_env = cx.tcx.param_env(fn_id)
-        && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, [])
+        && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, &[])
         && let Some(into_iter_ty) =
             make_normalized_projection_with_regions(cx.tcx, param_env, trait_id, sym!(IntoIter), [req_self_ty])
         && let req_res_ty = normalize_with_regions(cx.tcx, param_env, req_res_ty)
diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
index 744fd61bd13..dfb800ccf71 100644
--- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
@@ -9,6 +9,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat};
 use rustc_lint::LateContext;
 use rustc_span::edition::Edition;
+use rustc_span::sym;
 
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
@@ -51,7 +52,7 @@ pub(super) fn check<'tcx>(
             },
             [],
             _,
-        ) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "),
+        ) if method.ident.name == sym::iter_mut => (arg, "&mut "),
         ExprKind::MethodCall(
             method,
             Expr {
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 28ee24309cc..6edca2d55f6 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -76,7 +76,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
                     ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => {
                         *state = IncrementVisitorVarState::DontWarn;
                     },
-                    ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
+                    ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => {
                         *state = IncrementVisitorVarState::DontWarn;
                     },
                     _ => (),
@@ -226,7 +226,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
                             InitializeVisitorState::DontWarn
                         }
                     },
-                    ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
+                    ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) => {
                         self.state = InitializeVisitorState::DontWarn;
                     },
                     _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index d1061171e4d..6d16d188754 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -16,6 +16,7 @@ mod match_wild_enum;
 mod match_wild_err_arm;
 mod needless_match;
 mod overlapping_arms;
+mod redundant_guards;
 mod redundant_pattern_match;
 mod rest_pat_in_fully_bound_struct;
 mod significant_drop_in_scrutinee;
@@ -936,6 +937,36 @@ declare_clippy_lint! {
     "reimplementation of `filter`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for unnecessary guards in match expressions.
+    ///
+    /// ### Why is this bad?
+    /// It's more complex and much less readable. Making it part of the pattern can improve
+    /// exhaustiveness checking as well.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// match x {
+    ///     Some(x) if matches!(x, Some(1)) => ..,
+    ///     Some(x) if x == Some(2) => ..,
+    ///     _ => todo!(),
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// match x {
+    ///     Some(Some(1)) => ..,
+    ///     Some(Some(2)) => ..,
+    ///     _ => todo!(),
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub REDUNDANT_GUARDS,
+    complexity,
+    "checks for unnecessary guards in match expressions"
+}
+
 #[derive(Default)]
 pub struct Matches {
     msrv: Msrv,
@@ -978,6 +1009,7 @@ impl_lint_pass!(Matches => [
     TRY_ERR,
     MANUAL_MAP,
     MANUAL_FILTER,
+    REDUNDANT_GUARDS,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Matches {
@@ -1025,6 +1057,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                     needless_match::check_match(cx, ex, arms, expr);
                     match_on_vec_items::check(cx, ex);
                     match_str_case_mismatch::check(cx, ex, arms);
+                    redundant_guards::check(cx, arms);
 
                     if !in_constant(cx, expr.hir_id) {
                         manual_unwrap_or::check(cx, expr, ex, arms);
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
new file mode 100644
index 00000000000..6383326aa38
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -0,0 +1,190 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::path_to_local;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::visitors::{for_each_expr, is_local_used};
+use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{Arm, BinOpKind, Expr, ExprKind, Guard, MatchSource, Node, Pat, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+use std::ops::ControlFlow;
+
+use super::REDUNDANT_GUARDS;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
+    for outer_arm in arms {
+        let Some(guard) = outer_arm.guard else {
+            continue;
+        };
+
+        // `Some(x) if matches!(x, y)`
+        if let Guard::If(if_expr) = guard
+            && let ExprKind::Match(
+                scrutinee,
+                [
+                    arm,
+                    Arm {
+                        pat: Pat {
+                            kind: PatKind::Wild,
+                            ..
+                        },
+                        ..
+                    },
+                ],
+                MatchSource::Normal,
+            ) = if_expr.kind
+        {
+            emit_redundant_guards(
+                cx,
+                outer_arm,
+                if_expr.span,
+                scrutinee,
+                arm.pat.span,
+                arm.guard,
+            );
+        }
+        // `Some(x) if let Some(2) = x`
+        else if let Guard::IfLet(let_expr) = guard {
+            emit_redundant_guards(
+                cx,
+                outer_arm,
+                let_expr.span,
+                let_expr.init,
+                let_expr.pat.span,
+                None,
+            );
+        }
+        // `Some(x) if x == Some(2)`
+        else if let Guard::If(if_expr) = guard
+            && let ExprKind::Binary(bin_op, local, pat) = if_expr.kind
+            && matches!(bin_op.node, BinOpKind::Eq)
+            && expr_can_be_pat(cx, pat)
+            // Ensure they have the same type. If they don't, we'd need deref coercion which isn't
+            // possible (currently) in a pattern. In some cases, you can use something like
+            // `as_deref` or similar but in general, we shouldn't lint this as it'd create an
+            // extraordinary amount of FPs.
+            //
+            // This isn't necessary in the other two checks, as they must be a pattern already.
+            && cx.typeck_results().expr_ty(local) == cx.typeck_results().expr_ty(pat)
+        {
+            emit_redundant_guards(
+                cx,
+                outer_arm,
+                if_expr.span,
+                local,
+                pat.span,
+                None,
+            );
+        }
+    }
+}
+
+fn get_pat_binding<'tcx>(cx: &LateContext<'tcx>, guard_expr: &Expr<'_>, outer_arm: &Arm<'tcx>) -> Option<(Span, bool)> {
+    if let Some(local) = path_to_local(guard_expr) && !is_local_used(cx, outer_arm.body, local) {
+        let mut span = None;
+        let mut multiple_bindings = false;
+        // `each_binding` gives the `HirId` of the `Pat` itself, not the binding
+        outer_arm.pat.walk(|pat| {
+            if let PatKind::Binding(_, hir_id, _, _) = pat.kind
+                && hir_id == local
+                && span.replace(pat.span).is_some()
+            {
+                multiple_bindings = true;
+                return false;
+            }
+
+            true
+        });
+
+        // Ignore bindings from or patterns, like `First(x) | Second(x, _) | Third(x, _, _)`
+        if !multiple_bindings {
+            return span.map(|span| {
+                (
+                    span,
+                    !matches!(cx.tcx.hir().get_parent(local), Node::PatField(_)),
+                )
+            });
+        }
+    }
+
+    None
+}
+
+fn emit_redundant_guards<'tcx>(
+    cx: &LateContext<'tcx>,
+    outer_arm: &Arm<'tcx>,
+    guard_span: Span,
+    local: &Expr<'_>,
+    pat_span: Span,
+    inner_guard: Option<Guard<'_>>,
+) {
+    let mut app = Applicability::MaybeIncorrect;
+    let Some((pat_binding, can_use_shorthand)) = get_pat_binding(cx, local, outer_arm) else {
+        return;
+    };
+
+    span_lint_and_then(
+        cx,
+        REDUNDANT_GUARDS,
+        guard_span.source_callsite(),
+        "redundant guard",
+        |diag| {
+            let binding_replacement = snippet_with_applicability(cx, pat_span, "<binding_repl>", &mut app);
+            diag.multipart_suggestion_verbose(
+                "try",
+                vec![
+                    if can_use_shorthand {
+                        (pat_binding, binding_replacement.into_owned())
+                    } else {
+                        (pat_binding.shrink_to_hi(), format!(": {binding_replacement}"))
+                    },
+                    (
+                        guard_span.source_callsite().with_lo(outer_arm.pat.span.hi()),
+                        inner_guard.map_or_else(String::new, |guard| {
+                            let (prefix, span) = match guard {
+                                Guard::If(e) => ("if", e.span),
+                                Guard::IfLet(l) => ("if let", l.span),
+                            };
+
+                            format!(
+                                " {prefix} {}",
+                                snippet_with_applicability(cx, span, "<guard>", &mut app),
+                            )
+                        }),
+                    ),
+                ],
+                app,
+            );
+        },
+    );
+}
+
+/// Checks if the given `Expr` can also be represented as a `Pat`.
+fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    for_each_expr(expr, |expr| {
+        if match expr.kind {
+            ExprKind::ConstBlock(..) => cx.tcx.features().inline_const_pat,
+            ExprKind::Call(c, ..) if let ExprKind::Path(qpath) = c.kind => {
+                // Allow ctors
+                matches!(cx.qpath_res(&qpath, c.hir_id), Res::Def(DefKind::Ctor(..), ..))
+            },
+            ExprKind::Path(qpath) => {
+                matches!(
+                    cx.qpath_res(&qpath, expr.hir_id),
+                    Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Ctor(..), ..),
+                )
+            },
+            ExprKind::AddrOf(..)
+            | ExprKind::Array(..)
+            | ExprKind::Tup(..)
+            | ExprKind::Struct(..)
+            | ExprKind::Lit(..) => true,
+            _ => false,
+        } {
+            return ControlFlow::Continue(());
+        }
+
+        ControlFlow::Break(())
+    })
+    .is_none()
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index ad38f1394b4..9a7c00823b6 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -3,17 +3,19 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, walk_span_to_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
-use clippy_utils::visitors::any_temporaries_need_ordered_drop;
+use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr};
 use clippy_utils::{higher, is_expn_of, is_trait_method};
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
-use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp};
+use rustc_hir::{Arm, Expr, ExprKind, Guard, Node, Pat, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_span::{sym, Symbol};
+use std::fmt::Write;
+use std::ops::ControlFlow;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
@@ -201,30 +203,58 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
     if arms.len() == 2 {
         let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
 
-        if let Some(good_method) = found_good_method(cx, arms, node_pair) {
+        if let Some((good_method, maybe_guard)) = found_good_method(cx, arms, node_pair) {
             let span = is_expn_of(expr.span, "matches").unwrap_or(expr.span.to(op.span));
             let result_expr = match &op.kind {
                 ExprKind::AddrOf(_, _, borrowed) => borrowed,
                 _ => op,
             };
+            let mut sugg = format!("{}.{good_method}", snippet(cx, result_expr.span, "_"));
+
+            if let Some(guard) = maybe_guard {
+                let Guard::If(guard) = *guard else { return }; // `...is_none() && let ...` is a syntax error
+
+                // wow, the HIR for match guards in `PAT if let PAT = expr && expr => ...` is annoying!
+                // `guard` here is `Guard::If` with the let expression somewhere deep in the tree of exprs,
+                // counter to the intuition that it should be `Guard::IfLet`, so we need another check
+                // to see that there aren't any let chains anywhere in the guard, as that would break
+                // if we suggest `t.is_none() && (let X = y && z)` for:
+                // `match t { None if let X = y && z => true, _ => false }`
+                let has_nested_let_chain = for_each_expr(guard, |expr| {
+                    if matches!(expr.kind, ExprKind::Let(..)) {
+                        ControlFlow::Break(())
+                    } else {
+                        ControlFlow::Continue(())
+                    }
+                })
+                .is_some();
+
+                if has_nested_let_chain {
+                    return;
+                }
+
+                let guard = Sugg::hir(cx, guard, "..");
+                let _ = write!(sugg, " && {}", guard.maybe_par());
+            }
+
             span_lint_and_sugg(
                 cx,
                 REDUNDANT_PATTERN_MATCHING,
                 span,
                 &format!("redundant pattern matching, consider using `{good_method}`"),
                 "try",
-                format!("{}.{good_method}", snippet(cx, result_expr.span, "_")),
+                sugg,
                 Applicability::MachineApplicable,
             );
         }
     }
 }
 
-fn found_good_method<'a>(
+fn found_good_method<'tcx>(
     cx: &LateContext<'_>,
-    arms: &[Arm<'_>],
+    arms: &'tcx [Arm<'tcx>],
     node: (&PatKind<'_>, &PatKind<'_>),
-) -> Option<&'a str> {
+) -> Option<(&'static str, Option<&'tcx Guard<'tcx>>)> {
     match node {
         (
             PatKind::TupleStruct(ref path_left, patterns_left, _),
@@ -310,7 +340,11 @@ fn get_ident(path: &QPath<'_>) -> Option<rustc_span::symbol::Ident> {
     }
 }
 
-fn get_good_method<'a>(cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath<'_>) -> Option<&'a str> {
+fn get_good_method<'tcx>(
+    cx: &LateContext<'_>,
+    arms: &'tcx [Arm<'tcx>],
+    path_left: &QPath<'_>,
+) -> Option<(&'static str, Option<&'tcx Guard<'tcx>>)> {
     if let Some(name) = get_ident(path_left) {
         return match name.as_str() {
             "Ok" => {
@@ -376,16 +410,16 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte
 }
 
 #[expect(clippy::too_many_arguments)]
-fn find_good_method_for_match<'a>(
+fn find_good_method_for_match<'a, 'tcx>(
     cx: &LateContext<'_>,
-    arms: &[Arm<'_>],
+    arms: &'tcx [Arm<'tcx>],
     path_left: &QPath<'_>,
     path_right: &QPath<'_>,
     expected_item_left: Item,
     expected_item_right: Item,
     should_be_left: &'a str,
     should_be_right: &'a str,
-) -> Option<&'a str> {
+) -> Option<(&'a str, Option<&'tcx Guard<'tcx>>)> {
     let first_pat = arms[0].pat;
     let second_pat = arms[1].pat;
 
@@ -403,22 +437,22 @@ fn find_good_method_for_match<'a>(
 
     match body_node_pair {
         (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) {
-            (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
-            (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+            (LitKind::Bool(true), LitKind::Bool(false)) => Some((should_be_left, arms[0].guard.as_ref())),
+            (LitKind::Bool(false), LitKind::Bool(true)) => Some((should_be_right, arms[1].guard.as_ref())),
             _ => None,
         },
         _ => None,
     }
 }
 
-fn find_good_method_for_matches_macro<'a>(
+fn find_good_method_for_matches_macro<'a, 'tcx>(
     cx: &LateContext<'_>,
-    arms: &[Arm<'_>],
+    arms: &'tcx [Arm<'tcx>],
     path_left: &QPath<'_>,
     expected_item_left: Item,
     should_be_left: &'a str,
     should_be_right: &'a str,
-) -> Option<&'a str> {
+) -> Option<(&'a str, Option<&'tcx Guard<'tcx>>)> {
     let first_pat = arms[0].pat;
 
     let body_node_pair = if is_pat_variant(cx, first_pat, path_left, expected_item_left) {
@@ -429,8 +463,8 @@ fn find_good_method_for_matches_macro<'a>(
 
     match body_node_pair {
         (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) {
-            (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
-            (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+            (LitKind::Bool(true), LitKind::Bool(false)) => Some((should_be_left, arms[0].guard.as_ref())),
+            (LitKind::Bool(false), LitKind::Bool(true)) => Some((should_be_right, arms[1].guard.as_ref())),
             _ => None,
         },
         _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index 597a423b537..c9eaa185acc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -1,7 +1,9 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::macros::{is_panic, root_macro_call};
 use clippy_utils::source::{indent_of, reindent_multiline, snippet};
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_trait_method, path_to_local_id, peel_blocks, SpanlessEq};
+use clippy_utils::{higher, is_trait_method, path_to_local_id, peel_blocks, SpanlessEq};
+use hir::{Body, HirId, MatchSource, Pat};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -10,7 +12,7 @@ use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_span::source_map::Span;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use std::borrow::Cow;
 
 use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP};
@@ -48,6 +50,214 @@ fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &hir::Expr<'_>, map_ar
     is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
 }
 
+#[derive(Debug, Copy, Clone)]
+enum OffendingFilterExpr<'tcx> {
+    /// `.filter(|opt| opt.is_some())`
+    IsSome {
+        /// The receiver expression
+        receiver: &'tcx Expr<'tcx>,
+        /// If `Some`, then this contains the span of an expression that possibly contains side
+        /// effects: `.filter(|opt| side_effect(opt).is_some())`
+        ///                         ^^^^^^^^^^^^^^^^
+        ///
+        /// We will use this later for warning the user that the suggested fix may change
+        /// the behavior.
+        side_effect_expr_span: Option<Span>,
+    },
+    /// `.filter(|res| res.is_ok())`
+    IsOk {
+        /// The receiver expression
+        receiver: &'tcx Expr<'tcx>,
+        /// See `IsSome`
+        side_effect_expr_span: Option<Span>,
+    },
+    /// `.filter(|enum| matches!(enum, Enum::A(_)))`
+    Matches {
+        /// The DefId of the variant being matched
+        variant_def_id: hir::def_id::DefId,
+    },
+}
+
+#[derive(Debug)]
+enum CalledMethod {
+    OptionIsSome,
+    ResultIsOk,
+}
+
+/// The result of checking a `map` call, returned by `OffendingFilterExpr::check_map_call`
+#[derive(Debug)]
+enum CheckResult<'tcx> {
+    Method {
+        map_arg: &'tcx Expr<'tcx>,
+        /// The method that was called inside of `filter`
+        method: CalledMethod,
+        /// See `OffendingFilterExpr::IsSome`
+        side_effect_expr_span: Option<Span>,
+    },
+    PatternMatching {
+        /// The span of the variant being matched
+        /// if let Some(s) = enum
+        ///        ^^^^^^^
+        variant_span: Span,
+        /// if let Some(s) = enum
+        ///             ^
+        variant_ident: Ident,
+    },
+}
+
+impl<'tcx> OffendingFilterExpr<'tcx> {
+    pub fn check_map_call(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        map_body: &'tcx Body<'tcx>,
+        map_param_id: HirId,
+        filter_param_id: HirId,
+        is_filter_param_ref: bool,
+    ) -> Option<CheckResult<'tcx>> {
+        match *self {
+            OffendingFilterExpr::IsSome {
+                receiver,
+                side_effect_expr_span,
+            }
+            | OffendingFilterExpr::IsOk {
+                receiver,
+                side_effect_expr_span,
+            } => {
+                // check if closure ends with expect() or unwrap()
+                if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind
+                    && matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or)
+                    // .map(|y| f(y).copied().unwrap())
+                    //          ~~~~
+                    && let map_arg_peeled = match map_arg.kind {
+                        ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
+                            original_arg
+                        },
+                        _ => map_arg,
+                    }
+                    // .map(|y| y[.acceptable_method()].unwrap())
+                    && let simple_equal = (path_to_local_id(receiver, filter_param_id)
+                        && path_to_local_id(map_arg_peeled, map_param_id))
+                    && let eq_fallback = (|a: &Expr<'_>, b: &Expr<'_>| {
+                        // in `filter(|x| ..)`, replace `*x` with `x`
+                        let a_path = if_chain! {
+                            if !is_filter_param_ref;
+                            if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
+                            then { expr_path } else { a }
+                        };
+                        // let the filter closure arg and the map closure arg be equal
+                        path_to_local_id(a_path, filter_param_id)
+                            && path_to_local_id(b, map_param_id)
+                            && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
+                    })
+                    && (simple_equal
+                        || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(receiver, map_arg_peeled))
+                {
+                    Some(CheckResult::Method {
+                        map_arg,
+                        side_effect_expr_span,
+                        method: match self {
+                            OffendingFilterExpr::IsSome { .. } => CalledMethod::OptionIsSome,
+                            OffendingFilterExpr::IsOk { .. } => CalledMethod::ResultIsOk,
+                            OffendingFilterExpr::Matches { .. } => unreachable!("only IsSome and IsOk can get here"),
+                        }
+                    })
+                } else {
+                    None
+                }
+            },
+            OffendingFilterExpr::Matches { variant_def_id } => {
+                let expr_uses_local = |pat: &Pat<'_>, expr: &Expr<'_>| {
+                    if let PatKind::TupleStruct(QPath::Resolved(_, path), [subpat], _) = pat.kind
+                        && let PatKind::Binding(_, local_id, ident, _) = subpat.kind
+                        && path_to_local_id(expr.peel_blocks(), local_id)
+                        && let Some(local_variant_def_id) = path.res.opt_def_id()
+                        && local_variant_def_id == variant_def_id
+                    {
+                        Some((ident, pat.span))
+                    } else {
+                        None
+                    }
+                };
+
+                // look for:
+                // `if let Variant   (v) =         enum { v } else { unreachable!() }`
+                //         ^^^^^^^    ^            ^^^^            ^^^^^^^^^^^^^^^^^^
+                //    variant_span  variant_ident  scrutinee       else_ (blocks peeled later)
+                // OR
+                // `match enum {   Variant       (v) => v,      _ => unreachable!() }`
+                //        ^^^^     ^^^^^^^        ^                  ^^^^^^^^^^^^^^
+                //     scrutinee  variant_span  variant_ident        else_
+                let (scrutinee, else_, variant_ident, variant_span) =
+                    match higher::IfLetOrMatch::parse(cx, map_body.value) {
+                        // For `if let` we want to check that the variant matching arm references the local created by its pattern
+                        Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_)))
+                            if let Some((ident, span)) = expr_uses_local(pat, then) =>
+                        {
+                            (sc, else_, ident, span)
+                        },
+                        // For `match` we want to check that the "else" arm is the wildcard (`_`) pattern
+                        // and that the variant matching arm references the local created by its pattern
+                        Some(higher::IfLetOrMatch::Match(sc, [arm, wild_arm], MatchSource::Normal))
+                            if let PatKind::Wild = wild_arm.pat.kind
+                                && let Some((ident, span)) = expr_uses_local(arm.pat, arm.body.peel_blocks()) =>
+                        {
+                            (sc, wild_arm.body, ident, span)
+                        },
+                        _ => return None,
+                    };
+
+                if path_to_local_id(scrutinee, map_param_id)
+                    // else branch should be a `panic!` or `unreachable!` macro call
+                    && let Some(mac) = root_macro_call(else_.peel_blocks().span)
+                    && (is_panic(cx, mac.def_id) || cx.tcx.opt_item_name(mac.def_id) == Some(sym::unreachable))
+                {
+                    Some(CheckResult::PatternMatching { variant_span, variant_ident })
+                } else {
+                    None
+                }
+            },
+        }
+    }
+
+    fn hir(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, filter_param_id: HirId) -> Option<Self> {
+        if let ExprKind::MethodCall(path, receiver, [], _) = expr.kind
+            && let Some(recv_ty) = cx.typeck_results().expr_ty(receiver).peel_refs().ty_adt_def()
+        {
+            // we still want to lint if the expression possibly contains side effects,
+            // *but* it can't be machine-applicable then, because that can change the behavior of the program:
+            // .filter(|x| effect(x).is_some()).map(|x| effect(x).unwrap())
+            // vs.
+            // .filter_map(|x| effect(x))
+            // 
+            // the latter only calls `effect` once
+            let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span);
+
+            if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did())
+                && path.ident.name == sym!(is_some)
+            {
+                Some(Self::IsSome { receiver, side_effect_expr_span })
+            } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did())
+                && path.ident.name == sym!(is_ok)
+            {
+                Some(Self::IsOk { receiver, side_effect_expr_span })
+            } else {
+                None
+            }
+        } else if let Some(macro_call) = root_macro_call(expr.span)
+            && cx.tcx.get_diagnostic_name(macro_call.def_id) == Some(sym::matches_macro)
+            // we know for a fact that the wildcard pattern is the second arm
+            && let ExprKind::Match(scrutinee, [arm, _], _) = expr.kind
+            && path_to_local_id(scrutinee, filter_param_id)
+            && let PatKind::TupleStruct(QPath::Resolved(_, path), ..) = arm.pat.kind
+            && let Some(variant_def_id) = path.res.opt_def_id()
+        {
+            Some(OffendingFilterExpr::Matches { variant_def_id })
+        } else {
+            None
+        }
+    }
+}
+
 /// is `filter(|x| x.is_some()).map(|x| x.unwrap())`
 fn is_filter_some_map_unwrap(
     cx: &LateContext<'_>,
@@ -102,55 +312,18 @@ pub(super) fn check(
         } else {
             (filter_param.pat, false)
         };
-        // closure ends with is_some() or is_ok()
+
         if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
-        if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
-        if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
-        if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
-            Some(false)
-        } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) {
-            Some(true)
-        } else {
-            None
-        };
-        if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
+        if let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id);
 
-        // ...map(|x| ...unwrap())
         if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind;
         let map_body = cx.tcx.hir().body(map_body_id);
         if let [map_param] = map_body.params;
         if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
-        // closure ends with expect() or unwrap()
-        if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
-        if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
-
-        // .filter(..).map(|y| f(y).copied().unwrap())
-        //                     ~~~~
-        let map_arg_peeled = match map_arg.kind {
-            ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
-                original_arg
-            },
-            _ => map_arg,
-        };
 
-        // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap())
-        let simple_equal = path_to_local_id(filter_arg, filter_param_id)
-            && path_to_local_id(map_arg_peeled, map_param_id);
+        if let Some(check_result) =
+            offending_expr.check_map_call(cx, map_body, map_param_id, filter_param_id, is_filter_param_ref);
 
-        let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
-            // in `filter(|x| ..)`, replace `*x` with `x`
-            let a_path = if_chain! {
-                if !is_filter_param_ref;
-                if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
-                then { expr_path } else { a }
-            };
-            // let the filter closure arg and the map closure arg be equal
-            path_to_local_id(a_path, filter_param_id)
-                && path_to_local_id(b, map_param_id)
-                && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
-        };
-
-        if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled);
         then {
             let span = filter_span.with_hi(expr.span.hi());
             let (filter_name, lint) = if is_find {
@@ -159,22 +332,53 @@ pub(super) fn check(
                 ("filter", MANUAL_FILTER_MAP)
             };
             let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`");
-            let (to_opt, deref) = if is_result {
-                (".ok()", String::new())
-            } else {
-                let derefs = cx.typeck_results()
-                    .expr_adjustments(map_arg)
-                    .iter()
-                    .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
-                    .count();
 
-                ("", "*".repeat(derefs))
+            let (sugg, note_and_span, applicability) = match check_result {
+                CheckResult::Method { map_arg, method, side_effect_expr_span } => {
+                    let (to_opt, deref) = match method {
+                        CalledMethod::ResultIsOk => (".ok()", String::new()),
+                        CalledMethod::OptionIsSome => {
+                            let derefs = cx.typeck_results()
+                                .expr_adjustments(map_arg)
+                                .iter()
+                                .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
+                                .count();
+
+                            ("", "*".repeat(derefs))
+                        }
+                    };
+
+                    let sugg = format!(
+                        "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
+                        snippet(cx, map_arg.span, ".."),
+                    );
+                    let (note_and_span, applicability) = if let Some(span) = side_effect_expr_span {
+                        let note = "the suggestion might change the behavior of the program when merging `filter` and `map`, \
+                            because this expression potentially contains side effects and will only execute once";
+
+                        (Some((note, span)), Applicability::MaybeIncorrect)
+                    } else {
+                        (None, Applicability::MachineApplicable)
+                    };
+
+                    (sugg, note_and_span, applicability)
+                }
+                CheckResult::PatternMatching { variant_span, variant_ident } => {
+                    let pat = snippet(cx, variant_span, "<pattern>");
+
+                    (format!("{filter_name}_map(|{map_param_ident}| match {map_param_ident} {{ \
+                        {pat} => Some({variant_ident}), \
+                        _ => None \
+                    }})"), None, Applicability::MachineApplicable)
+                }
             };
-            let sugg = format!(
-                "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
-                snippet(cx, map_arg.span, ".."),
-            );
-            span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
+            span_lint_and_then(cx, lint, span, &msg, |diag| {
+                diag.span_suggestion(span, "try", sugg, applicability);
+
+                if let Some((note, span)) = note_and_span {
+                    diag.span_note(span, note);
+                }
+            });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
new file mode 100644
index 00000000000..4aee22a4afc
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
@@ -0,0 +1,45 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::paths::BOOL_THEN;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::is_copy;
+use clippy_utils::{is_from_proc_macro, is_trait_method, match_def_path, 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_span::{sym, Span};
+
+use super::FILTER_MAP_BOOL_THEN;
+
+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)
+        && is_trait_method(cx, expr, sym::Iterator)
+        && let ExprKind::Closure(closure) = arg.kind
+        && let body = cx.tcx.hir().body(closure.body)
+        && let value = peel_blocks(body.value)
+        // Indexing should be fine as `filter_map` always has 1 input, we unfortunately need both
+        // `inputs` and `params` here as we need both the type and the span
+        && let param_ty = closure.fn_decl.inputs[0]
+        && let param = body.params[0]
+        && is_copy(cx, cx.typeck_results().node_type(param_ty.hir_id).peel_refs())
+        && let ExprKind::MethodCall(_, recv, [then_arg], _) = value.kind
+        && let ExprKind::Closure(then_closure) = then_arg.kind
+        && let then_body = peel_blocks(cx.tcx.hir().body(then_closure.body).value)
+        && let Some(def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id)
+        && match_def_path(cx, def_id, &BOOL_THEN)
+        && !is_from_proc_macro(cx, expr)
+        && let Some(param_snippet) = snippet_opt(cx, param.span)
+        && let Some(filter) = snippet_opt(cx, recv.span)
+        && let Some(map) = snippet_opt(cx, then_body.span)
+    {
+        span_lint_and_sugg(
+            cx,
+            FILTER_MAP_BOOL_THEN,
+            call_span,
+            "usage of `bool::then` in `filter_map`",
+            "use `filter` then `map` instead",
+            format!("filter(|&{param_snippet}| {filter}).map(|{param_snippet}| {map})"),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
new file mode 100644
index 00000000000..1f8863f8521
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
@@ -0,0 +1,33 @@
+use super::FORMAT_COLLECT;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::{is_format_macro, root_macro_call_first_node};
+use clippy_utils::ty::is_type_lang_item;
+use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_lint::LateContext;
+use rustc_span::Span;
+
+/// Same as `peel_blocks` but only actually considers blocks that are not from an expansion.
+/// This is needed because always calling `peel_blocks` would otherwise remove parts of the
+/// `format!` macro, which would cause `root_macro_call_first_node` to return `None`.
+fn peel_non_expn_blocks<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+    match expr.kind {
+        ExprKind::Block(block, _) if !expr.span.from_expansion() => peel_non_expn_blocks(block.expr?),
+        _ => Some(expr),
+    }
+}
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, map_arg: &Expr<'_>, map_span: Span) {
+    if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String)
+        && let ExprKind::Closure(closure) = map_arg.kind
+        && let body = cx.tcx.hir().body(closure.body)
+        && let Some(value) = peel_non_expn_blocks(body.value)
+        && let Some(mac) = root_macro_call_first_node(cx, value)
+        && is_format_macro(cx, mac.def_id)
+    {
+        span_lint_and_then(cx, FORMAT_COLLECT, expr.span, "use of `format!` to build up a string from an iterator", |diag| {
+            diag.span_help(map_span, "call `fold` instead")
+                .span_help(value.span.source_callsite(), "... and use the `write!` macro here")
+                .note("this can be written more efficiently by appending to a `String` directly");
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
new file mode 100644
index 00000000000..6b696b42a69
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_zero.rs
@@ -0,0 +1,34 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::{is_from_proc_macro, is_trait_method};
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::ITER_SKIP_ZERO;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg_expr: &Expr<'_>) {
+    if !expr.span.from_expansion()
+        && is_trait_method(cx, expr, sym::Iterator)
+        && let Some(arg) = constant(cx, cx.typeck_results(), arg_expr).and_then(|constant| {
+            if let Constant::Int(arg) = constant {
+                Some(arg)
+            } else {
+                None
+            }
+        })
+        && arg == 0
+        && !is_from_proc_macro(cx, expr)
+    {
+        span_lint_and_then(cx, ITER_SKIP_ZERO, arg_expr.span, "usage of `.skip(0)`", |diag| {
+            diag.span_suggestion(
+                arg_expr.span,
+                "if you meant to skip the first element, use",
+                "1",
+                Applicability::MaybeIncorrect,
+            )
+            .note("this call to `skip` does nothing and is useless; remove it");
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 123ab520e48..dd694ce7393 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -21,11 +21,13 @@ mod expect_used;
 mod extend_with_drain;
 mod filetype_is_file;
 mod filter_map;
+mod filter_map_bool_then;
 mod filter_map_identity;
 mod filter_map_next;
 mod filter_next;
 mod flat_map_identity;
 mod flat_map_option;
+mod format_collect;
 mod from_iter_instead_of_collect;
 mod get_first;
 mod get_last_with_len;
@@ -44,6 +46,7 @@ mod iter_nth_zero;
 mod iter_on_single_or_empty_collections;
 mod iter_overeager_cloned;
 mod iter_skip_next;
+mod iter_skip_zero;
 mod iter_with_drain;
 mod iterator_step_by_zero;
 mod manual_next_back;
@@ -73,6 +76,7 @@ mod or_then_unwrap;
 mod path_buf_push_overwrite;
 mod range_zip_with_len;
 mod read_line_without_trim;
+mod readonly_write_lock;
 mod repeat_once;
 mod search_is_some;
 mod seek_from_current;
@@ -85,6 +89,7 @@ mod skip_while_next;
 mod stable_sort_primitive;
 mod str_splitn;
 mod string_extend_chars;
+mod string_lit_chars_any;
 mod suspicious_command_arg_space;
 mod suspicious_map;
 mod suspicious_splitn;
@@ -100,7 +105,6 @@ mod unnecessary_lazy_eval;
 mod unnecessary_literal_unwrap;
 mod unnecessary_sort_by;
 mod unnecessary_to_owned;
-mod unwrap_or_else_default;
 mod unwrap_used;
 mod useless_asref;
 mod utils;
@@ -114,7 +118,7 @@ use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, return_ty};
+use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_hir::{Expr, ExprKind, Node, Stmt, StmtKind, TraitItem, TraitItemKind};
@@ -473,29 +477,40 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of `_.unwrap_or_else(Default::default)` on `Option` and
-    /// `Result` values.
+    /// Checks for usages of the following functions with an argument that constructs a default value
+    /// (e.g., `Default::default` or `String::new`):
+    /// - `unwrap_or`
+    /// - `unwrap_or_else`
+    /// - `or_insert`
+    /// - `or_insert_with`
     ///
     /// ### Why is this bad?
-    /// Readability, these can be written as `_.unwrap_or_default`, which is
-    /// simpler and more concise.
+    /// Readability. Using `unwrap_or_default` in place of `unwrap_or`/`unwrap_or_else`, or `or_default`
+    /// in place of `or_insert`/`or_insert_with`, is simpler and more concise.
+    ///
+    /// ### Known problems
+    /// In some cases, the argument of `unwrap_or`, etc. is needed for type inference. The lint uses a
+    /// heuristic to try to identify such cases. However, the heuristic can produce false negatives.
     ///
     /// ### Examples
     /// ```rust
     /// # let x = Some(1);
-    /// x.unwrap_or_else(Default::default);
-    /// x.unwrap_or_else(u32::default);
+    /// # let mut map = std::collections::HashMap::<u64, String>::new();
+    /// x.unwrap_or(Default::default());
+    /// map.entry(42).or_insert_with(String::new);
     /// ```
     ///
     /// Use instead:
     /// ```rust
     /// # let x = Some(1);
+    /// # let mut map = std::collections::HashMap::<u64, String>::new();
     /// x.unwrap_or_default();
+    /// map.entry(42).or_default();
     /// ```
     #[clippy::version = "1.56.0"]
-    pub UNWRAP_OR_ELSE_DEFAULT,
+    pub UNWRAP_OR_DEFAULT,
     style,
-    "using `.unwrap_or_else(Default::default)`, which is more succinctly expressed as `.unwrap_or_default()`"
+    "using `.unwrap_or`, etc. with an argument that constructs a default value"
 }
 
 declare_clippy_lint! {
@@ -3378,6 +3393,152 @@ declare_clippy_lint! {
     "calling `Stdin::read_line`, then trying to parse it without first trimming"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `<string_lit>.chars().any(|i| i == c)`.
+    ///
+    /// ### Why is this bad?
+    /// It's significantly slower than using a pattern instead, like
+    /// `matches!(c, '\\' | '.' | '+')`.
+    ///
+    /// Despite this being faster, this is not `perf` as this is pretty common, and is a rather nice
+    /// way to check if a `char` is any in a set. In any case, this `restriction` lint is available
+    /// for situations where that additional performance is absolutely necessary.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let c = 'c';
+    /// "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # let c = 'c';
+    /// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub STRING_LIT_CHARS_ANY,
+    restriction,
+    "checks for `<string_lit>.chars().any(|i| i == c)`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `.map(|_| format!(..)).collect::<String>()`.
+    ///
+    /// ### Why is this bad?
+    /// This allocates a new string for every element in the iterator.
+    /// This can be done more efficiently by creating the `String` once and appending to it in `Iterator::fold`,
+    /// using either the `write!` macro which supports exactly the same syntax as the `format!` macro,
+    /// or concatenating with `+` in case the iterator yields `&str`/`String`.
+    ///
+    /// Note also that `write!`-ing into a `String` can never fail, despite the return type of `write!` being `std::fmt::Result`,
+    /// so it can be safely ignored or unwrapped.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn hex_encode(bytes: &[u8]) -> String {
+    ///     bytes.iter().map(|b| format!("{b:02X}")).collect()
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::fmt::Write;
+    /// fn hex_encode(bytes: &[u8]) -> String {
+    ///     bytes.iter().fold(String::new(), |mut output, b| {
+    ///         let _ = write!(output, "{b:02X}");
+    ///         output
+    ///     })
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub FORMAT_COLLECT,
+    perf,
+    "`format!`ing every element in a collection, then collecting the strings into a new `String`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `.skip(0)` on iterators.
+    ///
+    /// ### Why is this bad?
+    /// This was likely intended to be `.skip(1)` to skip the first element, as `.skip(0)` does
+    /// nothing. If not, the call should be removed.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let v = vec![1, 2, 3];
+    /// let x = v.iter().skip(0).collect::<Vec<_>>();
+    /// let y = v.iter().collect::<Vec<_>>();
+    /// assert_eq!(x, y);
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub ITER_SKIP_ZERO,
+    correctness,
+    "disallows `.skip(0)`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `bool::then` in `Iterator::filter_map`.
+    ///
+    /// ### Why is this bad?
+    /// This can be written with `filter` then `map` instead, which would reduce nesting and
+    /// separates the filtering from the transformation phase. This comes with no cost to
+    /// performance and is just cleaner.
+    ///
+    /// ### Limitations
+    /// Does not lint `bool::then_some`, as it eagerly evaluates its arguments rather than lazily.
+    /// This can create differing behavior, so better safe than sorry.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # fn really_expensive_fn(i: i32) -> i32 { i }
+    /// # let v = vec![];
+    /// _ = v.into_iter().filter_map(|i| (i % 2 == 0).then(|| really_expensive_fn(i)));
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # fn really_expensive_fn(i: i32) -> i32 { i }
+    /// # let v = vec![];
+    /// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i));
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub FILTER_MAP_BOOL_THEN,
+    style,
+    "checks for usage of `bool::then` in `Iterator::filter_map`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Looks for calls to `RwLock::write` where the lock is only used for reading.
+    ///
+    /// ### Why is this bad?
+    /// The write portion of `RwLock` is exclusive, meaning that no other thread
+    /// can access the lock while this writer is active.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::sync::RwLock;
+    /// fn assert_is_zero(lock: &RwLock<i32>) {
+    ///     let num = lock.write().unwrap();
+    ///     assert_eq!(*num, 0);
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// use std::sync::RwLock;
+    /// fn assert_is_zero(lock: &RwLock<i32>) {
+    ///     let num = lock.read().unwrap();
+    ///     assert_eq!(*num, 0);
+    /// }
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub READONLY_WRITE_LOCK,
+    nursery,
+    "acquiring a write lock when a read lock would work"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -3408,7 +3569,7 @@ impl_lint_pass!(Methods => [
     SHOULD_IMPLEMENT_TRAIT,
     WRONG_SELF_CONVENTION,
     OK_EXPECT,
-    UNWRAP_OR_ELSE_DEFAULT,
+    UNWRAP_OR_DEFAULT,
     MAP_UNWRAP_OR,
     RESULT_MAP_OR_INTO_OPTION,
     OPTION_MAP_OR_NONE,
@@ -3512,6 +3673,11 @@ impl_lint_pass!(Methods => [
     UNNECESSARY_LITERAL_UNWRAP,
     DRAIN_COLLECT,
     MANUAL_TRY_FOLD,
+    FORMAT_COLLECT,
+    STRING_LIT_CHARS_ANY,
+    ITER_SKIP_ZERO,
+    FILTER_MAP_BOOL_THEN,
+    READONLY_WRITE_LOCK
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -3666,8 +3832,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             then {
                 let first_arg_span = first_arg_ty.span;
                 let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
-                let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
-                    .self_ty();
+                let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
                 wrong_self_convention::check(
                     cx,
                     item.ident.name.as_str(),
@@ -3684,8 +3849,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             if item.ident.name == sym::new;
             if let TraitItemKind::Fn(_, _) = item.kind;
             let ret_ty = return_ty(cx, item.owner_id);
-            let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
-                .self_ty();
+            let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()).self_ty();
             if !ret_ty.contains(self_ty);
 
             then {
@@ -3733,8 +3897,9 @@ impl Methods {
                         Some((name @ ("cloned" | "copied"), recv2, [], _, _)) => {
                             iter_cloned_collect::check(cx, name, expr, recv2);
                         },
-                        Some(("map", m_recv, [m_arg], _, _)) => {
+                        Some(("map", m_recv, [m_arg], m_ident_span, _)) => {
                             map_collect_result_unit::check(cx, expr, m_recv, m_arg);
+                            format_collect::check(cx, expr, m_arg, m_ident_span);
                         },
                         Some(("take", take_self_arg, [take_arg], _, _)) => {
                             if self.msrv.meets(msrvs::STR_REPEAT) {
@@ -3790,6 +3955,7 @@ impl Methods {
                 },
                 ("filter_map", [arg]) => {
                     unnecessary_filter_map::check(cx, expr, arg, name);
+                    filter_map_bool_then::check(cx, expr, arg, call_span);
                     filter_map_identity::check(cx, expr, arg, span);
                 },
                 ("find_map", [arg]) => {
@@ -3833,7 +3999,16 @@ impl Methods {
                         unnecessary_join::check(cx, expr, recv, join_arg, span);
                     }
                 },
-                ("last", []) | ("skip", [_]) => {
+                ("skip", [arg]) => {
+                    iter_skip_zero::check(cx, expr, arg);
+
+                    if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
+                        if let ("cloned", []) = (name2, args2) {
+                            iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
+                        }
+                    }
+                }
+                ("last", []) => {
                     if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
                         if let ("cloned", []) = (name2, args2) {
                             iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
@@ -3885,6 +4060,13 @@ impl Methods {
                         }
                     }
                 },
+                ("any", [arg]) if let ExprKind::Closure(arg) = arg.kind
+                    && let body = cx.tcx.hir().body(arg.body)
+                    && let [param] = body.params
+                    && let Some(("chars", recv, _, _, _)) = method_call(recv) =>
+                {
+                    string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
+                }
                 ("nth", [n_arg]) => match method_call(recv) {
                     Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
                     Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
@@ -4027,7 +4209,6 @@ impl Methods {
                         Some(("map", recv, [map_arg], _, _))
                             if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {},
                         _ => {
-                            unwrap_or_else_default::check(cx, expr, recv, u_arg);
                             unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
                         },
                     }
@@ -4040,6 +4221,9 @@ impl Methods {
                         range_zip_with_len::check(cx, expr, iter_recv, arg);
                     }
                 },
+                ("write", []) => {
+                    readonly_write_lock::check(cx, expr, recv);
+                }
                 _ => {},
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 9165c1248f0..8b2f57160af 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -1,16 +1,17 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::eager_or_lazy::switch_to_lazy_eval;
 use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{contains_return, is_trait_item, last_path_segment};
+use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item};
+use clippy_utils::{contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
 use rustc_lint::LateContext;
+use rustc_middle::ty;
 use rustc_span::source_map::Span;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::symbol::{self, sym, Symbol};
+use {rustc_ast as ast, rustc_hir as hir};
 
-use super::OR_FUN_CALL;
+use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT};
 
 /// Checks for the `OR_FUN_CALL` lint.
 #[allow(clippy::too_many_lines)]
@@ -24,53 +25,72 @@ pub(super) fn check<'tcx>(
 ) {
     /// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`,
     /// `or_insert(T::new())` or `or_insert(T::default())`.
+    /// Similarly checks for `unwrap_or_else(T::new)`, `unwrap_or_else(T::default)`,
+    /// `or_insert_with(T::new)` or `or_insert_with(T::default)`.
     #[allow(clippy::too_many_arguments)]
     fn check_unwrap_or_default(
         cx: &LateContext<'_>,
         name: &str,
+        receiver: &hir::Expr<'_>,
         fun: &hir::Expr<'_>,
-        arg: &hir::Expr<'_>,
-        or_has_args: bool,
+        call_expr: Option<&hir::Expr<'_>>,
         span: Span,
         method_span: Span,
     ) -> bool {
-        let is_default_default = || is_trait_item(cx, fun, sym::Default);
+        if !expr_type_is_certain(cx, receiver) {
+            return false;
+        }
 
-        let implements_default = |arg, default_trait_id| {
-            let arg_ty = cx.typeck_results().expr_ty(arg);
-            implements_trait(cx, arg_ty, default_trait_id, &[])
+        let is_new = |fun: &hir::Expr<'_>| {
+            if let hir::ExprKind::Path(ref qpath) = fun.kind {
+                let path = last_path_segment(qpath).ident.name;
+                matches!(path, sym::new)
+            } else {
+                false
+            }
         };
 
-        if_chain! {
-            if !or_has_args;
-            if let Some(sugg) = match name {
-                "unwrap_or" => Some("unwrap_or_default"),
-                "or_insert" => Some("or_default"),
-                _ => None,
-            };
-            if let hir::ExprKind::Path(ref qpath) = fun.kind;
-            if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
-            let path = last_path_segment(qpath).ident.name;
-            // needs to target Default::default in particular or be *::new and have a Default impl
-            // available
-            if (matches!(path, kw::Default) && is_default_default())
-                || (matches!(path, sym::new) && implements_default(arg, default_trait_id));
-
-            then {
-                span_lint_and_sugg(
-                    cx,
-                    OR_FUN_CALL,
-                    method_span.with_hi(span.hi()),
-                    &format!("use of `{name}` followed by a call to `{path}`"),
-                    "try",
-                    format!("{sugg}()"),
-                    Applicability::MachineApplicable,
-                );
-
-                true
+        let output_type_implements_default = |fun| {
+            let fun_ty = cx.typeck_results().expr_ty(fun);
+            if let ty::FnDef(def_id, args) = fun_ty.kind() {
+                let output_ty = cx.tcx.fn_sig(def_id).instantiate(cx.tcx, args).skip_binder().output();
+                cx.tcx
+                    .get_diagnostic_item(sym::Default)
+                    .map_or(false, |default_trait_id| {
+                        implements_trait(cx, output_ty, default_trait_id, &[])
+                    })
             } else {
                 false
             }
+        };
+
+        let sugg = match (name, call_expr.is_some()) {
+            ("unwrap_or", true) | ("unwrap_or_else", false) => "unwrap_or_default",
+            ("or_insert", true) | ("or_insert_with", false) => "or_default",
+            _ => return false,
+        };
+
+        // needs to target Default::default in particular or be *::new and have a Default impl
+        // available
+        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),
+            }
+        {
+            span_lint_and_sugg(
+                cx,
+                UNWRAP_OR_DEFAULT,
+                method_span.with_hi(span.hi()),
+                &format!("use of `{name}` to construct default value"),
+                "try",
+                format!("{sugg}()"),
+                Applicability::MachineApplicable,
+            );
+
+            true
+        } else {
+            false
         }
     }
 
@@ -168,11 +188,16 @@ pub(super) fn check<'tcx>(
         match inner_arg.kind {
             hir::ExprKind::Call(fun, or_args) => {
                 let or_has_args = !or_args.is_empty();
-                if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) {
+                if or_has_args
+                    || !check_unwrap_or_default(cx, name, receiver, fun, Some(inner_arg), expr.span, method_span)
+                {
                     let fun_span = if or_has_args { None } else { Some(fun.span) };
                     check_general_case(cx, name, method_span, receiver, arg, None, expr.span, fun_span);
                 }
             },
+            hir::ExprKind::Path(..) | hir::ExprKind::Closure(..) => {
+                check_unwrap_or_default(cx, name, receiver, inner_arg, None, expr.span, method_span);
+            },
             hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => {
                 check_general_case(cx, name, method_span, receiver, arg, None, expr.span, None);
             },
@@ -189,3 +214,22 @@ pub(super) fn check<'tcx>(
         }
     }
 }
+
+fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
+    if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
+        let body = cx.tcx.hir().body(body);
+
+        if body.params.is_empty()
+            && let hir::Expr{ kind, .. } = &body.value
+            && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
+            && ident.name == sym::to_string
+            && let hir::Expr{ kind, .. } = self_arg
+            && let hir::ExprKind::Lit(lit) = kind
+            && let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node
+        {
+            return true;
+        }
+    }
+
+    false
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
index 8add0656101..81f9e2a77fc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
@@ -35,8 +35,8 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
                 && segment.ident.name == sym!(parse)
                 && let parse_result_ty = cx.typeck_results().expr_ty(parent)
                 && is_type_diagnostic_item(cx, parse_result_ty, sym::Result)
-                && let ty::Adt(_, substs) = parse_result_ty.kind()
-                && let Some(ok_ty) = substs[0].as_type()
+                && let ty::Adt(_, args) = parse_result_ty.kind()
+                && let Some(ok_ty) = args[0].as_type()
                 && parse_fails_on_trailing_newline(ok_ty)
             {
                 let local_snippet = snippet(cx, expr.span, "<expr>");
diff --git a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
new file mode 100644
index 00000000000..e3ec921da0c
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
@@ -0,0 +1,52 @@
+use super::READONLY_WRITE_LOCK;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::mir::{enclosing_mir, visit_local_usage};
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, Node};
+use rustc_lint::LateContext;
+use rustc_middle::mir::{Location, START_BLOCK};
+use rustc_span::sym;
+
+fn is_unwrap_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    if let ExprKind::MethodCall(path, receiver, ..) = expr.kind
+        && path.ident.name == sym::unwrap
+    {
+        is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::Result)
+    } else {
+        false
+    }
+}
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver: &Expr<'_>) {
+    if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::RwLock)
+        && let Node::Expr(unwrap_call_expr) = cx.tcx.hir().get_parent(expr.hir_id)
+        && is_unwrap_call(cx, unwrap_call_expr)
+        && let parent = cx.tcx.hir().get_parent(unwrap_call_expr.hir_id)
+        && let Node::Local(local) = parent
+        && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id)
+        && let Some((local, _)) = mir.local_decls.iter_enumerated().find(|(_, decl)| {
+            local.span.contains(decl.source_info.span)
+        })
+        && let Some(usages) = visit_local_usage(&[local], mir, Location {
+            block: START_BLOCK,
+            statement_index: 0,
+        })
+        && let [usage] = usages.as_slice()
+    {
+        let writer_never_mutated = usage.local_consume_or_mutate_locs.is_empty();
+
+        if writer_never_mutated {
+            span_lint_and_sugg(
+                cx,
+                READONLY_WRITE_LOCK,
+                expr.span,
+                "this write lock is used only for reading",
+                "consider using a read lock instead",
+                format!("{}.read()", snippet(cx, receiver.span, "<receiver>")),
+                Applicability::MaybeIncorrect // write lock might be intentional for enforcing exclusiveness
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs
new file mode 100644
index 00000000000..70da6ad58bd
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs
@@ -0,0 +1,58 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{Msrv, MATCHES_MACRO};
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local};
+use itertools::Itertools;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind, Param, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::STRING_LIT_CHARS_ANY;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    recv: &Expr<'_>,
+    param: &'tcx Param<'tcx>,
+    body: &Expr<'_>,
+    msrv: &Msrv,
+) {
+    if msrv.meets(MATCHES_MACRO)
+        && is_trait_method(cx, expr, sym::Iterator)
+        && let PatKind::Binding(_, arg, _, _) = param.pat.kind
+        && let ExprKind::Lit(lit_kind) = recv.kind
+        && let LitKind::Str(val, _) = lit_kind.node
+        && let ExprKind::Binary(kind, lhs, rhs) = body.kind
+        && let BinOpKind::Eq = kind.node
+        && let Some(lhs_path) = path_to_local(lhs)
+        && let Some(rhs_path) = path_to_local(rhs)
+        && let scrutinee = match (lhs_path == arg, rhs_path == arg) {
+            (true, false) => rhs,
+            (false, true) => lhs,
+            _ => return,
+        }
+        && !is_from_proc_macro(cx, expr)
+        && let Some(scrutinee_snip) = snippet_opt(cx, scrutinee.span)
+    {
+        // Normalize the char using `map` so `join` doesn't use `Display`, if we don't then
+        // something like `r"\"` will become `'\'`, which is of course invalid
+        let pat_snip = val.as_str().chars().map(|c| format!("{c:?}")).join(" | ");
+
+        span_lint_and_then(
+            cx,
+            STRING_LIT_CHARS_ANY,
+            expr.span,
+            "usage of `.chars().any(...)` to check if a char matches any from a string literal",
+            |diag| {
+                diag.span_suggestion_verbose(
+                    expr.span,
+                    "use `matches!(...)` instead",
+                    format!("matches!({scrutinee_snip}, {pat_snip})"),
+                    Applicability::MachineApplicable,
+                );
+            }
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
index 35137c97101..3404bdfe79b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
@@ -24,9 +24,9 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span)
 
     if let Some(Adjustment { target: recv_ty, .. }) = recv_adjusts.last()
         && let ty::Ref(_, ty, _) = recv_ty.kind()
-        && let ty::Adt(adt, substs) = ty.kind()
+        && let ty::Adt(adt, args) = ty.kind()
         && adt.is_box()
-        && is_dyn_any(cx, substs.type_at(0))
+        && is_dyn_any(cx, args.type_at(0))
     {
         span_lint_and_then(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index cc64a2e7948..fabf3fa0c0c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -77,6 +77,16 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc
             }
             (true, true)
         },
+        hir::ExprKind::MethodCall(segment, recv, [arg], _) => {
+            if segment.ident.name == sym!(then_some)
+                && cx.typeck_results().expr_ty(recv).is_bool()
+                && path_to_local_id(arg, arg_id)
+            {
+                (false, true)
+            } else {
+                (true, true)
+            }
+        },
         hir::ExprKind::Block(block, _) => block
             .expr
             .as_ref()
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index 111bcaaecec..937aac8d25e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -3,6 +3,8 @@ use clippy_utils::{is_res_lang_ctor, last_path_segment, path_res, MaybePath};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_middle::ty::print::with_forced_trimmed_paths;
 
 use super::UNNECESSARY_LITERAL_UNWRAP;
 
@@ -22,6 +24,7 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -
     }
 }
 
+#[expect(clippy::too_many_lines)]
 pub(super) fn check(
     cx: &LateContext<'_>,
     expr: &hir::Expr<'_>,
@@ -84,6 +87,34 @@ pub(super) fn check(
                 }
                 Some(suggs)
             },
+            ("None", "unwrap_or_default", _) => {
+                let ty = cx.typeck_results().expr_ty(expr);
+                let default_ty_string = if let ty::Adt(def, ..) = ty.kind() {
+                    with_forced_trimmed_paths!(format!("{}", cx.tcx.def_path_str(def.did())))
+                } else {
+                    "Default".to_string()
+                };
+                Some(vec![(expr.span, format!("{default_ty_string}::default()"))])
+            },
+            ("None", "unwrap_or", _) => Some(vec![
+                (expr.span.with_hi(args[0].span.lo()), String::new()),
+                (expr.span.with_lo(args[0].span.hi()), String::new()),
+            ]),
+            ("None", "unwrap_or_else", _) => match args[0].kind {
+                hir::ExprKind::Closure(hir::Closure {
+                    fn_decl:
+                        hir::FnDecl {
+                            output: hir::FnRetTy::DefaultReturn(span) | hir::FnRetTy::Return(hir::Ty { span, .. }),
+                            ..
+                        },
+                    ..
+                }) => Some(vec![
+                    (expr.span.with_hi(span.hi()), String::new()),
+                    (expr.span.with_lo(args[0].span.hi()), String::new()),
+                ]),
+                _ => None,
+            },
+            _ if call_args.is_empty() => None,
             (_, _, Some(_)) => None,
             ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![
                 (
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs
deleted file mode 100644
index 474a33b67e1..00000000000
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_or_else_default.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-//! Lint for `some_result_or_option.unwrap_or_else(Default::default)`
-
-use super::UNWRAP_OR_ELSE_DEFAULT;
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_default_equivalent_call;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
-use rustc_ast::ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_lint::LateContext;
-use rustc_span::{sym, symbol};
-
-pub(super) fn check<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx hir::Expr<'_>,
-    recv: &'tcx hir::Expr<'_>,
-    u_arg: &'tcx hir::Expr<'_>,
-) {
-    // something.unwrap_or_else(Default::default)
-    // ^^^^^^^^^- recv          ^^^^^^^^^^^^^^^^- u_arg
-    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- expr
-    let recv_ty = cx.typeck_results().expr_ty(recv);
-    let is_option = is_type_diagnostic_item(cx, recv_ty, sym::Option);
-    let is_result = is_type_diagnostic_item(cx, recv_ty, sym::Result);
-
-    if_chain! {
-        if is_option || is_result;
-        if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg);
-        then {
-            let mut applicability = Applicability::MachineApplicable;
-
-            span_lint_and_sugg(
-                cx,
-                UNWRAP_OR_ELSE_DEFAULT,
-                expr.span,
-                "use of `.unwrap_or_else(..)` to construct default value",
-                "try",
-                format!(
-                    "{}.unwrap_or_default()",
-                    snippet_with_applicability(cx, recv.span, "..", &mut applicability)
-                ),
-                applicability,
-            );
-        }
-    }
-}
-
-fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool {
-    if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind {
-        let body = cx.tcx.hir().body(body);
-
-        if body.params.is_empty()
-            && let hir::Expr{ kind, .. } = &body.value
-            && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
-            && ident == &symbol::Ident::from_str("to_string")
-            && let hir::Expr{ kind, .. } = self_arg
-            && let hir::ExprKind::Lit(lit) = kind
-            && let LitKind::Str(symbol::kw::Empty, _) = lit.node
-        {
-            return true;
-        }
-    }
-
-    false
-}
diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
index 2a60f2faca0..c79a1a7b9d4 100644
--- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
@@ -129,6 +129,14 @@ impl Visitor<'_> for IdentVisitor<'_, '_> {
                 return;
             }
 
+            // `struct Array<T, const N: usize>([T; N])`
+            //                        ^
+            if let Node::GenericParam(generic_param) = node
+                && let GenericParamKind::Const { .. } = generic_param.kind
+            {
+                return;
+            }
+
             if is_from_proc_macro(cx, &ident) {
                 return;
             }
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index d323a16c2a7..c634de960d1 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -1,16 +1,18 @@
 use super::needless_pass_by_value::requires_exact_signature;
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::source::snippet;
-use clippy_utils::{is_from_proc_macro, is_self};
-use if_chain::if_chain;
+use clippy_utils::{get_parent_node, inherits_cfg, is_from_proc_macro, is_self};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind};
+use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor};
+use rustc_hir::{Body, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath};
 use rustc_hir_typeck::expr_use_visitor as euv;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::associated_body;
+use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, UpvarId, UpvarPath};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::kw;
@@ -46,20 +48,24 @@ declare_clippy_lint! {
     "using a `&mut` argument when it's not mutated"
 }
 
-#[derive(Copy, Clone)]
-pub struct NeedlessPassByRefMut {
+#[derive(Clone)]
+pub struct NeedlessPassByRefMut<'tcx> {
     avoid_breaking_exported_api: bool,
+    used_fn_def_ids: FxHashSet<LocalDefId>,
+    fn_def_ids_to_maybe_unused_mut: FxIndexMap<LocalDefId, Vec<rustc_hir::Ty<'tcx>>>,
 }
 
-impl NeedlessPassByRefMut {
+impl NeedlessPassByRefMut<'_> {
     pub fn new(avoid_breaking_exported_api: bool) -> Self {
         Self {
             avoid_breaking_exported_api,
+            used_fn_def_ids: FxHashSet::default(),
+            fn_def_ids_to_maybe_unused_mut: FxIndexMap::default(),
         }
     }
 }
 
-impl_lint_pass!(NeedlessPassByRefMut => [NEEDLESS_PASS_BY_REF_MUT]);
+impl_lint_pass!(NeedlessPassByRefMut<'_> => [NEEDLESS_PASS_BY_REF_MUT]);
 
 fn should_skip<'tcx>(
     cx: &LateContext<'tcx>,
@@ -87,12 +93,12 @@ fn should_skip<'tcx>(
     is_from_proc_macro(cx, &input)
 }
 
-impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
+impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
         kind: FnKind<'tcx>,
-        decl: &'tcx FnDecl<'_>,
+        decl: &'tcx FnDecl<'tcx>,
         body: &'tcx Body<'_>,
         span: Span,
         fn_def_id: LocalDefId,
@@ -102,17 +108,17 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
         }
 
         let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
-
-        match kind {
+        let is_async = match kind {
             FnKind::ItemFn(.., header) => {
                 let attrs = cx.tcx.hir().attrs(hir_id);
                 if header.abi != Abi::Rust || requires_exact_signature(attrs) {
                     return;
                 }
+                header.is_async()
             },
-            FnKind::Method(..) => (),
+            FnKind::Method(.., sig) => sig.header.is_async(),
             FnKind::Closure => return,
-        }
+        };
 
         // Exclude non-inherent impls
         if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
@@ -128,63 +134,89 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
         let fn_sig = cx.tcx.liberate_late_bound_regions(fn_def_id.to_def_id(), fn_sig);
 
         // If there are no `&mut` argument, no need to go any further.
-        if !decl
+        let mut it = decl
             .inputs
             .iter()
             .zip(fn_sig.inputs())
             .zip(body.params)
-            .any(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
-        {
+            .filter(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
+            .peekable();
+        if it.peek().is_none() {
             return;
         }
-
         // Collect variables mutably used and spans which will need dereferencings from the
         // function body.
         let MutablyUsedVariablesCtxt { mutably_used_vars, .. } = {
             let mut ctx = MutablyUsedVariablesCtxt::default();
             let infcx = cx.tcx.infer_ctxt().build();
             euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
+            if is_async {
+                let closures = ctx.async_closures.clone();
+                let hir = cx.tcx.hir();
+                for closure in closures {
+                    ctx.prev_bind = None;
+                    ctx.prev_move_to_closure.clear();
+                    if let Some(body) = hir
+                        .find_by_def_id(closure)
+                        .and_then(associated_body)
+                        .map(|(_, body_id)| hir.body(body_id))
+                    {
+                        euv::ExprUseVisitor::new(&mut ctx, &infcx, closure, cx.param_env, cx.typeck_results())
+                            .consume_body(body);
+                    }
+                }
+            }
             ctx
         };
-
-        let mut it = decl
-            .inputs
-            .iter()
-            .zip(fn_sig.inputs())
-            .zip(body.params)
-            .filter(|((&input, &ty), arg)| !should_skip(cx, input, ty, arg))
-            .peekable();
-        if it.peek().is_none() {
-            return;
-        }
-        let show_semver_warning = self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id);
         for ((&input, &_), arg) in it {
             // Only take `&mut` arguments.
-            if_chain! {
-                if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind;
-                if !mutably_used_vars.contains(&canonical_id);
-                if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind;
-                then {
-                    // If the argument is never used mutably, we emit the warning.
-                    let sp = input.span;
-                    span_lint_and_then(
+            if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind
+                && !mutably_used_vars.contains(&canonical_id)
+            {
+                self.fn_def_ids_to_maybe_unused_mut.entry(fn_def_id).or_default().push(input);
+            }
+        }
+    }
+
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        cx.tcx.hir().visit_all_item_likes_in_crate(&mut FnNeedsMutVisitor {
+            cx,
+            used_fn_def_ids: &mut self.used_fn_def_ids,
+        });
+
+        for (fn_def_id, unused) in self
+            .fn_def_ids_to_maybe_unused_mut
+            .iter()
+            .filter(|(def_id, _)| !self.used_fn_def_ids.contains(def_id))
+        {
+            let show_semver_warning =
+                self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(*fn_def_id);
+
+            let mut is_cfged = None;
+            for input in unused {
+                // If the argument is never used mutably, we emit the warning.
+                let sp = input.span;
+                if let rustc_hir::TyKind::Ref(_, inner_ty) = input.kind {
+                    let is_cfged = is_cfged.get_or_insert_with(|| inherits_cfg(cx.tcx, *fn_def_id));
+                    span_lint_hir_and_then(
                         cx,
                         NEEDLESS_PASS_BY_REF_MUT,
+                        cx.tcx.hir().local_def_id_to_hir_id(*fn_def_id),
                         sp,
                         "this argument is a mutable reference, but not used mutably",
                         |diag| {
                             diag.span_suggestion(
                                 sp,
                                 "consider changing to".to_string(),
-                                format!(
-                                    "&{}",
-                                    snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),
-                                ),
+                                format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),),
                                 Applicability::Unspecified,
                             );
                             if show_semver_warning {
                                 diag.warn("changing this function will impact semver compatibility");
                             }
+                            if *is_cfged {
+                                diag.note("this is cfg-gated and may require further changes");
+                            }
                         },
                     );
                 }
@@ -197,7 +229,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut {
 struct MutablyUsedVariablesCtxt {
     mutably_used_vars: HirIdSet,
     prev_bind: Option<HirId>,
+    prev_move_to_closure: HirIdSet,
     aliases: HirIdMap<HirId>,
+    async_closures: FxHashSet<LocalDefId>,
 }
 
 impl MutablyUsedVariablesCtxt {
@@ -213,16 +247,27 @@ impl MutablyUsedVariablesCtxt {
 impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt {
     fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
         if let euv::Place {
-            base: euv::PlaceBase::Local(vid),
+            base:
+                euv::PlaceBase::Local(vid)
+                | euv::PlaceBase::Upvar(UpvarId {
+                    var_path: UpvarPath { hir_id: vid },
+                    ..
+                }),
             base_ty,
             ..
         } = &cmt.place
         {
             if let Some(bind_id) = self.prev_bind.take() {
-                self.aliases.insert(bind_id, *vid);
-            } else if matches!(base_ty.ref_mutability(), Some(Mutability::Mut)) {
+                if bind_id != *vid {
+                    self.aliases.insert(bind_id, *vid);
+                }
+            } else if !self.prev_move_to_closure.contains(vid)
+                && matches!(base_ty.ref_mutability(), Some(Mutability::Mut))
+            {
                 self.add_mutably_used_var(*vid);
             }
+            self.prev_bind = None;
+            self.prev_move_to_closure.remove(vid);
         }
     }
 
@@ -265,9 +310,73 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt {
         self.prev_bind = None;
     }
 
-    fn fake_read(&mut self, _: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {}
+    fn fake_read(
+        &mut self,
+        cmt: &rustc_hir_typeck::expr_use_visitor::PlaceWithHirId<'tcx>,
+        cause: FakeReadCause,
+        _id: HirId,
+    ) {
+        if let euv::Place {
+            base:
+                euv::PlaceBase::Upvar(UpvarId {
+                    var_path: UpvarPath { hir_id: vid },
+                    ..
+                }),
+            ..
+        } = &cmt.place
+        {
+            if let FakeReadCause::ForLet(Some(inner)) = cause {
+                // Seems like we are inside an async function. We need to store the closure `DefId`
+                // to go through it afterwards.
+                self.async_closures.insert(inner);
+                self.aliases.insert(cmt.hir_id, *vid);
+                self.prev_move_to_closure.insert(*vid);
+            }
+        }
+    }
 
     fn bind(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
         self.prev_bind = Some(id);
     }
 }
+
+/// A final pass to check for paths referencing this function that require the argument to be
+/// `&mut`, basically if the function is ever used as a `fn`-like argument.
+struct FnNeedsMutVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    used_fn_def_ids: &'a mut FxHashSet<LocalDefId>,
+}
+
+impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> {
+    type NestedFilter = OnlyBodies;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
+    }
+
+    fn visit_qpath(&mut self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, _: Span) {
+        walk_qpath(self, qpath, hir_id);
+
+        let Self { cx, used_fn_def_ids } = self;
+
+        // #11182; do not lint if mutability is required elsewhere
+        if let Node::Expr(expr) = cx.tcx.hir().get(hir_id)
+            && let Some(parent) = get_parent_node(cx.tcx, expr.hir_id)
+            && let ty::FnDef(def_id, _) = cx.tcx.typeck(cx.tcx.hir().enclosing_body_owner(hir_id)).expr_ty(expr).kind()
+            && let Some(def_id) = def_id.as_local()
+        {
+            if let Node::Expr(e) = parent
+                && let ExprKind::Call(call, _) = e.kind
+                && call.hir_id == expr.hir_id
+            {
+                return;
+            }
+
+            // We don't need to check each argument individually as you cannot coerce a function
+            // taking `&mut` -> `&`, for some reason, so if we've gotten this far we know it's
+            // passed as a `fn`-like argument (or is unified) and should ignore every "unused"
+            // argument entirely
+            used_fn_def_ids.insert(def_id);
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 5e26601537f..5ee26966fa7 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::ptr::get_spans;
 use clippy_utils::source::{snippet, snippet_opt};
 use clippy_utils::ty::{
-    implements_trait, implements_trait_with_env, is_copy, is_type_diagnostic_item, is_type_lang_item,
+    implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
 };
 use clippy_utils::{get_trait_def_id, is_self, paths};
 use if_chain::if_chain;
@@ -182,7 +182,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                 if !ty.is_mutable_ptr();
                 if !is_copy(cx, ty);
                 if ty.is_sized(cx.tcx, cx.param_env);
-                if !allowed_traits.iter().any(|&t| implements_trait_with_env(cx.tcx, cx.param_env, ty, t, [None]));
+                if !allowed_traits.iter().any(|&t| implements_trait_with_env_from_iter(
+                    cx.tcx,
+                    cx.param_env,
+                    ty,
+                    t,
+                    [Option::<ty::GenericArg<'tcx>>::None],
+                ));
                 if !implements_borrow_trait;
                 if !all_borrowable_trait;
 
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 8bb2fa92585..a70692d8ff8 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -154,7 +154,7 @@ fn is_value_unfrozen_raw<'tcx>(
             ty::Adt(def, ..) if def.is_union() => false,
             ty::Array(ty, _) => val.unwrap_branch().iter().any(|field| inner(cx, *field, ty)),
             ty::Adt(def, _) if def.is_union() => false,
-            ty::Adt(def, substs) if def.is_enum() => {
+            ty::Adt(def, args) if def.is_enum() => {
                 let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
                 let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
                 fields
@@ -164,19 +164,14 @@ fn is_value_unfrozen_raw<'tcx>(
                         def.variants()[variant_index]
                             .fields
                             .iter()
-                            .map(|field| field.ty(cx.tcx, substs)),
+                            .map(|field| field.ty(cx.tcx, args)),
                     )
                     .any(|(field, ty)| inner(cx, field, ty))
             },
-            ty::Adt(def, substs) => val
+            ty::Adt(def, args) => val
                 .unwrap_branch()
                 .iter()
-                .zip(
-                    def.non_enum_variant()
-                        .fields
-                        .iter()
-                        .map(|field| field.ty(cx.tcx, substs)),
-                )
+                .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
                 .any(|(field, ty)| inner(cx, *field, ty)),
             ty::Tuple(tys) => val
                 .unwrap_branch()
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 35dd8fabe6e..f9108145cdb 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -1,7 +1,7 @@
 use super::ARITHMETIC_SIDE_EFFECTS;
 use clippy_utils::consts::{constant, constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary};
+use clippy_utils::{expr_or_init, is_from_proc_macro, is_lint_allowed, peel_hir_expr_refs, peel_hir_expr_unary};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
@@ -138,8 +138,10 @@ impl ArithmeticSideEffects {
         ) {
             return;
         };
-        let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
-        let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
+        let (mut actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
+        let (mut actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
+        actual_lhs = expr_or_init(cx, actual_lhs);
+        actual_rhs = expr_or_init(cx, actual_rhs);
         let lhs_ty = cx.typeck_results().expr_ty(actual_lhs).peel_refs();
         let rhs_ty = cx.typeck_results().expr_ty(actual_rhs).peel_refs();
         if self.has_allowed_binary(lhs_ty, rhs_ty) {
diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
index 377bddeaa5f..9c7f7e1cd7f 100644
--- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::is_direct_expn_of;
-use if_chain::if_chain;
 use rustc_ast::ast::{Expr, ExprKind, MethodCall};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -36,21 +35,27 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]);
 
 impl EarlyLintPass for OptionEnvUnwrap {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if_chain! {
-            if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind;
-            if matches!(seg.ident.name, sym::expect | sym::unwrap);
-            if let ExprKind::Call(caller, _) = &receiver.kind;
-            if is_direct_expn_of(caller.span, "option_env").is_some();
-            then {
-                span_lint_and_help(
-                    cx,
-                    OPTION_ENV_UNWRAP,
-                    expr.span,
-                    "this will panic at run-time if the environment variable doesn't exist at compile-time",
-                    None,
-                    "consider using the `env!` macro instead"
-                );
-            }
+        fn lint(cx: &EarlyContext<'_>, span: Span) {
+            span_lint_and_help(
+                cx,
+                OPTION_ENV_UNWRAP,
+                span,
+                "this will panic at run-time if the environment variable doesn't exist at compile-time",
+                None,
+                "consider using the `env!` macro instead",
+            );
         }
+
+        if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind &&
+		matches!(seg.ident.name, sym::expect | sym::unwrap) {
+			if let ExprKind::Call(caller, _) = &receiver.kind &&
+            // If it exists, it will be ::core::option::Option::Some("<env var>").unwrap() (A method call in the HIR)
+            is_direct_expn_of(caller.span, "option_env").is_some() {
+				lint(cx, expr.span);
+			} else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR)
+            is_direct_expn_of(caller.span, "option_env").is_some() {
+				lint(cx, expr.span);
+			}
+		}
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 264c38df11f..42299d8d42f 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -26,6 +26,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
+use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use std::{fmt, iter};
@@ -163,6 +164,12 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
             }
 
             check_mut_from_ref(cx, sig, None);
+
+            if !matches!(sig.header.abi, Abi::Rust) {
+                // Ignore `extern` functions with non-Rust calling conventions
+                return;
+            }
+
             for arg in check_fn_args(
                 cx,
                 cx.tcx
@@ -222,6 +229,12 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
         };
 
         check_mut_from_ref(cx, sig, Some(body));
+
+        if !matches!(sig.header.abi, Abi::Rust) {
+            // Ignore `extern` functions with non-Rust calling conventions
+            return;
+        }
+
         let decl = sig.decl;
         let sig = cx.tcx.fn_sig(item_id).instantiate_identity().skip_binder();
         let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, &decl.output, body.params)
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
new file mode 100644
index 00000000000..140ae837a17
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -0,0 +1,103 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_from_proc_macro;
+use clippy_utils::ty::needs_ordered_drop;
+use rustc_hir::def::Res;
+use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::Ident;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for redundant redefinitions of local bindings.
+    ///
+    /// ### Why is this bad?
+    /// Redundant redefinitions of local bindings do not change behavior and are likely to be unintended.
+    ///
+    /// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let a = 0;
+    /// let a = a;
+    ///
+    /// fn foo(b: i32) {
+    ///    let b = b;
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let a = 0;
+    /// // no redefinition with the same name
+    ///
+    /// fn foo(b: i32) {
+    ///   // no redefinition with the same name
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub REDUNDANT_LOCALS,
+    correctness,
+    "redundant redefinition of a local binding"
+}
+declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
+
+impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+        if_chain! {
+            // the pattern is a single by-value binding
+            if let PatKind::Binding(BindingAnnotation(ByRef::No, mutability), _, ident, None) = local.pat.kind;
+            // the binding is not type-ascribed
+            if local.ty.is_none();
+            // the expression is a resolved path
+            if let Some(expr) = local.init;
+            if let ExprKind::Path(qpath @ QPath::Resolved(None, path)) = expr.kind;
+            // the path is a single segment equal to the local's name
+            if let [last_segment] = path.segments;
+            if last_segment.ident == ident;
+            // resolve the path to its defining binding pattern
+            if let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id);
+            if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id);
+            // the previous binding has the same mutability
+            if find_binding(binding_pat, ident).unwrap().1 == mutability;
+            // the local does not affect the code's drop behavior
+            if !affects_drop_behavior(cx, binding_id, local.hir_id, expr);
+            // the local is user-controlled
+            if !in_external_macro(cx.sess(), local.span);
+            if !is_from_proc_macro(cx, expr);
+            then {
+                span_lint_and_help(
+                    cx,
+                    REDUNDANT_LOCALS,
+                    vec![binding_pat.span, local.span],
+                    "redundant redefinition of a binding",
+                    None,
+                    &format!("remove the redefinition of `{ident}`"),
+                );
+            }
+        }
+    }
+}
+
+/// Find the annotation of a binding introduced by a pattern, or `None` if it's not introduced.
+fn find_binding(pat: &Pat<'_>, name: Ident) -> Option<BindingAnnotation> {
+    let mut ret = None;
+
+    pat.each_binding_or_first(&mut |annotation, _, _, ident| {
+        if ident == name {
+            ret = Some(annotation);
+        }
+    });
+
+    ret
+}
+
+/// Check if a rebinding of a local affects the code's drop behavior.
+fn affects_drop_behavior<'tcx>(cx: &LateContext<'tcx>, bind: HirId, rebind: HirId, rebind_expr: &Expr<'tcx>) -> bool {
+    let hir = cx.tcx.hir();
+
+    // the rebinding is in a different scope than the original binding
+    // and the type of the binding cares about drop order
+    hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
+        && needs_ordered_drop(cx, cx.typeck_results().expr_ty(rebind_expr))
+}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
index 038dfe8e480..ed42a422b4b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -5,6 +5,7 @@ use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::kw;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -64,7 +65,7 @@ impl RedundantStaticLifetimes {
                 if let Some(lifetime) = *optional_lifetime {
                     match borrow_type.ty.kind {
                         TyKind::Path(..) | TyKind::Slice(..) | TyKind::Array(..) | TyKind::Tup(..) => {
-                            if lifetime.ident.name == rustc_span::symbol::kw::StaticLifetime {
+                            if lifetime.ident.name == kw::StaticLifetime {
                                 let snip = snippet(cx, borrow_type.ty.span, "<type>");
                                 let sugg = format!("&{}{snip}", borrow_type.mutbl.prefix_str());
                                 span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index e532dd61a82..49bdc679604 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -30,6 +30,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::single_char_push_str", "clippy::single_char_add_str"),
     ("clippy::stutter", "clippy::module_name_repetitions"),
     ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
+    ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
     ("clippy::zero_width_space", "clippy::invisible_characters"),
     ("clippy::cast_ref_to_mut", "invalid_reference_casting"),
     ("clippy::clone_double_ref", "suspicious_double_ref_op"),
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 2a494ff1fa6..351bacf5691 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -1,12 +1,14 @@
-use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_opt, snippet_with_context};
 use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
-use clippy_utils::{fn_def_id, path_to_local_id, span_find_starting_semi};
+use clippy_utils::{fn_def_id, is_from_proc_macro, path_to_local_id, span_find_starting_semi};
 use core::ops::ControlFlow;
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem, MatchSource, PatKind, QPath, StmtKind};
+use rustc_hir::{
+    Block, Body, Expr, ExprKind, FnDecl, ItemKind, LangItem, MatchSource, OwnerNode, PatKind, QPath, Stmt, StmtKind,
+};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
@@ -76,6 +78,46 @@ declare_clippy_lint! {
     "using a return statement like `return expr;` where an expression would suffice"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for return statements on `Err` paired with the `?` operator.
+    ///
+    /// ### Why is this bad?
+    /// The `return` is unnecessary.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         return Err(...)?;
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    /// simplify to
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         Err(...)?;
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    /// if paired with `try_err`, use instead:
+    /// ```rust,ignore
+    /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
+    ///     if x == 0 {
+    ///         return Err(...);
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub NEEDLESS_RETURN_WITH_QUESTION_MARK,
+    style,
+    "using a return statement like `return Err(expr)?;` where removing it would suffice"
+}
+
 #[derive(PartialEq, Eq)]
 enum RetReplacement<'tcx> {
     Empty,
@@ -115,9 +157,35 @@ impl<'tcx> ToString for RetReplacement<'tcx> {
     }
 }
 
-declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]);
+declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN, NEEDLESS_RETURN_WITH_QUESTION_MARK]);
 
 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)
+            && let StmtKind::Semi(expr) = stmt.kind
+            && let ExprKind::Ret(Some(ret)) = expr.kind
+            && let ExprKind::Match(.., MatchSource::TryDesugar) = ret.kind
+            // Ensure this is not the final stmt, otherwise removing it would cause a compile error
+            && let OwnerNode::Item(item) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id))
+            && let ItemKind::Fn(_, _, body) = item.kind
+            && let block = cx.tcx.hir().body(body).value
+            && let ExprKind::Block(block, _) = block.kind
+            && let [.., final_stmt] = block.stmts
+            && final_stmt.hir_id != stmt.hir_id
+            && !is_from_proc_macro(cx, expr)
+        {
+            span_lint_and_sugg(
+                cx,
+                NEEDLESS_RETURN_WITH_QUESTION_MARK,
+                expr.span.until(ret.span),
+                "unneeded `return` statement with `?` operator",
+                "remove it",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
         // we need both a let-binding stmt and an expr
         if_chain! {
@@ -173,6 +241,10 @@ impl<'tcx> LateLintPass<'tcx> for Return {
         sp: Span,
         _: LocalDefId,
     ) {
+        if sp.from_expansion() {
+            return;
+        }
+
         match kind {
             FnKind::Closure => {
                 // when returning without value in closure, replace this `return`
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
index 355f907e257..c9547cd95dc 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned {
             if let Some(expr) = block.expr;
             let t_expr = cx.typeck_results().expr_ty(expr);
             if t_expr.is_unit();
-            let mut app = Applicability::MaybeIncorrect;
+            let mut app = Applicability::MachineApplicable;
             if let snippet = snippet_with_context(cx, expr.span, block.span.ctxt(), "}", &mut app).0;
             if !snippet.ends_with('}') && !snippet.ends_with(';');
             if cx.sess().source_map().is_multiline(block.span);
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index 3b282dbfa04..4b248c9c790 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{indent_of, snippet};
-use clippy_utils::{expr_or_init, get_attr, path_to_local};
+use clippy_utils::{expr_or_init, get_attr, path_to_local, peel_hir_expr_unary};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
@@ -235,7 +235,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx
 
     fn manage_has_expensive_expr_after_last_attr(&mut self) {
         let has_expensive_stmt = match self.ap.curr_stmt.kind {
-            hir::StmtKind::Expr(expr) if !is_expensive_expr(expr) => false,
+            hir::StmtKind::Expr(expr) if is_inexpensive_expr(expr) => false,
             hir::StmtKind::Local(local) if let Some(expr) = local.init
                 && let hir::ExprKind::Path(_) = expr.kind => false,
             _ => true
@@ -330,13 +330,13 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o
                             apa.last_method_span = span;
                         }
                     },
-                    hir::StmtKind::Semi(expr) => {
-                        if has_drop(expr, &apa.first_bind_ident, self.cx) {
+                    hir::StmtKind::Semi(semi_expr) => {
+                        if has_drop(semi_expr, &apa.first_bind_ident, self.cx) {
                             apa.has_expensive_expr_after_last_attr = false;
                             apa.last_stmt_span = DUMMY_SP;
                             return;
                         }
-                        if let hir::ExprKind::MethodCall(_, _, _, span) = expr.kind {
+                        if let hir::ExprKind::MethodCall(_, _, _, span) = semi_expr.kind {
                             apa.last_method_span = span;
                         }
                     },
@@ -434,16 +434,31 @@ fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_
         && let Res::Def(DefKind::Fn, did) = fun_path.res
         && lcx.tcx.is_diagnostic_item(sym::mem_drop, did)
         && let [first_arg, ..] = args
-        && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind
-        && let [first_arg_ps, .. ] = arg_path.segments
     {
-        &first_arg_ps.ident == first_bind_ident
-    }
-    else {
-        false
+        let has_ident = |local_expr: &hir::Expr<'_>| {
+            if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind
+                && let [first_arg_ps, .. ] = arg_path.segments
+                && &first_arg_ps.ident == first_bind_ident
+            {
+                true
+            }
+            else {
+                false
+            }
+        };
+        if has_ident(first_arg) {
+            return true;
+        }
+        if let hir::ExprKind::Tup(value) = &first_arg.kind && value.iter().any(has_ident) {
+            return true;
+        }
     }
+    false
 }
 
-fn is_expensive_expr(expr: &hir::Expr<'_>) -> bool {
-    !matches!(expr.kind, hir::ExprKind::Path(_))
+fn is_inexpensive_expr(expr: &hir::Expr<'_>) -> bool {
+    let actual = peel_hir_expr_unary(expr).0;
+    let is_path = matches!(actual.kind, hir::ExprKind::Path(_));
+    let is_lit = matches!(actual.kind, hir::ExprKind::Lit(_));
+    is_path || is_lit
 }
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 858135c8d46..54a33eb2986 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{
-    get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, SpanlessEq,
+    get_enclosing_block, is_expr_path_def_path, is_integer_literal, is_path_diagnostic_item, path_to_local,
+    path_to_local_id, paths, SpanlessEq,
 };
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor};
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
@@ -60,7 +60,24 @@ struct VecAllocation<'tcx> {
 
     /// Reference to the expression used as argument on `with_capacity` call. This is used
     /// to only match slow zero-filling idioms of the same length than vector initialization.
-    len_expr: &'tcx Expr<'tcx>,
+    size_expr: InitializedSize<'tcx>,
+}
+
+/// Initializer for the creation of the vector.
+///
+/// When `Vec::with_capacity(size)` is found, the `size` expression will be in
+/// `InitializedSize::Initialized`.
+///
+/// Otherwise, for `Vec::new()` calls, there is no allocation initializer yet, so
+/// `InitializedSize::Uninitialized` is used.
+/// Later, when a call to `.resize(size, 0)` or similar is found, it's set
+/// to `InitializedSize::Initialized(size)`.
+///
+/// Since it will be set to `InitializedSize::Initialized(size)` when a slow initialization is
+/// found, it is always safe to "unwrap" it at lint time.
+enum InitializedSize<'tcx> {
+    Initialized(&'tcx Expr<'tcx>),
+    Uninitialized,
 }
 
 /// Type of slow initialization
@@ -77,18 +94,14 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
         // Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)`
         if_chain! {
             if let ExprKind::Assign(left, right, _) = expr.kind;
-
-            // Extract variable
             if let Some(local_id) = path_to_local(left);
-
-            // Extract len argument
-            if let Some(len_arg) = Self::is_vec_with_capacity(cx, right);
+            if let Some(size_expr) = Self::as_vec_initializer(cx, right);
 
             then {
                 let vi = VecAllocation {
                     local_id,
                     allocation_expr: right,
-                    len_expr: len_arg,
+                    size_expr,
                 };
 
                 Self::search_initialization(cx, vi, expr.hir_id);
@@ -98,17 +111,18 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
 
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)`
+        // or `Vec::new()`
         if_chain! {
             if let StmtKind::Local(local) = stmt.kind;
             if let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind;
             if let Some(init) = local.init;
-            if let Some(len_arg) = Self::is_vec_with_capacity(cx, init);
+            if let Some(size_expr) = Self::as_vec_initializer(cx, init);
 
             then {
                 let vi = VecAllocation {
                     local_id,
                     allocation_expr: init,
-                    len_expr: len_arg,
+                    size_expr,
                 };
 
                 Self::search_initialization(cx, vi, stmt.hir_id);
@@ -118,19 +132,20 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit {
 }
 
 impl SlowVectorInit {
-    /// Checks if the given expression is `Vec::with_capacity(..)`. It will return the expression
-    /// of the first argument of `with_capacity` call if it matches or `None` if it does not.
-    fn is_vec_with_capacity<'tcx>(cx: &LateContext<'_>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
-        if_chain! {
-            if let ExprKind::Call(func, [arg]) = expr.kind;
-            if let ExprKind::Path(QPath::TypeRelative(ty, name)) = func.kind;
-            if name.ident.as_str() == "with_capacity";
-            if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec);
-            then {
-                Some(arg)
-            } else {
-                None
-            }
+    /// Looks for `Vec::with_capacity(size)` or `Vec::new()` calls and returns the initialized size,
+    /// if any. More specifically, it returns:
+    /// - `Some(InitializedSize::Initialized(size))` for `Vec::with_capacity(size)`
+    /// - `Some(InitializedSize::Uninitialized)` for `Vec::new()`
+    /// - `None` for other, unrelated kinds of expressions
+    fn as_vec_initializer<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<InitializedSize<'tcx>> {
+        if let ExprKind::Call(func, [len_expr]) = expr.kind
+            && is_expr_path_def_path(cx, func, &paths::VEC_WITH_CAPACITY)
+        {
+            Some(InitializedSize::Initialized(len_expr))
+        } else if matches!(expr.kind, ExprKind::Call(func, _) if is_expr_path_def_path(cx, func, &paths::VEC_NEW)) {
+            Some(InitializedSize::Uninitialized)
+        } else {
+            None
         }
     }
 
@@ -169,12 +184,19 @@ impl SlowVectorInit {
     }
 
     fn emit_lint(cx: &LateContext<'_>, slow_fill: &Expr<'_>, vec_alloc: &VecAllocation<'_>, msg: &str) {
-        let len_expr = Sugg::hir(cx, vec_alloc.len_expr, "len");
+        let len_expr = Sugg::hir(
+            cx,
+            match vec_alloc.size_expr {
+                InitializedSize::Initialized(expr) => expr,
+                InitializedSize::Uninitialized => unreachable!("size expression must be set by this point"),
+            },
+            "len",
+        );
 
         span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| {
             diag.span_suggestion(
                 vec_alloc.allocation_expr.span,
-                "consider replace allocation with",
+                "consider replacing this with",
                 format!("vec![0; {len_expr}]"),
                 Applicability::Unspecified,
             );
@@ -214,36 +236,45 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     }
 
     /// Checks if the given expression is resizing a vector with 0
-    fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) {
+    fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'tcx>) {
         if self.initialization_found
             && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind
             && path_to_local_id(self_arg, self.vec_alloc.local_id)
             && path.ident.name == sym!(resize)
             // Check that is filled with 0
-            && is_integer_literal(fill_arg, 0) {
-                // Check that len expression is equals to `with_capacity` expression
-                if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
-                    self.slow_expression = Some(InitializationType::Resize(expr));
-                } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
-                    self.slow_expression = Some(InitializationType::Resize(expr));
-                }
+            && is_integer_literal(fill_arg, 0)
+        {
+            let is_matching_resize = if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
+                // If we have a size expression, check that it is equal to what's passed to `resize`
+                SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
+                    || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity")
+            } else {
+                self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
+                true
+            };
+
+            if is_matching_resize {
+                self.slow_expression = Some(InitializationType::Resize(expr));
             }
+        }
     }
 
     /// Returns `true` if give expression is `repeat(0).take(...)`
-    fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
+    fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool {
         if_chain! {
             if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind;
             if take_path.ident.name == sym!(take);
             // Check that take is applied to `repeat(0)`
             if self.is_repeat_zero(recv);
             then {
-                // Check that len expression is equals to `with_capacity` expression
-                if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
-                    return true;
-                } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" {
-                    return true;
+                if let InitializedSize::Initialized(size_expr) = self.vec_alloc.size_expr {
+                    // Check that len expression is equals to `with_capacity` expression
+                    return SpanlessEq::new(self.cx).eq_expr(len_arg, size_expr)
+                        || matches!(len_arg.kind, ExprKind::MethodCall(path, ..) if path.ident.as_str() == "capacity")
                 }
+
+                self.vec_alloc.size_expr = InitializedSize::Initialized(len_arg);
+                return true;
             }
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
index 2e00ed042a8..7eec6982092 100644
--- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
@@ -1,21 +1,29 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::visitors::for_each_local_use_after_expr;
 use clippy_utils::{is_from_proc_macro, path_to_local};
+use itertools::Itertools;
 use rustc_ast::LitKind;
-use rustc_hir::{Expr, ExprKind, HirId, Node, Pat};
+use rustc_hir::{Expr, ExprKind, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use std::iter::once;
+use std::ops::ControlFlow;
 
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for tuple<=>array conversions that are not done with `.into()`.
     ///
     /// ### Why is this bad?
-    /// It may be unnecessary complexity. `.into()` works for converting tuples
-    /// <=> arrays of up to 12 elements and may convey intent more clearly.
+    /// It may be unnecessary complexity. `.into()` works for converting tuples<=> arrays of up to
+    /// 12 elements and conveys the intent more clearly, while also leaving less room for hard to
+    /// spot bugs!
+    ///
+    /// ### Known issues
+    /// The suggested code may hide potential asymmetry in some cases. See
+    /// [#11085](https://github.com/rust-lang/rust-clippy/issues/11085) for more info.
     ///
     /// ### Example
     /// ```rust,ignore
@@ -29,7 +37,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.72.0"]
     pub TUPLE_ARRAY_CONVERSIONS,
-    pedantic,
+    nursery,
     "checks for tuple<=>array conversions that are not done with `.into()`"
 }
 impl_lint_pass!(TupleArrayConversions => [TUPLE_ARRAY_CONVERSIONS]);
@@ -41,130 +49,152 @@ pub struct 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) {
-            match expr.kind {
-                ExprKind::Array(elements) if (1..=12).contains(&elements.len()) => check_array(cx, expr, elements),
-                ExprKind::Tup(elements) if (1..=12).contains(&elements.len()) => check_tuple(cx, expr, elements),
-                _ => {},
-            }
+        if in_external_macro(cx.sess(), expr.span) || !self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) {
+            return;
+        }
+
+        match expr.kind {
+            ExprKind::Array(elements) if (1..=12).contains(&elements.len()) => check_array(cx, expr, elements),
+            ExprKind::Tup(elements) if (1..=12).contains(&elements.len()) => check_tuple(cx, expr, elements),
+            _ => {},
         }
     }
 
     extract_msrv_attr!(LateContext);
 }
 
-#[expect(
-    clippy::blocks_in_if_conditions,
-    reason = "not a FP, but this is much easier to understand"
-)]
 fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
-    if should_lint(
-        cx,
-        elements,
-        // This is cursed.
-        Some,
-        |(first_id, local)| {
-            if let Node::Pat(pat) = local
-                && let parent = parent_pat(cx, pat)
-                && parent.hir_id == first_id
-            {
-                return matches!(
-                    cx.typeck_results().pat_ty(parent).peel_refs().kind(),
-                    ty::Tuple(len) if len.len() == elements.len()
-                );
-            }
-
-            false
-        },
-    ) || should_lint(
-        cx,
-        elements,
-        |(i, expr)| {
-            if let ExprKind::Field(path, field) = expr.kind && field.as_str() == i.to_string() {
-                return Some((i, path));
-            };
-
-            None
-        },
-        |(first_id, local)| {
-            if let Node::Pat(pat) = local
-                && let parent = parent_pat(cx, pat)
-                && parent.hir_id == first_id
-            {
-                return matches!(
-                    cx.typeck_results().pat_ty(parent).peel_refs().kind(),
-                    ty::Tuple(len) if len.len() == elements.len()
-                );
-            }
+    let (ty::Array(ty, _) | ty::Slice(ty)) = cx.typeck_results().expr_ty(expr).kind() else {
+        unreachable!("`expr` must be an array or slice due to `ExprKind::Array`");
+    };
+
+    if let [first, ..] = elements
+        && let Some(locals) = (match first.kind {
+            ExprKind::Field(_, _) => elements
+                .iter()
+                .enumerate()
+                .map(|(i, f)| -> Option<&'tcx Expr<'tcx>> {
+                    let ExprKind::Field(lhs, ident) = f.kind else {
+                        return None;
+                    };
+                    (ident.name.as_str() == i.to_string()).then_some(lhs)
+                })
+                .collect::<Option<Vec<_>>>(),
+            ExprKind::Path(_) => Some(elements.iter().collect()),
+            _ => None,
+        })
+        && all_bindings_are_for_conv(cx, &[*ty], expr, elements, &locals, ToType::Array)
+        && !is_from_proc_macro(cx, expr)
+    {
+        span_lint_and_help(
+            cx,
+            TUPLE_ARRAY_CONVERSIONS,
+            expr.span,
+            "it looks like you're trying to convert a tuple to an array",
+            None,
+            "use `.into()` instead, or `<[T; N]>::from` if type annotations are needed",
+        );
+    }
+}
 
-            false
-        },
-    ) {
-        emit_lint(cx, expr, ToType::Array);
+fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
+    if let ty::Tuple(tys) = cx.typeck_results().expr_ty(expr).kind()
+        && let [first, ..] = elements
+        // Fix #11100
+        && tys.iter().all_equal()
+        && let Some(locals) = (match first.kind {
+            ExprKind::Index(_, _) => elements
+                .iter()
+                .enumerate()
+                .map(|(i, i_expr)| -> Option<&'tcx Expr<'tcx>> {
+                    if let ExprKind::Index(lhs, index) = i_expr.kind
+                        && let ExprKind::Lit(lit) = index.kind
+                        && let LitKind::Int(val, _) = lit.node
+                    {
+                        return (val == i as u128).then_some(lhs);
+                    };
+
+                    None
+                })
+                .collect::<Option<Vec<_>>>(),
+            ExprKind::Path(_) => Some(elements.iter().collect()),
+            _ => None,
+        })
+        && all_bindings_are_for_conv(cx, tys, expr, elements, &locals, ToType::Tuple)
+        && !is_from_proc_macro(cx, expr)
+    {
+        span_lint_and_help(
+            cx,
+            TUPLE_ARRAY_CONVERSIONS,
+            expr.span,
+            "it looks like you're trying to convert an array to a tuple",
+            None,
+            "use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed",
+        );
     }
 }
 
-#[expect(
-    clippy::blocks_in_if_conditions,
-    reason = "not a FP, but this is much easier to understand"
-)]
+/// Checks that every binding in `elements` comes from the same parent `Pat` with the kind if there
+/// is a parent `Pat`. Returns false in any of the following cases:
+/// * `kind` does not match `pat.kind`
+/// * one or more elements in `elements` is not a binding
+/// * one or more bindings does not have the same parent `Pat`
+/// * one or more bindings are used after `expr`
+/// * the bindings do not all have the same type
 #[expect(clippy::cast_possible_truncation)]
-fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
-    if should_lint(cx, elements, Some, |(first_id, local)| {
-        if let Node::Pat(pat) = local
-                && let parent = parent_pat(cx, pat)
-                && parent.hir_id == first_id
-            {
-                return matches!(
-                    cx.typeck_results().pat_ty(parent).peel_refs().kind(),
-                    ty::Array(_, len) if len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len()
-                );
+fn all_bindings_are_for_conv<'tcx>(
+    cx: &LateContext<'tcx>,
+    final_tys: &[Ty<'tcx>],
+    expr: &Expr<'_>,
+    elements: &[Expr<'_>],
+    locals: &[&Expr<'_>],
+    kind: ToType,
+) -> bool {
+    let Some(locals) = locals.iter().map(|e| path_to_local(e)).collect::<Option<Vec<_>>>() else {
+        return false;
+    };
+    let Some(local_parents) = locals
+        .iter()
+        .map(|&l| cx.tcx.hir().find_parent(l))
+        .collect::<Option<Vec<_>>>()
+    else {
+        return false;
+    };
+
+    local_parents
+        .iter()
+        .map(|node| match node {
+            Node::Pat(pat) => kind.eq(&pat.kind).then_some(pat.hir_id),
+            Node::Local(l) => Some(l.hir_id),
+            _ => None,
+        })
+        .all_equal()
+        // Fix #11124, very convenient utils function! ❤️
+        && locals
+            .iter()
+            .all(|&l| for_each_local_use_after_expr(cx, l, expr.hir_id, |_| ControlFlow::Break::<()>(())).is_continue())
+        && local_parents.first().is_some_and(|node| {
+            let Some(ty) = match node {
+                Node::Pat(pat) => Some(pat.hir_id),
+                Node::Local(l) => Some(l.hir_id),
+                _ => None,
             }
-
-        false
-    }) || should_lint(
-        cx,
-        elements,
-        |(i, expr)| {
-            if let ExprKind::Index(path, index) = expr.kind
-                && let ExprKind::Lit(lit) = index.kind
-                && let LitKind::Int(val, _) = lit.node
-                && val as usize == i
-            {
-                return Some((i, path));
+            .map(|hir_id| cx.typeck_results().node_type(hir_id)) else {
+                return false;
             };
-
-            None
-        },
-        |(first_id, local)| {
-            if let Node::Pat(pat) = local
-                && let parent = parent_pat(cx, pat)
-                && parent.hir_id == first_id
-            {
-                return matches!(
-                    cx.typeck_results().pat_ty(parent).peel_refs().kind(),
-                    ty::Array(_, len) if len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len()
-                );
+            match (kind, ty.kind()) {
+                // Ensure the final type and the original type have the same length, and that there
+                // is no implicit `&mut`<=>`&` anywhere (#11100). Bit ugly, I know, but it works.
+                (ToType::Array, ty::Tuple(tys)) => {
+                    tys.len() == elements.len() && tys.iter().chain(final_tys.iter().copied()).all_equal()
+                },
+                (ToType::Tuple, ty::Array(ty, len)) => {
+                    len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len()
+                        && final_tys.iter().chain(once(ty)).all_equal()
+                },
+                _ => false,
             }
-
-            false
-        },
-    ) {
-        emit_lint(cx, expr, ToType::Tuple);
-    }
-}
-
-/// Walks up the `Pat` until it's reached the final containing `Pat`.
-fn parent_pat<'tcx>(cx: &LateContext<'tcx>, start: &'tcx Pat<'tcx>) -> &'tcx Pat<'tcx> {
-    let mut end = start;
-    for (_, node) in cx.tcx.hir().parent_iter(start.hir_id) {
-        if let Node::Pat(pat) = node {
-            end = pat;
-        } else {
-            break;
-        }
-    }
-    end
+        })
 }
 
 #[derive(Clone, Copy)]
@@ -173,61 +203,11 @@ enum ToType {
     Tuple,
 }
 
-impl ToType {
-    fn msg(self) -> &'static str {
-        match self {
-            ToType::Array => "it looks like you're trying to convert a tuple to an array",
-            ToType::Tuple => "it looks like you're trying to convert an array to a tuple",
-        }
-    }
-
-    fn help(self) -> &'static str {
+impl PartialEq<PatKind<'_>> for ToType {
+    fn eq(&self, other: &PatKind<'_>) -> bool {
         match self {
-            ToType::Array => "use `.into()` instead, or `<[T; N]>::from` if type annotations are needed",
-            ToType::Tuple => "use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed",
+            ToType::Array => matches!(other, PatKind::Tuple(_, _)),
+            ToType::Tuple => matches!(other, PatKind::Slice(_, _, _)),
         }
     }
 }
-
-fn emit_lint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, to_type: ToType) -> bool {
-    if !is_from_proc_macro(cx, expr) {
-        span_lint_and_help(
-            cx,
-            TUPLE_ARRAY_CONVERSIONS,
-            expr.span,
-            to_type.msg(),
-            None,
-            to_type.help(),
-        );
-
-        return true;
-    }
-
-    false
-}
-
-fn should_lint<'tcx>(
-    cx: &LateContext<'tcx>,
-    elements: &'tcx [Expr<'tcx>],
-    map: impl FnMut((usize, &'tcx Expr<'tcx>)) -> Option<(usize, &Expr<'_>)>,
-    predicate: impl FnMut((HirId, &Node<'tcx>)) -> bool,
-) -> bool {
-    if let Some(elements) = elements
-            .iter()
-            .enumerate()
-            .map(map)
-            .collect::<Option<Vec<_>>>()
-        && let Some(locals) = elements
-            .iter()
-            .map(|(_, element)| path_to_local(element).and_then(|local| cx.tcx.hir().find(local)))
-            .collect::<Option<Vec<_>>>()
-        && let [first, rest @ ..] = &*locals
-        && let Node::Pat(first_pat) = first
-        && let parent = parent_pat(cx, first_pat).hir_id
-        && rest.iter().chain(once(first)).map(|i| (parent, i)).all(predicate)
-    {
-        return true;
-    }
-
-    false
-}
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index 5e42cf7e4f3..bc7c3897a6e 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -1,11 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::is_def_id_trait_method;
+use rustc_hir::def::DefKind;
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, FnDecl, YieldSource};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::def_id::LocalDefId;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::{LocalDefId, LocalDefIdSet};
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -38,7 +39,24 @@ declare_clippy_lint! {
     "finds async functions with no await statements"
 }
 
-declare_lint_pass!(UnusedAsync => [UNUSED_ASYNC]);
+#[derive(Default)]
+pub struct UnusedAsync {
+    /// Keeps track of async functions used as values (i.e. path expressions to async functions that
+    /// are not immediately called)
+    async_fns_as_value: LocalDefIdSet,
+    /// Functions with unused `async`, linted post-crate after we've found all uses of local async
+    /// functions
+    unused_async_fns: Vec<UnusedAsyncFn>,
+}
+
+#[derive(Copy, Clone)]
+struct UnusedAsyncFn {
+    def_id: LocalDefId,
+    fn_span: Span,
+    await_in_async_block: Option<Span>,
+}
+
+impl_lint_pass!(UnusedAsync => [UNUSED_ASYNC]);
 
 struct AsyncFnVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
@@ -101,24 +119,70 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
             };
             walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), def_id);
             if !visitor.found_await {
-                span_lint_and_then(
-                    cx,
-                    UNUSED_ASYNC,
-                    span,
-                    "unused `async` for function with no await statements",
-                    |diag| {
-                        diag.help("consider removing the `async` from this function");
-
-                        if let Some(span) = visitor.await_in_async_block {
-                            diag.span_note(
-                                span,
-                                "`await` used in an async block, which does not require \
-                                the enclosing function to be `async`",
-                            );
-                        }
-                    },
-                );
+                // Don't lint just yet, but store the necessary information for later.
+                // The actual linting happens in `check_crate_post`, once we've found all
+                // uses of local async functions that do require asyncness to pass typeck
+                self.unused_async_fns.push(UnusedAsyncFn {
+                    await_in_async_block: visitor.await_in_async_block,
+                    fn_span: span,
+                    def_id,
+                });
             }
         }
     }
+
+    fn check_path(&mut self, cx: &LateContext<'tcx>, path: &rustc_hir::Path<'tcx>, hir_id: rustc_hir::HirId) {
+        fn is_node_func_call(node: Node<'_>, expected_receiver: Span) -> bool {
+            matches!(
+                node,
+                Node::Expr(Expr {
+                    kind: ExprKind::Call(Expr { span, .. }, _) | ExprKind::MethodCall(_, Expr { span, .. }, ..),
+                    ..
+                }) if *span == expected_receiver
+            )
+        }
+
+        // Find paths to local async functions that aren't immediately called.
+        // E.g. `async fn f() {}; let x = f;`
+        // Depending on how `x` is used, f's asyncness might be required despite not having any `await`
+        // statements, so don't lint at all if there are any such paths.
+        if let Some(def_id) = path.res.opt_def_id()
+            && let Some(local_def_id) = def_id.as_local()
+            && let Some(DefKind::Fn) = cx.tcx.opt_def_kind(def_id)
+            && cx.tcx.asyncness(def_id).is_async()
+            && !is_node_func_call(cx.tcx.hir().get_parent(hir_id), path.span)
+        {
+            self.async_fns_as_value.insert(local_def_id);
+        }
+    }
+
+    // After collecting all unused `async` and problematic paths to such functions,
+    // lint those unused ones that didn't have any path expressions to them.
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        let iter = self
+            .unused_async_fns
+            .iter()
+            .filter(|UnusedAsyncFn { def_id, .. }| (!self.async_fns_as_value.contains(def_id)));
+
+        for fun in iter {
+            span_lint_hir_and_then(
+                cx,
+                UNUSED_ASYNC,
+                cx.tcx.local_def_id_to_hir_id(fun.def_id),
+                fun.fn_span,
+                "unused `async` for function with no await statements",
+                |diag| {
+                    diag.help("consider removing the `async` from this function");
+
+                    if let Some(span) = fun.await_in_async_block {
+                        diag.span_note(
+                            span,
+                            "`await` used in an async block, which does not require \
+                            the enclosing function to be `async`",
+                        );
+                    }
+                },
+            );
+        }
+    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 76654bfe536..58ae0656db7 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -551,6 +551,16 @@ define_Conf! {
     ///
     /// Whether to allow `r#""#` when `r""` can be used
     (allow_one_hash_in_raw_strings: bool = false),
+    /// Lint: ABSOLUTE_PATHS.
+    ///
+    /// The maximum number of segments a path can have before being linted, anything above this will
+    /// be linted.
+    (absolute_paths_max_segments: u64 = 2),
+    /// Lint: ABSOLUTE_PATHS.
+    ///
+    /// Which crates to allow absolute paths from
+    (absolute_paths_allowed_crates: rustc_data_structures::fx::FxHashSet<String> =
+        rustc_data_structures::fx::FxHashSet::default()),
 }
 
 /// Search for the configuration file.
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index fb08256931f..4fef8c0717d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -18,7 +18,7 @@ const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configura
 // ==================================================================
 // Configuration
 // ==================================================================
-#[derive(Debug, Clone, Default)] //~ ERROR no such field
+#[derive(Debug, Clone, Default)]
 pub struct ClippyConfiguration {
     pub name: String,
     #[allow(dead_code)]
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 357ac40b455..802adbd4d2d 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -138,6 +138,7 @@ impl<'hir> IfLet<'hir> {
 }
 
 /// An `if let` or `match` expression. Useful for lints that trigger on one or the other.
+#[derive(Debug)]
 pub enum IfLetOrMatch<'hir> {
     /// Any `match` expression
     Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource),
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index fb359ee3bbe..85b3b005f93 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -252,15 +252,15 @@ impl HirEqInterExpr<'_, '_, '_> {
             return false;
         }
 
-        if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results {
-            if let (Some(l), Some(r)) = (
+        if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results
+            && typeck_lhs.expr_ty(left) == typeck_rhs.expr_ty(right)
+            && let (Some(l), Some(r)) = (
                 constant_simple(self.inner.cx, typeck_lhs, left),
                 constant_simple(self.inner.cx, typeck_rhs, right),
-            ) {
-                if l == r {
-                    return true;
-                }
-            }
+            )
+            && l == r
+        {
+            return true;
         }
 
         let is_eq = match (
@@ -494,10 +494,13 @@ impl HirEqInterExpr<'_, '_, '_> {
             loop {
                 use TokenKind::{BlockComment, LineComment, Whitespace};
                 if left_data.macro_def_id != right_data.macro_def_id
-                    || (matches!(left_data.kind, ExpnKind::Macro(MacroKind::Bang, name) if name == sym::cfg)
-                        && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| {
-                            !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. })
-                        }))
+                    || (matches!(
+                        left_data.kind,
+                        ExpnKind::Macro(MacroKind::Bang, name)
+                        if name == sym::cfg || name == sym::option_env
+                    ) && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| {
+                        !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. })
+                    }))
                 {
                     // Either a different chain of macro calls, or different arguments to the `cfg` macro.
                     return false;
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 45b99df46b0..cf30930b76e 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -89,21 +89,21 @@ use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{
     self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr,
-    ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
-    MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
-    TraitItem, TraitItemRef, TraitRef, TyKind, UnOp,
+    ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item,
+    ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy,
+    QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::mir::ConstantKind;
-use rustc_middle::ty as rustc_ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::binding::BindingMode;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
-    BorrowKind, ClosureKind, FloatTy, IntTy, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UintTy, UpvarCapture,
+    self as rustc_ty, Binder, BorrowKind, ClosureKind, FloatTy, IntTy, ParamEnv, ParamEnvAnd, Ty, TyCtxt, TypeAndMut,
+    TypeVisitableExt, UintTy, UpvarCapture,
 };
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::SourceMap;
@@ -113,7 +113,10 @@ use rustc_target::abi::Integer;
 
 use crate::consts::{constant, miri_to_const, Constant};
 use crate::higher::Range;
-use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param};
+use crate::ty::{
+    adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
+    ty_is_fn_once_param,
+};
 use crate::visitors::for_each_expr;
 
 use rustc_middle::hir::nested_filter;
@@ -2445,6 +2448,17 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
         .any(is_cfg_test)
 }
 
+/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
+pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+    let hir = tcx.hir();
+
+    tcx.has_attr(def_id, sym::cfg)
+        || hir
+            .parent_iter(hir.local_def_id_to_hir_id(def_id))
+            .flat_map(|(parent_id, _)| hir.attrs(parent_id))
+            .any(|attr| attr.has_name(sym::cfg))
+}
+
 /// Checks whether item either has `test` attribute applied, or
 /// is a module with `test` in its name.
 ///
@@ -2499,6 +2513,262 @@ pub fn walk_to_expr_usage<'tcx, T>(
     None
 }
 
+/// A type definition as it would be viewed from within a function.
+#[derive(Clone, Copy)]
+pub enum DefinedTy<'tcx> {
+    // Used for locals and closures defined within the function.
+    Hir(&'tcx hir::Ty<'tcx>),
+    /// Used for function signatures, and constant and static values. This includes the `ParamEnv`
+    /// from the definition site.
+    Mir(ParamEnvAnd<'tcx, Binder<'tcx, Ty<'tcx>>>),
+}
+
+/// The context an expressions value is used in.
+pub struct ExprUseCtxt<'tcx> {
+    /// The parent node which consumes the value.
+    pub node: ExprUseNode<'tcx>,
+    /// Any adjustments applied to the type.
+    pub adjustments: &'tcx [Adjustment<'tcx>],
+    /// Whether or not the type must unify with another code path.
+    pub is_ty_unified: bool,
+    /// Whether or not the value will be moved before it's used.
+    pub moved_before_use: bool,
+}
+
+/// The node which consumes a value.
+pub enum ExprUseNode<'tcx> {
+    /// Assignment to, or initializer for, a local
+    Local(&'tcx Local<'tcx>),
+    /// Initializer for a const or static item.
+    ConstStatic(OwnerId),
+    /// Implicit or explicit return from a function.
+    Return(OwnerId),
+    /// Initialization of a struct field.
+    Field(&'tcx ExprField<'tcx>),
+    /// An argument to a function.
+    FnArg(&'tcx Expr<'tcx>, usize),
+    /// An argument to a method.
+    MethodArg(HirId, Option<&'tcx GenericArgs<'tcx>>, usize),
+    /// The callee of a function call.
+    Callee,
+    /// Access of a field.
+    FieldAccess(Ident),
+}
+impl<'tcx> ExprUseNode<'tcx> {
+    /// Checks if the value is returned from the function.
+    pub fn is_return(&self) -> bool {
+        matches!(self, Self::Return(_))
+    }
+
+    /// Checks if the value is used as a method call receiver.
+    pub fn is_recv(&self) -> bool {
+        matches!(self, Self::MethodArg(_, _, 0))
+    }
+
+    /// Gets the needed type as it's defined without any type inference.
+    pub fn defined_ty(&self, cx: &LateContext<'tcx>) -> Option<DefinedTy<'tcx>> {
+        match *self {
+            Self::Local(Local { ty: Some(ty), .. }) => Some(DefinedTy::Hir(ty)),
+            Self::ConstStatic(id) => Some(DefinedTy::Mir(
+                cx.param_env
+                    .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())),
+            )),
+            Self::Return(id) => {
+                let hir_id = cx.tcx.hir().local_def_id_to_hir_id(id.def_id);
+                if let Some(Node::Expr(Expr {
+                    kind: ExprKind::Closure(c),
+                    ..
+                })) = cx.tcx.hir().find(hir_id)
+                {
+                    match c.fn_decl.output {
+                        FnRetTy::DefaultReturn(_) => None,
+                        FnRetTy::Return(ty) => Some(DefinedTy::Hir(ty)),
+                    }
+                } else {
+                    Some(DefinedTy::Mir(
+                        cx.param_env.and(cx.tcx.fn_sig(id).instantiate_identity().output()),
+                    ))
+                }
+            },
+            Self::Field(field) => match get_parent_expr_for_hir(cx, field.hir_id) {
+                Some(Expr {
+                    hir_id,
+                    kind: ExprKind::Struct(path, ..),
+                    ..
+                }) => adt_and_variant_of_res(cx, cx.qpath_res(path, *hir_id))
+                    .and_then(|(adt, variant)| {
+                        variant
+                            .fields
+                            .iter()
+                            .find(|f| f.name == field.ident.name)
+                            .map(|f| (adt, f))
+                    })
+                    .map(|(adt, field_def)| {
+                        DefinedTy::Mir(
+                            cx.tcx
+                                .param_env(adt.did())
+                                .and(Binder::dummy(cx.tcx.type_of(field_def.did).instantiate_identity())),
+                        )
+                    }),
+                _ => None,
+            },
+            Self::FnArg(callee, i) => {
+                let sig = expr_sig(cx, callee)?;
+                let (hir_ty, ty) = sig.input_with_hir(i)?;
+                Some(match hir_ty {
+                    Some(hir_ty) => DefinedTy::Hir(hir_ty),
+                    None => DefinedTy::Mir(
+                        sig.predicates_id()
+                            .map_or(ParamEnv::empty(), |id| cx.tcx.param_env(id))
+                            .and(ty),
+                    ),
+                })
+            },
+            Self::MethodArg(id, _, i) => {
+                let id = cx.typeck_results().type_dependent_def_id(id)?;
+                let sig = cx.tcx.fn_sig(id).skip_binder();
+                Some(DefinedTy::Mir(cx.tcx.param_env(id).and(sig.input(i))))
+            },
+            Self::Local(_) | Self::FieldAccess(..) | Self::Callee => None,
+        }
+    }
+}
+
+/// Gets the context an expression's value is used in.
+#[expect(clippy::too_many_lines)]
+pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<ExprUseCtxt<'tcx>> {
+    let mut adjustments = [].as_slice();
+    let mut is_ty_unified = false;
+    let mut moved_before_use = false;
+    let ctxt = e.span.ctxt();
+    walk_to_expr_usage(cx, e, &mut |parent, child_id| {
+        // LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead.
+        if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) {
+            adjustments = cx.typeck_results().expr_adjustments(e);
+        }
+        match parent {
+            Node::Local(l) if l.span.ctxt() == ctxt => Some(ExprUseCtxt {
+                node: ExprUseNode::Local(l),
+                adjustments,
+                is_ty_unified,
+                moved_before_use,
+            }),
+            Node::Item(&Item {
+                kind: ItemKind::Static(..) | ItemKind::Const(..),
+                owner_id,
+                span,
+                ..
+            })
+            | Node::TraitItem(&TraitItem {
+                kind: TraitItemKind::Const(..),
+                owner_id,
+                span,
+                ..
+            })
+            | Node::ImplItem(&ImplItem {
+                kind: ImplItemKind::Const(..),
+                owner_id,
+                span,
+                ..
+            }) if span.ctxt() == ctxt => Some(ExprUseCtxt {
+                node: ExprUseNode::ConstStatic(owner_id),
+                adjustments,
+                is_ty_unified,
+                moved_before_use,
+            }),
+
+            Node::Item(&Item {
+                kind: ItemKind::Fn(..),
+                owner_id,
+                span,
+                ..
+            })
+            | Node::TraitItem(&TraitItem {
+                kind: TraitItemKind::Fn(..),
+                owner_id,
+                span,
+                ..
+            })
+            | Node::ImplItem(&ImplItem {
+                kind: ImplItemKind::Fn(..),
+                owner_id,
+                span,
+                ..
+            }) if span.ctxt() == ctxt => Some(ExprUseCtxt {
+                node: ExprUseNode::Return(owner_id),
+                adjustments,
+                is_ty_unified,
+                moved_before_use,
+            }),
+
+            Node::ExprField(field) if field.span.ctxt() == ctxt => Some(ExprUseCtxt {
+                node: ExprUseNode::Field(field),
+                adjustments,
+                is_ty_unified,
+                moved_before_use,
+            }),
+
+            Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
+                ExprKind::Ret(_) => Some(ExprUseCtxt {
+                    node: ExprUseNode::Return(OwnerId {
+                        def_id: cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
+                    }),
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::Closure(closure) => Some(ExprUseCtxt {
+                    node: ExprUseNode::Return(OwnerId { def_id: closure.def_id }),
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::Call(func, args) => Some(ExprUseCtxt {
+                    node: match args.iter().position(|arg| arg.hir_id == child_id) {
+                        Some(i) => ExprUseNode::FnArg(func, i),
+                        None => ExprUseNode::Callee,
+                    },
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::MethodCall(name, _, args, _) => Some(ExprUseCtxt {
+                    node: ExprUseNode::MethodArg(
+                        parent.hir_id,
+                        name.args,
+                        args.iter().position(|arg| arg.hir_id == child_id).map_or(0, |i| i + 1),
+                    ),
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(ExprUseCtxt {
+                    node: ExprUseNode::FieldAccess(name),
+                    adjustments,
+                    is_ty_unified,
+                    moved_before_use,
+                }),
+                ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id != child_id => {
+                    is_ty_unified = true;
+                    moved_before_use = true;
+                    None
+                },
+                ExprKind::Block(_, Some(_)) | ExprKind::Break(..) => {
+                    is_ty_unified = true;
+                    moved_before_use = true;
+                    None
+                },
+                ExprKind::Block(..) => {
+                    moved_before_use = true;
+                    None
+                },
+                _ => None,
+            },
+            _ => None,
+        }
+    })
+}
+
 /// Tokenizes the input while keeping the text associated with each token.
 pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str)> {
     let mut pos = 0;
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
index 8e7513d740a..da04266863f 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_origin.rs
@@ -44,7 +44,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'a, 'tcx> {
         let lhs = place.local;
         match rvalue {
             // Only consider `&mut`, which can modify origin place
-            mir::Rvalue::Ref(_, rustc_middle::mir::BorrowKind::Mut { .. }, borrowed) |
+            mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, borrowed) |
             // _2: &mut _;
             // _3 = move _2
             mir::Rvalue::Use(mir::Operand::Move(borrowed))  |
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index f3677e6f614..914ea85ac28 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -149,6 +149,7 @@ pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
 pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"];
 pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
 pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
+pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"];
 pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
 pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
 pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
@@ -161,3 +162,6 @@ pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
 pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
 pub const FORMATTER: [&str; 3] = ["core", "fmt", "Formatter"];
 pub const DEBUG_STRUCT: [&str; 4] = ["core", "fmt", "builders", "DebugStruct"];
+pub const ORD_CMP: [&str; 4] = ["core", "cmp", "Ord", "cmp"];
+#[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so
+pub const BOOL_THEN: [&str; 4] = ["core", "bool", "<impl bool>", "then"];
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index fd39a246f48..d0e15aa8bb3 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -3,6 +3,7 @@
 #![allow(clippy::module_name_repetitions)]
 
 use core::ops::ControlFlow;
+use itertools::Itertools;
 use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
@@ -13,21 +14,26 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
+use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
-    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, IntTy,
-    List, ParamEnv, Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
-    UintTy, VariantDef, VariantDiscr,
+    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
+    GenericParamDefKind, IntTy, List, ParamEnv, Region, RegionKind, ToPredicate, TraitRef, Ty, TyCtxt,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{Size, VariantIdx};
-use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
+use rustc_trait_selection::traits::{Obligation, ObligationCause};
 use std::iter;
 
 use crate::{match_def_path, path_res, paths};
 
+mod type_certainty;
+pub use type_certainty::expr_type_is_certain;
+
 /// Checks if the given type implements copy.
 pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
@@ -204,15 +210,9 @@ pub fn implements_trait<'tcx>(
     cx: &LateContext<'tcx>,
     ty: Ty<'tcx>,
     trait_id: DefId,
-    ty_params: &[GenericArg<'tcx>],
+    args: &[GenericArg<'tcx>],
 ) -> bool {
-    implements_trait_with_env(
-        cx.tcx,
-        cx.param_env,
-        ty,
-        trait_id,
-        ty_params.iter().map(|&arg| Some(arg)),
-    )
+    implements_trait_with_env_from_iter(cx.tcx, cx.param_env, ty, trait_id, args.iter().map(|&x| Some(x)))
 }
 
 /// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
@@ -221,7 +221,18 @@ pub fn implements_trait_with_env<'tcx>(
     param_env: ParamEnv<'tcx>,
     ty: Ty<'tcx>,
     trait_id: DefId,
-    ty_params: impl IntoIterator<Item = Option<GenericArg<'tcx>>>,
+    args: &[GenericArg<'tcx>],
+) -> bool {
+    implements_trait_with_env_from_iter(tcx, param_env, ty, trait_id, args.iter().map(|&x| Some(x)))
+}
+
+/// Same as `implements_trait_from_env` but takes the arguments as an iterator.
+pub fn implements_trait_with_env_from_iter<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+    trait_id: DefId,
+    args: impl IntoIterator<Item = impl Into<Option<GenericArg<'tcx>>>>,
 ) -> bool {
     // Clippy shouldn't have infer types
     assert!(!ty.has_infer());
@@ -230,19 +241,37 @@ pub fn implements_trait_with_env<'tcx>(
     if ty.has_escaping_bound_vars() {
         return false;
     }
+
     let infcx = tcx.infer_ctxt().build();
-    let orig = TypeVariableOrigin {
-        kind: TypeVariableOriginKind::MiscVariable,
-        span: DUMMY_SP,
-    };
-    let ty_params = tcx.mk_args_from_iter(
-        ty_params
+    let trait_ref = TraitRef::new(
+        tcx,
+        trait_id,
+        Some(GenericArg::from(ty))
             .into_iter()
-            .map(|arg| arg.unwrap_or_else(|| infcx.next_ty_var(orig).into())),
+            .chain(args.into_iter().map(|arg| {
+                arg.into().unwrap_or_else(|| {
+                    let orig = TypeVariableOrigin {
+                        kind: TypeVariableOriginKind::MiscVariable,
+                        span: DUMMY_SP,
+                    };
+                    infcx.next_ty_var(orig).into()
+                })
+            })),
     );
+
+    debug_assert_eq!(tcx.def_kind(trait_id), DefKind::Trait);
+    #[cfg(debug_assertions)]
+    assert_generic_args_match(tcx, trait_id, trait_ref.args);
+
+    let obligation = Obligation {
+        cause: ObligationCause::dummy(),
+        param_env,
+        recursion_depth: 0,
+        predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
+    };
     infcx
-        .type_implements_trait(trait_id, [ty.into()].into_iter().chain(ty_params), param_env)
-        .must_apply_modulo_regions()
+        .evaluate_obligation(&obligation)
+        .is_ok_and(EvaluationResult::must_apply_modulo_regions)
 }
 
 /// Checks whether this type implements `Drop`.
@@ -390,6 +419,11 @@ pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangI
     }
 }
 
+/// Gets the diagnostic name of the type, if it has one
+pub fn type_diagnostic_name(cx: &LateContext<'_>, ty: Ty<'_>) -> Option<Symbol> {
+    ty.ty_adt_def().and_then(|adt| cx.tcx.get_diagnostic_name(adt.did()))
+}
+
 /// Return `true` if the passed `typ` is `isize` or `usize`.
 pub fn is_isize_or_usize(typ: Ty<'_>) -> bool {
     matches!(typ.kind(), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize))
@@ -739,7 +773,11 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
     let mut output = None;
     let lang_items = cx.tcx.lang_items();
 
-    for (pred, _) in cx.tcx.explicit_item_bounds(ty.def_id).iter_instantiated_copied(cx.tcx, ty.args) {
+    for (pred, _) in cx
+        .tcx
+        .explicit_item_bounds(ty.def_id)
+        .iter_instantiated_copied(cx.tcx, ty.args)
+    {
         match pred.kind().skip_binder() {
             ty::ClauseKind::Trait(p)
                 if (lang_items.fn_trait() == Some(p.def_id())
@@ -1007,12 +1045,60 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 {
     }
 }
 
+/// Asserts that the given arguments match the generic parameters of the given item.
+#[allow(dead_code)]
+fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[GenericArg<'tcx>]) {
+    let g = tcx.generics_of(did);
+    let parent = g.parent.map(|did| tcx.generics_of(did));
+    let count = g.parent_count + g.params.len();
+    let params = parent
+        .map_or([].as_slice(), |p| p.params.as_slice())
+        .iter()
+        .chain(&g.params)
+        .map(|x| &x.kind);
+
+    assert!(
+        count == args.len(),
+        "wrong number of arguments for `{did:?}`: expected `{count}`, found {}\n\
+            note: the expected arguments are: `[{}]`\n\
+            the given arguments are: `{args:#?}`",
+        args.len(),
+        params.clone().map(GenericParamDefKind::descr).format(", "),
+    );
+
+    if let Some((idx, (param, arg))) =
+        params
+            .clone()
+            .zip(args.iter().map(|&x| x.unpack()))
+            .enumerate()
+            .find(|(_, (param, arg))| match (param, arg) {
+                (GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
+                | (GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
+                | (GenericParamDefKind::Const { .. }, GenericArgKind::Const(_)) => false,
+                (
+                    GenericParamDefKind::Lifetime
+                    | GenericParamDefKind::Type { .. }
+                    | GenericParamDefKind::Const { .. },
+                    _,
+                ) => true,
+            })
+    {
+        panic!(
+            "incorrect argument for `{did:?}` at index `{idx}`: expected a {}, found `{arg:?}`\n\
+                note: the expected arguments are `[{}]`\n\
+                the given arguments are `{args:#?}`",
+            param.descr(),
+            params.clone().map(GenericParamDefKind::descr).format(", "),
+        );
+    }
+}
+
 /// Makes the projection type for the named associated type in the given impl or trait impl.
 ///
 /// This function is for associated types which are "known" to exist, and as such, will only return
 /// `None` when debug assertions are disabled in order to prevent ICE's. With debug assertions
 /// enabled this will check that the named associated type exists, the correct number of
-/// substitutions are given, and that the correct kinds of substitutions are given (lifetime,
+/// arguments are given, and that the correct kinds of arguments are given (lifetime,
 /// constant or type). This will not check if type normalization would succeed.
 pub fn make_projection<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -1036,49 +1122,7 @@ pub fn make_projection<'tcx>(
             return None;
         };
         #[cfg(debug_assertions)]
-        {
-            let generics = tcx.generics_of(assoc_item.def_id);
-            let generic_count = generics.parent_count + generics.params.len();
-            let params = generics
-                .parent
-                .map_or([].as_slice(), |id| &*tcx.generics_of(id).params)
-                .iter()
-                .chain(&generics.params)
-                .map(|x| &x.kind);
-
-            debug_assert!(
-                generic_count == args.len(),
-                "wrong number of args for `{:?}`: found `{}` expected `{generic_count}`.\n\
-                    note: the expected parameters are: {:#?}\n\
-                    the given arguments are: `{args:#?}`",
-                assoc_item.def_id,
-                args.len(),
-                params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>(),
-            );
-
-            if let Some((idx, (param, arg))) = params
-                .clone()
-                .zip(args.iter().map(GenericArg::unpack))
-                .enumerate()
-                .find(|(_, (param, arg))| {
-                    !matches!(
-                        (param, arg),
-                        (ty::GenericParamDefKind::Lifetime, GenericArgKind::Lifetime(_))
-                            | (ty::GenericParamDefKind::Type { .. }, GenericArgKind::Type(_))
-                            | (ty::GenericParamDefKind::Const { .. }, GenericArgKind::Const(_))
-                    )
-                })
-            {
-                debug_assert!(
-                    false,
-                    "mismatched subst type at index {idx}: expected a {}, found `{arg:?}`\n\
-                        note: the expected parameters are {:#?}\n\
-                        the given arguments are {args:#?}",
-                    param.descr(),
-                    params.map(ty::GenericParamDefKind::descr).collect::<Vec<_>>()
-                );
-            }
-        }
+        assert_generic_args_match(tcx, assoc_item.def_id, args);
 
         Some(tcx.mk_alias_ty(assoc_item.def_id, args))
     }
@@ -1093,7 +1137,7 @@ pub fn make_projection<'tcx>(
 /// Normalizes the named associated type in the given impl or trait impl.
 ///
 /// This function is for associated types which are "known" to be valid with the given
-/// substitutions, and as such, will only return `None` when debug assertions are disabled in order
+/// arguments, and as such, will only return `None` when debug assertions are disabled in order
 /// to prevent ICE's. With debug assertions enabled this will check that type normalization
 /// succeeds as well as everything checked by `make_projection`.
 pub fn make_normalized_projection<'tcx>(
@@ -1105,17 +1149,12 @@ pub fn make_normalized_projection<'tcx>(
 ) -> Option<Ty<'tcx>> {
     fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
         #[cfg(debug_assertions)]
-        if let Some((i, subst)) = ty
-            .args
-            .iter()
-            .enumerate()
-            .find(|(_, subst)| subst.has_late_bound_regions())
-        {
+        if let Some((i, arg)) = ty.args.iter().enumerate().find(|(_, arg)| arg.has_late_bound_regions()) {
             debug_assert!(
                 false,
                 "args contain late-bound region at index `{i}` which can't be normalized.\n\
                     use `TyCtxt::erase_late_bound_regions`\n\
-                    note: subst is `{subst:#?}`",
+                    note: arg is `{arg:#?}`",
             );
             return None;
         }
@@ -1183,17 +1222,12 @@ pub fn make_normalized_projection_with_regions<'tcx>(
 ) -> Option<Ty<'tcx>> {
     fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
         #[cfg(debug_assertions)]
-        if let Some((i, subst)) = ty
-            .args
-            .iter()
-            .enumerate()
-            .find(|(_, subst)| subst.has_late_bound_regions())
-        {
+        if let Some((i, arg)) = ty.args.iter().enumerate().find(|(_, arg)| arg.has_late_bound_regions()) {
             debug_assert!(
                 false,
                 "args contain late-bound region at index `{i}` which can't be normalized.\n\
                     use `TyCtxt::erase_late_bound_regions`\n\
-                    note: subst is `{subst:#?}`",
+                    note: arg is `{arg:#?}`",
             );
             return None;
         }
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/certainty.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/certainty.rs
new file mode 100644
index 00000000000..0e69ffa2212
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/certainty.rs
@@ -0,0 +1,122 @@
+use rustc_hir::def_id::DefId;
+use std::fmt::Debug;
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum Certainty {
+    /// Determining the type requires contextual information.
+    Uncertain,
+
+    /// The type can be determined purely from subexpressions. If the argument is `Some(..)`, the
+    /// specific `DefId` is known. Such arguments are needed to handle path segments whose `res` is
+    /// `Res::Err`.
+    Certain(Option<DefId>),
+
+    /// The heuristic believes that more than one `DefId` applies to a type---this is a bug.
+    Contradiction,
+}
+
+pub trait Meet {
+    fn meet(self, other: Self) -> Self;
+}
+
+pub trait TryJoin: Sized {
+    fn try_join(self, other: Self) -> Option<Self>;
+}
+
+impl Meet for Option<DefId> {
+    fn meet(self, other: Self) -> Self {
+        match (self, other) {
+            (None, _) | (_, None) => None,
+            (Some(lhs), Some(rhs)) => (lhs == rhs).then_some(lhs),
+        }
+    }
+}
+
+impl TryJoin for Option<DefId> {
+    fn try_join(self, other: Self) -> Option<Self> {
+        match (self, other) {
+            (Some(lhs), Some(rhs)) => (lhs == rhs).then_some(Some(lhs)),
+            (Some(def_id), _) | (_, Some(def_id)) => Some(Some(def_id)),
+            (None, None) => Some(None),
+        }
+    }
+}
+
+impl Meet for Certainty {
+    fn meet(self, other: Self) -> Self {
+        match (self, other) {
+            (Certainty::Uncertain, _) | (_, Certainty::Uncertain) => Certainty::Uncertain,
+            (Certainty::Certain(lhs), Certainty::Certain(rhs)) => Certainty::Certain(lhs.meet(rhs)),
+            (Certainty::Certain(inner), _) | (_, Certainty::Certain(inner)) => Certainty::Certain(inner),
+            (Certainty::Contradiction, Certainty::Contradiction) => Certainty::Contradiction,
+        }
+    }
+}
+
+impl Certainty {
+    /// Join two `Certainty`s preserving their `DefId`s (if any). Generally speaking, this method
+    /// should be used only when `self` and `other` refer directly to types. Otherwise,
+    /// `join_clearing_def_ids` should be used.
+    pub fn join(self, other: Self) -> Self {
+        match (self, other) {
+            (Certainty::Contradiction, _) | (_, Certainty::Contradiction) => Certainty::Contradiction,
+
+            (Certainty::Certain(lhs), Certainty::Certain(rhs)) => {
+                if let Some(inner) = lhs.try_join(rhs) {
+                    Certainty::Certain(inner)
+                } else {
+                    debug_assert!(false, "Contradiction with {lhs:?} and {rhs:?}");
+                    Certainty::Contradiction
+                }
+            },
+
+            (Certainty::Certain(inner), _) | (_, Certainty::Certain(inner)) => Certainty::Certain(inner),
+
+            (Certainty::Uncertain, Certainty::Uncertain) => Certainty::Uncertain,
+        }
+    }
+
+    /// Join two `Certainty`s after clearing their `DefId`s. This method should be used when `self`
+    /// or `other` do not necessarily refer to types, e.g., when they are aggregations of other
+    /// `Certainty`s.
+    pub fn join_clearing_def_ids(self, other: Self) -> Self {
+        self.clear_def_id().join(other.clear_def_id())
+    }
+
+    pub fn clear_def_id(self) -> Certainty {
+        if matches!(self, Certainty::Certain(_)) {
+            Certainty::Certain(None)
+        } else {
+            self
+        }
+    }
+
+    pub fn with_def_id(self, def_id: DefId) -> Certainty {
+        if matches!(self, Certainty::Certain(_)) {
+            Certainty::Certain(Some(def_id))
+        } else {
+            self
+        }
+    }
+
+    pub fn to_def_id(self) -> Option<DefId> {
+        match self {
+            Certainty::Certain(inner) => inner,
+            _ => None,
+        }
+    }
+
+    pub fn is_certain(self) -> bool {
+        matches!(self, Self::Certain(_))
+    }
+}
+
+/// Think: `iter.all(/* is certain */)`
+pub fn meet(iter: impl Iterator<Item = Certainty>) -> Certainty {
+    iter.fold(Certainty::Certain(None), Certainty::meet)
+}
+
+/// Think: `iter.any(/* is certain */)`
+pub fn join(iter: impl Iterator<Item = Certainty>) -> Certainty {
+    iter.fold(Certainty::Uncertain, Certainty::join)
+}
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
new file mode 100644
index 00000000000..45b5483e323
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -0,0 +1,320 @@
+//! A heuristic to tell whether an expression's type can be determined purely from its
+//! subexpressions, and the arguments and locals they use. Put another way, `expr_type_is_certain`
+//! tries to tell whether an expression's type can be determined without appeal to the surrounding
+//! context.
+//!
+//! This is, in some sense, a counterpart to `let_unit_value`'s `expr_needs_inferred_result`.
+//! Intuitively, that function determines whether an expression's type is needed for type inference,
+//! whereas `expr_type_is_certain` determines whether type inference is needed for an expression's
+//! type.
+//!
+//! As a heuristic, `expr_type_is_certain` may produce false negatives, but a false positive should
+//! be considered a bug.
+
+use crate::def_path_res;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{walk_qpath, walk_ty, Visitor};
+use rustc_hir::{self as hir, Expr, ExprKind, GenericArgs, HirId, Node, PathSegment, QPath, TyKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, AdtDef, GenericArgKind, Ty};
+use rustc_span::{Span, Symbol};
+
+mod certainty;
+use certainty::{join, meet, Certainty, Meet};
+
+pub fn expr_type_is_certain(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    expr_type_certainty(cx, expr).is_certain()
+}
+
+fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
+    let certainty = match &expr.kind {
+        ExprKind::Unary(_, expr)
+        | ExprKind::Field(expr, _)
+        | ExprKind::Index(expr, _)
+        | ExprKind::AddrOf(_, _, expr) => expr_type_certainty(cx, expr),
+
+        ExprKind::Array(exprs) => join(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
+
+        ExprKind::Call(callee, args) => {
+            let lhs = expr_type_certainty(cx, callee);
+            let rhs = if type_is_inferrable_from_arguments(cx, expr) {
+                meet(args.iter().map(|arg| expr_type_certainty(cx, arg)))
+            } else {
+                Certainty::Uncertain
+            };
+            lhs.join_clearing_def_ids(rhs)
+        },
+
+        ExprKind::MethodCall(method, receiver, args, _) => {
+            let mut receiver_type_certainty = expr_type_certainty(cx, receiver);
+            // Even if `receiver_type_certainty` is `Certain(Some(..))`, the `Self` type in the method
+            // identified by `type_dependent_def_id(..)` can differ. This can happen as a result of a `deref`,
+            // for example. So update the `DefId` in `receiver_type_certainty` (if any).
+            if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                && let Some(self_ty_def_id) = adt_def_id(self_ty(cx, method_def_id))
+            {
+                receiver_type_certainty = receiver_type_certainty.with_def_id(self_ty_def_id);
+            };
+            let lhs = path_segment_certainty(cx, receiver_type_certainty, method, false);
+            let rhs = if type_is_inferrable_from_arguments(cx, expr) {
+                meet(
+                    std::iter::once(receiver_type_certainty).chain(args.iter().map(|arg| expr_type_certainty(cx, arg))),
+                )
+            } else {
+                Certainty::Uncertain
+            };
+            lhs.join(rhs)
+        },
+
+        ExprKind::Tup(exprs) => meet(exprs.iter().map(|expr| expr_type_certainty(cx, expr))),
+
+        ExprKind::Binary(_, lhs, rhs) => expr_type_certainty(cx, lhs).meet(expr_type_certainty(cx, rhs)),
+
+        ExprKind::Lit(_) => Certainty::Certain(None),
+
+        ExprKind::Cast(_, ty) => type_certainty(cx, ty),
+
+        ExprKind::If(_, if_expr, Some(else_expr)) => {
+            expr_type_certainty(cx, if_expr).join(expr_type_certainty(cx, else_expr))
+        },
+
+        ExprKind::Path(qpath) => qpath_certainty(cx, qpath, false),
+
+        ExprKind::Struct(qpath, _, _) => qpath_certainty(cx, qpath, true),
+
+        _ => Certainty::Uncertain,
+    };
+
+    let expr_ty = cx.typeck_results().expr_ty(expr);
+    if let Some(def_id) = adt_def_id(expr_ty) {
+        certainty.with_def_id(def_id)
+    } else {
+        certainty
+    }
+}
+
+struct CertaintyVisitor<'cx, 'tcx> {
+    cx: &'cx LateContext<'tcx>,
+    certainty: Certainty,
+}
+
+impl<'cx, 'tcx> CertaintyVisitor<'cx, 'tcx> {
+    fn new(cx: &'cx LateContext<'tcx>) -> Self {
+        Self {
+            cx,
+            certainty: Certainty::Certain(None),
+        }
+    }
+}
+
+impl<'cx, 'tcx> Visitor<'cx> for CertaintyVisitor<'cx, 'tcx> {
+    fn visit_qpath(&mut self, qpath: &'cx QPath<'_>, hir_id: HirId, _: Span) {
+        self.certainty = self.certainty.meet(qpath_certainty(self.cx, qpath, true));
+        if self.certainty != Certainty::Uncertain {
+            walk_qpath(self, qpath, hir_id);
+        }
+    }
+
+    fn visit_ty(&mut self, ty: &'cx hir::Ty<'_>) {
+        if matches!(ty.kind, TyKind::Infer) {
+            self.certainty = Certainty::Uncertain;
+        }
+        if self.certainty != Certainty::Uncertain {
+            walk_ty(self, ty);
+        }
+    }
+}
+
+fn type_certainty(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Certainty {
+    // Handle `TyKind::Path` specially so that its `DefId` can be preserved.
+    //
+    // Note that `CertaintyVisitor::new` initializes the visitor's internal certainty to
+    // `Certainty::Certain(None)`. Furthermore, if a `TyKind::Path` is encountered while traversing
+    // `ty`, the result of the call to `qpath_certainty` is combined with the visitor's internal
+    // certainty using `Certainty::meet`. Thus, if the `TyKind::Path` were not treated specially here,
+    // the resulting certainty would be `Certainty::Certain(None)`.
+    if let TyKind::Path(qpath) = &ty.kind {
+        return qpath_certainty(cx, qpath, true);
+    }
+
+    let mut visitor = CertaintyVisitor::new(cx);
+    visitor.visit_ty(ty);
+    visitor.certainty
+}
+
+fn generic_args_certainty(cx: &LateContext<'_>, args: &GenericArgs<'_>) -> Certainty {
+    let mut visitor = CertaintyVisitor::new(cx);
+    visitor.visit_generic_args(args);
+    visitor.certainty
+}
+
+/// Tries to tell whether a `QPath` resolves to something certain, e.g., whether all of its path
+/// segments generic arguments are are instantiated.
+///
+/// `qpath` could refer to either a type or a value. The heuristic never needs the `DefId` of a
+/// value. So `DefId`s are retained only when `resolves_to_type` is true.
+fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bool) -> Certainty {
+    let certainty = match qpath {
+        QPath::Resolved(ty, path) => {
+            let len = path.segments.len();
+            path.segments.iter().enumerate().fold(
+                ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty)),
+                |parent_certainty, (i, path_segment)| {
+                    path_segment_certainty(cx, parent_certainty, path_segment, i != len - 1 || resolves_to_type)
+                },
+            )
+        },
+
+        QPath::TypeRelative(ty, path_segment) => {
+            path_segment_certainty(cx, type_certainty(cx, ty), path_segment, resolves_to_type)
+        },
+
+        QPath::LangItem(lang_item, _, _) => {
+            cx.tcx
+                .lang_items()
+                .get(*lang_item)
+                .map_or(Certainty::Uncertain, |def_id| {
+                    let generics = cx.tcx.generics_of(def_id);
+                    if generics.parent_count == 0 && generics.params.is_empty() {
+                        Certainty::Certain(if resolves_to_type { Some(def_id) } else { None })
+                    } else {
+                        Certainty::Uncertain
+                    }
+                })
+        },
+    };
+    debug_assert!(resolves_to_type || certainty.to_def_id().is_none());
+    certainty
+}
+
+fn path_segment_certainty(
+    cx: &LateContext<'_>,
+    parent_certainty: Certainty,
+    path_segment: &PathSegment<'_>,
+    resolves_to_type: bool,
+) -> Certainty {
+    let certainty = match update_res(cx, parent_certainty, path_segment).unwrap_or(path_segment.res) {
+        // A definition's type is certain if it refers to something without generics (e.g., a crate or module, or
+        // an unparameterized type), or the generics are instantiated with arguments that are certain.
+        //
+        // If the parent is uncertain, then the current path segment must account for the parent's generic arguments.
+        // Consider the following examples, where the current path segment is `None`:
+        // - `Option::None`             // uncertain; parent (i.e., `Option`) is uncertain
+        // - `Option::<Vec<u64>>::None` // certain; parent (i.e., `Option::<..>`) is certain
+        // - `Option::None::<Vec<u64>>` // certain; parent (i.e., `Option`) is uncertain
+        Res::Def(_, def_id) => {
+            // Checking `res_generics_def_id(..)` before calling `generics_of` avoids an ICE.
+            if cx.tcx.res_generics_def_id(path_segment.res).is_some() {
+                let generics = cx.tcx.generics_of(def_id);
+                let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && generics.params.is_empty()
+                {
+                    Certainty::Certain(None)
+                } else {
+                    Certainty::Uncertain
+                };
+                let rhs = path_segment
+                    .args
+                    .map_or(Certainty::Uncertain, |args| generic_args_certainty(cx, args));
+                // See the comment preceding `qpath_certainty`. `def_id` could refer to a type or a value.
+                let certainty = lhs.join_clearing_def_ids(rhs);
+                if resolves_to_type {
+                    if cx.tcx.def_kind(def_id) == DefKind::TyAlias {
+                        adt_def_id(cx.tcx.type_of(def_id).instantiate_identity())
+                            .map_or(certainty, |def_id| certainty.with_def_id(def_id))
+                    } else {
+                        certainty.with_def_id(def_id)
+                    }
+                } else {
+                    certainty
+                }
+            } else {
+                Certainty::Certain(None)
+            }
+        },
+
+        Res::PrimTy(_) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::SelfCtor(_) => {
+            Certainty::Certain(None)
+        },
+
+        // `get_parent` because `hir_id` refers to a `Pat`, and we're interested in the node containing the `Pat`.
+        Res::Local(hir_id) => match cx.tcx.hir().get_parent(hir_id) {
+            // An argument's type is always certain.
+            Node::Param(..) => Certainty::Certain(None),
+            // A local's type is certain if its type annotation is certain or it has an initializer whose
+            // type is certain.
+            Node::Local(local) => {
+                let lhs = local.ty.map_or(Certainty::Uncertain, |ty| type_certainty(cx, ty));
+                let rhs = local
+                    .init
+                    .map_or(Certainty::Uncertain, |init| expr_type_certainty(cx, init));
+                let certainty = lhs.join(rhs);
+                if resolves_to_type {
+                    certainty
+                } else {
+                    certainty.clear_def_id()
+                }
+            },
+            _ => Certainty::Uncertain,
+        },
+
+        _ => Certainty::Uncertain,
+    };
+    debug_assert!(resolves_to_type || certainty.to_def_id().is_none());
+    certainty
+}
+
+/// For at least some `QPath::TypeRelative`, the path segment's `res` can be `Res::Err`.
+/// `update_res` tries to fix the resolution when `parent_certainty` is `Certain(Some(..))`.
+fn update_res(cx: &LateContext<'_>, parent_certainty: Certainty, path_segment: &PathSegment<'_>) -> Option<Res> {
+    if path_segment.res == Res::Err && let Some(def_id) = parent_certainty.to_def_id() {
+        let mut def_path = cx.get_def_path(def_id);
+        def_path.push(path_segment.ident.name);
+        let reses = def_path_res(cx, &def_path.iter().map(Symbol::as_str).collect::<Vec<_>>());
+        if let [res] = reses.as_slice() { Some(*res) } else { None }
+    } else {
+        None
+    }
+}
+
+#[allow(clippy::cast_possible_truncation)]
+fn type_is_inferrable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let Some(callee_def_id) = (match expr.kind {
+        ExprKind::Call(callee, _) => {
+            let callee_ty = cx.typeck_results().expr_ty(callee);
+            if let ty::FnDef(callee_def_id, _) = callee_ty.kind() {
+                Some(*callee_def_id)
+            } else {
+                None
+            }
+        },
+        ExprKind::MethodCall(_, _, _, _) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
+        _ => None,
+    }) else {
+        return false;
+    };
+
+    let generics = cx.tcx.generics_of(callee_def_id);
+    let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
+
+    // Check that all type parameters appear in the functions input types.
+    (0..(generics.parent_count + generics.params.len()) as u32).all(|index| {
+        fn_sig
+            .inputs()
+            .iter()
+            .any(|input_ty| contains_param(*input_ty.skip_binder(), index))
+    })
+}
+
+fn self_ty<'tcx>(cx: &LateContext<'tcx>, method_def_id: DefId) -> Ty<'tcx> {
+    cx.tcx.fn_sig(method_def_id).skip_binder().inputs().skip_binder()[0]
+}
+
+fn adt_def_id(ty: Ty<'_>) -> Option<DefId> {
+    ty.peel_refs().ty_adt_def().map(AdtDef::did)
+}
+
+fn contains_param(ty: Ty<'_>, index: u32) -> bool {
+    ty.walk()
+        .any(|arg| matches!(arg.unpack(), GenericArgKind::Type(ty) if ty.is_param(index)))
+}
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 20993398d1b..39ef76348d7 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -1,14 +1,15 @@
-use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend};
+use crate::visitors::{for_each_expr, for_each_expr_with_closures, Descend, Visitable};
+use crate::{self as utils, get_enclosing_loop_or_multi_call_closure};
 use core::ops::ControlFlow;
+use hir::def::Res;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, Node};
+use rustc_hir::{self as hir, Expr, ExprKind, HirId, HirIdSet};
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty;
-use {crate as utils, rustc_hir as hir};
 
 /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
 pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> Option<HirIdSet> {
@@ -127,7 +128,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
     }
 
     fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
-        if let hir::def::Res::Local(id) = path.res {
+        if let Res::Local(id) = path.res {
             if self.binding_ids.contains(&id) {
                 self.usage_found = true;
             }
@@ -153,6 +154,17 @@ pub fn contains_return_break_continue_macro(expression: &Expr<'_>) -> bool {
     .is_some()
 }
 
+pub fn local_used_in<'tcx>(cx: &LateContext<'tcx>, local_id: HirId, v: impl Visitable<'tcx>) -> bool {
+    for_each_expr_with_closures(cx, v, |e| {
+        if utils::path_to_local_id(e, local_id) {
+            ControlFlow::Break(())
+        } else {
+            ControlFlow::Continue(())
+        }
+    })
+    .is_some()
+}
+
 pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr<'_>) -> bool {
     let Some(block) = utils::get_enclosing_block(cx, local_id) else {
         return false;
@@ -165,32 +177,21 @@ pub fn local_used_after_expr(cx: &LateContext<'_>, local_id: HirId, after: &Expr
     // let closure = || local;
     // closure();
     // closure();
-    let in_loop_or_closure = cx
-        .tcx
-        .hir()
-        .parent_iter(after.hir_id)
-        .take_while(|&(id, _)| id != block.hir_id)
-        .any(|(_, node)| {
-            matches!(
-                node,
-                Node::Expr(Expr {
-                    kind: ExprKind::Loop(..) | ExprKind::Closure { .. },
-                    ..
-                })
-            )
-        });
-    if in_loop_or_closure {
-        return true;
-    }
+    let loop_start = get_enclosing_loop_or_multi_call_closure(cx, after).map(|e| e.hir_id);
 
     let mut past_expr = false;
     for_each_expr_with_closures(cx, block, |e| {
-        if e.hir_id == after.hir_id {
+        if past_expr {
+            if utils::path_to_local_id(e, local_id) {
+                ControlFlow::Break(())
+            } else {
+                ControlFlow::Continue(Descend::Yes)
+            }
+        } else if e.hir_id == after.hir_id {
             past_expr = true;
             ControlFlow::Continue(Descend::No)
-        } else if past_expr && utils::path_to_local_id(e, local_id) {
-            ControlFlow::Break(())
         } else {
+            past_expr = Some(e.hir_id) == loop_start;
             ControlFlow::Continue(Descend::Yes)
         }
     })
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 8dafa723afa..09f447b27eb 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -52,6 +52,16 @@ pub trait Visitable<'tcx> {
     /// Calls the corresponding `visit_*` function on the visitor.
     fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
 }
+impl<'tcx, T> Visitable<'tcx> for &'tcx [T]
+where
+    &'tcx T: Visitable<'tcx>,
+{
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+        for x in self {
+            x.visit(visitor);
+        }
+    }
+}
 macro_rules! visitable_ref {
     ($t:ident, $f:ident) => {
         impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index b658101a10d..833608faff0 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-07-14"
+channel = "nightly-2023-07-28"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index ee17feed77a..1d89477dcc1 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -192,7 +192,7 @@ You can use tool lints to allow or deny lints from your code, eg.:
     );
 }
 
-const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";
+const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml";
 
 #[allow(clippy::too_many_lines)]
 pub fn main() {
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index cdc85cb33ca..26b655076cf 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -132,8 +132,7 @@ impl ClippyCmd {
         let clippy_args: String = self
             .clippy_args
             .iter()
-            .map(|arg| format!("{arg}__CLIPPY_HACKERY__"))
-            .collect();
+            .fold(String::new(), |s, arg| s + arg + "__CLIPPY_HACKERY__");
 
         // Currently, `CLIPPY_TERMINAL_WIDTH` is used only to format "unknown field" error messages.
         let terminal_width = termize::dimensions().map_or(0, |(w, _)| w);
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index f714b296233..385e25ce6b8 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -5,7 +5,7 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(unused_extern_crates)]
 
-use compiletest::{status_emitter, CommandBuilder};
+use compiletest::{status_emitter, CommandBuilder, OutputConflictHandling};
 use ui_test as compiletest;
 use ui_test::Mode as TestMode;
 
@@ -115,12 +115,12 @@ fn base_config(test_dir: &str) -> compiletest::Config {
         mode: TestMode::Yolo,
         stderr_filters: vec![],
         stdout_filters: vec![],
-        // FIXME(tgross35): deduplicate bless env once clippy can update
         output_conflict_handling: if var_os("RUSTC_BLESS").is_some_and(|v| v != "0")
-        || env::args().any(|arg| arg == "--bless") {
-            compiletest::OutputConflictHandling::Bless
+            || env::args().any(|arg| arg == "--bless")
+        {
+            OutputConflictHandling::Bless
         } else {
-            compiletest::OutputConflictHandling::Error("cargo test -- -- --bless".into())
+            OutputConflictHandling::Error("cargo uibless".into())
         },
         target: None,
         out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap_or("target".into())).join("ui_test"),
@@ -189,9 +189,6 @@ fn run_ui() {
                 .to_string()
         }),
     );
-    eprintln!("   Compiler: {}", config.program.display());
-
-    let name = config.root_dir.display().to_string();
 
     let test_filter = test_filter();
 
@@ -199,7 +196,7 @@ fn run_ui() {
         config,
         move |path| compiletest::default_file_filter(path) && test_filter(path),
         compiletest::default_per_file_config,
-        (status_emitter::Text, status_emitter::Gha::<true> { name }),
+        status_emitter::Text,
     )
     .unwrap();
     check_rustfix_coverage();
@@ -210,8 +207,19 @@ fn run_internal_tests() {
     if !RUN_INTERNAL_TESTS {
         return;
     }
-    let config = base_config("ui-internal");
-    compiletest::run_tests(config).unwrap();
+    let mut config = base_config("ui-internal");
+    if let OutputConflictHandling::Error(err) = &mut config.output_conflict_handling {
+        *err = "cargo uitest --features internal -- -- --bless".into();
+    }
+    let test_filter = test_filter();
+
+    compiletest::run_tests_generic(
+        config,
+        move |path| compiletest::default_file_filter(path) && test_filter(path),
+        compiletest::default_per_file_config,
+        status_emitter::Text,
+    )
+    .unwrap();
 }
 
 fn run_ui_toml() {
@@ -230,13 +238,11 @@ fn run_ui_toml() {
         "$$DIR",
     );
 
-    let name = config.root_dir.display().to_string();
-
     let test_filter = test_filter();
 
     ui_test::run_tests_generic(
         config,
-        |path| test_filter(path) && path.extension() == Some("rs".as_ref()),
+        |path| compiletest::default_file_filter(path) && test_filter(path),
         |config, path| {
             let mut config = config.clone();
             config
@@ -245,7 +251,7 @@ fn run_ui_toml() {
                 .push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into())));
             Some(config)
         },
-        (status_emitter::Text, status_emitter::Gha::<true> { name }),
+        status_emitter::Text,
     )
     .unwrap();
 }
@@ -286,8 +292,6 @@ fn run_ui_cargo() {
         "$$DIR",
     );
 
-    let name = config.root_dir.display().to_string();
-
     let test_filter = test_filter();
 
     ui_test::run_tests_generic(
@@ -298,7 +302,7 @@ fn run_ui_cargo() {
             config.out_dir = PathBuf::from("target/ui_test_cargo/").join(path.parent().unwrap());
             Some(config)
         },
-        (status_emitter::Text, status_emitter::Gha::<true> { name }),
+        status_emitter::Text,
     )
     .unwrap();
 }
diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs
index a771d8b87c8..031982edbe9 100644
--- a/src/tools/clippy/tests/integration.rs
+++ b/src/tools/clippy/tests/integration.rs
@@ -65,6 +65,30 @@ fn integration_test() {
         .expect("unable to run clippy");
 
     let stderr = String::from_utf8_lossy(&output.stderr);
+
+    // debug:
+    eprintln!("{stderr}");
+
+    // this is an internal test to make sure we would correctly panic on a delay_span_bug
+    if repo_name == "matthiaskrgr/clippy_ci_panic_test" {
+        // we need to kind of switch around our logic here:
+        // if we find a panic, everything is fine, if we don't panic, SOMETHING is broken about our testing
+
+        // the repo basically just contains a delay_span_bug that forces rustc/clippy to panic:
+        /*
+           #![feature(rustc_attrs)]
+           #[rustc_error(delay_span_bug_from_inside_query)]
+           fn main() {}
+        */
+
+        if stderr.find("error: internal compiler error").is_some() {
+            eprintln!("we saw that we intentionally panicked, yay");
+            return;
+        }
+
+        panic!("panic caused by delay_span_bug was NOT detected! Something is broken!");
+    }
+
     if let Some(backtrace_start) = stderr.find("error: internal compiler error") {
         static BACKTRACE_END_MSG: &str = "end of query stack";
         let backtrace_end = stderr[backtrace_start..]
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs
index 1a69bb24101..c67166fc4b0 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
 #![warn(clippy::cargo_common_metadata)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs
index 1a69bb24101..c67166fc4b0 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
 #![warn(clippy::cargo_common_metadata)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs
index 1a69bb24101..c67166fc4b0 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
 #![warn(clippy::cargo_common_metadata)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs
index 1a69bb24101..c67166fc4b0 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
 #![warn(clippy::cargo_common_metadata)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs
index 1a69bb24101..c67166fc4b0 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
 #![warn(clippy::cargo_common_metadata)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs
index 1a69bb24101..c67166fc4b0 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=cargo_common_metadata
 #![warn(clippy::cargo_common_metadata)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs
index 4dd9582aff8..74e40c09ebc 100644
--- a/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=feature_name
 #![warn(clippy::redundant_feature_names)]
 #![warn(clippy::negative_feature_names)]
 
diff --git a/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs
index 4dd9582aff8..74e40c09ebc 100644
--- a/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=feature_name
 #![warn(clippy::redundant_feature_names)]
 #![warn(clippy::negative_feature_names)]
 
diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
index c70d92e359e..ac21b3a4422 100644
--- a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs
@@ -1,3 +1,4 @@
+// FIXME: find a way to add rustflags to ui-cargo tests
 //@compile-flags: --remap-path-prefix {{src-base}}=/remapped
 
 #![warn(clippy::self_named_module_files)]
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs
index ece260b743d..4bc61dd6299 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=multiple_crate_versions
 #![warn(clippy::multiple_crate_versions)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs
index ece260b743d..4bc61dd6299 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=multiple_crate_versions
 #![warn(clippy::multiple_crate_versions)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs
index ece260b743d..4bc61dd6299 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=multiple_crate_versions
 #![warn(clippy::multiple_crate_versions)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs
index bb3a39d0720..3491ccb0d47 100644
--- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=wildcard_dependencies
 #![warn(clippy::wildcard_dependencies)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs
index bb3a39d0720..3491ccb0d47 100644
--- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs
@@ -1,4 +1,3 @@
-//@compile-flags: --crate-name=wildcard_dependencies
 #![warn(clippy::wildcard_dependencies)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index b88aeae2a9b..31df0ebd9fd 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -3,7 +3,7 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 error: the compiler unexpectedly panicked. this is a bug.
 
-note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new
+note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml
 
 note: rustc <version> running on <target>
 
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr
new file mode 100644
index 00000000000..a8900da4e6e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr
@@ -0,0 +1,28 @@
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:40:5
+   |
+LL |     std::f32::MAX;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::absolute-paths` implied by `-D warnings`
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:41:5
+   |
+LL |     core::f32::MAX;
+   |     ^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:42:5
+   |
+LL |     ::core::f32::MAX;
+   |     ^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:58:5
+   |
+LL |     ::std::f32::MAX;
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr
new file mode 100644
index 00000000000..41b70644be8
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.disallow_crates.stderr
@@ -0,0 +1,70 @@
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:40:5
+   |
+LL |     std::f32::MAX;
+   |     ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::absolute-paths` implied by `-D warnings`
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:41:5
+   |
+LL |     core::f32::MAX;
+   |     ^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:42:5
+   |
+LL |     ::core::f32::MAX;
+   |     ^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:43:5
+   |
+LL |     crate::a::b::c::C;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:44:5
+   |
+LL |     crate::a::b::c::d::e::f::F;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:45:5
+   |
+LL |     crate::a::A;
+   |     ^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:46:5
+   |
+LL |     crate::a::b::B;
+   |     ^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:47:5
+   |
+LL |     crate::a::b::c::C::ZERO;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:48:5
+   |
+LL |     helper::b::c::d::e::f();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:49:5
+   |
+LL |     ::helper::b::c::d::e::f();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: consider bringing this path into scope with the `use` keyword
+  --> $DIR/absolute_paths.rs:58:5
+   |
+LL |     ::std::f32::MAX;
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs
new file mode 100644
index 00000000000..d4c250a8ff2
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs
@@ -0,0 +1,97 @@
+//@aux-build:../../ui/auxiliary/proc_macros.rs:proc-macro
+//@aux-build:helper.rs
+//@revisions: allow_crates disallow_crates
+//@[allow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_crates
+//@[disallow_crates] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/disallow_crates
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::absolute_paths)]
+#![feature(decl_macro)]
+
+extern crate helper;
+#[macro_use]
+extern crate proc_macros;
+
+pub mod a {
+    pub mod b {
+        pub mod c {
+            pub struct C;
+
+            impl C {
+                pub const ZERO: u32 = 0;
+            }
+
+            pub mod d {
+                pub mod e {
+                    pub mod f {
+                        pub struct F;
+                    }
+                }
+            }
+        }
+
+        pub struct B;
+    }
+
+    pub struct A;
+}
+
+fn main() {
+    f32::max(1.0, 2.0);
+    std::f32::MAX;
+    core::f32::MAX;
+    ::core::f32::MAX;
+    crate::a::b::c::C;
+    crate::a::b::c::d::e::f::F;
+    crate::a::A;
+    crate::a::b::B;
+    crate::a::b::c::C::ZERO;
+    helper::b::c::d::e::f();
+    ::helper::b::c::d::e::f();
+    fn b() -> a::b::B {
+        todo!()
+    }
+    std::println!("a");
+    let x = 1;
+    std::ptr::addr_of!(x);
+    // Test we handle max segments with `PathRoot` properly; this has 4 segments but we should say it
+    // has 3
+    ::std::f32::MAX;
+    // Do not lint due to the above
+    ::helper::a();
+    // Do not lint
+    helper::a();
+    use crate::a::b::c::C;
+    use a::b;
+    use std::f32::MAX;
+    a::b::c::d::e::f::F;
+    b::c::C;
+    fn a() -> a::A {
+        todo!()
+    }
+    use a::b::c;
+
+    fn c() -> c::C {
+        todo!()
+    }
+    fn d() -> Result<(), ()> {
+        todo!()
+    }
+    external! {
+        crate::a::b::c::C::ZERO;
+    }
+    // For some reason, `path.span.from_expansion()` takes care of this for us
+    with_span! {
+        span
+        crate::a::b::c::C::ZERO;
+    }
+    macro_rules! local_crate {
+        () => {
+            crate::a::b::c::C::ZERO;
+        };
+    }
+    macro local_crate_2_0() {
+        crate::a::b::c::C::ZERO;
+    }
+    local_crate!();
+    local_crate_2_0!();
+}
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml b/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml
new file mode 100644
index 00000000000..59a621e9d1d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/allow_crates/clippy.toml
@@ -0,0 +1,2 @@
+absolute-paths-max-segments = 2
+absolute-paths-allowed-crates = ["crate", "helper"]
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs
new file mode 100644
index 00000000000..8e2678f5fe6
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/auxiliary/helper.rs
@@ -0,0 +1,11 @@
+pub fn a() {}
+
+pub mod b {
+    pub mod c {
+        pub mod d {
+            pub mod e {
+                pub fn f() {}
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml b/src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml
new file mode 100644
index 00000000000..d44d648c641
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/absolute_paths/disallow_crates/clippy.toml
@@ -0,0 +1 @@
+absolute-paths-max-segments = 2
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 6ba26e97730..cdabe6460cd 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,6 @@
 error: error reading Clippy's configuration file: unknown field `foobar`, expected one of
+           absolute-paths-allowed-crates
+           absolute-paths-max-segments
            accept-comment-above-attributes
            accept-comment-above-statement
            allow-dbg-in-tests
@@ -68,6 +70,8 @@ LL | foobar = 42
    | ^^^^^^
 
 error: error reading Clippy's configuration file: unknown field `barfoo`, expected one of
+           absolute-paths-allowed-crates
+           absolute-paths-max-segments
            accept-comment-above-attributes
            accept-comment-above-statement
            allow-dbg-in-tests
diff --git a/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs b/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs
index b6fcca0a791..2940c273255 100644
--- a/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs
+++ b/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs
@@ -1,6 +1,12 @@
+//@aux-build:proc_macros.rs:proc-macro
 #![warn(clippy::arc_with_non_send_sync)]
 #![allow(unused_variables)]
+
+#[macro_use]
+extern crate proc_macros;
+
 use std::cell::RefCell;
+use std::ptr::{null, null_mut};
 use std::sync::{Arc, Mutex};
 
 fn foo<T>(x: T) {
@@ -11,14 +17,32 @@ fn issue11076<T>() {
     let a: Arc<Vec<T>> = Arc::new(Vec::new());
 }
 
+fn issue11232() {
+    external! {
+        let a: Arc<*const u8> = Arc::new(null());
+        let a: Arc<*mut u8> = Arc::new(null_mut());
+    }
+    with_span! {
+        span
+        let a: Arc<*const u8> = Arc::new(null());
+        let a: Arc<*mut u8> = Arc::new(null_mut());
+    }
+}
+
 fn main() {
     let _ = Arc::new(42);
 
-    // !Sync
     let _ = Arc::new(RefCell::new(42));
+    //~^ ERROR: usage of an `Arc` that is not `Send` or `Sync`
+    //~| NOTE: the trait `Sync` is not implemented for `RefCell<i32>`
+
     let mutex = Mutex::new(1);
-    // !Send
     let _ = Arc::new(mutex.lock().unwrap());
-    // !Send + !Sync
+    //~^ ERROR: usage of an `Arc` that is not `Send` or `Sync`
+    //~| NOTE: the trait `Send` is not implemented for `MutexGuard<'_, i32>`
+
     let _ = Arc::new(&42 as *const i32);
+    //~^ ERROR: usage of an `Arc` that is not `Send` or `Sync`
+    //~| NOTE: the trait `Send` is not implemented for `*const i32`
+    //~| NOTE: the trait `Sync` is not implemented for `*const i32`
 }
diff --git a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr
index 7633b38dfb5..de3f2fb9e16 100644
--- a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr
+++ b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr
@@ -1,5 +1,5 @@
 error: usage of an `Arc` that is not `Send` or `Sync`
-  --> $DIR/arc_with_non_send_sync.rs:18:13
+  --> $DIR/arc_with_non_send_sync.rs:35:13
    |
 LL |     let _ = Arc::new(RefCell::new(42));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL |     let _ = Arc::new(RefCell::new(42));
    = note: `-D clippy::arc-with-non-send-sync` implied by `-D warnings`
 
 error: usage of an `Arc` that is not `Send` or `Sync`
-  --> $DIR/arc_with_non_send_sync.rs:21:13
+  --> $DIR/arc_with_non_send_sync.rs:40:13
    |
 LL |     let _ = Arc::new(mutex.lock().unwrap());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |     let _ = Arc::new(mutex.lock().unwrap());
    = help: consider using an `Rc` instead or wrapping the inner type with a `Mutex`
 
 error: usage of an `Arc` that is not `Send` or `Sync`
-  --> $DIR/arc_with_non_send_sync.rs:23:13
+  --> $DIR/arc_with_non_send_sync.rs:44:13
    |
 LL |     let _ = Arc::new(&42 as *const i32);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
index ed75acee8a2..2ac2fa22086 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
@@ -486,4 +486,11 @@ pub fn issue_11145() {
     x += 1;
 }
 
+pub fn issue_11262() {
+    let one = 1;
+    let zero = 0;
+    let _ = 2 / one;
+    let _ = 2 / zero;
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.fixed b/src/tools/clippy/tests/ui/comparison_to_empty.fixed
index c92dd509ebb..af219eed0b8 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.fixed
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.fixed
@@ -1,7 +1,8 @@
 //@run-rustfix
 
 #![warn(clippy::comparison_to_empty)]
-#![allow(clippy::useless_vec)]
+#![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
+#![feature(let_chains)]
 
 fn main() {
     // Disallow comparisons to empty
@@ -12,6 +13,11 @@ fn main() {
     let v = vec![0];
     let _ = v.is_empty();
     let _ = !v.is_empty();
+    if (*v).is_empty() {}
+    let s = [0].as_slice();
+    if s.is_empty() {}
+    if s.is_empty() {}
+    if s.is_empty() && s.is_empty() {}
 
     // Allow comparisons to non-empty
     let s = String::new();
@@ -21,4 +27,8 @@ fn main() {
     let v = vec![0];
     let _ = v == [0];
     let _ = v != [0];
+    if let [0] = &*v {}
+    let s = [0].as_slice();
+    if let [0] = s {}
+    if let [0] = &*s && s == [0] {}
 }
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.rs b/src/tools/clippy/tests/ui/comparison_to_empty.rs
index b3489714380..21e65184d50 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.rs
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.rs
@@ -1,7 +1,8 @@
 //@run-rustfix
 
 #![warn(clippy::comparison_to_empty)]
-#![allow(clippy::useless_vec)]
+#![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
+#![feature(let_chains)]
 
 fn main() {
     // Disallow comparisons to empty
@@ -12,6 +13,11 @@ fn main() {
     let v = vec![0];
     let _ = v == [];
     let _ = v != [];
+    if let [] = &*v {}
+    let s = [0].as_slice();
+    if let [] = s {}
+    if let [] = &*s {}
+    if let [] = &*s && s == [] {}
 
     // Allow comparisons to non-empty
     let s = String::new();
@@ -21,4 +27,8 @@ fn main() {
     let v = vec![0];
     let _ = v == [0];
     let _ = v != [0];
+    if let [0] = &*v {}
+    let s = [0].as_slice();
+    if let [0] = s {}
+    if let [0] = &*s && s == [0] {}
 }
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.stderr b/src/tools/clippy/tests/ui/comparison_to_empty.stderr
index cc09b17eb89..f29782ed80d 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.stderr
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.stderr
@@ -1,5 +1,5 @@
 error: comparison to empty slice
-  --> $DIR/comparison_to_empty.rs:9:13
+  --> $DIR/comparison_to_empty.rs:10:13
    |
 LL |     let _ = s == "";
    |             ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
@@ -7,22 +7,52 @@ LL |     let _ = s == "";
    = note: `-D clippy::comparison-to-empty` implied by `-D warnings`
 
 error: comparison to empty slice
-  --> $DIR/comparison_to_empty.rs:10:13
+  --> $DIR/comparison_to_empty.rs:11:13
    |
 LL |     let _ = s != "";
    |             ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()`
 
 error: comparison to empty slice
-  --> $DIR/comparison_to_empty.rs:13:13
+  --> $DIR/comparison_to_empty.rs:14:13
    |
 LL |     let _ = v == [];
    |             ^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()`
 
 error: comparison to empty slice
-  --> $DIR/comparison_to_empty.rs:14:13
+  --> $DIR/comparison_to_empty.rs:15:13
    |
 LL |     let _ = v != [];
    |             ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()`
 
-error: aborting due to 4 previous errors
+error: comparison to empty slice using `if let`
+  --> $DIR/comparison_to_empty.rs:16:8
+   |
+LL |     if let [] = &*v {}
+   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(*v).is_empty()`
+
+error: comparison to empty slice using `if let`
+  --> $DIR/comparison_to_empty.rs:18:8
+   |
+LL |     if let [] = s {}
+   |        ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice using `if let`
+  --> $DIR/comparison_to_empty.rs:19:8
+   |
+LL |     if let [] = &*s {}
+   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice using `if let`
+  --> $DIR/comparison_to_empty.rs:20:8
+   |
+LL |     if let [] = &*s && s == [] {}
+   |        ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: comparison to empty slice
+  --> $DIR/comparison_to_empty.rs:20:24
+   |
+LL |     if let [] = &*s && s == [] {}
+   |                        ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/error_impl_error.rs b/src/tools/clippy/tests/ui/error_impl_error.rs
new file mode 100644
index 00000000000..40ce4181bf3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/error_impl_error.rs
@@ -0,0 +1,90 @@
+#![allow(unused)]
+#![warn(clippy::error_impl_error)]
+#![no_main]
+
+pub mod a {
+    #[derive(Debug)]
+    pub struct Error;
+
+    impl std::fmt::Display for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for Error {}
+}
+
+mod b {
+    #[derive(Debug)]
+    pub(super) enum Error {}
+
+    impl std::fmt::Display for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for Error {}
+}
+
+pub mod c {
+    pub union Error {
+        a: u32,
+        b: u32,
+    }
+
+    impl std::fmt::Debug for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::fmt::Display for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for Error {}
+}
+
+pub mod d {
+    pub type Error = std::fmt::Error;
+}
+
+mod e {
+    #[derive(Debug)]
+    pub(super) struct MyError;
+
+    impl std::fmt::Display for MyError {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for MyError {}
+}
+
+pub mod f {
+    pub type MyError = std::fmt::Error;
+}
+
+// Do not lint module-private types
+
+mod g {
+    #[derive(Debug)]
+    enum Error {}
+
+    impl std::fmt::Display for Error {
+        fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            todo!()
+        }
+    }
+
+    impl std::error::Error for Error {}
+}
+
+mod h {
+    type Error = std::fmt::Error;
+}
diff --git a/src/tools/clippy/tests/ui/error_impl_error.stderr b/src/tools/clippy/tests/ui/error_impl_error.stderr
new file mode 100644
index 00000000000..f3e04b64167
--- /dev/null
+++ b/src/tools/clippy/tests/ui/error_impl_error.stderr
@@ -0,0 +1,45 @@
+error: exported type named `Error` that implements `Error`
+  --> $DIR/error_impl_error.rs:7:16
+   |
+LL |     pub struct Error;
+   |                ^^^^^
+   |
+note: `Error` was implemented here
+  --> $DIR/error_impl_error.rs:15:5
+   |
+LL |     impl std::error::Error for Error {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `-D clippy::error-impl-error` implied by `-D warnings`
+
+error: exported type named `Error` that implements `Error`
+  --> $DIR/error_impl_error.rs:20:21
+   |
+LL |     pub(super) enum Error {}
+   |                     ^^^^^
+   |
+note: `Error` was implemented here
+  --> $DIR/error_impl_error.rs:28:5
+   |
+LL |     impl std::error::Error for Error {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: exported type named `Error` that implements `Error`
+  --> $DIR/error_impl_error.rs:32:15
+   |
+LL |     pub union Error {
+   |               ^^^^^
+   |
+note: `Error` was implemented here
+  --> $DIR/error_impl_error.rs:49:5
+   |
+LL |     impl std::error::Error for Error {}
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: exported type alias named `Error` that implements `Error`
+  --> $DIR/error_impl_error.rs:53:14
+   |
+LL |     pub type Error = std::fmt::Error;
+   |              ^^^^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index db7bd99e0ae..ddabe7616d0 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -345,3 +345,58 @@ fn angle_brackets_and_args() {
     let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct);
     dyn_opt.map(<dyn TestTrait>::method_on_dyn);
 }
+
+fn _late_bound_to_early_bound_regions() {
+    struct Foo<'a>(&'a u32);
+    impl<'a> Foo<'a> {
+        fn f(x: &'a u32) -> Self {
+            Foo(x)
+        }
+    }
+    fn f(f: impl for<'a> Fn(&'a u32) -> Foo<'a>) -> Foo<'static> {
+        f(&0)
+    }
+
+    let _ = f(|x| Foo::f(x));
+
+    struct Bar;
+    impl<'a> From<&'a u32> for Bar {
+        fn from(x: &'a u32) -> Bar {
+            Bar
+        }
+    }
+    fn f2(f: impl for<'a> Fn(&'a u32) -> Bar) -> Bar {
+        f(&0)
+    }
+
+    let _ = f2(|x| <Bar>::from(x));
+
+    struct Baz<'a>(&'a u32);
+    fn f3(f: impl Fn(&u32) -> Baz<'_>) -> Baz<'static> {
+        f(&0)
+    }
+
+    let _ = f3(|x| Baz(x));
+}
+
+fn _mixed_late_bound_and_early_bound_regions() {
+    fn f<T>(t: T, f: impl Fn(T, &u32) -> u32) -> u32 {
+        f(t, &0)
+    }
+    fn f2<'a, T: 'a>(_: &'a T, y: &u32) -> u32 {
+        *y
+    }
+    let _ = f(&0, f2);
+}
+
+fn _closure_with_types() {
+    fn f<T>(x: T) -> T {
+        x
+    }
+    fn f2<T: Default>(f: impl Fn(T) -> T) -> T {
+        f(T::default())
+    }
+
+    let _ = f2(|x: u32| f(x));
+    let _ = f2(|x| -> u32 { f(x) });
+}
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index 52fc17686fd..92ecff6eb1a 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -345,3 +345,58 @@ fn angle_brackets_and_args() {
     let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct);
     dyn_opt.map(|d| d.method_on_dyn());
 }
+
+fn _late_bound_to_early_bound_regions() {
+    struct Foo<'a>(&'a u32);
+    impl<'a> Foo<'a> {
+        fn f(x: &'a u32) -> Self {
+            Foo(x)
+        }
+    }
+    fn f(f: impl for<'a> Fn(&'a u32) -> Foo<'a>) -> Foo<'static> {
+        f(&0)
+    }
+
+    let _ = f(|x| Foo::f(x));
+
+    struct Bar;
+    impl<'a> From<&'a u32> for Bar {
+        fn from(x: &'a u32) -> Bar {
+            Bar
+        }
+    }
+    fn f2(f: impl for<'a> Fn(&'a u32) -> Bar) -> Bar {
+        f(&0)
+    }
+
+    let _ = f2(|x| <Bar>::from(x));
+
+    struct Baz<'a>(&'a u32);
+    fn f3(f: impl Fn(&u32) -> Baz<'_>) -> Baz<'static> {
+        f(&0)
+    }
+
+    let _ = f3(|x| Baz(x));
+}
+
+fn _mixed_late_bound_and_early_bound_regions() {
+    fn f<T>(t: T, f: impl Fn(T, &u32) -> u32) -> u32 {
+        f(t, &0)
+    }
+    fn f2<'a, T: 'a>(_: &'a T, y: &u32) -> u32 {
+        *y
+    }
+    let _ = f(&0, |x, y| f2(x, y));
+}
+
+fn _closure_with_types() {
+    fn f<T>(x: T) -> T {
+        x
+    }
+    fn f2<T: Default>(f: impl Fn(T) -> T) -> T {
+        f(T::default())
+    }
+
+    let _ = f2(|x: u32| f(x));
+    let _ = f2(|x| -> u32 { f(x) });
+}
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index 0ac0b901df4..ff40a2074e5 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -158,5 +158,11 @@ error: redundant closure
 LL |     dyn_opt.map(|d| d.method_on_dyn());
    |                 ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn`
 
-error: aborting due to 26 previous errors
+error: redundant closure
+  --> $DIR/eta.rs:389:19
+   |
+LL |     let _ = f(&0, |x, y| f2(x, y));
+   |                   ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2`
+
+error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.fixed b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed
new file mode 100644
index 00000000000..3e72fee4b07
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed
@@ -0,0 +1,44 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+    clippy::clone_on_copy,
+    clippy::map_identity,
+    clippy::unnecessary_lazy_evaluations,
+    unused
+)]
+#![warn(clippy::filter_map_bool_then)]
+
+#[macro_use]
+extern crate proc_macros;
+
+#[derive(Clone, PartialEq)]
+struct NonCopy;
+
+fn main() {
+    let v = vec![1, 2, 3, 4, 5, 6];
+    v.clone().iter().filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+    v.clone().into_iter().filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+    v.clone()
+        .into_iter()
+        .filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+    v.clone()
+        .into_iter()
+        .filter(|&i| i != 1000)
+        .filter(|&i| (i % 2 == 0)).map(|i| i + 1);
+    v.iter()
+        .copied()
+        .filter(|&i| i != 1000)
+        .filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1);
+    // Do not lint
+    let v = vec![NonCopy, NonCopy];
+    v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i));
+    external! {
+        let v = vec![1, 2, 3, 4, 5, 6];
+        v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    }
+    with_span! {
+        span
+        let v = vec![1, 2, 3, 4, 5, 6];
+        v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    }
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.rs b/src/tools/clippy/tests/ui/filter_map_bool_then.rs
new file mode 100644
index 00000000000..38a04e57de4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.rs
@@ -0,0 +1,44 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+    clippy::clone_on_copy,
+    clippy::map_identity,
+    clippy::unnecessary_lazy_evaluations,
+    unused
+)]
+#![warn(clippy::filter_map_bool_then)]
+
+#[macro_use]
+extern crate proc_macros;
+
+#[derive(Clone, PartialEq)]
+struct NonCopy;
+
+fn main() {
+    let v = vec![1, 2, 3, 4, 5, 6];
+    v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    v.clone()
+        .into_iter()
+        .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) });
+    v.clone()
+        .into_iter()
+        .filter(|&i| i != 1000)
+        .filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    v.iter()
+        .copied()
+        .filter(|&i| i != 1000)
+        .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1));
+    // Do not lint
+    let v = vec![NonCopy, NonCopy];
+    v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i));
+    external! {
+        let v = vec![1, 2, 3, 4, 5, 6];
+        v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    }
+    with_span! {
+        span
+        let v = vec![1, 2, 3, 4, 5, 6];
+        v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+    }
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr
new file mode 100644
index 00000000000..b411cd83dfd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr
@@ -0,0 +1,34 @@
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:19:22
+   |
+LL |     v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+   |
+   = note: `-D clippy::filter-map-bool-then` implied by `-D warnings`
+
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:20:27
+   |
+LL |     v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1));
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:23:10
+   |
+LL |         .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) });
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:27:10
+   |
+LL |         .filter_map(|i| (i % 2 == 0).then(|| i + 1));
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)`
+
+error: usage of `bool::then` in `filter_map`
+  --> $DIR/filter_map_bool_then.rs:31:10
+   |
+LL |         .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1));
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1)`
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/format_collect.rs b/src/tools/clippy/tests/ui/format_collect.rs
new file mode 100644
index 00000000000..c7f2b7b6950
--- /dev/null
+++ b/src/tools/clippy/tests/ui/format_collect.rs
@@ -0,0 +1,31 @@
+#![allow(unused, dead_code)]
+#![warn(clippy::format_collect)]
+
+fn hex_encode(bytes: &[u8]) -> String {
+    bytes.iter().map(|b| format!("{b:02X}")).collect()
+}
+
+#[rustfmt::skip]
+fn hex_encode_deep(bytes: &[u8]) -> String {
+    bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect()
+}
+
+macro_rules! fmt {
+    ($x:ident) => {
+        format!("{x:02X}", x = $x)
+    };
+}
+
+fn from_macro(bytes: &[u8]) -> String {
+    bytes.iter().map(|x| fmt!(x)).collect()
+}
+
+fn with_block() -> String {
+    (1..10)
+        .map(|s| {
+            let y = 1;
+            format!("{s} {y}")
+        })
+        .collect()
+}
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/format_collect.stderr b/src/tools/clippy/tests/ui/format_collect.stderr
new file mode 100644
index 00000000000..d918f1ed466
--- /dev/null
+++ b/src/tools/clippy/tests/ui/format_collect.stderr
@@ -0,0 +1,62 @@
+error: use of `format!` to build up a string from an iterator
+  --> $DIR/format_collect.rs:5:5
+   |
+LL |     bytes.iter().map(|b| format!("{b:02X}")).collect()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: call `fold` instead
+  --> $DIR/format_collect.rs:5:18
+   |
+LL |     bytes.iter().map(|b| format!("{b:02X}")).collect()
+   |                  ^^^
+help: ... and use the `write!` macro here
+  --> $DIR/format_collect.rs:5:26
+   |
+LL |     bytes.iter().map(|b| format!("{b:02X}")).collect()
+   |                          ^^^^^^^^^^^^^^^^^^
+   = note: this can be written more efficiently by appending to a `String` directly
+   = note: `-D clippy::format-collect` implied by `-D warnings`
+
+error: use of `format!` to build up a string from an iterator
+  --> $DIR/format_collect.rs:10:5
+   |
+LL |     bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect()
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: call `fold` instead
+  --> $DIR/format_collect.rs:10:18
+   |
+LL |     bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect()
+   |                  ^^^
+help: ... and use the `write!` macro here
+  --> $DIR/format_collect.rs:10:32
+   |
+LL |     bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect()
+   |                                ^^^^^^^^^^^^^^^^^^
+   = note: this can be written more efficiently by appending to a `String` directly
+
+error: use of `format!` to build up a string from an iterator
+  --> $DIR/format_collect.rs:24:5
+   |
+LL | /     (1..10)
+LL | |         .map(|s| {
+LL | |             let y = 1;
+LL | |             format!("{s} {y}")
+LL | |         })
+LL | |         .collect()
+   | |__________________^
+   |
+help: call `fold` instead
+  --> $DIR/format_collect.rs:25:10
+   |
+LL |         .map(|s| {
+   |          ^^^
+help: ... and use the `write!` macro here
+  --> $DIR/format_collect.rs:27:13
+   |
+LL |             format!("{s} {y}")
+   |             ^^^^^^^^^^^^^^^^^^
+   = note: this can be written more efficiently by appending to a `String` directly
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.fixed b/src/tools/clippy/tests/ui/four_forward_slashes.fixed
new file mode 100644
index 00000000000..54b2c414b62
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes.fixed
@@ -0,0 +1,48 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
+#![warn(clippy::four_forward_slashes)]
+#![no_main]
+#![rustfmt::skip]
+
+#[macro_use]
+extern crate proc_macros;
+
+/// whoops
+fn a() {}
+
+/// whoops
+#[allow(dead_code)]
+fn b() {}
+
+/// whoops
+/// two borked comments!
+#[track_caller]
+fn c() {}
+
+fn d() {}
+
+#[test]
+/// between attributes
+#[allow(dead_code)]
+fn g() {}
+
+/// not very start of contents
+fn h() {}
+
+fn i() {
+    //// don't lint me bozo
+    todo!()
+}
+
+external! {
+    //// don't lint me bozo
+    fn e() {}
+}
+
+with_span! {
+    span
+    //// don't lint me bozo
+    fn f() {}
+}
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.rs b/src/tools/clippy/tests/ui/four_forward_slashes.rs
new file mode 100644
index 00000000000..facdc8cb17d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes.rs
@@ -0,0 +1,48 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
+#![warn(clippy::four_forward_slashes)]
+#![no_main]
+#![rustfmt::skip]
+
+#[macro_use]
+extern crate proc_macros;
+
+//// whoops
+fn a() {}
+
+//// whoops
+#[allow(dead_code)]
+fn b() {}
+
+//// whoops
+//// two borked comments!
+#[track_caller]
+fn c() {}
+
+fn d() {}
+
+#[test]
+//// between attributes
+#[allow(dead_code)]
+fn g() {}
+
+    //// not very start of contents
+fn h() {}
+
+fn i() {
+    //// don't lint me bozo
+    todo!()
+}
+
+external! {
+    //// don't lint me bozo
+    fn e() {}
+}
+
+with_span! {
+    span
+    //// don't lint me bozo
+    fn f() {}
+}
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.stderr b/src/tools/clippy/tests/ui/four_forward_slashes.stderr
new file mode 100644
index 00000000000..89162e6b010
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes.stderr
@@ -0,0 +1,68 @@
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+  --> $DIR/four_forward_slashes.rs:12:1
+   |
+LL | / //// whoops
+LL | | fn a() {}
+   | |_
+   |
+   = note: `-D clippy::four-forward-slashes` implied by `-D warnings`
+help: make this a doc comment by removing one `/`
+   |
+LL + /// whoops
+   |
+
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+  --> $DIR/four_forward_slashes.rs:15:1
+   |
+LL | / //// whoops
+LL | | #[allow(dead_code)]
+LL | | fn b() {}
+   | |_
+   |
+help: make this a doc comment by removing one `/`
+   |
+LL + /// whoops
+   |
+
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+  --> $DIR/four_forward_slashes.rs:19:1
+   |
+LL | / //// whoops
+LL | | //// two borked comments!
+LL | | #[track_caller]
+LL | | fn c() {}
+   | |_
+   |
+help: turn these into doc comments by removing one `/`
+   |
+LL + /// whoops
+LL ~ /// two borked comments!
+   |
+
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+  --> $DIR/four_forward_slashes.rs:27:1
+   |
+LL | / //// between attributes
+LL | | #[allow(dead_code)]
+LL | | fn g() {}
+   | |_
+   |
+help: make this a doc comment by removing one `/`
+   |
+LL + /// between attributes
+   |
+
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+  --> $DIR/four_forward_slashes.rs:31:1
+   |
+LL | /     //// not very start of contents
+LL | | fn h() {}
+   | |_
+   |
+help: make this a doc comment by removing one `/`
+   |
+LL + /// not very start of contents
+   |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed
new file mode 100644
index 00000000000..ce272b4c6cd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed
@@ -0,0 +1,7 @@
+/// borked doc comment on the first line. doesn't combust!
+fn a() {}
+
+//@run-rustfix
+// This test's entire purpose is to make sure we don't panic if the comment with four slashes
+// extends to the first line of the file. This is likely pretty rare in production, but an ICE is an
+// ICE.
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs
new file mode 100644
index 00000000000..d8f82d4410b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs
@@ -0,0 +1,7 @@
+//// borked doc comment on the first line. doesn't combust!
+fn a() {}
+
+//@run-rustfix
+// This test's entire purpose is to make sure we don't panic if the comment with four slashes
+// extends to the first line of the file. This is likely pretty rare in production, but an ICE is an
+// ICE.
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr
new file mode 100644
index 00000000000..7944da14feb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr
@@ -0,0 +1,15 @@
+error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't
+  --> $DIR/four_forward_slashes_first_line.rs:1:1
+   |
+LL | / //// borked doc comment on the first line. doesn't combust!
+LL | | fn a() {}
+   | |_
+   |
+   = note: `-D clippy::four-forward-slashes` implied by `-D warnings`
+help: make this a doc comment by removing one `/`
+   |
+LL + /// borked doc comment on the first line. doesn't combust!
+   |
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.rs b/src/tools/clippy/tests/ui/if_same_then_else.rs
index dad4543f84c..e84b20e9fef 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else.rs
+++ b/src/tools/clippy/tests/ui/if_same_then_else.rs
@@ -214,4 +214,45 @@ mod issue_8836 {
     }
 }
 
+mod issue_11213 {
+    fn reproducer(x: bool) -> bool {
+        if x {
+            0_u8.is_power_of_two()
+        } else {
+            0_u16.is_power_of_two()
+        }
+    }
+
+    // a more obvious reproducer that shows
+    // why the code above is problematic:
+    fn v2(x: bool) -> bool {
+        trait Helper {
+            fn is_u8(&self) -> bool;
+        }
+        impl Helper for u8 {
+            fn is_u8(&self) -> bool {
+                true
+            }
+        }
+        impl Helper for u16 {
+            fn is_u8(&self) -> bool {
+                false
+            }
+        }
+
+        // this is certainly not the same code in both branches
+        // it returns a different bool depending on the branch.
+        if x { 0_u8.is_u8() } else { 0_u16.is_u8() }
+    }
+
+    fn do_lint(x: bool) -> bool {
+        // but do lint if the type of the literal is the same
+        if x {
+            0_u8.is_power_of_two()
+        } else {
+            0_u8.is_power_of_two()
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.stderr b/src/tools/clippy/tests/ui/if_same_then_else.stderr
index a34fc565590..774cc08685a 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else.stderr
+++ b/src/tools/clippy/tests/ui/if_same_then_else.stderr
@@ -108,5 +108,23 @@ LL | |         bar + 1;
 LL | |     }
    | |_____^
 
-error: aborting due to 5 previous errors
+error: this `if` has identical blocks
+  --> $DIR/if_same_then_else.rs:250:14
+   |
+LL |           if x {
+   |  ______________^
+LL | |             0_u8.is_power_of_two()
+LL | |         } else {
+   | |_________^
+   |
+note: same as this
+  --> $DIR/if_same_then_else.rs:252:16
+   |
+LL |           } else {
+   |  ________________^
+LL | |             0_u8.is_power_of_two()
+LL | |         }
+   | |_________^
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.rs b/src/tools/clippy/tests/ui/ifs_same_cond.rs
index 5c338e3c5c8..ad77346b75f 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.rs
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.rs
@@ -46,6 +46,10 @@ fn ifs_same_cond() {
         // ok, functions
     } else if v.len() == 42 {
     }
+
+    if let Some(env1) = option_env!("ENV1") {
+    } else if let Some(env2) = option_env!("ENV2") {
+    }
 }
 
 fn issue10272() {
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.stderr b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
index 8d70934476c..3f52c10b762 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.stderr
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.stderr
@@ -36,13 +36,13 @@ LL |     if 2 * a == 1 {
    |        ^^^^^^^^^^
 
 error: this `if` has the same condition as a previous `if`
-  --> $DIR/ifs_same_cond.rs:54:15
+  --> $DIR/ifs_same_cond.rs:58:15
    |
 LL |     } else if a.contains("ah") {
    |               ^^^^^^^^^^^^^^^^
    |
 note: same as this
-  --> $DIR/ifs_same_cond.rs:53:8
+  --> $DIR/ifs_same_cond.rs:57:8
    |
 LL |     if a.contains("ah") {
    |        ^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed
index dd4fdd98822..2f51bf27480 100644
--- a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.fixed
@@ -1,5 +1,4 @@
 //@run-rustfix
-#![allow(unused)]
 #![no_main]
 
 use std::cmp::Ordering;
@@ -112,3 +111,35 @@ impl PartialOrd<u32> for F {
         todo!();
     }
 }
+
+// #11178, do not lint
+
+#[derive(Eq, PartialEq)]
+struct G(u32);
+
+impl Ord for G {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for G {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Self::cmp(self, other))
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct H(u32);
+
+impl Ord for H {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for H {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Ord::cmp(self, other))
+    }
+}
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs
index 522e82299c0..47127bdaec2 100644
--- a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.rs
@@ -1,5 +1,4 @@
 //@run-rustfix
-#![allow(unused)]
 #![no_main]
 
 use std::cmp::Ordering;
@@ -116,3 +115,35 @@ impl PartialOrd<u32> for F {
         todo!();
     }
 }
+
+// #11178, do not lint
+
+#[derive(Eq, PartialEq)]
+struct G(u32);
+
+impl Ord for G {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for G {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Self::cmp(self, other))
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct H(u32);
+
+impl Ord for H {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for H {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(Ord::cmp(self, other))
+    }
+}
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr
index 0e477798c40..66048fc9000 100644
--- a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type.stderr
@@ -1,5 +1,5 @@
 error: incorrect implementation of `partial_cmp` on an `Ord` type
-  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:18:1
+  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:17:1
    |
 LL | /  impl PartialOrd for A {
 LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
@@ -13,7 +13,7 @@ LL | |  }
    = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default
 
 error: incorrect implementation of `partial_cmp` on an `Ord` type
-  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:52:1
+  --> $DIR/incorrect_partial_ord_impl_on_ord_type.rs:51:1
    |
 LL | / impl PartialOrd for C {
 LL | |     fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs
new file mode 100644
index 00000000000..3a3b84f93c4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs
@@ -0,0 +1,51 @@
+// This test's filename is... a bit verbose. But it ensures we suggest the correct code when `Ord`
+// is not in scope.
+#![no_main]
+#![no_implicit_prelude]
+
+extern crate std;
+
+use std::cmp::{self, Eq, Ordering, PartialEq, PartialOrd};
+use std::option::Option::{self, Some};
+use std::todo;
+
+// lint
+
+#[derive(Eq, PartialEq)]
+struct A(u32);
+
+impl cmp::Ord for A {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for A {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        // NOTE: This suggestion is wrong, as `Ord` is not in scope. But this should be fine as it isn't
+        // automatically applied
+        todo!();
+    }
+}
+
+#[derive(Eq, PartialEq)]
+struct B(u32);
+
+impl B {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl cmp::Ord for B {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for B {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        // This calls `B.cmp`, not `Ord::cmp`!
+        Some(self.cmp(other))
+    }
+}
diff --git a/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr
new file mode 100644
index 00000000000..f4374c28128
--- /dev/null
+++ b/src/tools/clippy/tests/ui/incorrect_partial_ord_impl_on_ord_type_fully_qual.stderr
@@ -0,0 +1,31 @@
+error: incorrect implementation of `partial_cmp` on an `Ord` type
+  --> $DIR/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs:23:1
+   |
+LL | /  impl PartialOrd for A {
+LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+   | | _____________________________________________________________-
+LL | ||         // NOTE: This suggestion is wrong, as `Ord` is not in scope. But this should be fine as it isn't
+LL | ||         // automatically applied
+LL | ||         todo!();
+LL | ||     }
+   | ||_____- help: change this to: `{ Some(self.cmp(other)) }`
+LL | |  }
+   | |__^
+   |
+   = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default
+
+error: incorrect implementation of `partial_cmp` on an `Ord` type
+  --> $DIR/incorrect_partial_ord_impl_on_ord_type_fully_qual.rs:46:1
+   |
+LL | /  impl PartialOrd for B {
+LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+   | | _____________________________________________________________-
+LL | ||         // This calls `B.cmp`, not `Ord::cmp`!
+LL | ||         Some(self.cmp(other))
+LL | ||     }
+   | ||_____- help: change this to: `{ Some(std::cmp::Ord::cmp(self, other)) }`
+LL | |  }
+   | |__^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/infinite_loop.stderr b/src/tools/clippy/tests/ui/infinite_loop.stderr
index 701b3cd1904..04559f9ada4 100644
--- a/src/tools/clippy/tests/ui/infinite_loop.stderr
+++ b/src/tools/clippy/tests/ui/infinite_loop.stderr
@@ -1,11 +1,3 @@
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/infinite_loop.rs:7:17
-   |
-LL | fn fn_mutref(i: &mut i32) {
-   |                 ^^^^^^^^ help: consider changing to: `&i32`
-   |
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
 error: variables in the condition are not mutated in the loop body
   --> $DIR/infinite_loop.rs:20:11
    |
@@ -99,5 +91,13 @@ LL |     while y < 10 {
    = note: this loop contains `return`s or `break`s
    = help: rewrite it as `if cond { loop { } }`
 
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/infinite_loop.rs:7:17
+   |
+LL | fn fn_mutref(i: &mut i32) {
+   |                 ^^^^^^^^ help: consider changing to: `&i32`
+   |
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
 error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/inherent_to_string.rs b/src/tools/clippy/tests/ui/inherent_to_string.rs
index aeb0a0c1e2e..adb0389a043 100644
--- a/src/tools/clippy/tests/ui/inherent_to_string.rs
+++ b/src/tools/clippy/tests/ui/inherent_to_string.rs
@@ -1,5 +1,4 @@
-#![warn(clippy::inherent_to_string)]
-#![deny(clippy::inherent_to_string_shadow_display)]
+#![allow(improper_ctypes_definitions)]
 
 use std::fmt;
 
@@ -14,6 +13,9 @@ struct D;
 struct E;
 struct F;
 struct G;
+struct H;
+struct I;
+struct J;
 
 impl A {
     // Should be detected; emit warning
@@ -80,6 +82,26 @@ impl G {
     }
 }
 
+// Issue #11201
+
+impl H {
+    unsafe fn to_string(&self) -> String {
+        "G.to_string()".to_string()
+    }
+}
+
+impl I {
+    extern "C" fn to_string(&self) -> String {
+        "G.to_string()".to_string()
+    }
+}
+
+impl J {
+    unsafe extern "C" fn to_string(&self) -> String {
+        "G.to_string()".to_string()
+    }
+}
+
 fn main() {
     let a = A;
     a.to_string();
diff --git a/src/tools/clippy/tests/ui/inherent_to_string.stderr b/src/tools/clippy/tests/ui/inherent_to_string.stderr
index 443fecae1aa..579b3c8c56f 100644
--- a/src/tools/clippy/tests/ui/inherent_to_string.stderr
+++ b/src/tools/clippy/tests/ui/inherent_to_string.stderr
@@ -1,5 +1,5 @@
 error: implementation of inherent method `to_string(&self) -> String` for type `A`
-  --> $DIR/inherent_to_string.rs:20:5
+  --> $DIR/inherent_to_string.rs:22:5
    |
 LL | /     fn to_string(&self) -> String {
 LL | |         "A.to_string()".to_string()
@@ -10,7 +10,7 @@ LL | |     }
    = note: `-D clippy::inherent-to-string` implied by `-D warnings`
 
 error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`
-  --> $DIR/inherent_to_string.rs:44:5
+  --> $DIR/inherent_to_string.rs:46:5
    |
 LL | /     fn to_string(&self) -> String {
 LL | |         "C.to_string()".to_string()
@@ -18,11 +18,7 @@ LL | |     }
    | |_____^
    |
    = help: remove the inherent method from type `C`
-note: the lint level is defined here
-  --> $DIR/inherent_to_string.rs:2:9
-   |
-LL | #![deny(clippy::inherent_to_string_shadow_display)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: `#[deny(clippy::inherent_to_string_shadow_display)]` on by default
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.fixed b/src/tools/clippy/tests/ui/iter_skip_zero.fixed
new file mode 100644
index 00000000000..1eb0984fe07
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_skip_zero.fixed
@@ -0,0 +1,25 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::useless_vec, unused)]
+#![warn(clippy::iter_skip_zero)]
+
+#[macro_use]
+extern crate proc_macros;
+
+use std::iter::once;
+
+fn main() {
+    let _ = [1, 2, 3].iter().skip(1);
+    let _ = vec![1, 2, 3].iter().skip(1);
+    let _ = once([1, 2, 3]).skip(1);
+    let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(1)).skip(1);
+    // Don't lint
+    let _ = [1, 2, 3].iter().skip(1);
+    let _ = vec![1, 2, 3].iter().skip(1);
+    external! {
+        let _ = [1, 2, 3].iter().skip(0);
+    }
+    with_span! {
+        let _ = [1, 2, 3].iter().skip(0);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.rs b/src/tools/clippy/tests/ui/iter_skip_zero.rs
new file mode 100644
index 00000000000..8c103ab1d5b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_skip_zero.rs
@@ -0,0 +1,25 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::useless_vec, unused)]
+#![warn(clippy::iter_skip_zero)]
+
+#[macro_use]
+extern crate proc_macros;
+
+use std::iter::once;
+
+fn main() {
+    let _ = [1, 2, 3].iter().skip(0);
+    let _ = vec![1, 2, 3].iter().skip(0);
+    let _ = once([1, 2, 3]).skip(0);
+    let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0);
+    // Don't lint
+    let _ = [1, 2, 3].iter().skip(1);
+    let _ = vec![1, 2, 3].iter().skip(1);
+    external! {
+        let _ = [1, 2, 3].iter().skip(0);
+    }
+    with_span! {
+        let _ = [1, 2, 3].iter().skip(0);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.stderr b/src/tools/clippy/tests/ui/iter_skip_zero.stderr
new file mode 100644
index 00000000000..80fecd59e6d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_skip_zero.stderr
@@ -0,0 +1,43 @@
+error: usage of `.skip(0)`
+  --> $DIR/iter_skip_zero.rs:12:35
+   |
+LL |     let _ = [1, 2, 3].iter().skip(0);
+   |                                   ^ help: if you meant to skip the first element, use: `1`
+   |
+   = note: this call to `skip` does nothing and is useless; remove it
+   = note: `-D clippy::iter-skip-zero` implied by `-D warnings`
+
+error: usage of `.skip(0)`
+  --> $DIR/iter_skip_zero.rs:13:39
+   |
+LL |     let _ = vec![1, 2, 3].iter().skip(0);
+   |                                       ^ help: if you meant to skip the first element, use: `1`
+   |
+   = note: this call to `skip` does nothing and is useless; remove it
+
+error: usage of `.skip(0)`
+  --> $DIR/iter_skip_zero.rs:14:34
+   |
+LL |     let _ = once([1, 2, 3]).skip(0);
+   |                                  ^ help: if you meant to skip the first element, use: `1`
+   |
+   = note: this call to `skip` does nothing and is useless; remove it
+
+error: usage of `.skip(0)`
+  --> $DIR/iter_skip_zero.rs:15:71
+   |
+LL |     let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0);
+   |                                                                       ^ help: if you meant to skip the first element, use: `1`
+   |
+   = note: this call to `skip` does nothing and is useless; remove it
+
+error: usage of `.skip(0)`
+  --> $DIR/iter_skip_zero.rs:15:62
+   |
+LL |     let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0);
+   |                                                              ^ help: if you meant to skip the first element, use: `1`
+   |
+   = note: this call to `skip` does nothing and is useless; remove it
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/let_and_return.rs b/src/tools/clippy/tests/ui/let_and_return.rs
index 7e4d783a026..64665cc906f 100644
--- a/src/tools/clippy/tests/ui/let_and_return.rs
+++ b/src/tools/clippy/tests/ui/let_and_return.rs
@@ -169,4 +169,14 @@ mod issue_5729 {
     }
 }
 
+// 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 main() {}
diff --git a/src/tools/clippy/tests/ui/let_underscore_future.stderr b/src/tools/clippy/tests/ui/let_underscore_future.stderr
index 9e69fb04133..ff1e2b8c901 100644
--- a/src/tools/clippy/tests/ui/let_underscore_future.stderr
+++ b/src/tools/clippy/tests/ui/let_underscore_future.stderr
@@ -1,11 +1,3 @@
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/let_underscore_future.rs:11:35
-   |
-LL | fn do_something_to_future(future: &mut impl Future<Output = ()>) {}
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&impl Future<Output = ()>`
-   |
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
 error: non-binding `let` on a future
   --> $DIR/let_underscore_future.rs:14:5
    |
@@ -31,5 +23,13 @@ LL |     let _ = future;
    |
    = help: consider awaiting the future or dropping explicitly with `std::mem::drop`
 
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/let_underscore_future.rs:11:35
+   |
+LL | fn do_something_to_future(future: &mut impl Future<Output = ()>) {}
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&impl Future<Output = ()>`
+   |
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.fixed b/src/tools/clippy/tests/ui/manual_filter_map.fixed
index 9dd376df2b4..35872a39a71 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.fixed
+++ b/src/tools/clippy/tests/ui/manual_filter_map.fixed
@@ -120,3 +120,27 @@ fn issue_8920() {
         .iter()
         .filter_map(|f| f.result_field.to_owned().ok());
 }
+
+fn issue8010() {
+    #[derive(Clone)]
+    enum Enum {
+        A(i32),
+        B,
+    }
+
+    let iter = [Enum::A(123), Enum::B].into_iter();
+
+    let _x = iter.clone().filter_map(|x| match x { Enum::A(s) => Some(s), _ => None });
+    let _x = iter.clone().filter(|x| matches!(x, Enum::B)).map(|x| match x {
+        Enum::A(s) => s,
+        _ => unreachable!(),
+    });
+    let _x = iter
+        .clone()
+        .filter_map(|x| match x { Enum::A(s) => Some(s), _ => None });
+    #[allow(clippy::unused_unit)]
+    let _x = iter
+        .clone()
+        .filter(|x| matches!(x, Enum::B))
+        .map(|x| if let Enum::B = x { () } else { unreachable!() });
+}
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.rs b/src/tools/clippy/tests/ui/manual_filter_map.rs
index 6dd1e066aeb..50d8d2722c2 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.rs
+++ b/src/tools/clippy/tests/ui/manual_filter_map.rs
@@ -133,3 +133,31 @@ fn issue_8920() {
         .filter(|f| f.result_field.is_ok())
         .map(|f| f.result_field.to_owned().unwrap());
 }
+
+fn issue8010() {
+    #[derive(Clone)]
+    enum Enum {
+        A(i32),
+        B,
+    }
+
+    let iter = [Enum::A(123), Enum::B].into_iter();
+
+    let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x {
+        Enum::A(s) => s,
+        _ => unreachable!(),
+    });
+    let _x = iter.clone().filter(|x| matches!(x, Enum::B)).map(|x| match x {
+        Enum::A(s) => s,
+        _ => unreachable!(),
+    });
+    let _x = iter
+        .clone()
+        .filter(|x| matches!(x, Enum::A(_)))
+        .map(|x| if let Enum::A(s) = x { s } else { unreachable!() });
+    #[allow(clippy::unused_unit)]
+    let _x = iter
+        .clone()
+        .filter(|x| matches!(x, Enum::B))
+        .map(|x| if let Enum::B = x { () } else { unreachable!() });
+}
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.stderr b/src/tools/clippy/tests/ui/manual_filter_map.stderr
index 882468b0f5f..0e8672c0293 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.stderr
+++ b/src/tools/clippy/tests/ui/manual_filter_map.stderr
@@ -4,6 +4,11 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)`
 LL |     let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
    |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:9:30
+   |
+LL |     let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
+   |                              ^^^^^^^^^^
    = note: `-D clippy::manual-filter-map` implied by `-D warnings`
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
@@ -11,12 +16,24 @@ error: `filter(..).map(..)` can be simplified as `filter_map(..)`
    |
 LL |     let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:12:31
+   |
+LL |     let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
+   |                               ^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
   --> $DIR/manual_filter_map.rs:15:19
    |
 LL |     let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:15:31
+   |
+LL |     let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
+   |                               ^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
   --> $DIR/manual_filter_map.rs:18:10
@@ -25,6 +42,12 @@ LL |           .filter(|&x| to_ref(to_opt(x)).is_some())
    |  __________^
 LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:18:22
+   |
+LL |         .filter(|&x| to_ref(to_opt(x)).is_some())
+   |                      ^^^^^^^^^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
   --> $DIR/manual_filter_map.rs:21:10
@@ -33,6 +56,12 @@ LL |           .filter(|x| to_ref(to_opt(*x)).is_some())
    |  __________^
 LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:21:21
+   |
+LL |         .filter(|x| to_ref(to_opt(*x)).is_some())
+   |                     ^^^^^^^^^^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
   --> $DIR/manual_filter_map.rs:25:10
@@ -41,6 +70,12 @@ LL |           .filter(|&x| to_ref(to_res(x)).is_ok())
    |  __________^
 LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:25:22
+   |
+LL |         .filter(|&x| to_ref(to_res(x)).is_ok())
+   |                      ^^^^^^^^^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
   --> $DIR/manual_filter_map.rs:28:10
@@ -49,6 +84,12 @@ LL |           .filter(|x| to_ref(to_res(*x)).is_ok())
    |  __________^
 LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:28:21
+   |
+LL |         .filter(|x| to_ref(to_res(*x)).is_ok())
+   |                     ^^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_filter_map.rs:34:27
@@ -75,6 +116,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
    |
 LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:37:41
+   |
+LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
+   |                                         ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_filter_map.rs:39:30
@@ -117,6 +164,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
    |
 LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_filter_map.rs:45:45
+   |
+LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
+   |                                             ^^^^^^^^^
 
 error: `filter(..).map(..)` can be simplified as `filter_map(..)`
   --> $DIR/manual_filter_map.rs:93:10
@@ -190,5 +243,23 @@ LL |           .filter(|f| f.result_field.is_ok())
 LL | |         .map(|f| f.result_field.to_owned().unwrap());
    | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.to_owned().ok())`
 
-error: aborting due to 27 previous errors
+error: `filter(..).map(..)` can be simplified as `filter_map(..)`
+  --> $DIR/manual_filter_map.rs:146:27
+   |
+LL |       let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x {
+   |  ___________________________^
+LL | |         Enum::A(s) => s,
+LL | |         _ => unreachable!(),
+LL | |     });
+   | |______^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })`
+
+error: `filter(..).map(..)` can be simplified as `filter_map(..)`
+  --> $DIR/manual_filter_map.rs:156:10
+   |
+LL |           .filter(|x| matches!(x, Enum::A(_)))
+   |  __________^
+LL | |         .map(|x| if let Enum::A(s) = x { s } else { unreachable!() });
+   | |_____________________________________________________________________^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })`
+
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_find_map.stderr b/src/tools/clippy/tests/ui/manual_find_map.stderr
index 693a06bb559..4e52b5efacf 100644
--- a/src/tools/clippy/tests/ui/manual_find_map.stderr
+++ b/src/tools/clippy/tests/ui/manual_find_map.stderr
@@ -4,6 +4,11 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
 LL |     let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))`
    |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:9:28
+   |
+LL |     let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
+   |                            ^^^^^^^^^^
    = note: `-D clippy::manual-find-map` implied by `-D warnings`
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
@@ -11,12 +16,24 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
    |
 LL |     let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:12:29
+   |
+LL |     let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
+   |                             ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:15:19
    |
 LL |     let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:15:29
+   |
+LL |     let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
+   |                             ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:18:10
@@ -25,6 +42,12 @@ LL |           .find(|&x| to_ref(to_opt(x)).is_some())
    |  __________^
 LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:18:20
+   |
+LL |         .find(|&x| to_ref(to_opt(x)).is_some())
+   |                    ^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:21:10
@@ -33,6 +56,12 @@ LL |           .find(|x| to_ref(to_opt(*x)).is_some())
    |  __________^
 LL | |         .map(|y| to_ref(to_opt(y)).unwrap());
    | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:21:19
+   |
+LL |         .find(|x| to_ref(to_opt(*x)).is_some())
+   |                   ^^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:25:10
@@ -41,6 +70,12 @@ LL |           .find(|&x| to_ref(to_res(x)).is_ok())
    |  __________^
 LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:25:20
+   |
+LL |         .find(|&x| to_ref(to_res(x)).is_ok())
+   |                    ^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:28:10
@@ -49,6 +84,12 @@ LL |           .find(|x| to_ref(to_res(*x)).is_ok())
    |  __________^
 LL | |         .map(|y| to_ref(to_res(y)).unwrap());
    | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:28:19
+   |
+LL |         .find(|x| to_ref(to_res(*x)).is_ok())
+   |                   ^^^^^^^^^^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:34:26
@@ -91,6 +132,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
    |
 LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:40:41
+   |
+LL |     iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
+   |                                         ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:42:30
@@ -133,6 +180,12 @@ error: `find(..).map(..)` can be simplified as `find_map(..)`
    |
 LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())`
+   |
+note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
+  --> $DIR/manual_find_map.rs:48:45
+   |
+LL |     iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
+   |                                             ^^^^^^^^^
 
 error: `find(..).map(..)` can be simplified as `find_map(..)`
   --> $DIR/manual_find_map.rs:96:10
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
index 60f59066173..f19149cf9de 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed
@@ -5,7 +5,8 @@
     unreachable_patterns,
     dead_code,
     clippy::equatable_if_let,
-    clippy::needless_borrowed_reference
+    clippy::needless_borrowed_reference,
+    clippy::redundant_guards
 )]
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
index afdf1069f5e..8f4e58981ea 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs
@@ -5,7 +5,8 @@
     unreachable_patterns,
     dead_code,
     clippy::equatable_if_let,
-    clippy::needless_borrowed_reference
+    clippy::needless_borrowed_reference,
+    clippy::redundant_guards
 )]
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
index c8c1e5da05f..b57b26284ff 100644
--- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
+++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr
@@ -1,5 +1,5 @@
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:15:14
+  --> $DIR/match_expr_like_matches_macro.rs:16:14
    |
 LL |       let _y = match x {
    |  ______________^
@@ -11,7 +11,7 @@ LL | |     };
    = note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/match_expr_like_matches_macro.rs:21:14
+  --> $DIR/match_expr_like_matches_macro.rs:22:14
    |
 LL |       let _w = match x {
    |  ______________^
@@ -23,7 +23,7 @@ LL | |     };
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/match_expr_like_matches_macro.rs:27:14
+  --> $DIR/match_expr_like_matches_macro.rs:28:14
    |
 LL |       let _z = match x {
    |  ______________^
@@ -33,7 +33,7 @@ LL | |     };
    | |_____^ help: try: `x.is_none()`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:33:15
+  --> $DIR/match_expr_like_matches_macro.rs:34:15
    |
 LL |       let _zz = match x {
    |  _______________^
@@ -43,13 +43,13 @@ LL | |     };
    | |_____^ help: try: `!matches!(x, Some(r) if r == 0)`
 
 error: if let .. else expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:39:16
+  --> $DIR/match_expr_like_matches_macro.rs:40:16
    |
 LL |     let _zzz = if let Some(5) = x { true } else { false };
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(x, Some(5))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:63:20
+  --> $DIR/match_expr_like_matches_macro.rs:64:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -60,7 +60,7 @@ LL | |         };
    | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:73:20
+  --> $DIR/match_expr_like_matches_macro.rs:74:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -73,7 +73,7 @@ LL | |         };
    | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:83:20
+  --> $DIR/match_expr_like_matches_macro.rs:84:20
    |
 LL |           let _ans = match x {
    |  ____________________^
@@ -84,7 +84,7 @@ LL | |         };
    | |_________^ help: try: `!matches!(x, E::B(_) | E::C)`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:143:18
+  --> $DIR/match_expr_like_matches_macro.rs:144:18
    |
 LL |           let _z = match &z {
    |  __________________^
@@ -94,7 +94,7 @@ LL | |         };
    | |_________^ help: try: `matches!(z, Some(3))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:152:18
+  --> $DIR/match_expr_like_matches_macro.rs:153:18
    |
 LL |           let _z = match &z {
    |  __________________^
@@ -104,7 +104,7 @@ LL | |         };
    | |_________^ help: try: `matches!(&z, Some(3))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:169:21
+  --> $DIR/match_expr_like_matches_macro.rs:170:21
    |
 LL |               let _ = match &z {
    |  _____________________^
@@ -114,7 +114,7 @@ LL | |             };
    | |_____________^ help: try: `matches!(&z, AnEnum::X)`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:183:20
+  --> $DIR/match_expr_like_matches_macro.rs:184:20
    |
 LL |           let _res = match &val {
    |  ____________________^
@@ -124,7 +124,7 @@ LL | |         };
    | |_________^ help: try: `matches!(&val, &Some(ref _a))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:195:20
+  --> $DIR/match_expr_like_matches_macro.rs:196:20
    |
 LL |           let _res = match &val {
    |  ____________________^
@@ -134,7 +134,7 @@ LL | |         };
    | |_________^ help: try: `matches!(&val, &Some(ref _a))`
 
 error: match expression looks like `matches!` macro
-  --> $DIR/match_expr_like_matches_macro.rs:253:14
+  --> $DIR/match_expr_like_matches_macro.rs:254:14
    |
 LL |       let _y = match Some(5) {
    |  ______________^
diff --git a/src/tools/clippy/tests/ui/min_ident_chars.rs b/src/tools/clippy/tests/ui/min_ident_chars.rs
index 0fab224a29d..03784442e2c 100644
--- a/src/tools/clippy/tests/ui/min_ident_chars.rs
+++ b/src/tools/clippy/tests/ui/min_ident_chars.rs
@@ -81,3 +81,7 @@ fn b() {}
 fn wrong_pythagoras(a: f32, b: f32) -> f32 {
     a * a + a * b
 }
+
+mod issue_11163 {
+    struct Array<T, const N: usize>([T; N]);
+}
diff --git a/src/tools/clippy/tests/ui/mut_key.stderr b/src/tools/clippy/tests/ui/mut_key.stderr
index 02a0da86a4b..3f756f5f0e5 100644
--- a/src/tools/clippy/tests/ui/mut_key.stderr
+++ b/src/tools/clippy/tests/ui/mut_key.stderr
@@ -12,14 +12,6 @@ error: mutable key type
 LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
    |                                                                        ^^^^^^^^^^^^
 
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/mut_key.rs:31:32
-   |
-LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&HashMap<Key, usize>`
-   |
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
 error: mutable key type
   --> $DIR/mut_key.rs:32:5
    |
@@ -110,5 +102,13 @@ error: mutable key type
 LL |     let _map = HashMap::<Arc<Cell<usize>>, usize>::new();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/mut_key.rs:31:32
+   |
+LL | fn should_not_take_this_arg(m: &mut HashMap<Key, usize>, _n: usize) -> HashSet<Key> {
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&HashMap<Key, usize>`
+   |
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
 error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/mut_reference.stderr b/src/tools/clippy/tests/ui/mut_reference.stderr
index 23c812475c2..1fdfbf9227e 100644
--- a/src/tools/clippy/tests/ui/mut_reference.stderr
+++ b/src/tools/clippy/tests/ui/mut_reference.stderr
@@ -1,17 +1,3 @@
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/mut_reference.rs:4:33
-   |
-LL | fn takes_a_mutable_reference(a: &mut i32) {}
-   |                                 ^^^^^^^^ help: consider changing to: `&i32`
-   |
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/mut_reference.rs:11:44
-   |
-LL |     fn takes_a_mutable_reference(&self, a: &mut i32) {}
-   |                                            ^^^^^^^^ help: consider changing to: `&i32`
-
 error: the function `takes_an_immutable_reference` doesn't need a mutable reference
   --> $DIR/mut_reference.rs:17:34
    |
@@ -32,5 +18,13 @@ error: the method `takes_an_immutable_reference` doesn't need a mutable referenc
 LL |     my_struct.takes_an_immutable_reference(&mut 42);
    |                                            ^^^^^^^
 
-error: aborting due to 5 previous errors
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/mut_reference.rs:11:44
+   |
+LL |     fn takes_a_mutable_reference(&self, a: &mut i32) {}
+   |                                            ^^^^^^^^ help: consider changing to: `&i32`
+   |
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
index 5e7280995c6..ae7b018d0e2 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
@@ -1,9 +1,10 @@
-#![allow(unused)]
+#![allow(clippy::if_same_then_else, clippy::no_effect)]
+#![feature(lint_reasons)]
 
 use std::ptr::NonNull;
 
-// Should only warn for `s`.
 fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
     *x += *b + s.len() as u32;
 }
 
@@ -27,8 +28,8 @@ fn foo5(s: &mut Vec<u32>) {
     foo2(s);
 }
 
-// Should warn.
 fn foo6(s: &mut Vec<u32>) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
     non_mut_ref(s);
 }
 
@@ -40,13 +41,13 @@ impl Bar {
     // Should not warn on `&mut self`.
     fn bar(&mut self) {}
 
-    // Should warn about `vec`
     fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
+        //~^ ERROR: this argument is a mutable reference, but not used mutably
         vec.len()
     }
 
-    // Should warn about `vec` (and not `self`).
     fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
+        //~^ ERROR: this argument is a mutable reference, but not used mutably
         vec.len()
     }
 }
@@ -91,6 +92,110 @@ impl<T> Mut<T> {
 // Should not warn.
 fn unused(_: &mut u32, _b: &mut u8) {}
 
+// Should not warn.
+async fn f1(x: &mut i32) {
+    *x += 1;
+}
+// Should not warn.
+async fn f2(x: &mut i32, y: String) {
+    *x += 1;
+}
+// Should not warn.
+async fn f3(x: &mut i32, y: String, z: String) {
+    *x += 1;
+}
+// Should not warn.
+async fn f4(x: &mut i32, y: i32) {
+    *x += 1;
+}
+// Should not warn.
+async fn f5(x: i32, y: &mut i32) {
+    *y += 1;
+}
+// Should not warn.
+async fn f6(x: i32, y: &mut i32, z: &mut i32) {
+    *y += 1;
+    *z += 1;
+}
+// Should not warn.
+async fn f7(x: &mut i32, y: i32, z: &mut i32, a: i32) {
+    *x += 1;
+    *z += 1;
+}
+
+async fn a1(x: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a2(x: &mut i32, y: String) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a3(x: &mut i32, y: String, z: String) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a4(x: &mut i32, y: i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a5(x: i32, y: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a6(x: i32, y: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", x);
+}
+async fn a7(x: i32, y: i32, z: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", z);
+}
+async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    println!("{:?}", z);
+}
+
+// Should not warn (passed as closure which takes `&mut`).
+fn passed_as_closure(s: &mut u32) {}
+
+// Should not warn.
+fn passed_as_local(s: &mut u32) {}
+
+// Should not warn.
+fn ty_unify_1(s: &mut u32) {}
+
+// Should not warn.
+fn ty_unify_2(s: &mut u32) {}
+
+// Should not warn.
+fn passed_as_field(s: &mut u32) {}
+
+fn closure_takes_mut(s: fn(&mut u32)) {}
+
+struct A {
+    s: fn(&mut u32),
+}
+
+// Should warn.
+fn used_as_path(s: &mut u32) {}
+
+// Make sure lint attributes work fine
+#[expect(clippy::needless_pass_by_ref_mut)]
+fn lint_attr(s: &mut u32) {}
+
+#[cfg(not(feature = "a"))]
+fn cfg_warn(s: &mut u32) {}
+//~^ ERROR: this argument is a mutable reference, but not used mutably
+//~| NOTE: this is cfg-gated and may require further changes
+
+#[cfg(not(feature = "a"))]
+mod foo {
+    fn cfg_warn(s: &mut u32) {}
+    //~^ ERROR: this argument is a mutable reference, but not used mutably
+    //~| NOTE: this is cfg-gated and may require further changes
+}
+
 fn main() {
     let mut u = 0;
     let mut v = vec![0];
@@ -102,4 +207,9 @@ fn main() {
     alias_check(&mut v);
     alias_check2(&mut v);
     println!("{u}");
+    closure_takes_mut(passed_as_closure);
+    A { s: passed_as_field };
+    used_as_path;
+    let _: fn(&mut u32) = passed_as_local;
+    let _ = if v[0] == 0 { ty_unify_1 } else { ty_unify_2 };
 }
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
index 5e9d80bb6c4..0d426ce32f9 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
@@ -24,5 +24,75 @@ error: this argument is a mutable reference, but not used mutably
 LL |     fn badger(&mut self, vec: &mut Vec<i32>) -> usize {
    |                               ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
 
-error: aborting due to 4 previous errors
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:126:16
+   |
+LL | async fn a1(x: &mut i32) {
+   |                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:130:16
+   |
+LL | async fn a2(x: &mut i32, y: String) {
+   |                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:134:16
+   |
+LL | async fn a3(x: &mut i32, y: String, z: String) {
+   |                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:138:16
+   |
+LL | async fn a4(x: &mut i32, y: i32) {
+   |                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:142:24
+   |
+LL | async fn a5(x: i32, y: &mut i32) {
+   |                        ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:146:24
+   |
+LL | async fn a6(x: i32, y: &mut i32) {
+   |                        ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:150:32
+   |
+LL | async fn a7(x: i32, y: i32, z: &mut i32) {
+   |                                ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:154:24
+   |
+LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
+   |                        ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:154:45
+   |
+LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
+   |                                             ^^^^^^^^ help: consider changing to: `&i32`
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:188:16
+   |
+LL | fn cfg_warn(s: &mut u32) {}
+   |                ^^^^^^^^ help: consider changing to: `&u32`
+   |
+   = note: this is cfg-gated and may require further changes
+
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/needless_pass_by_ref_mut.rs:194:20
+   |
+LL |     fn cfg_warn(s: &mut u32) {}
+   |                    ^^^^^^^^ help: consider changing to: `&u32`
+   |
+   = note: this is cfg-gated and may require further changes
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed
new file mode 100644
index 00000000000..d6e47d07b0f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed
@@ -0,0 +1,40 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+    clippy::needless_return,
+    clippy::no_effect,
+    clippy::unit_arg,
+    clippy::useless_conversion,
+    unused
+)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn a() -> u32 {
+    return 0;
+}
+
+fn b() -> Result<u32, u32> {
+    return Err(0);
+}
+
+// Do not lint
+fn c() -> Option<()> {
+    return None?;
+}
+
+fn main() -> Result<(), ()> {
+    Err(())?;
+    return Ok::<(), ()>(());
+    Err(())?;
+    Ok::<(), ()>(());
+    return Err(().into());
+    external! {
+        return Err(())?;
+    }
+    with_span! {
+        return Err(())?;
+    }
+    Err(())
+}
diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs
new file mode 100644
index 00000000000..4fc04d363a9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs
@@ -0,0 +1,40 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(
+    clippy::needless_return,
+    clippy::no_effect,
+    clippy::unit_arg,
+    clippy::useless_conversion,
+    unused
+)]
+
+#[macro_use]
+extern crate proc_macros;
+
+fn a() -> u32 {
+    return 0;
+}
+
+fn b() -> Result<u32, u32> {
+    return Err(0);
+}
+
+// Do not lint
+fn c() -> Option<()> {
+    return None?;
+}
+
+fn main() -> Result<(), ()> {
+    return Err(())?;
+    return Ok::<(), ()>(());
+    Err(())?;
+    Ok::<(), ()>(());
+    return Err(().into());
+    external! {
+        return Err(())?;
+    }
+    with_span! {
+        return Err(())?;
+    }
+    Err(())
+}
diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr b/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr
new file mode 100644
index 00000000000..e1d91638d2c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr
@@ -0,0 +1,10 @@
+error: unneeded `return` statement with `?` operator
+  --> $DIR/needless_return_with_question_mark.rs:28:5
+   |
+LL |     return Err(())?;
+   |     ^^^^^^^ help: remove it
+   |
+   = note: `-D clippy::needless-return-with-question-mark` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.rs b/src/tools/clippy/tests/ui/option_env_unwrap.rs
index 65a1b467f81..61dbad939db 100644
--- a/src/tools/clippy/tests/ui/option_env_unwrap.rs
+++ b/src/tools/clippy/tests/ui/option_env_unwrap.rs
@@ -9,6 +9,7 @@ use proc_macros::{external, inline_macros};
 fn main() {
     let _ = option_env!("PATH").unwrap();
     let _ = option_env!("PATH").expect("environment variable PATH isn't set");
+    let _ = option_env!("__Y__do_not_use").unwrap(); // This test only works if you don't have a __Y__do_not_use env variable in your environment.
     let _ = inline!(option_env!($"PATH").unwrap());
     let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
     let _ = external!(option_env!($"PATH").unwrap());
diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.stderr b/src/tools/clippy/tests/ui/option_env_unwrap.stderr
index 7bba62686ee..cfa9dd58a30 100644
--- a/src/tools/clippy/tests/ui/option_env_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/option_env_unwrap.stderr
@@ -16,7 +16,15 @@ LL |     let _ = option_env!("PATH").expect("environment variable PATH isn't set
    = help: consider using the `env!` macro instead
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:12:21
+  --> $DIR/option_env_unwrap.rs:12:13
+   |
+LL |     let _ = option_env!("__Y__do_not_use").unwrap(); // This test only works if you don't have a __Y__do_not_use env variable in your env...
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider using the `env!` macro instead
+
+error: this will panic at run-time if the environment variable doesn't exist at compile-time
+  --> $DIR/option_env_unwrap.rs:13:21
    |
 LL |     let _ = inline!(option_env!($"PATH").unwrap());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +33,7 @@ LL |     let _ = inline!(option_env!($"PATH").unwrap());
    = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:13:21
+  --> $DIR/option_env_unwrap.rs:14:21
    |
 LL |     let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -34,7 +42,7 @@ LL |     let _ = inline!(option_env!($"PATH").expect($"environment variable PATH
    = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:14:13
+  --> $DIR/option_env_unwrap.rs:15:13
    |
 LL |     let _ = external!(option_env!($"PATH").unwrap());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -43,7 +51,7 @@ LL |     let _ = external!(option_env!($"PATH").unwrap());
    = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this will panic at run-time if the environment variable doesn't exist at compile-time
-  --> $DIR/option_env_unwrap.rs:15:13
+  --> $DIR/option_env_unwrap.rs:16:13
    |
 LL |     let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set"));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -51,5 +59,5 @@ LL |     let _ = external!(option_env!($"PATH").expect($"environment variable PA
    = help: consider using the `env!` macro instead
    = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index 8e59e4375d2..6fee3cce619 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -5,7 +5,8 @@
     clippy::redundant_closure,
     clippy::ref_option_ref,
     clippy::equatable_if_let,
-    clippy::let_unit_value
+    clippy::let_unit_value,
+    clippy::redundant_locals
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index e72edf2a8e3..4b3cf948a1b 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -5,7 +5,8 @@
     clippy::redundant_closure,
     clippy::ref_option_ref,
     clippy::equatable_if_let,
-    clippy::let_unit_value
+    clippy::let_unit_value,
+    clippy::redundant_locals
 )]
 
 fn bad1(string: Option<&str>) -> (bool, &str) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index aa2da217400..350f0f07e13 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -1,5 +1,5 @@
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:12:5
+  --> $DIR/option_if_let_else.rs:13:5
    |
 LL | /     if let Some(x) = string {
 LL | |         (true, x)
@@ -11,19 +11,19 @@ LL | |     }
    = note: `-D clippy::option-if-let-else` implied by `-D warnings`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:30:13
+  --> $DIR/option_if_let_else.rs:31:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:31:13
+  --> $DIR/option_if_let_else.rs:32:13
    |
 LL |     let _ = if let Some(s) = &num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:32:13
+  --> $DIR/option_if_let_else.rs:33:13
    |
 LL |       let _ = if let Some(s) = &mut num {
    |  _____________^
@@ -43,13 +43,13 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:38:13
+  --> $DIR/option_if_let_else.rs:39:13
    |
 LL |     let _ = if let Some(ref s) = num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:39:13
+  --> $DIR/option_if_let_else.rs:40:13
    |
 LL |       let _ = if let Some(mut s) = num {
    |  _____________^
@@ -69,7 +69,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:45:13
+  --> $DIR/option_if_let_else.rs:46:13
    |
 LL |       let _ = if let Some(ref mut s) = num {
    |  _____________^
@@ -89,7 +89,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:54:5
+  --> $DIR/option_if_let_else.rs:55:5
    |
 LL | /     if let Some(x) = arg {
 LL | |         let y = x * x;
@@ -108,7 +108,7 @@ LL +     })
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:67:13
+  --> $DIR/option_if_let_else.rs:68:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -120,7 +120,7 @@ LL | |     };
    | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:76:13
+  --> $DIR/option_if_let_else.rs:77:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -143,7 +143,7 @@ LL ~     }, |x| x * x * x * x);
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:109:13
+  --> $DIR/option_if_let_else.rs:110:13
    |
 LL | /             if let Some(idx) = s.find('.') {
 LL | |                 vec![s[..idx].to_string(), s[idx..].to_string()]
@@ -153,7 +153,7 @@ LL | |             }
    | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:120:5
+  --> $DIR/option_if_let_else.rs:121:5
    |
 LL | /     if let Ok(binding) = variable {
 LL | |         println!("Ok {binding}");
@@ -172,13 +172,13 @@ LL +     })
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:142:13
+  --> $DIR/option_if_let_else.rs:143:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:152:13
+  --> $DIR/option_if_let_else.rs:153:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -200,13 +200,13 @@ LL ~         });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:180:13
+  --> $DIR/option_if_let_else.rs:181:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:184:13
+  --> $DIR/option_if_let_else.rs:185:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -226,7 +226,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:223:13
+  --> $DIR/option_if_let_else.rs:224:13
    |
 LL |       let _ = match s {
    |  _____________^
@@ -236,7 +236,7 @@ LL | |     };
    | |_____^ help: try: `s.map_or(1, |string| string.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:227:13
+  --> $DIR/option_if_let_else.rs:228:13
    |
 LL |       let _ = match Some(10) {
    |  _____________^
@@ -246,7 +246,7 @@ LL | |     };
    | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:233:13
+  --> $DIR/option_if_let_else.rs:234:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -256,7 +256,7 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:237:13
+  --> $DIR/option_if_let_else.rs:238:13
    |
 LL |       let _ = match res {
    |  _____________^
@@ -266,13 +266,13 @@ LL | |     };
    | |_____^ help: try: `res.map_or(1, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:241:13
+  --> $DIR/option_if_let_else.rs:242:13
    |
 LL |     let _ = if let Ok(a) = res { a + 1 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:258:9
+  --> $DIR/option_if_let_else.rs:259:9
    |
 LL | /         match initial {
 LL | |             Some(value) => do_something(value),
@@ -281,7 +281,7 @@ LL | |         }
    | |_________^ help: try: `initial.as_ref().map_or({}, |value| do_something(value))`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:265:9
+  --> $DIR/option_if_let_else.rs:266:9
    |
 LL | /         match initial {
 LL | |             Some(value) => do_something2(value),
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 6deff0f3240..581f3ad45c7 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -190,7 +190,7 @@ mod issue8239 {
                 acc.push_str(&f);
                 acc
             })
-            .unwrap_or_default();
+            .unwrap_or(String::new());
     }
 
     fn more_to_max_suggestion_highest_lines_1() {
@@ -203,7 +203,7 @@ mod issue8239 {
                 acc.push_str(&f);
                 acc
             })
-            .unwrap_or_default();
+            .unwrap_or(String::new());
     }
 
     fn equal_to_max_suggestion_highest_lines() {
@@ -215,7 +215,7 @@ mod issue8239 {
                 acc.push_str(&f);
                 acc
             })
-            .unwrap_or_default();
+            .unwrap_or(String::new());
     }
 
     fn less_than_max_suggestion_highest_lines() {
@@ -226,7 +226,7 @@ mod issue8239 {
             acc.push_str(&f);
             acc
         })
-        .unwrap_or_default();
+        .unwrap_or(String::new());
     }
 }
 
@@ -257,4 +257,59 @@ mod issue8993 {
     }
 }
 
+mod lazy {
+    use super::*;
+
+    fn foo() {
+        struct Foo;
+
+        impl Foo {
+            fn new() -> Foo {
+                Foo
+            }
+        }
+
+        struct FakeDefault;
+        impl FakeDefault {
+            fn default() -> Self {
+                FakeDefault
+            }
+        }
+
+        impl Default for FakeDefault {
+            fn default() -> Self {
+                FakeDefault
+            }
+        }
+
+        let with_new = Some(vec![1]);
+        with_new.unwrap_or_default();
+
+        let with_default_trait = Some(1);
+        with_default_trait.unwrap_or_default();
+
+        let with_default_type = Some(1);
+        with_default_type.unwrap_or_default();
+
+        let real_default = None::<FakeDefault>;
+        real_default.unwrap_or_default();
+
+        let mut map = HashMap::<u64, String>::new();
+        map.entry(42).or_default();
+
+        let mut btree = BTreeMap::<u64, String>::new();
+        btree.entry(42).or_default();
+
+        let stringy = Some(String::new());
+        let _ = stringy.unwrap_or_default();
+
+        // negative tests
+        let self_default = None::<FakeDefault>;
+        self_default.unwrap_or_else(<FakeDefault>::default);
+
+        let without_default = Some(Foo);
+        without_default.unwrap_or_else(Foo::new);
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index b05b33e6ee2..1f3987eb891 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -257,4 +257,59 @@ mod issue8993 {
     }
 }
 
+mod lazy {
+    use super::*;
+
+    fn foo() {
+        struct Foo;
+
+        impl Foo {
+            fn new() -> Foo {
+                Foo
+            }
+        }
+
+        struct FakeDefault;
+        impl FakeDefault {
+            fn default() -> Self {
+                FakeDefault
+            }
+        }
+
+        impl Default for FakeDefault {
+            fn default() -> Self {
+                FakeDefault
+            }
+        }
+
+        let with_new = Some(vec![1]);
+        with_new.unwrap_or_else(Vec::new);
+
+        let with_default_trait = Some(1);
+        with_default_trait.unwrap_or_else(Default::default);
+
+        let with_default_type = Some(1);
+        with_default_type.unwrap_or_else(u64::default);
+
+        let real_default = None::<FakeDefault>;
+        real_default.unwrap_or_else(<FakeDefault as Default>::default);
+
+        let mut map = HashMap::<u64, String>::new();
+        map.entry(42).or_insert_with(String::new);
+
+        let mut btree = BTreeMap::<u64, String>::new();
+        btree.entry(42).or_insert_with(String::new);
+
+        let stringy = Some(String::new());
+        let _ = stringy.unwrap_or_else(String::new);
+
+        // negative tests
+        let self_default = None::<FakeDefault>;
+        self_default.unwrap_or_else(<FakeDefault>::default);
+
+        let without_default = Some(Foo);
+        without_default.unwrap_or_else(Foo::new);
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 7342b0c2914..519f0916562 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -6,11 +6,13 @@ LL |     with_constructor.unwrap_or(make());
    |
    = note: `-D clippy::or-fun-call` implied by `-D warnings`
 
-error: use of `unwrap_or` followed by a call to `new`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:56:14
    |
 LL |     with_new.unwrap_or(Vec::new());
    |              ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+   |
+   = note: `-D clippy::unwrap-or-default` implied by `-D warnings`
 
 error: use of `unwrap_or` followed by a function call
   --> $DIR/or_fun_call.rs:59:21
@@ -30,13 +32,13 @@ error: use of `unwrap_or` followed by a function call
 LL |     with_err_args.unwrap_or(Vec::with_capacity(12));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))`
 
-error: use of `unwrap_or` followed by a call to `default`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:68:24
    |
 LL |     with_default_trait.unwrap_or(Default::default());
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `unwrap_or` followed by a call to `default`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:71:23
    |
 LL |     with_default_type.unwrap_or(u64::default());
@@ -48,13 +50,13 @@ error: use of `unwrap_or` followed by a function call
 LL |     self_default.unwrap_or(<FakeDefault>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(<FakeDefault>::default)`
 
-error: use of `unwrap_or` followed by a call to `default`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:77:18
    |
 LL |     real_default.unwrap_or(<FakeDefault as Default>::default());
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `unwrap_or` followed by a call to `new`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:80:14
    |
 LL |     with_vec.unwrap_or(vec![]);
@@ -66,31 +68,31 @@ error: use of `unwrap_or` followed by a function call
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)`
 
-error: use of `or_insert` followed by a call to `new`
+error: use of `or_insert` to construct default value
   --> $DIR/or_fun_call.rs:86:19
    |
 LL |     map.entry(42).or_insert(String::new());
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
-error: use of `or_insert` followed by a call to `new`
+error: use of `or_insert` to construct default value
   --> $DIR/or_fun_call.rs:89:23
    |
 LL |     map_vec.entry(42).or_insert(vec![]);
    |                       ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
-error: use of `or_insert` followed by a call to `new`
+error: use of `or_insert` to construct default value
   --> $DIR/or_fun_call.rs:92:21
    |
 LL |     btree.entry(42).or_insert(String::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
-error: use of `or_insert` followed by a call to `new`
+error: use of `or_insert` to construct default value
   --> $DIR/or_fun_call.rs:95:25
    |
 LL |     btree_vec.entry(42).or_insert(vec![]);
    |                         ^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
-error: use of `unwrap_or` followed by a call to `new`
+error: use of `unwrap_or` to construct default value
   --> $DIR/or_fun_call.rs:98:21
    |
 LL |     let _ = stringy.unwrap_or(String::new());
@@ -132,30 +134,6 @@ error: use of `unwrap_or` followed by a function call
 LL |         None.unwrap_or( unsafe { ptr_to_ref(s) }    );
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
 
-error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:193:14
-   |
-LL |             .unwrap_or(String::new());
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-
-error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:206:14
-   |
-LL |             .unwrap_or(String::new());
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-
-error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:218:14
-   |
-LL |             .unwrap_or(String::new());
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-
-error: use of `unwrap_or` followed by a call to `new`
-  --> $DIR/or_fun_call.rs:229:10
-   |
-LL |         .unwrap_or(String::new());
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
-
 error: use of `map_or` followed by a function call
   --> $DIR/or_fun_call.rs:254:25
    |
@@ -168,5 +146,47 @@ error: use of `map_or` followed by a function call
 LL |         let _ = Some(4).map_or(g(), f);
    |                         ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
 
-error: aborting due to 28 previous errors
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:286:18
+   |
+LL |         with_new.unwrap_or_else(Vec::new);
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:289:28
+   |
+LL |         with_default_trait.unwrap_or_else(Default::default);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:292:27
+   |
+LL |         with_default_type.unwrap_or_else(u64::default);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:295:22
+   |
+LL |         real_default.unwrap_or_else(<FakeDefault as Default>::default);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `or_insert_with` to construct default value
+  --> $DIR/or_fun_call.rs:298:23
+   |
+LL |         map.entry(42).or_insert_with(String::new);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+
+error: use of `or_insert_with` to construct default value
+  --> $DIR/or_fun_call.rs:301:25
+   |
+LL |         btree.entry(42).or_insert_with(String::new);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/or_fun_call.rs:304:25
+   |
+LL |         let _ = stringy.unwrap_or_else(String::new);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: aborting due to 31 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index 13e993d247b..08075c382a2 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -267,3 +267,16 @@ mod issue_9218 {
         todo!()
     }
 }
+
+mod issue_11181 {
+    extern "C" fn allowed(_v: &Vec<u32>) {}
+
+    struct S;
+    impl S {
+        extern "C" fn allowed(_v: &Vec<u32>) {}
+    }
+
+    trait T {
+        extern "C" fn allowed(_v: &Vec<u32>) {}
+    }
+}
diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
index c6025ef1f4d..ff2ad8644b4 100644
--- a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
+++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs
@@ -1,5 +1,9 @@
 #![warn(clippy::read_zero_byte_vec)]
-#![allow(clippy::unused_io_amount, clippy::needless_pass_by_ref_mut)]
+#![allow(
+    clippy::unused_io_amount,
+    clippy::needless_pass_by_ref_mut,
+    clippy::slow_vector_initialization
+)]
 use std::fs::File;
 use std::io;
 use std::io::prelude::*;
diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
index 08ba9753d7c..4c7f605f4c2 100644
--- a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
+++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr
@@ -1,5 +1,5 @@
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:17:5
+  --> $DIR/read_zero_byte_vec.rs:21:5
    |
 LL |     f.read_exact(&mut data).unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data).unwrap();`
@@ -7,55 +7,55 @@ LL |     f.read_exact(&mut data).unwrap();
    = note: `-D clippy::read-zero-byte-vec` implied by `-D warnings`
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:21:5
+  --> $DIR/read_zero_byte_vec.rs:25:5
    |
 LL |     f.read_exact(&mut data2)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)?;`
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:25:5
+  --> $DIR/read_zero_byte_vec.rs:29:5
    |
 LL |     f.read_exact(&mut data3)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:29:5
+  --> $DIR/read_zero_byte_vec.rs:33:5
    |
 LL |     let _ = f.read(&mut data4)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:34:9
+  --> $DIR/read_zero_byte_vec.rs:38:9
    |
 LL |         f.read(&mut data5)
    |         ^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:40:9
+  --> $DIR/read_zero_byte_vec.rs:44:9
    |
 LL |         f.read(&mut data6)
    |         ^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:70:5
+  --> $DIR/read_zero_byte_vec.rs:74:5
    |
 LL |     r.read(&mut data).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:74:5
+  --> $DIR/read_zero_byte_vec.rs:78:5
    |
 LL |     r.read_exact(&mut data2).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:80:5
+  --> $DIR/read_zero_byte_vec.rs:84:5
    |
 LL |     r.read(&mut data).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: reading zero byte data to `Vec`
-  --> $DIR/read_zero_byte_vec.rs:84:5
+  --> $DIR/read_zero_byte_vec.rs:88:5
    |
 LL |     r.read_exact(&mut data2).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.rs b/src/tools/clippy/tests/ui/readonly_write_lock.rs
new file mode 100644
index 00000000000..656b45787e8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/readonly_write_lock.rs
@@ -0,0 +1,42 @@
+#![warn(clippy::readonly_write_lock)]
+
+use std::sync::RwLock;
+
+fn mutate_i32(x: &mut i32) {
+    *x += 1;
+}
+
+fn accept_i32(_: i32) {}
+
+fn main() {
+    let lock = RwLock::new(42);
+    let lock2 = RwLock::new(1234);
+
+    {
+        let writer = lock.write().unwrap();
+        dbg!(&writer);
+    }
+
+    {
+        let writer = lock.write().unwrap();
+        accept_i32(*writer);
+    }
+
+    {
+        let mut writer = lock.write().unwrap();
+        mutate_i32(&mut writer);
+        dbg!(&writer);
+    }
+
+    {
+        let mut writer = lock.write().unwrap();
+        *writer += 1;
+    }
+
+    {
+        let mut writer1 = lock.write().unwrap();
+        let mut writer2 = lock2.write().unwrap();
+        *writer2 += 1;
+        *writer1 = *writer2;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.stderr b/src/tools/clippy/tests/ui/readonly_write_lock.stderr
new file mode 100644
index 00000000000..e3d8fce7b2c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/readonly_write_lock.stderr
@@ -0,0 +1,16 @@
+error: this write lock is used only for reading
+  --> $DIR/readonly_write_lock.rs:16:22
+   |
+LL |         let writer = lock.write().unwrap();
+   |                      ^^^^^^^^^^^^ help: consider using a read lock instead: `lock.read()`
+   |
+   = note: `-D clippy::readonly-write-lock` implied by `-D warnings`
+
+error: this write lock is used only for reading
+  --> $DIR/readonly_write_lock.rs:21:22
+   |
+LL |         let writer = lock.write().unwrap();
+   |                      ^^^^^^^^^^^^ help: consider using a read lock instead: `lock.read()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_guards.fixed b/src/tools/clippy/tests/ui/redundant_guards.fixed
new file mode 100644
index 00000000000..77ac7666864
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_guards.fixed
@@ -0,0 +1,133 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(if_let_guard)]
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::redundant_guards)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct A(u32);
+
+struct B {
+    e: Option<A>,
+}
+
+struct C(u32, u32);
+
+fn main() {
+    let c = C(1, 2);
+    match c {
+        C(x, 1) => ..,
+        _ => todo!(),
+    };
+
+    let x = Some(Some(1));
+    match x {
+        Some(Some(1)) if true => ..,
+        Some(Some(1)) => {
+            println!("a");
+            ..
+        },
+        Some(Some(1)) => ..,
+        Some(Some(2)) => ..,
+        // Don't lint, since x is used in the body
+        Some(x) if let Some(1) = x => {
+            x;
+            ..
+        }
+        _ => todo!(),
+    };
+    let y = 1;
+    match x {
+        // Don't inline these, since y is not from the pat
+        Some(x) if matches!(y, 1 if true) => ..,
+        Some(x) if let 1 = y => ..,
+        Some(x) if y == 2 => ..,
+        _ => todo!(),
+    };
+    let a = A(1);
+    match a {
+        _ if a.0 == 1 => {},
+        _ => todo!(),
+    }
+    let b = B { e: Some(A(0)) };
+    match b {
+        B { e: Some(A(2)) } => ..,
+        _ => todo!(),
+    };
+    // Do not lint, since we cannot represent this as a pattern (at least, without a conversion)
+    let v = Some(vec![1u8, 2, 3]);
+    match v {
+        Some(x) if x == [1] => {},
+        _ => {},
+    }
+
+    external! {
+        let x = Some(Some(1));
+        match x {
+            Some(x) if let Some(1) = x => ..,
+            _ => todo!(),
+        };
+    }
+    with_span! {
+        span
+        let x = Some(Some(1));
+        match x {
+            Some(x) if let Some(1) = x => ..,
+            _ => todo!(),
+        };
+    }
+}
+
+enum E {
+    A(&'static str),
+    B(&'static str),
+    C(&'static str),
+}
+
+fn i() {
+    match E::A("") {
+        // Do not lint
+        E::A(x) | E::B(x) | E::C(x) if x == "from an or pattern" => {},
+        E::A("not from an or pattern") => {},
+        _ => {},
+    };
+}
+
+fn h(v: Option<u32>) {
+    match v {
+        Some(0) => ..,
+        _ => ..,
+    };
+}
+
+// Do not lint
+
+fn f(s: Option<std::ffi::OsString>) {
+    match s {
+        Some(x) if x == "a" => {},
+        _ => {},
+    }
+}
+
+struct S {
+    a: usize,
+}
+
+impl PartialEq for S {
+    fn eq(&self, _: &Self) -> bool {
+        true
+    }
+}
+
+impl Eq for S {}
+
+static CONST_S: S = S { a: 1 };
+
+fn g(opt_s: Option<S>) {
+    match opt_s {
+        Some(x) if x == CONST_S => {},
+        _ => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_guards.rs b/src/tools/clippy/tests/ui/redundant_guards.rs
new file mode 100644
index 00000000000..b072e4ea14d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_guards.rs
@@ -0,0 +1,133 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![feature(if_let_guard)]
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::redundant_guards)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct A(u32);
+
+struct B {
+    e: Option<A>,
+}
+
+struct C(u32, u32);
+
+fn main() {
+    let c = C(1, 2);
+    match c {
+        C(x, y) if let 1 = y => ..,
+        _ => todo!(),
+    };
+
+    let x = Some(Some(1));
+    match x {
+        Some(x) if matches!(x, Some(1) if true) => ..,
+        Some(x) if matches!(x, Some(1)) => {
+            println!("a");
+            ..
+        },
+        Some(x) if let Some(1) = x => ..,
+        Some(x) if x == Some(2) => ..,
+        // Don't lint, since x is used in the body
+        Some(x) if let Some(1) = x => {
+            x;
+            ..
+        }
+        _ => todo!(),
+    };
+    let y = 1;
+    match x {
+        // Don't inline these, since y is not from the pat
+        Some(x) if matches!(y, 1 if true) => ..,
+        Some(x) if let 1 = y => ..,
+        Some(x) if y == 2 => ..,
+        _ => todo!(),
+    };
+    let a = A(1);
+    match a {
+        _ if a.0 == 1 => {},
+        _ => todo!(),
+    }
+    let b = B { e: Some(A(0)) };
+    match b {
+        B { e } if matches!(e, Some(A(2))) => ..,
+        _ => todo!(),
+    };
+    // Do not lint, since we cannot represent this as a pattern (at least, without a conversion)
+    let v = Some(vec![1u8, 2, 3]);
+    match v {
+        Some(x) if x == [1] => {},
+        _ => {},
+    }
+
+    external! {
+        let x = Some(Some(1));
+        match x {
+            Some(x) if let Some(1) = x => ..,
+            _ => todo!(),
+        };
+    }
+    with_span! {
+        span
+        let x = Some(Some(1));
+        match x {
+            Some(x) if let Some(1) = x => ..,
+            _ => todo!(),
+        };
+    }
+}
+
+enum E {
+    A(&'static str),
+    B(&'static str),
+    C(&'static str),
+}
+
+fn i() {
+    match E::A("") {
+        // Do not lint
+        E::A(x) | E::B(x) | E::C(x) if x == "from an or pattern" => {},
+        E::A(y) if y == "not from an or pattern" => {},
+        _ => {},
+    };
+}
+
+fn h(v: Option<u32>) {
+    match v {
+        x if matches!(x, Some(0)) => ..,
+        _ => ..,
+    };
+}
+
+// Do not lint
+
+fn f(s: Option<std::ffi::OsString>) {
+    match s {
+        Some(x) if x == "a" => {},
+        _ => {},
+    }
+}
+
+struct S {
+    a: usize,
+}
+
+impl PartialEq for S {
+    fn eq(&self, _: &Self) -> bool {
+        true
+    }
+}
+
+impl Eq for S {}
+
+static CONST_S: S = S { a: 1 };
+
+fn g(opt_s: Option<S>) {
+    match opt_s {
+        Some(x) if x == CONST_S => {},
+        _ => {},
+    }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_guards.stderr b/src/tools/clippy/tests/ui/redundant_guards.stderr
new file mode 100644
index 00000000000..c2a92071d1d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_guards.stderr
@@ -0,0 +1,98 @@
+error: redundant guard
+  --> $DIR/redundant_guards.rs:21:20
+   |
+LL |         C(x, y) if let 1 = y => ..,
+   |                    ^^^^^^^^^
+   |
+   = note: `-D clippy::redundant-guards` implied by `-D warnings`
+help: try
+   |
+LL -         C(x, y) if let 1 = y => ..,
+LL +         C(x, 1) => ..,
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:27:20
+   |
+LL |         Some(x) if matches!(x, Some(1) if true) => ..,
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL |         Some(Some(1)) if true => ..,
+   |              ~~~~~~~  ~~~~~~~
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:28:20
+   |
+LL |         Some(x) if matches!(x, Some(1)) => {
+   |                    ^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         Some(x) if matches!(x, Some(1)) => {
+LL +         Some(Some(1)) => {
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:32:20
+   |
+LL |         Some(x) if let Some(1) = x => ..,
+   |                    ^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         Some(x) if let Some(1) = x => ..,
+LL +         Some(Some(1)) => ..,
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:33:20
+   |
+LL |         Some(x) if x == Some(2) => ..,
+   |                    ^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         Some(x) if x == Some(2) => ..,
+LL +         Some(Some(2)) => ..,
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:56:20
+   |
+LL |         B { e } if matches!(e, Some(A(2))) => ..,
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         B { e } if matches!(e, Some(A(2))) => ..,
+LL +         B { e: Some(A(2)) } => ..,
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:93:20
+   |
+LL |         E::A(y) if y == "not from an or pattern" => {},
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         E::A(y) if y == "not from an or pattern" => {},
+LL +         E::A("not from an or pattern") => {},
+   |
+
+error: redundant guard
+  --> $DIR/redundant_guards.rs:100:14
+   |
+LL |         x if matches!(x, Some(0)) => ..,
+   |              ^^^^^^^^^^^^^^^^^^^^
+   |
+help: try
+   |
+LL -         x if matches!(x, Some(0)) => ..,
+LL +         Some(0) => ..,
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_locals.rs b/src/tools/clippy/tests/ui/redundant_locals.rs
new file mode 100644
index 00000000000..e74c78a50b6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_locals.rs
@@ -0,0 +1,111 @@
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(unused, clippy::no_effect, clippy::needless_pass_by_ref_mut)]
+#![warn(clippy::redundant_locals)]
+
+extern crate proc_macros;
+use proc_macros::{external, with_span};
+
+fn main() {}
+
+fn immutable() {
+    let x = 1;
+    let x = x;
+}
+
+fn mutable() {
+    let mut x = 1;
+    let mut x = x;
+}
+
+fn upgraded_mutability() {
+    let x = 1;
+    let mut x = x;
+}
+
+fn downgraded_mutability() {
+    let mut x = 1;
+    let x = x;
+}
+
+fn coercion(par: &mut i32) {
+    let par: &i32 = par;
+
+    let x: &mut i32 = &mut 1;
+    let x: &i32 = x;
+}
+
+fn parameter(x: i32) {
+    let x = x;
+}
+
+fn many() {
+    let x = 1;
+    let x = x;
+    let x = x;
+    let x = x;
+    let x = x;
+}
+
+fn interleaved() {
+    let a = 1;
+    let b = 2;
+    let a = a;
+    let b = b;
+}
+
+fn block() {
+    {
+        let x = 1;
+        let x = x;
+    }
+}
+
+fn closure() {
+    || {
+        let x = 1;
+        let x = x;
+    };
+    |x: i32| {
+        let x = x;
+    };
+}
+
+fn consequential_drop_order() {
+    use std::sync::Mutex;
+
+    let mutex = Mutex::new(1);
+    let guard = mutex.lock().unwrap();
+
+    {
+        let guard = guard;
+    }
+}
+
+fn inconsequential_drop_order() {
+    let x = 1;
+
+    {
+        let x = x;
+    }
+}
+
+fn macros() {
+    macro_rules! rebind {
+        ($x:ident) => {
+            let $x = 1;
+            let $x = $x;
+        };
+    }
+
+    rebind!(x);
+
+    external! {
+        let x = 1;
+        let x = x;
+    }
+    with_span! {
+        span
+        let x = 1;
+        let x = x;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_locals.stderr b/src/tools/clippy/tests/ui/redundant_locals.stderr
new file mode 100644
index 00000000000..df07dd2f453
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_locals.stderr
@@ -0,0 +1,136 @@
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:11:9
+   |
+LL |     let x = 1;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+   = note: `-D clippy::redundant-locals` implied by `-D warnings`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:16:9
+   |
+LL |     let mut x = 1;
+   |         ^^^^^
+LL |     let mut x = x;
+   |     ^^^^^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:37:14
+   |
+LL | fn parameter(x: i32) {
+   |              ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:42:9
+   |
+LL |     let x = 1;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:43:9
+   |
+LL |     let x = x;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:44:9
+   |
+LL |     let x = x;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:45:9
+   |
+LL |     let x = x;
+   |         ^
+LL |     let x = x;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:50:9
+   |
+LL |     let a = 1;
+   |         ^
+LL |     let b = 2;
+LL |     let a = a;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `a`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:51:9
+   |
+LL |     let b = 2;
+   |         ^
+LL |     let a = a;
+LL |     let b = b;
+   |     ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `b`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:58:13
+   |
+LL |         let x = 1;
+   |             ^
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:65:13
+   |
+LL |         let x = 1;
+   |             ^
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:68:6
+   |
+LL |     |x: i32| {
+   |      ^
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: redundant redefinition of a binding
+  --> $DIR/redundant_locals.rs:85:9
+   |
+LL |     let x = 1;
+   |         ^
+...
+LL |         let x = x;
+   |         ^^^^^^^^^^
+   |
+   = help: remove the redefinition of `x`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index a63ba5809e4..d9fcd98c56e 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -10,6 +10,20 @@
     clippy::equatable_if_let,
     clippy::if_same_then_else
 )]
+#![feature(let_chains, if_let_guard)]
+
+fn issue_11174<T>(boolean: bool, maybe_some: Option<T>) -> bool {
+    maybe_some.is_none() && (!boolean)
+}
+
+fn issue_11174_edge_cases<T>(boolean: bool, boolean2: bool, maybe_some: Option<T>) {
+    let _ = maybe_some.is_none() && (boolean || boolean2); // guard needs parentheses
+    let _ = match maybe_some { // can't use `matches!` here
+                               // because `expr` metavars in macros don't allow let exprs
+        None if let Some(x) = Some(0) && x > 5 => true,
+        _ => false
+    };
+}
 
 fn main() {
     if None::<()>.is_none() {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index 631f9091672..cbd9494f15a 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -10,6 +10,20 @@
     clippy::equatable_if_let,
     clippy::if_same_then_else
 )]
+#![feature(let_chains, if_let_guard)]
+
+fn issue_11174<T>(boolean: bool, maybe_some: Option<T>) -> bool {
+    matches!(maybe_some, None if !boolean)
+}
+
+fn issue_11174_edge_cases<T>(boolean: bool, boolean2: bool, maybe_some: Option<T>) {
+    let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses
+    let _ = match maybe_some { // can't use `matches!` here
+                               // because `expr` metavars in macros don't allow let exprs
+        None if let Some(x) = Some(0) && x > 5 => true,
+        _ => false
+    };
+}
 
 fn main() {
     if let None = None::<()> {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
index 097ca827a42..b0e43924dbc 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
@@ -1,49 +1,61 @@
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:15:12
+  --> $DIR/redundant_pattern_matching_option.rs:16:5
    |
-LL |     if let None = None::<()> {}
-   |     -------^^^^------------- help: try: `if None::<()>.is_none()`
+LL |     matches!(maybe_some, None if !boolean)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (!boolean)`
    |
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:20:13
+   |
+LL |     let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (boolean || boolean2)`
+
+error: redundant pattern matching, consider using `is_none()`
+  --> $DIR/redundant_pattern_matching_option.rs:29:12
+   |
+LL |     if let None = None::<()> {}
+   |     -------^^^^------------- help: try: `if None::<()>.is_none()`
+
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:17:12
+  --> $DIR/redundant_pattern_matching_option.rs:31:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:19:12
+  --> $DIR/redundant_pattern_matching_option.rs:33:12
    |
 LL |     if let Some(_) = Some(42) {
    |     -------^^^^^^^----------- help: try: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:25:15
+  --> $DIR/redundant_pattern_matching_option.rs:39:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:27:15
+  --> $DIR/redundant_pattern_matching_option.rs:41:15
    |
 LL |     while let None = Some(42) {}
    |     ----------^^^^----------- help: try: `while Some(42).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:29:15
+  --> $DIR/redundant_pattern_matching_option.rs:43:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:32:15
+  --> $DIR/redundant_pattern_matching_option.rs:46:15
    |
 LL |     while let Some(_) = v.pop() {
    |     ----------^^^^^^^---------- help: try: `while v.pop().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:40:5
+  --> $DIR/redundant_pattern_matching_option.rs:54:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -52,7 +64,7 @@ LL | |     };
    | |_____^ help: try: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:45:5
+  --> $DIR/redundant_pattern_matching_option.rs:59:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -61,7 +73,7 @@ LL | |     };
    | |_____^ help: try: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:50:13
+  --> $DIR/redundant_pattern_matching_option.rs:64:13
    |
 LL |       let _ = match None::<()> {
    |  _____________^
@@ -71,55 +83,55 @@ LL | |     };
    | |_____^ help: try: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:56:20
+  --> $DIR/redundant_pattern_matching_option.rs:70:20
    |
 LL |     let _ = if let Some(_) = opt { true } else { false };
    |             -------^^^^^^^------ help: try: `if opt.is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:62:20
+  --> $DIR/redundant_pattern_matching_option.rs:76:20
    |
 LL |     let _ = if let Some(_) = gen_opt() {
    |             -------^^^^^^^------------ help: try: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:64:19
+  --> $DIR/redundant_pattern_matching_option.rs:78:19
    |
 LL |     } else if let None = gen_opt() {
    |            -------^^^^------------ help: try: `if gen_opt().is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:70:12
+  --> $DIR/redundant_pattern_matching_option.rs:84:12
    |
 LL |     if let Some(..) = gen_opt() {}
    |     -------^^^^^^^^------------ help: try: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:85:12
+  --> $DIR/redundant_pattern_matching_option.rs:99:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:87:12
+  --> $DIR/redundant_pattern_matching_option.rs:101:12
    |
 LL |     if let None = None::<()> {}
    |     -------^^^^------------- help: try: `if None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:89:15
+  --> $DIR/redundant_pattern_matching_option.rs:103:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:91:15
+  --> $DIR/redundant_pattern_matching_option.rs:105:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:93:5
+  --> $DIR/redundant_pattern_matching_option.rs:107:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -128,7 +140,7 @@ LL | |     };
    | |_____^ help: try: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:98:5
+  --> $DIR/redundant_pattern_matching_option.rs:112:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -137,19 +149,19 @@ LL | |     };
    | |_____^ help: try: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:106:12
+  --> $DIR/redundant_pattern_matching_option.rs:120:12
    |
 LL |     if let None = *(&None::<()>) {}
    |     -------^^^^----------------- help: try: `if (&None::<()>).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:107:12
+  --> $DIR/redundant_pattern_matching_option.rs:121:12
    |
 LL |     if let None = *&None::<()> {}
    |     -------^^^^--------------- help: try: `if (&None::<()>).is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:113:5
+  --> $DIR/redundant_pattern_matching_option.rs:127:5
    |
 LL | /     match x {
 LL | |         Some(_) => true,
@@ -158,7 +170,7 @@ LL | |     };
    | |_____^ help: try: `x.is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:118:5
+  --> $DIR/redundant_pattern_matching_option.rs:132:5
    |
 LL | /     match x {
 LL | |         None => true,
@@ -167,7 +179,7 @@ LL | |     };
    | |_____^ help: try: `x.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:123:5
+  --> $DIR/redundant_pattern_matching_option.rs:137:5
    |
 LL | /     match x {
 LL | |         Some(_) => false,
@@ -176,7 +188,7 @@ LL | |     };
    | |_____^ help: try: `x.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:128:5
+  --> $DIR/redundant_pattern_matching_option.rs:142:5
    |
 LL | /     match x {
 LL | |         None => false,
@@ -185,16 +197,16 @@ LL | |     };
    | |_____^ help: try: `x.is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:143:13
+  --> $DIR/redundant_pattern_matching_option.rs:157:13
    |
 LL |     let _ = matches!(x, Some(_));
    |             ^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:145:13
+  --> $DIR/redundant_pattern_matching_option.rs:159:13
    |
 LL |     let _ = matches!(x, None);
    |             ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()`
 
-error: aborting due to 28 previous errors
+error: aborting due to 30 previous errors
 
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 03d9ea41a0b..8ec19b120d1 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -27,6 +27,7 @@
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
+#![allow(clippy::unwrap_or_default)]
 #![allow(clippy::invisible_characters)]
 #![allow(suspicious_double_ref_op)]
 #![allow(invalid_nan_comparisons)]
@@ -78,6 +79,7 @@
 #![warn(clippy::single_char_add_str)]
 #![warn(clippy::module_name_repetitions)]
 #![warn(clippy::recursive_format_impl)]
+#![warn(clippy::unwrap_or_default)]
 #![warn(clippy::invisible_characters)]
 #![warn(invalid_reference_casting)]
 #![warn(suspicious_double_ref_op)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index c028fcb5a37..51a5976eb61 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -27,6 +27,7 @@
 #![allow(clippy::single_char_add_str)]
 #![allow(clippy::module_name_repetitions)]
 #![allow(clippy::recursive_format_impl)]
+#![allow(clippy::unwrap_or_default)]
 #![allow(clippy::invisible_characters)]
 #![allow(suspicious_double_ref_op)]
 #![allow(invalid_nan_comparisons)]
@@ -78,6 +79,7 @@
 #![warn(clippy::single_char_push_str)]
 #![warn(clippy::stutter)]
 #![warn(clippy::to_string_in_display)]
+#![warn(clippy::unwrap_or_else_default)]
 #![warn(clippy::zero_width_space)]
 #![warn(clippy::cast_ref_to_mut)]
 #![warn(clippy::clone_double_ref)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 4d8a7fd70f4..e420ea1d2ad 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -7,316 +7,322 @@ LL | #![warn(clippy::almost_complete_letter_range)]
    = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::blacklisted_name)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
 
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::derive_hash_xor_eq)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
 error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::integer_arithmetic)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
 
 error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::logic_bug)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
 
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:71:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:72:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:73:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:74:9
+  --> $DIR/rename.rs:75:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:75:9
+  --> $DIR/rename.rs:76:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:76:9
+  --> $DIR/rename.rs:77:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:77:9
+  --> $DIR/rename.rs:78:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:78:9
+  --> $DIR/rename.rs:79:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:79:9
+  --> $DIR/rename.rs:80:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:80:9
+  --> $DIR/rename.rs:81:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
+error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
+  --> $DIR/rename.rs:82:9
+   |
+LL | #![warn(clippy::unwrap_or_else_default)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
+
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:81:9
+  --> $DIR/rename.rs:83:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
-  --> $DIR/rename.rs:82:9
+  --> $DIR/rename.rs:84:9
    |
 LL | #![warn(clippy::cast_ref_to_mut)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
 
 error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
-  --> $DIR/rename.rs:83:9
+  --> $DIR/rename.rs:85:9
    |
 LL | #![warn(clippy::clone_double_ref)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
 
 error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
-  --> $DIR/rename.rs:84:9
+  --> $DIR/rename.rs:86:9
    |
 LL | #![warn(clippy::cmp_nan)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:85:9
+  --> $DIR/rename.rs:87:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
-  --> $DIR/rename.rs:86:9
+  --> $DIR/rename.rs:88:9
    |
 LL | #![warn(clippy::drop_copy)]
    |         ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
 
 error: lint `clippy::drop_ref` has been renamed to `dropping_references`
-  --> $DIR/rename.rs:87:9
+  --> $DIR/rename.rs:89:9
    |
 LL | #![warn(clippy::drop_ref)]
    |         ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:88:9
+  --> $DIR/rename.rs:90:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:89:9
+  --> $DIR/rename.rs:91:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
-  --> $DIR/rename.rs:90:9
+  --> $DIR/rename.rs:92:9
    |
 LL | #![warn(clippy::for_loops_over_fallibles)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
 
 error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
-  --> $DIR/rename.rs:91:9
+  --> $DIR/rename.rs:93:9
    |
 LL | #![warn(clippy::forget_copy)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
 
 error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
-  --> $DIR/rename.rs:92:9
+  --> $DIR/rename.rs:94:9
    |
 LL | #![warn(clippy::forget_ref)]
    |         ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
 
 error: lint `clippy::fn_null_check` has been renamed to `incorrect_fn_null_checks`
-  --> $DIR/rename.rs:93:9
+  --> $DIR/rename.rs:95:9
    |
 LL | #![warn(clippy::fn_null_check)]
    |         ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `incorrect_fn_null_checks`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:94:9
+  --> $DIR/rename.rs:96:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:95:9
+  --> $DIR/rename.rs:97:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:96:9
+  --> $DIR/rename.rs:98:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
-  --> $DIR/rename.rs:97:9
+  --> $DIR/rename.rs:99:9
    |
 LL | #![warn(clippy::invalid_utf8_in_unchecked)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
 
 error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
-  --> $DIR/rename.rs:98:9
+  --> $DIR/rename.rs:100:9
    |
 LL | #![warn(clippy::let_underscore_drop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:99:9
+  --> $DIR/rename.rs:101:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:100:9
+  --> $DIR/rename.rs:102:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
-  --> $DIR/rename.rs:101:9
+  --> $DIR/rename.rs:103:9
    |
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:102:9
+  --> $DIR/rename.rs:104:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
-  --> $DIR/rename.rs:103:9
+  --> $DIR/rename.rs:105:9
    |
 LL | #![warn(clippy::undropped_manually_drops)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `undropped_manually_drops`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:104:9
+  --> $DIR/rename.rs:106:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:105:9
+  --> $DIR/rename.rs:107:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 53 previous errors
+error: aborting due to 54 previous errors
 
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed
new file mode 100644
index 00000000000..653f4533b33
--- /dev/null
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed
@@ -0,0 +1,123 @@
+//@run-rustfix
+#![warn(clippy::semicolon_if_nothing_returned)]
+#![allow(clippy::redundant_closure, clippy::uninlined_format_args, clippy::needless_late_init)]
+
+fn get_unit() {}
+
+// the functions below trigger the lint
+fn main() {
+    println!("Hello");
+}
+
+fn hello() {
+    get_unit();
+}
+
+fn basic101(x: i32) {
+    let y: i32;
+    y = x + 1;
+}
+
+#[rustfmt::skip]
+fn closure_error() {
+    let _d = || {
+        hello();
+    };
+}
+
+#[rustfmt::skip]
+fn unsafe_checks_error() {
+    use std::mem::MaybeUninit;
+    use std::ptr;
+
+    let mut s = MaybeUninit::<String>::uninit();
+    let _d = || unsafe {
+        ptr::drop_in_place(s.as_mut_ptr());
+    };
+}
+
+// this is fine
+fn print_sum(a: i32, b: i32) {
+    println!("{}", a + b);
+    assert_eq!(true, false);
+}
+
+fn foo(x: i32) {
+    let y: i32;
+    if x < 1 {
+        y = 4;
+    } else {
+        y = 5;
+    }
+}
+
+fn bar(x: i32) {
+    let y: i32;
+    match x {
+        1 => y = 4,
+        _ => y = 32,
+    }
+}
+
+fn foobar(x: i32) {
+    let y: i32;
+    'label: {
+        y = x + 1;
+    }
+}
+
+fn loop_test(x: i32) {
+    let y: i32;
+    for &ext in &["stdout", "stderr", "fixed"] {
+        println!("{}", ext);
+    }
+}
+
+fn closure() {
+    let _d = || hello();
+}
+
+#[rustfmt::skip]
+fn closure_block() {
+    let _d = || { hello() };
+}
+
+unsafe fn some_unsafe_op() {}
+unsafe fn some_other_unsafe_fn() {}
+
+fn do_something() {
+    unsafe { some_unsafe_op() };
+
+    unsafe { some_other_unsafe_fn() };
+}
+
+fn unsafe_checks() {
+    use std::mem::MaybeUninit;
+    use std::ptr;
+
+    let mut s = MaybeUninit::<String>::uninit();
+    let _d = || unsafe { ptr::drop_in_place(s.as_mut_ptr()) };
+}
+
+// Issue #7768
+#[rustfmt::skip]
+fn macro_with_semicolon() {
+    macro_rules! repro {
+        () => {
+            while false {
+            }
+        };
+    }
+    repro!();
+}
+
+fn function_returning_option() -> Option<i32> {
+    Some(1)
+}
+
+// No warning
+fn let_else_stmts() {
+    let Some(x) = function_returning_option() else {
+        return;
+    };
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
index 8e7f1d862cf..9db038219b4 100644
--- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs
@@ -1,5 +1,6 @@
+//@run-rustfix
 #![warn(clippy::semicolon_if_nothing_returned)]
-#![allow(clippy::redundant_closure, clippy::uninlined_format_args)]
+#![allow(clippy::redundant_closure, clippy::uninlined_format_args, clippy::needless_late_init)]
 
 fn get_unit() {}
 
diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
index 8d9a67585cf..78813e7cc1c 100644
--- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
+++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr
@@ -1,5 +1,5 @@
 error: consider adding a `;` to the last statement for consistent formatting
-  --> $DIR/semicolon_if_nothing_returned.rs:8:5
+  --> $DIR/semicolon_if_nothing_returned.rs:9:5
    |
 LL |     println!("Hello")
    |     ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");`
@@ -7,25 +7,25 @@ LL |     println!("Hello")
    = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings`
 
 error: consider adding a `;` to the last statement for consistent formatting
-  --> $DIR/semicolon_if_nothing_returned.rs:12:5
+  --> $DIR/semicolon_if_nothing_returned.rs:13:5
    |
 LL |     get_unit()
    |     ^^^^^^^^^^ help: add a `;` here: `get_unit();`
 
 error: consider adding a `;` to the last statement for consistent formatting
-  --> $DIR/semicolon_if_nothing_returned.rs:17:5
+  --> $DIR/semicolon_if_nothing_returned.rs:18:5
    |
 LL |     y = x + 1
    |     ^^^^^^^^^ help: add a `;` here: `y = x + 1;`
 
 error: consider adding a `;` to the last statement for consistent formatting
-  --> $DIR/semicolon_if_nothing_returned.rs:23:9
+  --> $DIR/semicolon_if_nothing_returned.rs:24:9
    |
 LL |         hello()
    |         ^^^^^^^ help: add a `;` here: `hello();`
 
 error: consider adding a `;` to the last statement for consistent formatting
-  --> $DIR/semicolon_if_nothing_returned.rs:34:9
+  --> $DIR/semicolon_if_nothing_returned.rs:35:9
    |
 LL |         ptr::drop_in_place(s.as_mut_ptr())
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `ptr::drop_in_place(s.as_mut_ptr());`
diff --git a/src/tools/clippy/tests/ui/shadow.rs b/src/tools/clippy/tests/ui/shadow.rs
index 9be8c5e59d0..1b40a43d019 100644
--- a/src/tools/clippy/tests/ui/shadow.rs
+++ b/src/tools/clippy/tests/ui/shadow.rs
@@ -1,7 +1,12 @@
 //@aux-build:proc_macro_derive.rs:proc-macro
 
 #![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)]
-#![allow(clippy::let_unit_value, clippy::needless_if)]
+#![allow(
+    clippy::let_unit_value,
+    clippy::needless_if,
+    clippy::redundant_guards,
+    clippy::redundant_locals
+)]
 
 extern crate proc_macro_derive;
 
diff --git a/src/tools/clippy/tests/ui/shadow.stderr b/src/tools/clippy/tests/ui/shadow.stderr
index 8321f6df224..88b02f53be1 100644
--- a/src/tools/clippy/tests/ui/shadow.stderr
+++ b/src/tools/clippy/tests/ui/shadow.stderr
@@ -1,278 +1,278 @@
 error: `x` is shadowed by itself in `x`
-  --> $DIR/shadow.rs:19:9
+  --> $DIR/shadow.rs:24:9
    |
 LL |     let x = x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:18:9
+  --> $DIR/shadow.rs:23:9
    |
 LL |     let x = 1;
    |         ^
    = note: `-D clippy::shadow-same` implied by `-D warnings`
 
 error: `mut x` is shadowed by itself in `&x`
-  --> $DIR/shadow.rs:20:13
+  --> $DIR/shadow.rs:25:13
    |
 LL |     let mut x = &x;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:19:9
+  --> $DIR/shadow.rs:24:9
    |
 LL |     let x = x;
    |         ^
 
 error: `x` is shadowed by itself in `&mut x`
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:26:9
    |
 LL |     let x = &mut x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:20:9
+  --> $DIR/shadow.rs:25:9
    |
 LL |     let mut x = &x;
    |         ^^^^^
 
 error: `x` is shadowed by itself in `*x`
-  --> $DIR/shadow.rs:22:9
+  --> $DIR/shadow.rs:27:9
    |
 LL |     let x = *x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:21:9
+  --> $DIR/shadow.rs:26:9
    |
 LL |     let x = &mut x;
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:27:9
+  --> $DIR/shadow.rs:32:9
    |
 LL |     let x = x.0;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:26:9
+  --> $DIR/shadow.rs:31:9
    |
 LL |     let x = ([[0]], ());
    |         ^
    = note: `-D clippy::shadow-reuse` implied by `-D warnings`
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:28:9
+  --> $DIR/shadow.rs:33:9
    |
 LL |     let x = x[0];
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:27:9
+  --> $DIR/shadow.rs:32:9
    |
 LL |     let x = x.0;
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:29:10
+  --> $DIR/shadow.rs:34:10
    |
 LL |     let [x] = x;
    |          ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:28:9
+  --> $DIR/shadow.rs:33:9
    |
 LL |     let x = x[0];
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:30:9
+  --> $DIR/shadow.rs:35:9
    |
 LL |     let x = Some(x);
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:29:10
+  --> $DIR/shadow.rs:34:10
    |
 LL |     let [x] = x;
    |          ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:31:9
+  --> $DIR/shadow.rs:36:9
    |
 LL |     let x = foo(x);
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:30:9
+  --> $DIR/shadow.rs:35:9
    |
 LL |     let x = Some(x);
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:32:9
+  --> $DIR/shadow.rs:37:9
    |
 LL |     let x = || x;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:31:9
+  --> $DIR/shadow.rs:36:9
    |
 LL |     let x = foo(x);
    |         ^
 
 error: `x` is shadowed
-  --> $DIR/shadow.rs:33:9
+  --> $DIR/shadow.rs:38:9
    |
 LL |     let x = Some(1).map(|_| x)?;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:32:9
+  --> $DIR/shadow.rs:37:9
    |
 LL |     let x = || x;
    |         ^
 
 error: `y` is shadowed
-  --> $DIR/shadow.rs:35:9
+  --> $DIR/shadow.rs:40:9
    |
 LL |     let y = match y {
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:34:9
+  --> $DIR/shadow.rs:39:9
    |
 LL |     let y = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:50:9
+  --> $DIR/shadow.rs:55:9
    |
 LL |     let x = 2;
    |         ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:49:9
+  --> $DIR/shadow.rs:54:9
    |
 LL |     let x = 1;
    |         ^
    = note: `-D clippy::shadow-unrelated` implied by `-D warnings`
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:55:13
+  --> $DIR/shadow.rs:60:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:54:10
+  --> $DIR/shadow.rs:59:10
    |
 LL |     fn f(x: u32) {
    |          ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:60:14
+  --> $DIR/shadow.rs:65:14
    |
 LL |         Some(x) => {
    |              ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:57:9
+  --> $DIR/shadow.rs:62:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:61:17
+  --> $DIR/shadow.rs:66:17
    |
 LL |             let x = 1;
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:60:14
+  --> $DIR/shadow.rs:65:14
    |
 LL |         Some(x) => {
    |              ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:65:17
+  --> $DIR/shadow.rs:70:17
    |
 LL |     if let Some(x) = Some(1) {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:57:9
+  --> $DIR/shadow.rs:62:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:66:20
+  --> $DIR/shadow.rs:71:20
    |
 LL |     while let Some(x) = Some(1) {}
    |                    ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:57:9
+  --> $DIR/shadow.rs:62:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:67:15
+  --> $DIR/shadow.rs:72:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:57:9
+  --> $DIR/shadow.rs:62:9
    |
 LL |     let x = 1;
    |         ^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:68:13
+  --> $DIR/shadow.rs:73:13
    |
 LL |         let x = 1;
    |             ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:67:15
+  --> $DIR/shadow.rs:72:15
    |
 LL |     let _ = |[x]: [u32; 1]| {
    |               ^
 
 error: `y` is shadowed
-  --> $DIR/shadow.rs:71:17
+  --> $DIR/shadow.rs:76:17
    |
 LL |     if let Some(y) = y {}
    |                 ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:70:9
+  --> $DIR/shadow.rs:75:9
    |
 LL |     let y = Some(1);
    |         ^
 
 error: `_b` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:107:9
+  --> $DIR/shadow.rs:112:9
    |
 LL |     let _b = _a;
    |         ^^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:106:28
+  --> $DIR/shadow.rs:111:28
    |
 LL | pub async fn foo2(_a: i32, _b: i64) {
    |                            ^^
 
 error: `x` shadows a previous, unrelated binding
-  --> $DIR/shadow.rs:113:21
+  --> $DIR/shadow.rs:118:21
    |
 LL |         if let Some(x) = Some(1) { x } else { 1 }
    |                     ^
    |
 note: previous binding is here
-  --> $DIR/shadow.rs:112:13
+  --> $DIR/shadow.rs:117:13
    |
 LL |         let x = 1;
    |             ^
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
index 2ae9fa34d14..a3bb05bf176 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
+++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
@@ -39,15 +39,6 @@ LL | |     }
    |
    = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
 
-error: this argument is a mutable reference, but not used mutably
-  --> $DIR/method_list_2.rs:38:31
-   |
-LL |     pub fn hash(&self, state: &mut T) {
-   |                               ^^^^^^ help: consider changing to: `&T`
-   |
-   = warning: changing this function will impact semver compatibility
-   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
-
 error: method `index` can be confused for the standard trait method `std::ops::Index::index`
   --> $DIR/method_list_2.rs:42:5
    |
@@ -158,5 +149,14 @@ LL | |     }
    |
    = help: consider implementing the trait `std::ops::Sub` or choosing a less ambiguous method name
 
+error: this argument is a mutable reference, but not used mutably
+  --> $DIR/method_list_2.rs:38:31
+   |
+LL |     pub fn hash(&self, state: &mut T) {
+   |                               ^^^^^^ help: consider changing to: `&T`
+   |
+   = warning: changing this function will impact semver compatibility
+   = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
+
 error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.fixed b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
index eb8524167c4..8065e9e5fbc 100644
--- a/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed
@@ -51,6 +51,33 @@ pub fn issue_11128() {
     }
 }
 
+pub fn issue_11160() -> bool {
+    let mutex = Mutex::new(1i32);
+    let lock = mutex.lock().unwrap();
+    let _ = lock.abs();
+    true
+}
+
+pub fn issue_11189() {
+    struct Number {
+        pub value: u32,
+    }
+
+    fn do_something() -> Result<(), ()> {
+        let number = Mutex::new(Number { value: 1 });
+        let number2 = Mutex::new(Number { value: 2 });
+        let number3 = Mutex::new(Number { value: 3 });
+        let mut lock = number.lock().unwrap();
+        let mut lock2 = number2.lock().unwrap();
+        let mut lock3 = number3.lock().unwrap();
+        lock.value += 1;
+        lock2.value += 1;
+        lock3.value += 1;
+        drop((lock, lock2, lock3));
+        Ok(())
+    }
+}
+
 pub fn path_return_can_be_ignored() -> i32 {
     let mutex = Mutex::new(1);
     let lock = mutex.lock().unwrap();
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.rs b/src/tools/clippy/tests/ui/significant_drop_tightening.rs
index f7fa65ea922..1620b76843a 100644
--- a/src/tools/clippy/tests/ui/significant_drop_tightening.rs
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.rs
@@ -50,6 +50,33 @@ pub fn issue_11128() {
     }
 }
 
+pub fn issue_11160() -> bool {
+    let mutex = Mutex::new(1i32);
+    let lock = mutex.lock().unwrap();
+    let _ = lock.abs();
+    true
+}
+
+pub fn issue_11189() {
+    struct Number {
+        pub value: u32,
+    }
+
+    fn do_something() -> Result<(), ()> {
+        let number = Mutex::new(Number { value: 1 });
+        let number2 = Mutex::new(Number { value: 2 });
+        let number3 = Mutex::new(Number { value: 3 });
+        let mut lock = number.lock().unwrap();
+        let mut lock2 = number2.lock().unwrap();
+        let mut lock3 = number3.lock().unwrap();
+        lock.value += 1;
+        lock2.value += 1;
+        lock3.value += 1;
+        drop((lock, lock2, lock3));
+        Ok(())
+    }
+}
+
 pub fn path_return_can_be_ignored() -> i32 {
     let mutex = Mutex::new(1);
     let lock = mutex.lock().unwrap();
diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
index ca4fede17c9..b5cad88ad3f 100644
--- a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr
@@ -23,7 +23,7 @@ LL +     drop(lock);
    |
 
 error: temporary with significant `Drop` can be early dropped
-  --> $DIR/significant_drop_tightening.rs:79:13
+  --> $DIR/significant_drop_tightening.rs:106:13
    |
 LL | /     {
 LL | |         let mutex = Mutex::new(1i32);
@@ -43,7 +43,7 @@ LL +         drop(lock);
    |
 
 error: temporary with significant `Drop` can be early dropped
-  --> $DIR/significant_drop_tightening.rs:100:13
+  --> $DIR/significant_drop_tightening.rs:127:13
    |
 LL | /     {
 LL | |         let mutex = Mutex::new(1i32);
@@ -67,7 +67,7 @@ LL +
    |
 
 error: temporary with significant `Drop` can be early dropped
-  --> $DIR/significant_drop_tightening.rs:106:17
+  --> $DIR/significant_drop_tightening.rs:133:17
    |
 LL | /     {
 LL | |         let mutex = Mutex::new(vec![1i32]);
diff --git a/src/tools/clippy/tests/ui/single_match.fixed b/src/tools/clippy/tests/ui/single_match.fixed
index e7b1fd6a85f..163ba94aff8 100644
--- a/src/tools/clippy/tests/ui/single_match.fixed
+++ b/src/tools/clippy/tests/ui/single_match.fixed
@@ -4,6 +4,7 @@
     unused,
     clippy::uninlined_format_args,
     clippy::needless_if,
+    clippy::redundant_guards,
     clippy::redundant_pattern_matching
 )]
 fn dummy() {}
diff --git a/src/tools/clippy/tests/ui/single_match.rs b/src/tools/clippy/tests/ui/single_match.rs
index 1515a7053e5..0dcdb125ffd 100644
--- a/src/tools/clippy/tests/ui/single_match.rs
+++ b/src/tools/clippy/tests/ui/single_match.rs
@@ -4,6 +4,7 @@
     unused,
     clippy::uninlined_format_args,
     clippy::needless_if,
+    clippy::redundant_guards,
     clippy::redundant_pattern_matching
 )]
 fn dummy() {}
diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr
index 76f7e789589..d3536159949 100644
--- a/src/tools/clippy/tests/ui/single_match.stderr
+++ b/src/tools/clippy/tests/ui/single_match.stderr
@@ -1,5 +1,5 @@
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:14:5
+  --> $DIR/single_match.rs:15:5
    |
 LL | /     match x {
 LL | |         Some(y) => {
@@ -18,7 +18,7 @@ LL ~     };
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:22:5
+  --> $DIR/single_match.rs:23:5
    |
 LL | /     match x {
 LL | |         // Note the missing block braces.
@@ -30,7 +30,7 @@ LL | |     }
    | |_____^ help: try: `if let Some(y) = x { println!("{:?}", y) }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:31:5
+  --> $DIR/single_match.rs:32:5
    |
 LL | /     match z {
 LL | |         (2..=3, 7..=9) => dummy(),
@@ -39,7 +39,7 @@ LL | |     };
    | |_____^ help: try: `if let (2..=3, 7..=9) = z { dummy() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:60:5
+  --> $DIR/single_match.rs:61:5
    |
 LL | /     match x {
 LL | |         Some(y) => dummy(),
@@ -48,7 +48,7 @@ LL | |     };
    | |_____^ help: try: `if let Some(y) = x { dummy() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:65:5
+  --> $DIR/single_match.rs:66:5
    |
 LL | /     match y {
 LL | |         Ok(y) => dummy(),
@@ -57,7 +57,7 @@ LL | |     };
    | |_____^ help: try: `if let Ok(y) = y { dummy() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:72:5
+  --> $DIR/single_match.rs:73:5
    |
 LL | /     match c {
 LL | |         Cow::Borrowed(..) => dummy(),
@@ -66,7 +66,7 @@ LL | |     };
    | |_____^ help: try: `if let Cow::Borrowed(..) = c { dummy() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:93:5
+  --> $DIR/single_match.rs:94:5
    |
 LL | /     match x {
 LL | |         "test" => println!(),
@@ -75,7 +75,7 @@ LL | |     }
    | |_____^ help: try: `if x == "test" { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:106:5
+  --> $DIR/single_match.rs:107:5
    |
 LL | /     match x {
 LL | |         Foo::A => println!(),
@@ -84,7 +84,7 @@ LL | |     }
    | |_____^ help: try: `if x == Foo::A { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:112:5
+  --> $DIR/single_match.rs:113:5
    |
 LL | /     match x {
 LL | |         FOO_C => println!(),
@@ -93,7 +93,7 @@ LL | |     }
    | |_____^ help: try: `if x == FOO_C { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:117:5
+  --> $DIR/single_match.rs:118:5
    |
 LL | /     match &&x {
 LL | |         Foo::A => println!(),
@@ -102,7 +102,7 @@ LL | |     }
    | |_____^ help: try: `if x == Foo::A { println!() }`
 
 error: you seem to be trying to use `match` for an equality check. Consider using `if`
-  --> $DIR/single_match.rs:123:5
+  --> $DIR/single_match.rs:124:5
    |
 LL | /     match &x {
 LL | |         Foo::A => println!(),
@@ -111,7 +111,7 @@ LL | |     }
    | |_____^ help: try: `if x == &Foo::A { println!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:140:5
+  --> $DIR/single_match.rs:141:5
    |
 LL | /     match x {
 LL | |         Bar::A => println!(),
@@ -120,7 +120,7 @@ LL | |     }
    | |_____^ help: try: `if let Bar::A = x { println!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:148:5
+  --> $DIR/single_match.rs:149:5
    |
 LL | /     match x {
 LL | |         None => println!(),
@@ -129,7 +129,7 @@ LL | |     };
    | |_____^ help: try: `if let None = x { println!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:170:5
+  --> $DIR/single_match.rs:171:5
    |
 LL | /     match x {
 LL | |         (Some(_), _) => {},
@@ -138,7 +138,7 @@ LL | |     }
    | |_____^ help: try: `if let (Some(_), _) = x {}`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:176:5
+  --> $DIR/single_match.rs:177:5
    |
 LL | /     match x {
 LL | |         (Some(E::V), _) => todo!(),
@@ -147,7 +147,7 @@ LL | |     }
    | |_____^ help: try: `if let (Some(E::V), _) = x { todo!() }`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:182:5
+  --> $DIR/single_match.rs:183:5
    |
 LL | /     match (Some(42), Some(E::V), Some(42)) {
 LL | |         (.., Some(E::V), _) => {},
@@ -156,7 +156,7 @@ LL | |     }
    | |_____^ help: try: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}`
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:254:5
+  --> $DIR/single_match.rs:255:5
    |
 LL | /     match bar {
 LL | |         Some(v) => unsafe {
@@ -176,7 +176,7 @@ LL +     } }
    |
 
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:262:5
+  --> $DIR/single_match.rs:263:5
    |
 LL | /     match bar {
 LL | |         #[rustfmt::skip]
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
index 16be9f6d203..cfb856861b8 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.rs
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
@@ -4,6 +4,7 @@ fn main() {
     resize_vector();
     extend_vector();
     mixed_extend_resize_vector();
+    from_empty_vec();
 }
 
 fn extend_vector() {
@@ -59,6 +60,21 @@ fn resize_vector() {
     vec1.resize(10, 0);
 }
 
+fn from_empty_vec() {
+    // Resize with constant expression
+    let len = 300;
+    let mut vec1 = Vec::new();
+    vec1.resize(len, 0);
+
+    // Resize with len expression
+    let mut vec3 = Vec::new();
+    vec3.resize(len - 10, 0);
+
+    // Reinitialization should be warned
+    vec1 = Vec::new();
+    vec1.resize(10, 0);
+}
+
 fn do_stuff(vec: &mut [u8]) {}
 
 fn extend_vector_with_manipulations_between() {
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
index 22376680a8e..532ce4ac191 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr
@@ -1,84 +1,108 @@
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:13:5
+  --> $DIR/slow_vector_initialization.rs:14:5
    |
 LL |     let mut vec1 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
 LL |     vec1.extend(repeat(0).take(len));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::slow-vector-initialization` implied by `-D warnings`
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:17:5
+  --> $DIR/slow_vector_initialization.rs:18:5
    |
 LL |     let mut vec2 = Vec::with_capacity(len - 10);
-   |                    ---------------------------- help: consider replace allocation with: `vec![0; len - 10]`
+   |                    ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
 LL |     vec2.extend(repeat(0).take(len - 10));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:24:5
+  --> $DIR/slow_vector_initialization.rs:25:5
    |
 LL |     let mut vec4 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
 LL |     vec4.extend(repeat(0).take(vec4.capacity()));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:34:5
+  --> $DIR/slow_vector_initialization.rs:35:5
    |
 LL |     let mut resized_vec = Vec::with_capacity(30);
-   |                           ---------------------- help: consider replace allocation with: `vec![0; 30]`
+   |                           ---------------------- help: consider replacing this with: `vec![0; 30]`
 LL |     resized_vec.resize(30, 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:37:5
+  --> $DIR/slow_vector_initialization.rs:38:5
    |
 LL |     let mut extend_vec = Vec::with_capacity(30);
-   |                          ---------------------- help: consider replace allocation with: `vec![0; 30]`
+   |                          ---------------------- help: consider replacing this with: `vec![0; 30]`
 LL |     extend_vec.extend(repeat(0).take(30));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:44:5
+  --> $DIR/slow_vector_initialization.rs:45:5
    |
 LL |     let mut vec1 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
 LL |     vec1.resize(len, 0);
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:52:5
+  --> $DIR/slow_vector_initialization.rs:53:5
    |
 LL |     let mut vec3 = Vec::with_capacity(len - 10);
-   |                    ---------------------------- help: consider replace allocation with: `vec![0; len - 10]`
+   |                    ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
 LL |     vec3.resize(len - 10, 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:55:5
+  --> $DIR/slow_vector_initialization.rs:56:5
    |
 LL |     let mut vec4 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replace allocation with: `vec![0; len]`
+   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
 LL |     vec4.resize(vec4.capacity(), 0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: slow zero-filling initialization
-  --> $DIR/slow_vector_initialization.rs:59:5
+  --> $DIR/slow_vector_initialization.rs:60:5
    |
 LL |     vec1 = Vec::with_capacity(10);
-   |            ---------------------- help: consider replace allocation with: `vec![0; 10]`
+   |            ---------------------- help: consider replacing this with: `vec![0; 10]`
+LL |     vec1.resize(10, 0);
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:67:5
+   |
+LL |     let mut vec1 = Vec::new();
+   |                    ---------- help: consider replacing this with: `vec![0; len]`
+LL |     vec1.resize(len, 0);
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:71:5
+   |
+LL |     let mut vec3 = Vec::new();
+   |                    ---------- help: consider replacing this with: `vec![0; len - 10]`
+LL |     vec3.resize(len - 10, 0);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: slow zero-filling initialization
+  --> $DIR/slow_vector_initialization.rs:75:5
+   |
+LL |     vec1 = Vec::new();
+   |            ---------- help: consider replacing this with: `vec![0; 10]`
 LL |     vec1.resize(10, 0);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: this argument is a mutable reference, but not used mutably
-  --> $DIR/slow_vector_initialization.rs:62:18
+  --> $DIR/slow_vector_initialization.rs:78:18
    |
 LL | fn do_stuff(vec: &mut [u8]) {}
    |                  ^^^^^^^^^ help: consider changing to: `&[u8]`
    |
    = note: `-D clippy::needless-pass-by-ref-mut` implied by `-D warnings`
 
-error: aborting due to 10 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.fixed b/src/tools/clippy/tests/ui/string_lit_chars_any.fixed
new file mode 100644
index 00000000000..d7ab9c3397a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_lit_chars_any.fixed
@@ -0,0 +1,50 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::eq_op, clippy::needless_raw_string_hashes, clippy::no_effect, unused)]
+#![warn(clippy::string_lit_chars_any)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct NotStringLit;
+
+impl NotStringLit {
+    fn chars(&self) -> impl Iterator<Item = char> {
+        "c".chars()
+    }
+}
+
+fn main() {
+    let c = 'c';
+    matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+    matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+    matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+    matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+    #[rustfmt::skip]
+    matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+    // Do not lint
+    NotStringLit.chars().any(|x| x == c);
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| {
+        let c = 'c';
+        x == c
+    });
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| {
+        1;
+        x == c
+    });
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == x);
+    "\\.+*?()|[]{}^$#&-~".chars().any(|_x| c == c);
+    matches!(
+        c,
+        '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'
+    );
+    external! {
+        let c = 'c';
+        "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+    }
+    with_span! {
+        span
+        let c = 'c';
+        "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.rs b/src/tools/clippy/tests/ui/string_lit_chars_any.rs
new file mode 100644
index 00000000000..9408d7bb239
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_lit_chars_any.rs
@@ -0,0 +1,50 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs:proc-macro
+#![allow(clippy::eq_op, clippy::needless_raw_string_hashes, clippy::no_effect, unused)]
+#![warn(clippy::string_lit_chars_any)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct NotStringLit;
+
+impl NotStringLit {
+    fn chars(&self) -> impl Iterator<Item = char> {
+        "c".chars()
+    }
+}
+
+fn main() {
+    let c = 'c';
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+    r#"\.+*?()|[]{}^$#&-~"#.chars().any(|x| x == c);
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| c == x);
+    r#"\.+*?()|[]{}^$#&-~"#.chars().any(|x| c == x);
+    #[rustfmt::skip]
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| { x == c });
+    // Do not lint
+    NotStringLit.chars().any(|x| x == c);
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| {
+        let c = 'c';
+        x == c
+    });
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| {
+        1;
+        x == c
+    });
+    "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == x);
+    "\\.+*?()|[]{}^$#&-~".chars().any(|_x| c == c);
+    matches!(
+        c,
+        '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'
+    );
+    external! {
+        let c = 'c';
+        "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+    }
+    with_span! {
+        span
+        let c = 'c';
+        "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.stderr b/src/tools/clippy/tests/ui/string_lit_chars_any.stderr
new file mode 100644
index 00000000000..ff951b73ded
--- /dev/null
+++ b/src/tools/clippy/tests/ui/string_lit_chars_any.stderr
@@ -0,0 +1,58 @@
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+  --> $DIR/string_lit_chars_any.rs:19:5
+   |
+LL |     "//.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::string-lit-chars-any` implied by `-D warnings`
+help: use `matches!(...)` instead
+   |
+LL |     matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+  --> $DIR/string_lit_chars_any.rs:20:5
+   |
+LL |     r#"/.+*?()|[]{}^$#&-~"#.chars().any(|x| x == c);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `matches!(...)` instead
+   |
+LL |     matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+  --> $DIR/string_lit_chars_any.rs:21:5
+   |
+LL |     "//.+*?()|[]{}^$#&-~".chars().any(|x| c == x);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `matches!(...)` instead
+   |
+LL |     matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+  --> $DIR/string_lit_chars_any.rs:22:5
+   |
+LL |     r#"/.+*?()|[]{}^$#&-~"#.chars().any(|x| c == x);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `matches!(...)` instead
+   |
+LL |     matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: usage of `.chars().any(...)` to check if a char matches any from a string literal
+  --> $DIR/string_lit_chars_any.rs:24:5
+   |
+LL |     "//.+*?()|[]{}^$#&-~".chars().any(|x| { x == c });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use `matches!(...)` instead
+   |
+LL |     matches!(c, '//' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
+   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/swap.fixed b/src/tools/clippy/tests/ui/swap.fixed
index 22f904e3fd9..7b74a83b6df 100644
--- a/src/tools/clippy/tests/ui/swap.fixed
+++ b/src/tools/clippy/tests/ui/swap.fixed
@@ -11,7 +11,8 @@
     unused_assignments,
     unused_variables,
     clippy::let_and_return,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::redundant_locals
 )]
 
 struct Foo(u32);
diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs
index ada64f89e6d..93855cd7b5c 100644
--- a/src/tools/clippy/tests/ui/swap.rs
+++ b/src/tools/clippy/tests/ui/swap.rs
@@ -11,7 +11,8 @@
     unused_assignments,
     unused_variables,
     clippy::let_and_return,
-    clippy::useless_vec
+    clippy::useless_vec,
+    clippy::redundant_locals
 )]
 
 struct Foo(u32);
diff --git a/src/tools/clippy/tests/ui/swap.stderr b/src/tools/clippy/tests/ui/swap.stderr
index a3b9c2b744c..1097b29bba0 100644
--- a/src/tools/clippy/tests/ui/swap.stderr
+++ b/src/tools/clippy/tests/ui/swap.stderr
@@ -1,5 +1,5 @@
 error: this looks like you are swapping `bar.a` and `bar.b` manually
-  --> $DIR/swap.rs:28:5
+  --> $DIR/swap.rs:29:5
    |
 LL | /     let temp = bar.a;
 LL | |     bar.a = bar.b;
@@ -10,7 +10,7 @@ LL | |     bar.b = temp;
    = note: `-D clippy::manual-swap` implied by `-D warnings`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:40:5
+  --> $DIR/swap.rs:41:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -18,7 +18,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:49:5
+  --> $DIR/swap.rs:50:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -26,7 +26,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:68:5
+  --> $DIR/swap.rs:69:5
    |
 LL | /     let temp = foo[0];
 LL | |     foo[0] = foo[1];
@@ -34,7 +34,7 @@ LL | |     foo[1] = temp;
    | |__________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:79:5
+  --> $DIR/swap.rs:80:5
    |
 LL | /     a ^= b;
 LL | |     b ^= a;
@@ -42,7 +42,7 @@ LL | |     a ^= b;
    | |___________^ help: try: `std::mem::swap(&mut a, &mut b);`
 
 error: this looks like you are swapping `bar.a` and `bar.b` manually
-  --> $DIR/swap.rs:87:5
+  --> $DIR/swap.rs:88:5
    |
 LL | /     bar.a ^= bar.b;
 LL | |     bar.b ^= bar.a;
@@ -50,7 +50,7 @@ LL | |     bar.a ^= bar.b;
    | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);`
 
 error: this looks like you are swapping elements of `foo` manually
-  --> $DIR/swap.rs:95:5
+  --> $DIR/swap.rs:96:5
    |
 LL | /     foo[0] ^= foo[1];
 LL | |     foo[1] ^= foo[0];
@@ -58,7 +58,7 @@ LL | |     foo[0] ^= foo[1];
    | |_____________________^ help: try: `foo.swap(0, 1);`
 
 error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually
-  --> $DIR/swap.rs:124:5
+  --> $DIR/swap.rs:125:5
    |
 LL | /     let temp = foo[0][1];
 LL | |     foo[0][1] = bar[1][0];
@@ -68,7 +68,7 @@ LL | |     bar[1][0] = temp;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `a` and `b` manually
-  --> $DIR/swap.rs:138:7
+  --> $DIR/swap.rs:139:7
    |
 LL |       ; let t = a;
    |  _______^
@@ -79,7 +79,7 @@ LL | |     b = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `c.0` and `a` manually
-  --> $DIR/swap.rs:147:7
+  --> $DIR/swap.rs:148:7
    |
 LL |       ; let t = c.0;
    |  _______^
@@ -90,7 +90,7 @@ LL | |     a = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `b` and `a` manually
-  --> $DIR/swap.rs:173:5
+  --> $DIR/swap.rs:174:5
    |
 LL | /     let t = b;
 LL | |     b = a;
@@ -100,7 +100,7 @@ LL | |     a = t;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:135:5
+  --> $DIR/swap.rs:136:5
    |
 LL | /     a = b;
 LL | |     b = a;
@@ -110,7 +110,7 @@ LL | |     b = a;
    = note: `-D clippy::almost-swapped` implied by `-D warnings`
 
 error: this looks like you are trying to swap `c.0` and `a`
-  --> $DIR/swap.rs:144:5
+  --> $DIR/swap.rs:145:5
    |
 LL | /     c.0 = a;
 LL | |     a = c.0;
@@ -119,7 +119,7 @@ LL | |     a = c.0;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:151:5
+  --> $DIR/swap.rs:152:5
    |
 LL | /     let a = b;
 LL | |     let b = a;
@@ -128,7 +128,7 @@ LL | |     let b = a;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `d` and `c`
-  --> $DIR/swap.rs:156:5
+  --> $DIR/swap.rs:157:5
    |
 LL | /     d = c;
 LL | |     c = d;
@@ -137,7 +137,7 @@ LL | |     c = d;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are trying to swap `a` and `b`
-  --> $DIR/swap.rs:160:5
+  --> $DIR/swap.rs:161:5
    |
 LL | /     let a = b;
 LL | |     b = a;
@@ -146,7 +146,7 @@ LL | |     b = a;
    = note: or maybe you should use `std::mem::replace`?
 
 error: this looks like you are swapping `s.0.x` and `s.0.y` manually
-  --> $DIR/swap.rs:208:5
+  --> $DIR/swap.rs:209:5
    |
 LL | /     let t = s.0.x;
 LL | |     s.0.x = s.0.y;
diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed
index 1816740870a..930489fab76 100644
--- a/src/tools/clippy/tests/ui/try_err.fixed
+++ b/src/tools/clippy/tests/ui/try_err.fixed
@@ -2,7 +2,11 @@
 //@aux-build:proc_macros.rs:proc-macro
 
 #![deny(clippy::try_err)]
-#![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
+#![allow(
+    clippy::unnecessary_wraps,
+    clippy::needless_question_mark,
+    clippy::needless_return_with_question_mark
+)]
 
 extern crate proc_macros;
 use proc_macros::{external, inline_macros};
diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs
index 0e47c4d023e..f5baf3d8f74 100644
--- a/src/tools/clippy/tests/ui/try_err.rs
+++ b/src/tools/clippy/tests/ui/try_err.rs
@@ -2,7 +2,11 @@
 //@aux-build:proc_macros.rs:proc-macro
 
 #![deny(clippy::try_err)]
-#![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
+#![allow(
+    clippy::unnecessary_wraps,
+    clippy::needless_question_mark,
+    clippy::needless_return_with_question_mark
+)]
 
 extern crate proc_macros;
 use proc_macros::{external, inline_macros};
diff --git a/src/tools/clippy/tests/ui/try_err.stderr b/src/tools/clippy/tests/ui/try_err.stderr
index 79f7b70224a..9968b383ebb 100644
--- a/src/tools/clippy/tests/ui/try_err.stderr
+++ b/src/tools/clippy/tests/ui/try_err.stderr
@@ -1,5 +1,5 @@
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:19:9
+  --> $DIR/try_err.rs:23:9
    |
 LL |         Err(err)?;
    |         ^^^^^^^^^ help: try: `return Err(err)`
@@ -11,25 +11,25 @@ LL | #![deny(clippy::try_err)]
    |         ^^^^^^^^^^^^^^^
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:29:9
+  --> $DIR/try_err.rs:33:9
    |
 LL |         Err(err)?;
    |         ^^^^^^^^^ help: try: `return Err(err.into())`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:49:17
+  --> $DIR/try_err.rs:53:17
    |
 LL |                 Err(err)?;
    |                 ^^^^^^^^^ help: try: `return Err(err)`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:68:17
+  --> $DIR/try_err.rs:72:17
    |
 LL |                 Err(err)?;
    |                 ^^^^^^^^^ help: try: `return Err(err.into())`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:88:23
+  --> $DIR/try_err.rs:92:23
    |
 LL |             Err(_) => Err(1)?,
    |                       ^^^^^^^ help: try: `return Err(1)`
@@ -37,7 +37,7 @@ LL |             Err(_) => Err(1)?,
    = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:95:23
+  --> $DIR/try_err.rs:99:23
    |
 LL |             Err(_) => Err(inline!(1))?,
    |                       ^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(1))`
@@ -45,31 +45,31 @@ LL |             Err(_) => Err(inline!(1))?,
    = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:122:9
+  --> $DIR/try_err.rs:126:9
    |
 LL |         Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:129:9
+  --> $DIR/try_err.rs:133:9
    |
 LL |         Err(io::ErrorKind::WriteZero)?
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:131:9
+  --> $DIR/try_err.rs:135:9
    |
 LL |         Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))?
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:139:9
+  --> $DIR/try_err.rs:143:9
    |
 LL |         Err(io::ErrorKind::NotFound)?
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))`
 
 error: returning an `Err(_)` with the `?` operator
-  --> $DIR/try_err.rs:148:16
+  --> $DIR/try_err.rs:152:16
    |
 LL |         return Err(42)?;
    |                ^^^^^^^^ help: try: `Err(42)`
diff --git a/src/tools/clippy/tests/ui/tuple_array_conversions.rs b/src/tools/clippy/tests/ui/tuple_array_conversions.rs
index f96a7c97f1a..569415acbce 100644
--- a/src/tools/clippy/tests/ui/tuple_array_conversions.rs
+++ b/src/tools/clippy/tests/ui/tuple_array_conversions.rs
@@ -52,6 +52,36 @@ fn main() {
         let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect();
         let t2: Vec<(u32, u32)> = v1.iter().map(|&[a, b]| (a, b)).collect();
     }
+    // FP #11082; needs discussion
+    let (a, b) = (1.0f64, 2.0f64);
+    let _: &[f64] = &[a, b];
+    // FP #11085; impossible to fix
+    let [src, dest]: [_; 2] = [1, 2];
+    (src, dest);
+    // FP #11100
+    fn issue_11100_array_to_tuple(this: [&mut i32; 2]) -> (&i32, &mut i32) {
+        let [input, output] = this;
+        (input, output)
+    }
+
+    fn issue_11100_tuple_to_array<'a>(this: (&'a mut i32, &'a mut i32)) -> [&'a i32; 2] {
+        let (input, output) = this;
+        [input, output]
+    }
+    // FP #11124
+    // tuple=>array
+    let (a, b) = (1, 2);
+    [a, b];
+    let x = a;
+    // array=>tuple
+    let [a, b] = [1, 2];
+    (a, b);
+    let x = a;
+    // FP #11144
+    let (a, (b, c)) = (1, (2, 3));
+    [a, c];
+    let [[a, b], [c, d]] = [[1, 2], [3, 4]];
+    (a, c);
 }
 
 #[clippy::msrv = "1.70.0"]
diff --git a/src/tools/clippy/tests/ui/tuple_array_conversions.stderr b/src/tools/clippy/tests/ui/tuple_array_conversions.stderr
index be653e8efb7..50bdcf29d1f 100644
--- a/src/tools/clippy/tests/ui/tuple_array_conversions.stderr
+++ b/src/tools/clippy/tests/ui/tuple_array_conversions.stderr
@@ -15,14 +15,6 @@ LL |     let x = [x.0, x.1];
    |
    = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed
 
-error: it looks like you're trying to convert an array to a tuple
-  --> $DIR/tuple_array_conversions.rs:13:13
-   |
-LL |     let x = (x[0], x[1]);
-   |             ^^^^^^^^^^^^
-   |
-   = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed
-
 error: it looks like you're trying to convert a tuple to an array
   --> $DIR/tuple_array_conversions.rs:16:53
    |
@@ -55,8 +47,24 @@ LL |     t1.iter().for_each(|&(a, b)| _ = [a, b]);
    |
    = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed
 
+error: it looks like you're trying to convert a tuple to an array
+  --> $DIR/tuple_array_conversions.rs:57:22
+   |
+LL |     let _: &[f64] = &[a, b];
+   |                      ^^^^^^
+   |
+   = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed
+
 error: it looks like you're trying to convert an array to a tuple
-  --> $DIR/tuple_array_conversions.rs:69:13
+  --> $DIR/tuple_array_conversions.rs:60:5
+   |
+LL |     (src, dest);
+   |     ^^^^^^^^^^^
+   |
+   = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed
+
+error: it looks like you're trying to convert an array to a tuple
+  --> $DIR/tuple_array_conversions.rs:99:13
    |
 LL |     let x = (x[0], x[1]);
    |             ^^^^^^^^^^^^
@@ -64,20 +72,12 @@ LL |     let x = (x[0], x[1]);
    = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed
 
 error: it looks like you're trying to convert a tuple to an array
-  --> $DIR/tuple_array_conversions.rs:70:13
+  --> $DIR/tuple_array_conversions.rs:100:13
    |
 LL |     let x = [x.0, x.1];
    |             ^^^^^^^^^^
    |
    = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed
 
-error: it looks like you're trying to convert an array to a tuple
-  --> $DIR/tuple_array_conversions.rs:72:13
-   |
-LL |     let x = (x[0], x[1]);
-   |             ^^^^^^^^^^^^
-   |
-   = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed
-
 error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
index 8efd44baf59..2bf02f13414 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed
@@ -38,6 +38,16 @@ mod fake_libc {
     }
 }
 
+fn aaa() -> ::std::primitive::u32 {
+    0
+}
+
+use std::primitive::u32 as UnsignedThirtyTwoBitInteger;
+
+fn bbb() -> UnsignedThirtyTwoBitInteger {
+    0
+}
+
 #[rustfmt::skip]
 fn main() {
     // Test cast_unnecessary
@@ -105,6 +115,13 @@ fn main() {
     extern_fake_libc::getpid_SAFE_TRUTH() as i32;
     let pid = unsafe { fake_libc::getpid() };
     pid as i32;
+    aaa();
+    let x = aaa();
+    aaa();
+    // Will not lint currently.
+    bbb() as u32;
+    let x = bbb();
+    bbb() as u32;
 
     let i8_ptr: *const i8 = &1;
     let u8_ptr: *const u8 = &1;
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs
index c7723ef51f9..25b6b0f9b07 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs
@@ -38,6 +38,16 @@ mod fake_libc {
     }
 }
 
+fn aaa() -> ::std::primitive::u32 {
+    0
+}
+
+use std::primitive::u32 as UnsignedThirtyTwoBitInteger;
+
+fn bbb() -> UnsignedThirtyTwoBitInteger {
+    0
+}
+
 #[rustfmt::skip]
 fn main() {
     // Test cast_unnecessary
@@ -105,6 +115,13 @@ fn main() {
     extern_fake_libc::getpid_SAFE_TRUTH() as i32;
     let pid = unsafe { fake_libc::getpid() };
     pid as i32;
+    aaa() as u32;
+    let x = aaa();
+    aaa() as u32;
+    // Will not lint currently.
+    bbb() as u32;
+    let x = bbb();
+    bbb() as u32;
 
     let i8_ptr: *const i8 = &1;
     let u8_ptr: *const u8 = &1;
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
index f0443556fb4..19411a01b67 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
@@ -7,226 +7,238 @@ LL |     ptr as *const T
    = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:44:5
+  --> $DIR/unnecessary_cast.rs:54:5
    |
 LL |     1i32 as i32;
    |     ^^^^^^^^^^^ help: try: `1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:45:5
+  --> $DIR/unnecessary_cast.rs:55:5
    |
 LL |     1f32 as f32;
    |     ^^^^^^^^^^^ help: try: `1_f32`
 
 error: casting to the same type is unnecessary (`bool` -> `bool`)
-  --> $DIR/unnecessary_cast.rs:46:5
+  --> $DIR/unnecessary_cast.rs:56:5
    |
 LL |     false as bool;
    |     ^^^^^^^^^^^^^ help: try: `false`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:49:5
+  --> $DIR/unnecessary_cast.rs:59:5
    |
 LL |     -1_i32 as i32;
    |     ^^^^^^^^^^^^^ help: try: `-1_i32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:50:5
+  --> $DIR/unnecessary_cast.rs:60:5
    |
 LL |     - 1_i32 as i32;
    |     ^^^^^^^^^^^^^^ help: try: `- 1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:51:5
+  --> $DIR/unnecessary_cast.rs:61:5
    |
 LL |     -1f32 as f32;
    |     ^^^^^^^^^^^^ help: try: `-1_f32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:52:5
+  --> $DIR/unnecessary_cast.rs:62:5
    |
 LL |     1_i32 as i32;
    |     ^^^^^^^^^^^^ help: try: `1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:53:5
+  --> $DIR/unnecessary_cast.rs:63:5
    |
 LL |     1_f32 as f32;
    |     ^^^^^^^^^^^^ help: try: `1_f32`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
-  --> $DIR/unnecessary_cast.rs:55:22
+  --> $DIR/unnecessary_cast.rs:65:22
    |
 LL |     let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
-  --> $DIR/unnecessary_cast.rs:57:5
+  --> $DIR/unnecessary_cast.rs:67:5
    |
 LL |     [1u8, 2].as_ptr() as *const u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*mut u8` -> `*mut u8`)
-  --> $DIR/unnecessary_cast.rs:59:5
+  --> $DIR/unnecessary_cast.rs:69:5
    |
 LL |     [1u8, 2].as_mut_ptr() as *mut u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_mut_ptr()`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`)
-  --> $DIR/unnecessary_cast.rs:70:5
+  --> $DIR/unnecessary_cast.rs:80:5
    |
 LL |     owo::<u32>([1u32].as_ptr()) as *const u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `owo::<u32>([1u32].as_ptr())`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`)
-  --> $DIR/unnecessary_cast.rs:71:5
+  --> $DIR/unnecessary_cast.rs:81:5
    |
 LL |     uwu::<u32, u8>([1u32].as_ptr()) as *const u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u8>([1u32].as_ptr())`
 
 error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`)
-  --> $DIR/unnecessary_cast.rs:73:5
+  --> $DIR/unnecessary_cast.rs:83:5
    |
 LL |     uwu::<u32, u32>([1u32].as_ptr()) as *const u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::<u32, u32>([1u32].as_ptr())`
 
+error: casting to the same type is unnecessary (`u32` -> `u32`)
+  --> $DIR/unnecessary_cast.rs:118:5
+   |
+LL |     aaa() as u32;
+   |     ^^^^^^^^^^^^ help: try: `aaa()`
+
+error: casting to the same type is unnecessary (`u32` -> `u32`)
+  --> $DIR/unnecessary_cast.rs:120:5
+   |
+LL |     aaa() as u32;
+   |     ^^^^^^^^^^^^ help: try: `aaa()`
+
 error: casting integer literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:139:9
+  --> $DIR/unnecessary_cast.rs:156:9
    |
 LL |         100 as f32;
    |         ^^^^^^^^^^ help: try: `100_f32`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:140:9
+  --> $DIR/unnecessary_cast.rs:157:9
    |
 LL |         100 as f64;
    |         ^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:141:9
+  --> $DIR/unnecessary_cast.rs:158:9
    |
 LL |         100_i32 as f64;
    |         ^^^^^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:142:17
+  --> $DIR/unnecessary_cast.rs:159:17
    |
 LL |         let _ = -100 as f32;
    |                 ^^^^^^^^^^^ help: try: `-100_f32`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:143:17
+  --> $DIR/unnecessary_cast.rs:160:17
    |
 LL |         let _ = -100 as f64;
    |                 ^^^^^^^^^^^ help: try: `-100_f64`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:144:17
+  --> $DIR/unnecessary_cast.rs:161:17
    |
 LL |         let _ = -100_i32 as f64;
    |                 ^^^^^^^^^^^^^^^ help: try: `-100_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:145:9
+  --> $DIR/unnecessary_cast.rs:162:9
    |
 LL |         100. as f32;
    |         ^^^^^^^^^^^ help: try: `100_f32`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:146:9
+  --> $DIR/unnecessary_cast.rs:163:9
    |
 LL |         100. as f64;
    |         ^^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:158:9
+  --> $DIR/unnecessary_cast.rs:175:9
    |
 LL |         1 as u32;
    |         ^^^^^^^^ help: try: `1_u32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:159:9
+  --> $DIR/unnecessary_cast.rs:176:9
    |
 LL |         0x10 as i32;
    |         ^^^^^^^^^^^ help: try: `0x10_i32`
 
 error: casting integer literal to `usize` is unnecessary
-  --> $DIR/unnecessary_cast.rs:160:9
+  --> $DIR/unnecessary_cast.rs:177:9
    |
 LL |         0b10 as usize;
    |         ^^^^^^^^^^^^^ help: try: `0b10_usize`
 
 error: casting integer literal to `u16` is unnecessary
-  --> $DIR/unnecessary_cast.rs:161:9
+  --> $DIR/unnecessary_cast.rs:178:9
    |
 LL |         0o73 as u16;
    |         ^^^^^^^^^^^ help: try: `0o73_u16`
 
 error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:162:9
+  --> $DIR/unnecessary_cast.rs:179:9
    |
 LL |         1_000_000_000 as u32;
    |         ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:164:9
+  --> $DIR/unnecessary_cast.rs:181:9
    |
 LL |         1.0 as f64;
    |         ^^^^^^^^^^ help: try: `1.0_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:165:9
+  --> $DIR/unnecessary_cast.rs:182:9
    |
 LL |         0.5 as f32;
    |         ^^^^^^^^^^ help: try: `0.5_f32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:169:17
+  --> $DIR/unnecessary_cast.rs:186:17
    |
 LL |         let _ = -1 as i32;
    |                 ^^^^^^^^^ help: try: `-1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:170:17
+  --> $DIR/unnecessary_cast.rs:187:17
    |
 LL |         let _ = -1.0 as f32;
    |                 ^^^^^^^^^^^ help: try: `-1.0_f32`
 
 error: casting to the same type is unnecessary (`i32` -> `i32`)
-  --> $DIR/unnecessary_cast.rs:176:18
+  --> $DIR/unnecessary_cast.rs:193:18
    |
 LL |         let _ = &(x as i32);
    |                  ^^^^^^^^^^ help: try: `{ x }`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:182:22
+  --> $DIR/unnecessary_cast.rs:199:22
    |
 LL |         let _: i32 = -(1) as i32;
    |                      ^^^^^^^^^^^ help: try: `-1_i32`
 
 error: casting integer literal to `i64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:184:22
+  --> $DIR/unnecessary_cast.rs:201:22
    |
 LL |         let _: i64 = -(1) as i64;
    |                      ^^^^^^^^^^^ help: try: `-1_i64`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:191:22
+  --> $DIR/unnecessary_cast.rs:208:22
    |
 LL |         let _: f64 = (-8.0 as f64).exp();
    |                      ^^^^^^^^^^^^^ help: try: `(-8.0_f64)`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast.rs:193:23
+  --> $DIR/unnecessary_cast.rs:210:23
    |
 LL |         let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior
    |                       ^^^^^^^^^^^^ help: try: `8.0_f64`
 
 error: casting to the same type is unnecessary (`f32` -> `f32`)
-  --> $DIR/unnecessary_cast.rs:201:20
+  --> $DIR/unnecessary_cast.rs:218:20
    |
 LL |         let _num = foo() as f32;
    |                    ^^^^^^^^^^^^ help: try: `foo()`
 
-error: aborting due to 38 previous errors
+error: aborting due to 40 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.rs b/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
index 8e01c2674f1..3c8c6ec94c1 100644
--- a/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
@@ -148,3 +148,9 @@ mod comment_1052978898 {
         })
     }
 }
+
+fn issue11260() {
+    // #11260 is about unnecessary_find_map, but the fix also kind of applies to
+    // unnecessary_filter_map
+    let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n));
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
index 5585b10ab90..2d5403ce394 100644
--- a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
@@ -34,5 +34,11 @@ error: this `.filter_map` can be written more simply using `.map`
 LL |     let _ = (0..4).filter_map(|x| Some(x + 1));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: this `.filter_map` can be written more simply using `.filter`
+  --> $DIR/unnecessary_filter_map.rs:155:14
+   |
+LL |     let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_find_map.rs b/src/tools/clippy/tests/ui/unnecessary_find_map.rs
index a52390861b4..2c228fbbc95 100644
--- a/src/tools/clippy/tests/ui/unnecessary_find_map.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_find_map.rs
@@ -21,3 +21,9 @@ fn main() {
 fn find_map_none_changes_item_type() -> Option<bool> {
     "".chars().find_map(|_| None)
 }
+
+fn issue11260() {
+    let y = Some(1);
+    let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n));
+    let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(y)); // different option, so can't be just `.find()`
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_find_map.stderr b/src/tools/clippy/tests/ui/unnecessary_find_map.stderr
index fb33c122fe3..3a995b41b17 100644
--- a/src/tools/clippy/tests/ui/unnecessary_find_map.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_find_map.stderr
@@ -34,5 +34,11 @@ error: this `.find_map` can be written more simply using `.map(..).next()`
 LL |     let _ = (0..4).find_map(|x| Some(x + 1));
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: this `.find_map` can be written more simply using `.find`
+  --> $DIR/unnecessary_find_map.rs:27:14
+   |
+LL |     let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed
index 276cd800b89..72d52c62355 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed
@@ -16,12 +16,23 @@ fn unwrap_option_some() {
     1;
 }
 
+#[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }`
 fn unwrap_option_none() {
     let _val = panic!();
     let _val = panic!("this always happens");
+    let _val: String = String::default();
+    let _val: u16 = 234;
+    let _val: u16 = 234;
+    let _val: u16 = { 234 };
+    let _val: u16 =  { 234 };
 
     panic!();
     panic!("this always happens");
+    String::default();
+    234;
+    234;
+    { 234 };
+     { 234 };
 }
 
 fn unwrap_result_ok() {
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs
index 3065778d779..7d713ea205f 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs
@@ -16,12 +16,23 @@ fn unwrap_option_some() {
     Some(1).expect("this never happens");
 }
 
+#[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }`
 fn unwrap_option_none() {
     let _val = None::<()>.unwrap();
     let _val = None::<()>.expect("this always happens");
+    let _val: String = None.unwrap_or_default();
+    let _val: u16 = None.unwrap_or(234);
+    let _val: u16 = None.unwrap_or_else(|| 234);
+    let _val: u16 = None.unwrap_or_else(|| { 234 });
+    let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
 
     None::<()>.unwrap();
     None::<()>.expect("this always happens");
+    None::<String>.unwrap_or_default();
+    None::<u16>.unwrap_or(234);
+    None::<u16>.unwrap_or_else(|| 234);
+    None::<u16>.unwrap_or_else(|| { 234 });
+    None::<u16>.unwrap_or_else(|| -> u16 { 234 });
 }
 
 fn unwrap_result_ok() {
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
index 5823313b736..7f603d6ef58 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
@@ -48,13 +48,13 @@ LL +     1;
    |
 
 error: used `unwrap()` on `None` value
-  --> $DIR/unnecessary_literal_unwrap.rs:20:16
+  --> $DIR/unnecessary_literal_unwrap.rs:21:16
    |
 LL |     let _val = None::<()>.unwrap();
    |                ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()`
 
 error: used `expect()` on `None` value
-  --> $DIR/unnecessary_literal_unwrap.rs:21:16
+  --> $DIR/unnecessary_literal_unwrap.rs:22:16
    |
 LL |     let _val = None::<()>.expect("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -64,14 +64,68 @@ help: remove the `None` and `expect()`
 LL |     let _val = panic!("this always happens");
    |                ~~~~~~~                     ~
 
+error: used `unwrap_or_default()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:23:24
+   |
+LL |     let _val: String = None.unwrap_or_default();
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()`
+
+error: used `unwrap_or()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:24:21
+   |
+LL |     let _val: u16 = None.unwrap_or(234);
+   |                     ^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or()`
+   |
+LL -     let _val: u16 = None.unwrap_or(234);
+LL +     let _val: u16 = 234;
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:25:21
+   |
+LL |     let _val: u16 = None.unwrap_or_else(|| 234);
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     let _val: u16 = None.unwrap_or_else(|| 234);
+LL +     let _val: u16 = 234;
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:26:21
+   |
+LL |     let _val: u16 = None.unwrap_or_else(|| { 234 });
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     let _val: u16 = None.unwrap_or_else(|| { 234 });
+LL +     let _val: u16 = { 234 };
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:27:21
+   |
+LL |     let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
+LL +     let _val: u16 =  { 234 };
+   |
+
 error: used `unwrap()` on `None` value
-  --> $DIR/unnecessary_literal_unwrap.rs:23:5
+  --> $DIR/unnecessary_literal_unwrap.rs:29:5
    |
 LL |     None::<()>.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()`
 
 error: used `expect()` on `None` value
-  --> $DIR/unnecessary_literal_unwrap.rs:24:5
+  --> $DIR/unnecessary_literal_unwrap.rs:30:5
    |
 LL |     None::<()>.expect("this always happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -81,8 +135,62 @@ help: remove the `None` and `expect()`
 LL |     panic!("this always happens");
    |     ~~~~~~~                     ~
 
+error: used `unwrap_or_default()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:31:5
+   |
+LL |     None::<String>.unwrap_or_default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()`
+
+error: used `unwrap_or()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:32:5
+   |
+LL |     None::<u16>.unwrap_or(234);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or()`
+   |
+LL -     None::<u16>.unwrap_or(234);
+LL +     234;
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:33:5
+   |
+LL |     None::<u16>.unwrap_or_else(|| 234);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     None::<u16>.unwrap_or_else(|| 234);
+LL +     234;
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:34:5
+   |
+LL |     None::<u16>.unwrap_or_else(|| { 234 });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     None::<u16>.unwrap_or_else(|| { 234 });
+LL +     { 234 };
+   |
+
+error: used `unwrap_or_else()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap.rs:35:5
+   |
+LL |     None::<u16>.unwrap_or_else(|| -> u16 { 234 });
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `None` and `unwrap_or_else()`
+   |
+LL -     None::<u16>.unwrap_or_else(|| -> u16 { 234 });
+LL +      { 234 };
+   |
+
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:28:16
+  --> $DIR/unnecessary_literal_unwrap.rs:39:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,7 +202,7 @@ LL +     let _val = 1;
    |
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:29:16
+  --> $DIR/unnecessary_literal_unwrap.rs:40:16
    |
 LL |     let _val = Ok::<_, ()>(1).expect("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -106,7 +214,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:30:16
+  --> $DIR/unnecessary_literal_unwrap.rs:41:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -117,7 +225,7 @@ LL |     let _val = panic!("{:?}", 1);
    |                ~~~~~~~~~~~~~~  ~
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:31:16
+  --> $DIR/unnecessary_literal_unwrap.rs:42:16
    |
 LL |     let _val = Ok::<_, ()>(1).expect_err("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -128,7 +236,7 @@ LL |     let _val = panic!("{1}: {:?}", 1, "this always happens");
    |                ~~~~~~~~~~~~~~~~~~~  ~
 
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:33:5
+  --> $DIR/unnecessary_literal_unwrap.rs:44:5
    |
 LL |     Ok::<_, ()>(1).unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -140,7 +248,7 @@ LL +     1;
    |
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:34:5
+  --> $DIR/unnecessary_literal_unwrap.rs:45:5
    |
 LL |     Ok::<_, ()>(1).expect("this never happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -152,7 +260,7 @@ LL +     1;
    |
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:35:5
+  --> $DIR/unnecessary_literal_unwrap.rs:46:5
    |
 LL |     Ok::<_, ()>(1).unwrap_err();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +271,7 @@ LL |     panic!("{:?}", 1);
    |     ~~~~~~~~~~~~~~  ~
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:36:5
+  --> $DIR/unnecessary_literal_unwrap.rs:47:5
    |
 LL |     Ok::<_, ()>(1).expect_err("this always happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -174,7 +282,7 @@ LL |     panic!("{1}: {:?}", 1, "this always happens");
    |     ~~~~~~~~~~~~~~~~~~~  ~
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:40:16
+  --> $DIR/unnecessary_literal_unwrap.rs:51:16
    |
 LL |     let _val = Err::<(), _>(1).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -186,7 +294,7 @@ LL +     let _val = 1;
    |
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:41:16
+  --> $DIR/unnecessary_literal_unwrap.rs:52:16
    |
 LL |     let _val = Err::<(), _>(1).expect_err("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -198,7 +306,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:42:16
+  --> $DIR/unnecessary_literal_unwrap.rs:53:16
    |
 LL |     let _val = Err::<(), _>(1).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +317,7 @@ LL |     let _val = panic!("{:?}", 1);
    |                ~~~~~~~~~~~~~~  ~
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:43:16
+  --> $DIR/unnecessary_literal_unwrap.rs:54:16
    |
 LL |     let _val = Err::<(), _>(1).expect("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +328,7 @@ LL |     let _val = panic!("{1}: {:?}", 1, "this always happens");
    |                ~~~~~~~~~~~~~~~~~~~  ~
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:45:5
+  --> $DIR/unnecessary_literal_unwrap.rs:56:5
    |
 LL |     Err::<(), _>(1).unwrap_err();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -232,7 +340,7 @@ LL +     1;
    |
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:46:5
+  --> $DIR/unnecessary_literal_unwrap.rs:57:5
    |
 LL |     Err::<(), _>(1).expect_err("this never happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -244,7 +352,7 @@ LL +     1;
    |
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:47:5
+  --> $DIR/unnecessary_literal_unwrap.rs:58:5
    |
 LL |     Err::<(), _>(1).unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -255,7 +363,7 @@ LL |     panic!("{:?}", 1);
    |     ~~~~~~~~~~~~~~  ~
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:48:5
+  --> $DIR/unnecessary_literal_unwrap.rs:59:5
    |
 LL |     Err::<(), _>(1).expect("this always happens");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -266,7 +374,7 @@ LL |     panic!("{1}: {:?}", 1, "this always happens");
    |     ~~~~~~~~~~~~~~~~~~~  ~
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:52:16
+  --> $DIR/unnecessary_literal_unwrap.rs:63:16
    |
 LL |     let _val = Some(1).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^
@@ -278,7 +386,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:53:16
+  --> $DIR/unnecessary_literal_unwrap.rs:64:16
    |
 LL |     let _val = Some(1).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -290,7 +398,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:54:16
+  --> $DIR/unnecessary_literal_unwrap.rs:65:16
    |
 LL |     let _val = Some(1).unwrap_or_else(|| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -302,7 +410,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:56:5
+  --> $DIR/unnecessary_literal_unwrap.rs:67:5
    |
 LL |     Some(1).unwrap_or(2);
    |     ^^^^^^^^^^^^^^^^^^^^
@@ -314,7 +422,7 @@ LL +     1;
    |
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:57:5
+  --> $DIR/unnecessary_literal_unwrap.rs:68:5
    |
 LL |     Some(1).unwrap_or_default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -326,7 +434,7 @@ LL +     1;
    |
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:58:5
+  --> $DIR/unnecessary_literal_unwrap.rs:69:5
    |
 LL |     Some(1).unwrap_or_else(|| 2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -338,7 +446,7 @@ LL +     1;
    |
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:62:16
+  --> $DIR/unnecessary_literal_unwrap.rs:73:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -350,7 +458,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:63:16
+  --> $DIR/unnecessary_literal_unwrap.rs:74:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -362,7 +470,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:64:16
+  --> $DIR/unnecessary_literal_unwrap.rs:75:16
    |
 LL |     let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -374,7 +482,7 @@ LL +     let _val = 1;
    |
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:66:5
+  --> $DIR/unnecessary_literal_unwrap.rs:77:5
    |
 LL |     Ok::<_, ()>(1).unwrap_or(2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -386,7 +494,7 @@ LL +     1;
    |
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:67:5
+  --> $DIR/unnecessary_literal_unwrap.rs:78:5
    |
 LL |     Ok::<_, ()>(1).unwrap_or_default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -398,7 +506,7 @@ LL +     1;
    |
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:68:5
+  --> $DIR/unnecessary_literal_unwrap.rs:79:5
    |
 LL |     Ok::<_, ()>(1).unwrap_or_else(|_| 2);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -410,7 +518,7 @@ LL +     1;
    |
 
 error: used `unwrap_unchecked()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:82:22
+  --> $DIR/unnecessary_literal_unwrap.rs:93:22
    |
 LL |     let _ = unsafe { Some(1).unwrap_unchecked() };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -422,7 +530,7 @@ LL +     let _ = 1;
    |
 
 error: used `unwrap_unchecked()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:83:22
+  --> $DIR/unnecessary_literal_unwrap.rs:94:22
    |
 LL |     let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -434,7 +542,7 @@ LL +     let _ = unsafe { 1 + *(&1 as *const i32) }; // needs to keep the unsafe
    |
 
 error: used `unwrap_unchecked()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap.rs:84:22
+  --> $DIR/unnecessary_literal_unwrap.rs:95:22
    |
 LL |     let _ = unsafe { Some(1).unwrap_unchecked() } + 1;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -446,7 +554,7 @@ LL +     let _ = 1 + 1;
    |
 
 error: used `unwrap_unchecked()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:85:22
+  --> $DIR/unnecessary_literal_unwrap.rs:96:22
    |
 LL |     let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -458,7 +566,7 @@ LL +     let _ = 1;
    |
 
 error: used `unwrap_unchecked()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:86:22
+  --> $DIR/unnecessary_literal_unwrap.rs:97:22
    |
 LL |     let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -470,7 +578,7 @@ LL +     let _ = unsafe { 1 + *(&1 as *const i32) };
    |
 
 error: used `unwrap_unchecked()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap.rs:87:22
+  --> $DIR/unnecessary_literal_unwrap.rs:98:22
    |
 LL |     let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1;
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -482,7 +590,7 @@ LL +     let _ = 1 + 1;
    |
 
 error: used `unwrap_err_unchecked()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap.rs:88:22
+  --> $DIR/unnecessary_literal_unwrap.rs:99:22
    |
 LL |     let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() };
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -493,5 +601,5 @@ LL -     let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() };
 LL +     let _ = 123;
    |
 
-error: aborting due to 43 previous errors
+error: aborting due to 53 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs
index 711fdce3962..41300aceb41 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs
@@ -21,6 +21,8 @@ fn unwrap_option_none() {
     let val = None::<()>;
     let _val2 = val.unwrap();
     let _val2 = val.expect("this always happens");
+    let _val3: u8 = None.unwrap_or_default();
+    None::<()>.unwrap_or_default();
 }
 
 fn unwrap_result_ok() {
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr
index feb9325b77a..2d1270d4717 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr
@@ -95,509 +95,521 @@ help: remove the `None` and `expect()`
 LL |     let val = None::<()>;
    |               ^^^^^^^^^^
 
+error: used `unwrap_or_default()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:24:21
+   |
+LL |     let _val3: u8 = None.unwrap_or_default();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `Default::default()`
+
+error: used `unwrap_or_default()` on `None` value
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:25:5
+   |
+LL |     None::<()>.unwrap_or_default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `Default::default()`
+
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:28:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:30:17
    |
 LL |     let _val2 = val.unwrap();
    |                 ^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:31:17
    |
 LL |     let _val2 = val.expect("this never happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:30:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:32:17
    |
 LL |     let _val2 = val.unwrap_err();
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:31:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:33:17
    |
 LL |     let _val2 = val.expect_err("this always happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:27:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:29:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:35:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).expect("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:36:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).expect("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:39:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:37:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:39:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).expect_err("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:38:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).expect_err("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:41:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:43:17
    |
 LL |     let _val2 = val.unwrap();
    |                 ^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:44:17
    |
 LL |     let _val2 = val.expect("this never happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:43:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:45:17
    |
 LL |     let _val2 = val.unwrap_err();
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:44:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:46:17
    |
 LL |     let _val2 = val.expect_err("this always happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:40:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:42:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:49:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:51:17
    |
 LL |     let _val2 = val.unwrap_err();
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15
    |
 LL |     let val = Err::<(), _>(1);
    |               ^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:52:17
    |
 LL |     let _val2 = val.expect_err("this never happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15
    |
 LL |     let val = Err::<(), _>(1);
    |               ^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:51:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:53:17
    |
 LL |     let _val2 = val.unwrap();
    |                 ^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15
    |
 LL |     let val = Err::<(), _>(1);
    |               ^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:52:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:54:17
    |
 LL |     let _val2 = val.expect("this always happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:48:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:50:15
    |
 LL |     let val = Err::<(), _>(1);
    |               ^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:56:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:56:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:57:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:57:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:60:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:58:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:60:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:59:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:16
    |
 LL |     let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens");
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:62:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:64:17
    |
 LL |     let _val2 = val.unwrap_err();
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15
    |
 LL |     let val = Err::<(), usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect_err()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:65:17
    |
 LL |     let _val2 = val.expect_err("this never happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect_err()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15
    |
 LL |     let val = Err::<(), usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:64:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:66:17
    |
 LL |     let _val2 = val.unwrap();
    |                 ^^^^^^^^^^^^
    |
 help: remove the `Err` and `unwrap()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15
    |
 LL |     let val = Err::<(), usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `expect()` on `Err` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:65:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:67:17
    |
 LL |     let _val2 = val.expect("this always happens");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Err` and `expect()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:61:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:63:15
    |
 LL |     let val = Err::<(), usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:70:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:72:17
    |
 LL |     let _val2 = val.unwrap_or(2);
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:15
    |
 LL |     let val = Some(1);
    |               ^^^^^^^
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:73:17
    |
 LL |     let _val2 = val.unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:15
    |
 LL |     let val = Some(1);
    |               ^^^^^^^
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:72:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:74:17
    |
 LL |     let _val2 = val.unwrap_or_else(|| 2);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:69:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:71:15
    |
 LL |     let val = Some(1);
    |               ^^^^^^^
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:76:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:76:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:77:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:79:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:77:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:79:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or_else(|| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:78:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:16
    |
 LL |     let _val = Some::<usize>([1, 2, 3].iter().sum()).unwrap_or_else(|| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:81:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:83:17
    |
 LL |     let _val2 = val.unwrap_or(2);
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:15
    |
 LL |     let val = Some::<usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:84:17
    |
 LL |     let _val2 = val.unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:15
    |
 LL |     let val = Some::<usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Some` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:83:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:85:17
    |
 LL |     let _val2 = val.unwrap_or_else(|| 2);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Some` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:80:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:82:15
    |
 LL |     let val = Some::<usize>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:88:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:90:17
    |
 LL |     let _val2 = val.unwrap_or(2);
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:91:17
    |
 LL |     let _val2 = val.unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:90:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:92:17
    |
 LL |     let _val2 = val.unwrap_or_else(|_| 2);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:87:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:89:15
    |
 LL |     let val = Ok::<_, ()>(1);
    |               ^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:94:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:94:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or(2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:95:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:97:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:95:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:97:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or_default();
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:96:16
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:16
    |
 LL |     let _val = Ok::<usize, ()>([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2);
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:99:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:101:17
    |
 LL |     let _val2 = val.unwrap_or(2);
    |                 ^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_default()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:102:17
    |
 LL |     let _val2 = val.unwrap_or_default();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_default()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: used `unwrap_or_else()` on `Ok` value
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:101:17
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:103:17
    |
 LL |     let _val2 = val.unwrap_or_else(|_| 2);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: remove the `Ok` and `unwrap_or_else()`
-  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:98:15
+  --> $DIR/unnecessary_literal_unwrap_unfixable.rs:100:15
    |
 LL |     let val = Ok::<usize, ()>([1, 2, 3].iter().sum());
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 50 previous errors
+error: aborting due to 52 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs
index 69e46ab4736..1d188025e41 100644
--- a/src/tools/clippy/tests/ui/unused_async.rs
+++ b/src/tools/clippy/tests/ui/unused_async.rs
@@ -37,6 +37,23 @@ mod issue10459 {
     }
 }
 
+mod issue9695 {
+    use std::future::Future;
+
+    async fn f() {}
+    async fn f2() {}
+    async fn f3() {}
+
+    fn needs_async_fn<F: Future<Output = ()>>(_: fn() -> F) {}
+
+    fn test() {
+        let x = f;
+        needs_async_fn(x); // async needed in f
+        needs_async_fn(f2); // async needed in f2
+        f3(); // async not needed in f3
+    }
+}
+
 async fn foo() -> i32 {
     4
 }
diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr
index ffae8366b88..8d9b72c4886 100644
--- a/src/tools/clippy/tests/ui/unused_async.stderr
+++ b/src/tools/clippy/tests/ui/unused_async.stderr
@@ -17,7 +17,15 @@ LL |             ready(()).await;
    = note: `-D clippy::unused-async` implied by `-D warnings`
 
 error: unused `async` for function with no await statements
-  --> $DIR/unused_async.rs:40:1
+  --> $DIR/unused_async.rs:45:5
+   |
+LL |     async fn f3() {}
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing the `async` from this function
+
+error: unused `async` for function with no await statements
+  --> $DIR/unused_async.rs:57:1
    |
 LL | / async fn foo() -> i32 {
 LL | |     4
@@ -27,7 +35,7 @@ LL | | }
    = help: consider removing the `async` from this function
 
 error: unused `async` for function with no await statements
-  --> $DIR/unused_async.rs:51:5
+  --> $DIR/unused_async.rs:68:5
    |
 LL | /     async fn unused(&self) -> i32 {
 LL | |         1
@@ -36,5 +44,5 @@ LL | |     }
    |
    = help: consider removing the `async` from this function
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
index 08b89a18bbb..acdb96942ba 100644
--- a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
+++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed
@@ -1,10 +1,10 @@
 //@run-rustfix
 
-#![warn(clippy::unwrap_or_else_default)]
+#![warn(clippy::unwrap_or_default)]
 #![allow(dead_code)]
 #![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)]
 
-/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
+/// Checks implementation of the `UNWRAP_OR_DEFAULT` lint.
 fn unwrap_or_else_default() {
     struct Foo;
 
@@ -74,4 +74,62 @@ fn unwrap_or_else_default() {
     empty_string.unwrap_or_default();
 }
 
+fn type_certainty(option: Option<Vec<u64>>) {
+    option.unwrap_or_default().push(1);
+
+    let option: std::option::Option<std::vec::Vec<u64>> = None;
+    option.unwrap_or_default().push(1);
+
+    let option: Option<Vec<u64>> = None;
+    option.unwrap_or_default().push(1);
+
+    let option = std::option::Option::<std::vec::Vec<u64>>::None;
+    option.unwrap_or_default().push(1);
+
+    let option = Option::<Vec<u64>>::None;
+    option.unwrap_or_default().push(1);
+
+    let option = std::option::Option::None::<std::vec::Vec<u64>>;
+    option.unwrap_or_default().push(1);
+
+    let option = Option::None::<Vec<u64>>;
+    option.unwrap_or_default().push(1);
+
+    let option = None::<Vec<u64>>;
+    option.unwrap_or_default().push(1);
+
+    // should not be changed: type annotation with infer, unconcretized initializer
+    let option: Option<Vec<_>> = None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    // should not be changed: no type annotation, unconcretized initializer
+    let option = Option::None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    // should not be changed: no type annotation, unconcretized initializer
+    let option = None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    type Alias = Option<Vec<u32>>;
+    let option: Alias = Option::<Vec<u32>>::Some(Vec::new());
+    option.unwrap_or_default().push(1);
+}
+
+fn method_call_with_deref() {
+    use std::cell::RefCell;
+    use std::collections::HashMap;
+
+    let cell = RefCell::new(HashMap::<u64, HashMap<u64, String>>::new());
+
+    let mut outer_map = cell.borrow_mut();
+
+    #[allow(unused_assignments)]
+    let mut option = None;
+    option = Some(0);
+
+    let inner_map = outer_map.get_mut(&option.unwrap()).unwrap();
+
+    let _ = inner_map.entry(0).or_default();
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs
index ad2a744908f..55ccd00e1a2 100644
--- a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs
+++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs
@@ -1,10 +1,10 @@
 //@run-rustfix
 
-#![warn(clippy::unwrap_or_else_default)]
+#![warn(clippy::unwrap_or_default)]
 #![allow(dead_code)]
 #![allow(clippy::unnecessary_wraps, clippy::unnecessary_literal_unwrap)]
 
-/// Checks implementation of the `UNWRAP_OR_ELSE_DEFAULT` lint.
+/// Checks implementation of the `UNWRAP_OR_DEFAULT` lint.
 fn unwrap_or_else_default() {
     struct Foo;
 
@@ -74,4 +74,62 @@ fn unwrap_or_else_default() {
     empty_string.unwrap_or_else(|| "".to_string());
 }
 
+fn type_certainty(option: Option<Vec<u64>>) {
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option: std::option::Option<std::vec::Vec<u64>> = None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option: Option<Vec<u64>> = None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option = std::option::Option::<std::vec::Vec<u64>>::None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option = Option::<Vec<u64>>::None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option = std::option::Option::None::<std::vec::Vec<u64>>;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option = Option::None::<Vec<u64>>;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    let option = None::<Vec<u64>>;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    // should not be changed: type annotation with infer, unconcretized initializer
+    let option: Option<Vec<_>> = None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    // should not be changed: no type annotation, unconcretized initializer
+    let option = Option::None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    // should not be changed: no type annotation, unconcretized initializer
+    let option = None;
+    option.unwrap_or_else(Vec::new).push(1);
+
+    type Alias = Option<Vec<u32>>;
+    let option: Alias = Option::<Vec<u32>>::Some(Vec::new());
+    option.unwrap_or_else(Vec::new).push(1);
+}
+
+fn method_call_with_deref() {
+    use std::cell::RefCell;
+    use std::collections::HashMap;
+
+    let cell = RefCell::new(HashMap::<u64, HashMap<u64, String>>::new());
+
+    let mut outer_map = cell.borrow_mut();
+
+    #[allow(unused_assignments)]
+    let mut option = None;
+    option = Some(0);
+
+    let inner_map = outer_map.get_mut(&option.unwrap()).unwrap();
+
+    let _ = inner_map.entry(0).or_insert_with(Default::default);
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
index d2b9212223f..af662c6def7 100644
--- a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
+++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr
@@ -1,40 +1,100 @@
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:48:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:48:14
    |
 LL |     with_new.unwrap_or_else(Vec::new);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_new.unwrap_or_default()`
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
    |
-   = note: `-D clippy::unwrap-or-else-default` implied by `-D warnings`
+   = note: `-D clippy::unwrap-or-default` implied by `-D warnings`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:62:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:62:23
    |
 LL |     with_real_default.unwrap_or_else(<HasDefaultAndDuplicate as Default>::default);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_real_default.unwrap_or_default()`
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:65:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:65:24
    |
 LL |     with_default_trait.unwrap_or_else(Default::default);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_trait.unwrap_or_default()`
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:68:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:68:23
    |
 LL |     with_default_type.unwrap_or_else(u64::default);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:71:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:71:23
    |
 LL |     with_default_type.unwrap_or_else(Vec::new);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()`
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: use of `.unwrap_or_else(..)` to construct default value
-  --> $DIR/unwrap_or_else_default.rs:74:5
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:74:18
    |
 LL |     empty_string.unwrap_or_else(|| "".to_string());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()`
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
-error: aborting due to 6 previous errors
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:78:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:81:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:84:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:87:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:90:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:93:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:96:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:99:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `unwrap_or_else` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:115:12
+   |
+LL |     option.unwrap_or_else(Vec::new).push(1);
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
+
+error: use of `or_insert_with` to construct default value
+  --> $DIR/unwrap_or_else_default.rs:132:32
+   |
+LL |     let _ = inner_map.entry(0).or_insert_with(Default::default);
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index c40b71f6ca7..6856bb0ab37 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -9,6 +9,9 @@ allow-unauthenticated = [
 # See https://github.com/rust-lang/triagebot/wiki/Shortcuts
 [shortcut]
 
+# Have rustbot inform users about the *No Merge Policy*
+[no-merges]
+
 [autolabel."S-waiting-on-review"]
 new_pr = true
 
@@ -27,4 +30,6 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB
     "@Alexendoo",
     "@dswij",
     "@Jarcho",
+    "@blyxyas",
+    "@Centri3",
 ]