about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/clippy/.github/workflows/clippy.yml2
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml10
-rw-r--r--src/tools/clippy/.github/workflows/clippy_dev.yml2
-rw-r--r--src/tools/clippy/.github/workflows/deploy.yml4
-rw-r--r--src/tools/clippy/.github/workflows/remark.yml2
-rw-r--r--src/tools/clippy/CHANGELOG.md7
-rw-r--r--src/tools/clippy/COPYRIGHT2
-rw-r--r--src/tools/clippy/LICENSE-APACHE2
-rw-r--r--src/tools/clippy/LICENSE-MIT2
-rw-r--r--src/tools/clippy/README.md4
-rw-r--r--src/tools/clippy/book/src/README.md2
-rw-r--r--src/tools/clippy/book/src/SUMMARY.md1
-rw-r--r--src/tools/clippy/book/src/continuous_integration/github_actions.md2
-rw-r--r--src/tools/clippy/book/src/continuous_integration/gitlab.md16
-rw-r--r--src/tools/clippy/book/src/development/macro_expansions.md2
-rw-r--r--src/tools/clippy/book/src/development/type_checking.md4
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md10
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs7
-rw-r--r--src/tools/clippy/clippy_config/src/metadata.rs3
-rw-r--r--src/tools/clippy/clippy_config/src/msrvs.rs2
-rw-r--r--src/tools/clippy/clippy_config/src/types.rs6
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs141
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_with_brackets.rs (renamed from src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs)56
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/instant_subtraction.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/item_name_repetitions.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_filter.rs206
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs142
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs115
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/redundant_as_str.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_split.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs123
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/utils.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/mutex_atomic.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/identity_op.rs208
-rw-r--r--src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs83
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/serde_api.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs102
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unconditional_recursion.rs413
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs13
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs6
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/rustc_tools_util/README.md2
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_underscore_fields/all_pub_fields/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_underscore_fields/exported/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr60
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.exported.stderr12
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs66
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--src/tools/clippy/tests/ui/as_conversions.rs2
-rw-r--r--src/tools/clippy/tests/ui/cast.rs49
-rw-r--r--src/tools/clippy/tests/ui/cast.stderr74
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-8821.fixed10
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-8821.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-8821.stderr11
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed4
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs2
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr26
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed36
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs34
-rw-r--r--src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr44
-rw-r--r--src/tools/clippy/tests/ui/eager_transmute.fixed35
-rw-r--r--src/tools/clippy/tests/ui/eager_transmute.rs35
-rw-r--r--src/tools/clippy/tests/ui/eager_transmute.stderr117
-rw-r--r--src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.fixed27
-rw-r--r--src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.rs27
-rw-r--r--src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.stderr36
-rw-r--r--src/tools/clippy/tests/ui/identity_op.fixed94
-rw-r--r--src/tools/clippy/tests/ui/identity_op.rs94
-rw-r--r--src/tools/clippy/tests/ui/identity_op.stderr154
-rw-r--r--src/tools/clippy/tests/ui/if_then_some_else_none.rs5
-rw-r--r--src/tools/clippy/tests/ui/into_iter_without_iter.rs39
-rw-r--r--src/tools/clippy/tests/ui/into_iter_without_iter.stderr38
-rw-r--r--src/tools/clippy/tests/ui/iter_filter_is_ok.fixed193
-rw-r--r--src/tools/clippy/tests/ui/iter_filter_is_ok.rs193
-rw-r--r--src/tools/clippy/tests/ui/iter_filter_is_ok.stderr74
-rw-r--r--src/tools/clippy/tests/ui/iter_filter_is_some.fixed231
-rw-r--r--src/tools/clippy/tests/ui/iter_filter_is_some.rs231
-rw-r--r--src/tools/clippy/tests/ui/iter_filter_is_some.stderr62
-rw-r--r--src/tools/clippy/tests/ui/iter_without_into_iter.rs31
-rw-r--r--src/tools/clippy/tests/ui/iter_without_into_iter.stderr40
-rw-r--r--src/tools/clippy/tests/ui/let_unit.fixed50
-rw-r--r--src/tools/clippy/tests/ui/let_unit.rs48
-rw-r--r--src/tools/clippy/tests/ui/let_unit.stderr56
-rw-r--r--src/tools/clippy/tests/ui/manual_is_variant_and.fixed51
-rw-r--r--src/tools/clippy/tests/ui/manual_is_variant_and.rs57
-rw-r--r--src/tools/clippy/tests/ui/manual_is_variant_and.stderr82
-rw-r--r--src/tools/clippy/tests/ui/map_clone.fixed24
-rw-r--r--src/tools/clippy/tests/ui/map_clone.rs24
-rw-r--r--src/tools/clippy/tests/ui/map_clone.stderr44
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.fixed6
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.rs6
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.stderr10
-rw-r--r--src/tools/clippy/tests/ui/mutex_atomic.rs19
-rw-r--r--src/tools/clippy/tests/ui/mutex_atomic.stderr30
-rw-r--r--src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed4
-rw-r--r--src/tools/clippy/tests/ui/non_octal_unix_permissions.rs4
-rw-r--r--src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr2
-rw-r--r--src/tools/clippy/tests/ui/option_as_ref_cloned.fixed21
-rw-r--r--src/tools/clippy/tests/ui/option_as_ref_cloned.rs21
-rw-r--r--src/tools/clippy/tests/ui/option_as_ref_cloned.stderr37
-rw-r--r--src/tools/clippy/tests/ui/redundant_as_str.fixed2
-rw-r--r--src/tools/clippy/tests/ui/redundant_as_str.rs2
-rw-r--r--src/tools/clippy/tests/ui/regex.rs2
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.fixed2
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.rs2
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.stderr26
-rw-r--r--src/tools/clippy/tests/ui/str_split.fixed145
-rw-r--r--src/tools/clippy/tests/ui/str_split.rs145
-rw-r--r--src/tools/clippy/tests/ui/str_split.stderr65
-rw-r--r--src/tools/clippy/tests/ui/struct_fields.rs24
-rw-r--r--src/tools/clippy/tests/ui/struct_fields.stderr28
-rw-r--r--src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed30
-rw-r--r--src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs30
-rw-r--r--src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr29
-rw-r--r--src/tools/clippy/tests/ui/unconditional_recursion.rs108
-rw-r--r--src/tools/clippy/tests/ui/unconditional_recursion.stderr95
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed13
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs13
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr126
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_safety_comment.rs21
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed18
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs18
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr24
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.fixed14
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.rs14
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.stderr42
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.fixed4
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.rs4
-rw-r--r--src/tools/clippy/tests/ui/vec.fixed7
-rw-r--r--src/tools/clippy/tests/ui/vec.rs7
-rw-r--r--src/tools/clippy/triagebot.toml1
157 files changed, 5166 insertions, 819 deletions
diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml
index 99d80bec025..5ba960db66d 100644
--- a/src/tools/clippy/.github/workflows/clippy.yml
+++ b/src/tools/clippy/.github/workflows/clippy.yml
@@ -38,7 +38,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
 
     - name: Install toolchain
       run: rustup show active-toolchain
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 73c25550742..012797e5ca7 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -26,7 +26,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
       with:
         ref: ${{ github.ref }}
 
@@ -72,7 +72,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
 
     - name: Install i686 dependencies
       if: matrix.host == 'i686-unknown-linux-gnu'
@@ -151,7 +151,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
 
     - name: Install toolchain
       run: rustup show active-toolchain
@@ -175,7 +175,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
 
     - name: Install toolchain
       run: rustup show active-toolchain
@@ -231,7 +231,7 @@ jobs:
         github_token: "${{ secrets.github_token }}"
 
     - name: Checkout
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
 
     - name: Install toolchain
       run: rustup show active-toolchain
diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml
index 0f0e3f2db92..37f18a4c087 100644
--- a/src/tools/clippy/.github/workflows/clippy_dev.yml
+++ b/src/tools/clippy/.github/workflows/clippy_dev.yml
@@ -24,7 +24,7 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
 
     # Run
     - name: Build
diff --git a/src/tools/clippy/.github/workflows/deploy.yml b/src/tools/clippy/.github/workflows/deploy.yml
index 999ee7acfe7..94f494b65c4 100644
--- a/src/tools/clippy/.github/workflows/deploy.yml
+++ b/src/tools/clippy/.github/workflows/deploy.yml
@@ -21,10 +21,10 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
 
     - name: Checkout
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
       with:
         ref: ${{ env.TARGET_BRANCH }}
         path: 'out'
diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml
index 30bd476332f..05e1b3b9202 100644
--- a/src/tools/clippy/.github/workflows/remark.yml
+++ b/src/tools/clippy/.github/workflows/remark.yml
@@ -16,7 +16,7 @@ jobs:
     steps:
     # Setup
     - name: Checkout
-      uses: actions/checkout@v3
+      uses: actions/checkout@v4
 
     - name: Setup Node.js
       uses: actions/setup-node@v3
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index f82421a687b..4d32bbec914 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5105,6 +5105,7 @@ Released 2018-09-13
 [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
 [`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop
 [`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum
+[`empty_enum_variants_with_brackets`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum_variants_with_brackets
 [`empty_line_after_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_doc_comments
 [`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr
 [`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop
@@ -5294,6 +5295,7 @@ Released 2018-09-13
 [`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
 [`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite
 [`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite
+[`manual_is_variant_and`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_variant_and
 [`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else
 [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str
 [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
@@ -5440,6 +5442,7 @@ Released 2018-09-13
 [`only_used_in_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#only_used_in_recursion
 [`op_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#op_ref
 [`option_and_then_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_and_then_some
+[`option_as_ref_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_cloned
 [`option_as_ref_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_as_ref_deref
 [`option_env_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_env_unwrap
 [`option_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#option_expect_used
@@ -5483,6 +5486,7 @@ Released 2018-09-13
 [`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
 [`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
 [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
+[`pub_underscore_fields`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields
 [`pub_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_use
 [`pub_with_shorthand`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_with_shorthand
 [`pub_without_shorthand`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_without_shorthand
@@ -5580,6 +5584,7 @@ Released 2018-09-13
 [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
 [`std_instead_of_alloc`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_alloc
 [`std_instead_of_core`]: https://rust-lang.github.io/rust-clippy/master/index.html#std_instead_of_core
+[`str_split_at_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_split_at_newline
 [`str_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#str_to_string
 [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add
 [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign
@@ -5612,6 +5617,7 @@ Released 2018-09-13
 [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
 [`test_attr_in_doctest`]: https://rust-lang.github.io/rust-clippy/master/index.html#test_attr_in_doctest
 [`tests_outside_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#tests_outside_test_module
+[`thread_local_initializer_can_be_made_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#thread_local_initializer_can_be_made_const
 [`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
 [`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
 [`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args
@@ -5810,4 +5816,5 @@ Released 2018-09-13
 [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles
 [`enforce-iter-loop-reborrow`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enforce-iter-loop-reborrow
 [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items
+[`pub-underscore-fields-behavior`]: https://doc.rust-lang.org/clippy/lint_configuration.html#pub-underscore-fields-behavior
 <!-- end autogenerated links to configuration documentation -->
diff --git a/src/tools/clippy/COPYRIGHT b/src/tools/clippy/COPYRIGHT
index 82703b18fd7..219693d63d9 100644
--- a/src/tools/clippy/COPYRIGHT
+++ b/src/tools/clippy/COPYRIGHT
@@ -1,6 +1,6 @@
 // REUSE-IgnoreStart
 
-Copyright 2014-2022 The Rust Project Developers
+Copyright 2014-2024 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
diff --git a/src/tools/clippy/LICENSE-APACHE b/src/tools/clippy/LICENSE-APACHE
index 0d62c37278e..506582c31d6 100644
--- a/src/tools/clippy/LICENSE-APACHE
+++ b/src/tools/clippy/LICENSE-APACHE
@@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
    same "printed page" as the copyright notice for easier
    identification within third-party archives.
 
-Copyright 2014-2022 The Rust Project Developers
+Copyright 2014-2024 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/src/tools/clippy/LICENSE-MIT b/src/tools/clippy/LICENSE-MIT
index b724b24aa83..6d8ee9afb61 100644
--- a/src/tools/clippy/LICENSE-MIT
+++ b/src/tools/clippy/LICENSE-MIT
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2014-2022 The Rust Project Developers
+Copyright (c) 2014-2024 The Rust Project Developers
 
 Permission is hereby granted, free of charge, to any
 person obtaining a copy of this software and associated
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index 5d490645d89..fa18447090c 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -5,7 +5,7 @@
 
 A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 
-[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 700 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 
 Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
 You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
@@ -278,7 +278,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT
 
 <!-- REUSE-IgnoreStart -->
 
-Copyright 2014-2023 The Rust Project Developers
+Copyright 2014-2024 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license
diff --git a/src/tools/clippy/book/src/README.md b/src/tools/clippy/book/src/README.md
index 486ea3df704..e7972b0db19 100644
--- a/src/tools/clippy/book/src/README.md
+++ b/src/tools/clippy/book/src/README.md
@@ -6,7 +6,7 @@
 A collection of lints to catch common mistakes and improve your
 [Rust](https://github.com/rust-lang/rust) code.
 
-[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 700 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 
 Lints are divided into categories, each with a default [lint
 level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how
diff --git a/src/tools/clippy/book/src/SUMMARY.md b/src/tools/clippy/book/src/SUMMARY.md
index b02457307d7..a048fbbd8ac 100644
--- a/src/tools/clippy/book/src/SUMMARY.md
+++ b/src/tools/clippy/book/src/SUMMARY.md
@@ -9,6 +9,7 @@
 - [Clippy's Lints](lints.md)
 - [Continuous Integration](continuous_integration/README.md)
     - [GitHub Actions](continuous_integration/github_actions.md)
+    - [GitLab CI](continuous_integration/gitlab.md)
     - [Travis CI](continuous_integration/travis.md)
 - [Development](development/README.md)
     - [Basics](development/basics.md)
diff --git a/src/tools/clippy/book/src/continuous_integration/github_actions.md b/src/tools/clippy/book/src/continuous_integration/github_actions.md
index 339287a7dd9..b588c8f0f02 100644
--- a/src/tools/clippy/book/src/continuous_integration/github_actions.md
+++ b/src/tools/clippy/book/src/continuous_integration/github_actions.md
@@ -15,7 +15,7 @@ jobs:
   clippy_check:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
       - name: Run Clippy
         run: cargo clippy --all-targets --all-features
 ```
diff --git a/src/tools/clippy/book/src/continuous_integration/gitlab.md b/src/tools/clippy/book/src/continuous_integration/gitlab.md
new file mode 100644
index 00000000000..bb3ef246c2f
--- /dev/null
+++ b/src/tools/clippy/book/src/continuous_integration/gitlab.md
@@ -0,0 +1,16 @@
+# GitLab CI
+
+You can add Clippy to GitLab CI by using the latest stable [rust docker image](https://hub.docker.com/_/rust),
+as it is shown in the `.gitlab-ci.yml` CI configuration file below,
+
+```yml
+# Make sure CI fails on all warnings, including Clippy lints
+variables:
+  RUSTFLAGS: "-Dwarnings"
+
+clippy_check:
+  image: rust:latest
+  script:
+    - rustup component add clippy
+    - cargo clippy --all-targets --all-features
+```
diff --git a/src/tools/clippy/book/src/development/macro_expansions.md b/src/tools/clippy/book/src/development/macro_expansions.md
index c5eb000272d..aecca9ef72e 100644
--- a/src/tools/clippy/book/src/development/macro_expansions.md
+++ b/src/tools/clippy/book/src/development/macro_expansions.md
@@ -102,7 +102,7 @@ let x: Option<u32> = Some(42);
 m!(x, x.unwrap());
 ```
 
-If the `m!(x, x.unwrapp());` line is expanded, we would get two expanded
+If the `m!(x, x.unwrap());` line is expanded, we would get two expanded
 expressions:
 
 - `x.is_some()` (from the `$a.is_some()` line in the `m` macro)
diff --git a/src/tools/clippy/book/src/development/type_checking.md b/src/tools/clippy/book/src/development/type_checking.md
index a8c9660da4c..dc29ab5d08d 100644
--- a/src/tools/clippy/book/src/development/type_checking.md
+++ b/src/tools/clippy/book/src/development/type_checking.md
@@ -133,7 +133,7 @@ in this chapter:
 - [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html)
 - [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html)
 
-[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html#variant.Adt
+[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html#variant.Adt
 [AdtDef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html
 [expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty
 [node_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.node_type
@@ -144,7 +144,7 @@ in this chapter:
 [LateLintPass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html
 [pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/typeck_results/struct.TypeckResults.html#method.pat_ty
 [Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html
-[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html
+[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/ty_kind/enum.TyKind.html
 [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html
 [middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html
 [hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 7c9a8eb1bfb..3b62ae0524a 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -805,3 +805,13 @@ for _ in &mut *rmvec {}
 * [`missing_errors_doc`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc)
 
 
+## `pub-underscore-fields-behavior`
+
+
+**Default Value:** `"PublicallyExported"`
+
+---
+**Affected lints:**
+* [`pub_underscore_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields)
+
+
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index a4f368397ce..5477d9b83a7 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -1,5 +1,5 @@
 use crate::msrvs::Msrv;
-use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, Rename};
+use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename};
 use crate::ClippyConfiguration;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_session::Session;
@@ -547,6 +547,11 @@ define_Conf! {
     ///
     /// Whether to also run the listed lints on private items.
     (check_private_items: bool = false),
+    /// Lint: PUB_UNDERSCORE_FIELDS
+    ///
+    /// Lint "public" fields in a struct that are prefixed with an underscore based on their
+    /// exported visibility, or whether they are marked as "pub".
+    (pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PublicallyExported),
 }
 
 /// Search for the configuration file.
diff --git a/src/tools/clippy/clippy_config/src/metadata.rs b/src/tools/clippy/clippy_config/src/metadata.rs
index 2451fbc91e8..3ba2796e18d 100644
--- a/src/tools/clippy/clippy_config/src/metadata.rs
+++ b/src/tools/clippy/clippy_config/src/metadata.rs
@@ -96,6 +96,9 @@ fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
         doc_comment.make_ascii_lowercase();
         let lints: Vec<String> = doc_comment
             .split_off(DOC_START.len())
+            .lines()
+            .next()
+            .unwrap()
             .split(", ")
             .map(str::to_string)
             .collect();
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index dae9f09ec00..72d5b9aff28 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -17,7 +17,7 @@ macro_rules! msrv_aliases {
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
     1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
-    1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN }
+    1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN }
     1,68,0 { PATH_MAIN_SEPARATOR_STR }
     1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
     1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
diff --git a/src/tools/clippy/clippy_config/src/types.rs b/src/tools/clippy/clippy_config/src/types.rs
index df48cc3f5e3..baee09629ac 100644
--- a/src/tools/clippy/clippy_config/src/types.rs
+++ b/src/tools/clippy/clippy_config/src/types.rs
@@ -126,3 +126,9 @@ unimplemented_serialize! {
     Rename,
     MacroMatcher,
 }
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
+pub enum PubUnderscoreFieldsBehaviour {
+    PublicallyExported,
+    AllPubFields,
+}
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 31a42734c13..5d9cde06cd8 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -67,7 +67,7 @@ pub fn create(
     if pass == "early" {
         println!(
             "\n\
-            NOTE: Use a late pass unless you need something specific from\
+            NOTE: Use a late pass unless you need something specific from\n\
             an early pass, as they lack many features and utilities"
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index bd12ee40628..1df5a25f674 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -1,12 +1,14 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{method_chain_args, sext};
-use rustc_hir::{Expr, ExprKind};
+use clippy_utils::{clip, method_chain_args, sext};
+use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, UintTy};
 
 use super::CAST_SIGN_LOSS;
 
+const METHODS_RET_POSITIVE: &[&str] = &["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
+
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
     if should_lint(cx, cast_op, cast_from, cast_to) {
         span_lint(
@@ -25,33 +27,28 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
                 return false;
             }
 
-            // Don't lint for positive constants.
-            let const_val = constant(cx, cx.typeck_results(), cast_op);
-            if let Some(Constant::Int(n)) = const_val
-                && let ty::Int(ity) = *cast_from.kind()
-                && sext(cx.tcx, n, ity) >= 0
-            {
+            // Don't lint if `cast_op` is known to be positive.
+            if let Sign::ZeroOrPositive = expr_sign(cx, cast_op, cast_from) {
                 return false;
             }
 
-            // Don't lint for the result of methods that always return non-negative values.
-            if let ExprKind::MethodCall(path, ..) = cast_op.kind {
-                let mut method_name = path.ident.name.as_str();
-                let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"];
-
-                if method_name == "unwrap"
-                    && let Some(arglist) = method_chain_args(cast_op, &["unwrap"])
-                    && let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind
-                {
-                    method_name = inner_path.ident.name.as_str();
-                }
-
-                if allowed_methods.iter().any(|&name| method_name == name) {
-                    return false;
-                }
+            let (mut uncertain_count, mut negative_count) = (0, 0);
+            // Peel off possible binary expressions, e.g. x * x * y => [x, x, y]
+            let Some(exprs) = exprs_with_selected_binop_peeled(cast_op) else {
+                // Assume cast sign lose if we cannot determine the sign of `cast_op`
+                return true;
+            };
+            for expr in exprs {
+                let ty = cx.typeck_results().expr_ty(expr);
+                match expr_sign(cx, expr, ty) {
+                    Sign::Negative => negative_count += 1,
+                    Sign::Uncertain => uncertain_count += 1,
+                    Sign::ZeroOrPositive => (),
+                };
             }
 
-            true
+            // Lint if there are odd number of uncertain or negative results
+            uncertain_count % 2 == 1 || negative_count % 2 == 1
         },
 
         (false, true) => !cast_to.is_signed(),
@@ -59,3 +56,97 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast
         (_, _) => false,
     }
 }
+
+fn get_const_int_eval(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Option<i128> {
+    if let Constant::Int(n) = constant(cx, cx.typeck_results(), expr)?
+        && let ty::Int(ity) = *ty.kind()
+    {
+        return Some(sext(cx.tcx, n, ity));
+    }
+    None
+}
+
+enum Sign {
+    ZeroOrPositive,
+    Negative,
+    Uncertain,
+}
+
+fn expr_sign(cx: &LateContext<'_>, expr: &Expr<'_>, ty: Ty<'_>) -> Sign {
+    // Try evaluate this expr first to see if it's positive
+    if let Some(val) = get_const_int_eval(cx, expr, ty) {
+        return if val >= 0 { Sign::ZeroOrPositive } else { Sign::Negative };
+    }
+    // Calling on methods that always return non-negative values.
+    if let ExprKind::MethodCall(path, caller, args, ..) = expr.kind {
+        let mut method_name = path.ident.name.as_str();
+
+        if method_name == "unwrap"
+            && let Some(arglist) = method_chain_args(expr, &["unwrap"])
+            && let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind
+        {
+            method_name = inner_path.ident.name.as_str();
+        }
+
+        if method_name == "pow"
+            && let [arg] = args
+        {
+            return pow_call_result_sign(cx, caller, arg);
+        } else if METHODS_RET_POSITIVE.iter().any(|&name| method_name == name) {
+            return Sign::ZeroOrPositive;
+        }
+    }
+
+    Sign::Uncertain
+}
+
+/// Return the sign of the `pow` call's result.
+///
+/// If the caller is a positive number, the result is always positive,
+/// If the `power_of` is a even number, the result is always positive as well,
+/// Otherwise a [`Sign::Uncertain`] will be returned.
+fn pow_call_result_sign(cx: &LateContext<'_>, caller: &Expr<'_>, power_of: &Expr<'_>) -> Sign {
+    let caller_ty = cx.typeck_results().expr_ty(caller);
+    if let Some(caller_val) = get_const_int_eval(cx, caller, caller_ty)
+        && caller_val >= 0
+    {
+        return Sign::ZeroOrPositive;
+    }
+
+    if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), power_of)
+        && clip(cx.tcx, n, UintTy::U32) % 2 == 0
+    {
+        return Sign::ZeroOrPositive;
+    }
+
+    Sign::Uncertain
+}
+
+/// Peels binary operators such as [`BinOpKind::Mul`], [`BinOpKind::Div`] or [`BinOpKind::Rem`],
+/// which the result could always be positive under certain condition.
+///
+/// Other operators such as `+`/`-` causing the result's sign hard to determine, which we will
+/// return `None`
+fn exprs_with_selected_binop_peeled<'a>(expr: &'a Expr<'_>) -> Option<Vec<&'a Expr<'a>>> {
+    #[inline]
+    fn collect_operands<'a>(expr: &'a Expr<'a>, operands: &mut Vec<&'a Expr<'a>>) -> Option<()> {
+        match expr.kind {
+            ExprKind::Binary(op, lhs, rhs) => {
+                if matches!(op.node, BinOpKind::Mul | BinOpKind::Div | BinOpKind::Rem) {
+                    collect_operands(lhs, operands);
+                    operands.push(rhs);
+                } else {
+                    // Things are complicated when there are other binary ops exist,
+                    // abort checking by returning `None` for now.
+                    return None;
+                }
+            },
+            _ => operands.push(expr),
+        }
+        Some(())
+    }
+
+    let mut res = vec![];
+    collect_operands(expr, &mut res)?;
+    Some(res)
+}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index eae9dfac064..20230106d53 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -150,7 +150,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO,
     crate::empty_drop::EMPTY_DROP_INFO,
     crate::empty_enum::EMPTY_ENUM_INFO,
-    crate::empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO,
+    crate::empty_with_brackets::EMPTY_ENUM_VARIANTS_WITH_BRACKETS_INFO,
+    crate::empty_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO,
     crate::endian_bytes::BIG_ENDIAN_BYTES_INFO,
     crate::endian_bytes::HOST_ENDIAN_BYTES_INFO,
     crate::endian_bytes::LITTLE_ENDIAN_BYTES_INFO,
@@ -385,6 +386,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::JOIN_ABSOLUTE_PATHS_INFO,
     crate::methods::MANUAL_FILTER_MAP_INFO,
     crate::methods::MANUAL_FIND_MAP_INFO,
+    crate::methods::MANUAL_IS_VARIANT_AND_INFO,
     crate::methods::MANUAL_NEXT_BACK_INFO,
     crate::methods::MANUAL_OK_OR_INFO,
     crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO,
@@ -408,6 +410,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::NO_EFFECT_REPLACE_INFO,
     crate::methods::OBFUSCATED_IF_ELSE_INFO,
     crate::methods::OK_EXPECT_INFO,
+    crate::methods::OPTION_AS_REF_CLONED_INFO,
     crate::methods::OPTION_AS_REF_DEREF_INFO,
     crate::methods::OPTION_FILTER_MAP_INFO,
     crate::methods::OPTION_MAP_OR_ERR_OK_INFO,
@@ -433,6 +436,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::STABLE_SORT_PRIMITIVE_INFO,
     crate::methods::STRING_EXTEND_CHARS_INFO,
     crate::methods::STRING_LIT_CHARS_ANY_INFO,
+    crate::methods::STR_SPLIT_AT_NEWLINE_INFO,
     crate::methods::SUSPICIOUS_COMMAND_ARG_SPACE_INFO,
     crate::methods::SUSPICIOUS_MAP_INFO,
     crate::methods::SUSPICIOUS_SPLITN_INFO,
@@ -576,6 +580,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::ptr::MUT_FROM_REF_INFO,
     crate::ptr::PTR_ARG_INFO,
     crate::ptr_offset_with_cast::PTR_OFFSET_WITH_CAST_INFO,
+    crate::pub_underscore_fields::PUB_UNDERSCORE_FIELDS_INFO,
     crate::pub_use::PUB_USE_INFO,
     crate::question_mark::QUESTION_MARK_INFO,
     crate::question_mark_used::QUESTION_MARK_USED_INFO,
@@ -648,6 +653,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO,
     crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO,
     crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO,
+    crate::thread_local_initializer_can_be_made_const::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST_INFO,
     crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO,
     crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO,
     crate::trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 64a924a776a..712bc075650 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -4,7 +4,7 @@ use clippy_utils::{get_parent_node, numeric_literal};
 use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, walk_stmt, Visitor};
-use rustc_hir::{Body, Expr, ExprKind, HirId, ItemKind, Lit, Node, Stmt, StmtKind};
+use rustc_hir::{Block, Body, Expr, ExprKind, FnRetTy, HirId, ItemKind, Lit, Node, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty};
@@ -122,13 +122,42 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         match &expr.kind {
+            ExprKind::Block(
+                Block {
+                    stmts, expr: Some(_), ..
+                },
+                _,
+            ) => {
+                if let Some(parent) = self.cx.tcx.hir().find_parent(expr.hir_id)
+                    && let Some(fn_sig) = parent.fn_sig()
+                    && let FnRetTy::Return(_ty) = fn_sig.decl.output
+                {
+                    // We cannot check the exact type since it's a `hir::Ty`` which does not implement `is_numeric`
+                    self.ty_bounds.push(ExplicitTyBound(true));
+                    for stmt in *stmts {
+                        self.visit_stmt(stmt);
+                    }
+                    self.ty_bounds.pop();
+                    // Ignore return expr since we know its type was inferred from return ty
+                    return;
+                }
+            },
+
+            // Ignore return expr since we know its type was inferred from return ty
+            ExprKind::Ret(_) => return,
+
             ExprKind::Call(func, args) => {
                 if let Some(fn_sig) = fn_sig_opt(self.cx, func.hir_id) {
                     for (expr, bound) in iter::zip(*args, fn_sig.skip_binder().inputs()) {
-                        // Push found arg type, then visit arg.
-                        self.ty_bounds.push((*bound).into());
-                        self.visit_expr(expr);
-                        self.ty_bounds.pop();
+                        // If is from macro, try to use last bound type (typically pushed when visiting stmt),
+                        // otherwise push found arg type, then visit arg,
+                        if expr.span.from_expansion() {
+                            self.visit_expr(expr);
+                        } else {
+                            self.ty_bounds.push((*bound).into());
+                            self.visit_expr(expr);
+                            self.ty_bounds.pop();
+                        }
                     }
                     return;
                 }
@@ -137,7 +166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
             ExprKind::MethodCall(_, receiver, args, _) => {
                 if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
                     let fn_sig = self.cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
-                    for (expr, bound) in iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) {
+                    for (expr, bound) in iter::zip(iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) {
                         self.ty_bounds.push((*bound).into());
                         self.visit_expr(expr);
                         self.ty_bounds.pop();
diff --git a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
index 3cf67b3ecbf..969df6d85b5 100644
--- a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_opt;
-use rustc_ast::ast::{Item, ItemKind, VariantData};
+use rustc_ast::ast::{Item, ItemKind, Variant, VariantData};
 use rustc_errors::Applicability;
 use rustc_lexer::TokenKind;
 use rustc_lint::{EarlyContext, EarlyLintPass};
@@ -27,9 +27,38 @@ declare_clippy_lint! {
     restriction,
     "finds struct declarations with empty brackets"
 }
-declare_lint_pass!(EmptyStructsWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS]);
 
-impl EarlyLintPass for EmptyStructsWithBrackets {
+declare_clippy_lint! {
+    /// ### What it does
+    /// Finds enum variants without fields that are declared with empty brackets.
+    ///
+    /// ### Why is this bad?
+    /// Empty brackets while defining enum variants are redundant and can be omitted.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// enum MyEnum {
+    ///     HasData(u8),
+    ///     HasNoData(), // redundant parentheses
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// enum MyEnum {
+    ///     HasData(u8),
+    ///     HasNoData,
+    /// }
+    /// ```
+    #[clippy::version = "1.77.0"]
+    pub EMPTY_ENUM_VARIANTS_WITH_BRACKETS,
+    restriction,
+    "finds enum variants with empty brackets"
+}
+
+declare_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VARIANTS_WITH_BRACKETS]);
+
+impl EarlyLintPass for EmptyWithBrackets {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
         let span_after_ident = item.span.with_lo(item.ident.span.hi());
 
@@ -53,6 +82,27 @@ impl EarlyLintPass for EmptyStructsWithBrackets {
             );
         }
     }
+
+    fn check_variant(&mut self, cx: &EarlyContext<'_>, variant: &Variant) {
+        let span_after_ident = variant.span.with_lo(variant.ident.span.hi());
+
+        if has_brackets(&variant.data) && has_no_fields(cx, &variant.data, span_after_ident) {
+            span_lint_and_then(
+                cx,
+                EMPTY_ENUM_VARIANTS_WITH_BRACKETS,
+                span_after_ident,
+                "enum variant has empty brackets",
+                |diagnostic| {
+                    diagnostic.span_suggestion_hidden(
+                        span_after_ident,
+                        "remove the brackets",
+                        "",
+                        Applicability::MaybeIncorrect,
+                    );
+                },
+            );
+        }
+    }
 }
 
 fn has_no_ident_token(braces_span_str: &str) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index cd6c46a71a8..8f48941c4a9 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::eager_or_lazy::switch_to_eager_eval;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks};
+use clippy_utils::{contains_return, higher, in_constant, is_else_clause, is_res_lang_ctor, path_res, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::{Expr, ExprKind};
@@ -74,6 +74,11 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
             return;
         }
 
+        // `bool::then()` and `bool::then_some()` are not const
+        if in_constant(cx, expr.hir_id) {
+            return;
+        }
+
         let ctxt = expr.span.ctxt();
 
         if let Some(higher::If {
diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
index 655f4b82aa4..17b6256f982 100644
--- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
+++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
@@ -40,7 +40,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Lints subtraction between an [`Instant`] and a [`Duration`].
+    /// Lints subtraction between an `Instant` and a `Duration`.
     ///
     /// ### Why is this bad?
     /// Unchecked subtraction could cause underflow on certain platforms, leading to
@@ -57,9 +57,6 @@ declare_clippy_lint! {
     /// # use std::time::{Instant, Duration};
     /// let time_passed = Instant::now().checked_sub(Duration::from_secs(5));
     /// ```
-    ///
-    /// [`Duration`]: std::time::Duration
-    /// [`Instant::now()`]: std::time::Instant::now;
     #[clippy::version = "1.67.0"]
     pub UNCHECKED_DURATION_SUBTRACTION,
     pedantic,
diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
index a9f1612ff05..276c1abb60c 100644
--- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -1,6 +1,7 @@
 //! lint on enum variants that are prefixed or suffixed by the same characters
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir};
+use clippy_utils::is_bool;
 use clippy_utils::macros::span_is_local;
 use clippy_utils::source::is_present_in_source;
 use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case};
@@ -231,6 +232,10 @@ fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &
             (false, _) => ("pre", prefix),
             (true, false) => ("post", postfix),
         };
+        if fields.iter().all(|field| is_bool(field.ty)) {
+            // If all fields are booleans, we don't want to emit this lint.
+            return;
+        }
         span_lint_and_help(
             cx,
             STRUCT_FIELD_NAMES,
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index c9dc48668f2..903d3a2ab89 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -5,7 +5,8 @@ use clippy_utils::ty::{implements_trait, make_normalized_projection};
 use rustc_ast::Mutability;
 use rustc_errors::Applicability;
 use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::declare_lint_pass;
 use rustc_span::{sym, Symbol};
@@ -152,7 +153,8 @@ fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol
 
 impl LateLintPass<'_> for IterWithoutIntoIter {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
-        if let ItemKind::Impl(imp) = item.kind
+        if !in_external_macro(cx.sess(), item.span)
+            && let ItemKind::Impl(imp) = item.kind
             && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind
             && let Some(trait_ref) = imp.of_trait
             && trait_ref
@@ -219,7 +221,8 @@ impl {self_ty_without_ref} {{
             _ => return,
         };
 
-        if let ImplItemKind::Fn(sig, _) = item.kind
+        if !in_external_macro(cx.sess(), item.span)
+            && let ImplItemKind::Fn(sig, _) = item.kind
             && let FnRetTy::Return(ret) = sig.decl.output
             && is_nameable_in_impl_trait(ret)
             && cx.tcx.generics_of(item_did).params.is_empty()
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 755a4ff525d..efdd3925949 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -115,7 +115,7 @@ mod duplicate_mod;
 mod else_if_without_else;
 mod empty_drop;
 mod empty_enum;
-mod empty_structs_with_brackets;
+mod empty_with_brackets;
 mod endian_bytes;
 mod entry;
 mod enum_clike;
@@ -272,6 +272,7 @@ mod permissions_set_readonly_false;
 mod precedence;
 mod ptr;
 mod ptr_offset_with_cast;
+mod pub_underscore_fields;
 mod pub_use;
 mod question_mark;
 mod question_mark_used;
@@ -322,6 +323,7 @@ mod swap_ptr_to_ref;
 mod tabs_in_doc_comments;
 mod temporary_assignment;
 mod tests_outside_test_module;
+mod thread_local_initializer_can_be_made_const;
 mod to_digit_is_some;
 mod trailing_empty_array;
 mod trait_bounds;
@@ -571,6 +573,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         verbose_bit_mask_threshold,
         warn_on_all_wildcard_imports,
         check_private_items,
+        pub_underscore_fields_behavior,
 
         blacklisted_names: _,
         cyclomatic_complexity_threshold: _,
@@ -947,7 +950,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         })
     });
     store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
-    store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets));
+    store.register_early_pass(|| Box::new(empty_with_brackets::EmptyWithBrackets));
     store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
     store.register_early_pass(|| Box::new(pub_use::PubUse));
     store.register_late_pass(|_| Box::new(format_push_string::FormatPushString));
@@ -1080,7 +1083,15 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity));
     store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences));
     store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions));
-    store.register_late_pass(|_| Box::new(unconditional_recursion::UnconditionalRecursion));
+    store.register_late_pass(|_| Box::<unconditional_recursion::UnconditionalRecursion>::default());
+    store.register_late_pass(move |_| {
+        Box::new(pub_underscore_fields::PubUnderscoreFields {
+            behavior: pub_underscore_fields_behavior,
+        })
+    });
+    store.register_late_pass(move |_| {
+        Box::new(thread_local_initializer_can_be_made_const::ThreadLocalInitializerCanBeMadeConst::new(msrv()))
+    });
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
index 8a0955147bb..29957e423b0 100644
--- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
@@ -96,8 +96,7 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> boo
                 ExprKind::Path(qpath) => cx
                     .qpath_res(qpath, fm_arg.hir_id)
                     .opt_def_id()
-                    .map(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD))
-                    .unwrap_or_default(),
+                    .is_some_and(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)),
                 // Detect `|x| x.ok()`
                 ExprKind::Closure(Closure { body, .. }) => {
                     if let Body {
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 7cfd3d346b6..e489899c19e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -26,13 +26,14 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
         hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
             let body = cx.tcx.hir().body(body);
             let closure_expr = peel_blocks(body.value);
-            let arg_id = body.params[0].pat.hir_id;
             match closure_expr.kind {
                 hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
                     if ident.name == method_name
                         && let hir::ExprKind::Path(path) = &receiver.kind
                         && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id)
+                        && !body.params.is_empty()
                     {
+                        let arg_id = body.params[0].pat.hir_id;
                         return arg_id == *local;
                     }
                     false
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
index ade8e3155fa..9f84321ced4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
@@ -1,87 +1,197 @@
+use clippy_utils::ty::get_iterator_item_ty;
+use hir::ExprKind;
 use rustc_lint::{LateContext, LintContext};
 
 use super::{ITER_FILTER_IS_OK, ITER_FILTER_IS_SOME};
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, reindent_multiline};
-use clippy_utils::{is_trait_method, peel_blocks, span_contains_comment};
+use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_comment};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir::def::Res;
 use rustc_hir::QPath;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 use std::borrow::Cow;
 
-fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) -> bool {
-    match &expr.kind {
-        hir::ExprKind::Path(QPath::TypeRelative(_, mname)) => mname.ident.name == method_name,
-        hir::ExprKind::Path(QPath::Resolved(_, segments)) => {
-            segments.segments.last().unwrap().ident.name == method_name
+///
+/// Returns true if the expression is a method call to `method_name`
+/// e.g. `a.method_name()` or `Option::method_name`.
+///
+/// The type-checker verifies for us that the method accepts the right kind of items
+/// (e.g. `Option::is_some` accepts `Option<_>`), so we don't need to check that.
+///
+/// How to capture each case:
+///
+/// `.filter(|a| { std::option::Option::is_some(a) })`
+///          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- this is a closure, getting unwrapped and
+/// recursively checked.
+/// `std::option::Option::is_some(a)`
+///  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- this is a call. It unwraps to a path with
+/// `QPath::TypeRelative`. Since this is a type relative path, we need to check the method name, the
+/// type, and that the parameter of the closure is passed in the call. This part is the dual of
+/// `receiver.method_name()` below.
+///
+/// `filter(std::option::Option::is_some);`
+///          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- this is a type relative path, like above, we check the
+/// type and the method name.
+///
+/// `filter(|a| a.is_some());`
+///         ^^^^^^^^^^^^^^^ <- this is a method call inside a closure,
+/// we check that the parameter of the closure is the receiver of the method call and don't allow
+/// any other parameters.
+fn is_method(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    type_symbol: Symbol,
+    method_name: Symbol,
+    params: &[&hir::Pat<'_>],
+) -> bool {
+    fn pat_is_recv(ident: Ident, param: &hir::Pat<'_>) -> bool {
+        match param.kind {
+            hir::PatKind::Binding(_, _, other, _) => ident == other,
+            hir::PatKind::Ref(pat, _) => pat_is_recv(ident, pat),
+            _ => false,
+        }
+    }
+    match expr.kind {
+        hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, recv, ..) => {
+            // compare the identifier of the receiver to the parameter
+            // we are in a filter => closure has a single parameter and a single, non-block
+            // expression, this means that the parameter shadows all outside variables with
+            // the same name => avoid FPs. If the parameter is not the receiver, then this hits
+            // outside variables => avoid FP
+            if ident.name == method_name
+                && let ExprKind::Path(QPath::Resolved(None, path)) = recv.kind
+                && let &[seg] = path.segments
+                && params.iter().any(|p| pat_is_recv(seg.ident, p))
+            {
+                return true;
+            }
+            false
+        },
+        // This is used to check for complete paths via `|a| std::option::Option::is_some(a)`
+        // this then unwraps to a path with `QPath::TypeRelative`
+        // we pass the params as they've been passed to the current call through the closure
+        hir::ExprKind::Call(expr, [param]) => {
+            // this will hit the `QPath::TypeRelative` case and check that the method name is correct
+            if is_method(cx, expr, type_symbol, method_name, params)
+                // we then check that this is indeed passing the parameter of the closure
+                && let ExprKind::Path(QPath::Resolved(None, path)) = param.kind
+                && let &[seg] = path.segments
+                && params.iter().any(|p| pat_is_recv(seg.ident, p))
+            {
+                return true;
+            }
+            false
+        },
+        hir::ExprKind::Path(QPath::TypeRelative(ty, mname)) => {
+            let ty = cx.typeck_results().node_type(ty.hir_id);
+            if let Some(did) = cx.tcx.get_diagnostic_item(type_symbol)
+                && ty.ty_adt_def() == cx.tcx.type_of(did).skip_binder().ty_adt_def()
+            {
+                return mname.ident.name == method_name;
+            }
+            false
         },
-        hir::ExprKind::MethodCall(segment, _, _, _) => segment.ident.name == method_name,
         hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
             let body = cx.tcx.hir().body(body);
             let closure_expr = peel_blocks(body.value);
-            let arg_id = body.params[0].pat.hir_id;
-            match closure_expr.kind {
-                hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
-                    if ident.name == method_name
-                        && let hir::ExprKind::Path(path) = &receiver.kind
-                        && let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id)
-                    {
-                        return arg_id == *local;
-                    }
-                    false
-                },
-                _ => false,
-            }
+            let params = body.params.iter().map(|param| param.pat).collect::<Vec<_>>();
+            is_method(cx, closure_expr, type_symbol, method_name, params.as_slice())
         },
         _ => false,
     }
 }
 
 fn parent_is_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
-    if let hir::Node::Expr(parent_expr) = cx.tcx.hir().get_parent(expr.hir_id) {
-        is_method(cx, parent_expr, rustc_span::sym::map)
-    } else {
-        false
+    if let Some(expr) = get_parent_expr(cx, expr)
+        && is_trait_method(cx, expr, sym::Iterator)
+        && let hir::ExprKind::MethodCall(path, _, _, _) = expr.kind
+        && path.ident.name == rustc_span::sym::map
+    {
+        return true;
     }
+    false
 }
 
-#[allow(clippy::too_many_arguments)]
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir::Expr<'_>, filter_span: Span) {
-    let is_iterator = is_trait_method(cx, expr, sym::Iterator);
-    let parent_is_not_map = !parent_is_map(cx, expr);
+enum FilterType {
+    IsSome,
+    IsOk,
+}
 
-    if is_iterator
-        && parent_is_not_map
-        && is_method(cx, filter_arg, sym!(is_some))
-        && !span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi()))
+/// Returns the `FilterType` of the expression if it is a filter over an Iter<Option> or
+/// Iter<Result> with the parent expression not being a map, and not having a comment in the span of
+/// the filter. If it is not a filter over an Iter<Option> or Iter<Result> then it returns None
+///
+/// How this is done:
+/// 1. we know that this is invoked in a method call with `filter` as the method name via `mod.rs`
+/// 2. we check that we are in a trait method. Therefore we are in an
+/// `(x as Iterator).filter({filter_arg})` method call.
+/// 3. we check that the parent expression is not a map. This is because we don't want to lint
+///    twice, and we already have a specialized lint for that.
+/// 4. we check that the span of the filter does not contain a comment.
+/// 5. we get the type of the `Item` in the `Iterator`, and compare against the type of Option and
+///   Result.
+/// 6. we finally check the contents of the filter argument to see if it is a call to `is_some` or
+///   `is_ok`.
+/// 7. if all of the above are true, then we return the `FilterType`
+fn expression_type(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    filter_arg: &hir::Expr<'_>,
+    filter_span: Span,
+) -> Option<FilterType> {
+    if !is_trait_method(cx, expr, sym::Iterator)
+        || parent_is_map(cx, expr)
+        || span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi()))
     {
-        span_lint_and_sugg(
+        return None;
+    }
+    if let hir::ExprKind::MethodCall(_, receiver, _, _) = expr.kind
+        && let receiver_ty = cx.typeck_results().expr_ty(receiver)
+        && let Some(iter_item_ty) = get_iterator_item_ty(cx, receiver_ty)
+    {
+        if let Some(opt_defid) = cx.tcx.get_diagnostic_item(sym::Option)
+            && let opt_ty = cx.tcx.type_of(opt_defid).skip_binder()
+            && iter_item_ty.ty_adt_def() == opt_ty.ty_adt_def()
+            && is_method(cx, filter_arg, sym::Option, sym!(is_some), &[])
+        {
+            return Some(FilterType::IsSome);
+        }
+
+        if let Some(opt_defid) = cx.tcx.get_diagnostic_item(sym::Result)
+            && let opt_ty = cx.tcx.type_of(opt_defid).skip_binder()
+            && iter_item_ty.ty_adt_def() == opt_ty.ty_adt_def()
+            && is_method(cx, filter_arg, sym::Result, sym!(is_ok), &[])
+        {
+            return Some(FilterType::IsOk);
+        }
+    }
+    None
+}
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir::Expr<'_>, filter_span: Span) {
+    // we are in a filter inside an iterator
+    match expression_type(cx, expr, filter_arg, filter_span) {
+        None => (),
+        Some(FilterType::IsOk) => span_lint_and_sugg(
             cx,
-            ITER_FILTER_IS_SOME,
+            ITER_FILTER_IS_OK,
             filter_span.with_hi(expr.span.hi()),
-            "`filter` for `is_some` on iterator over `Option`",
+            "`filter` for `is_ok` on iterator over `Result`s",
             "consider using `flatten` instead",
             reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(),
             Applicability::HasPlaceholders,
-        );
-    }
-    if is_iterator
-        && parent_is_not_map
-        && is_method(cx, filter_arg, sym!(is_ok))
-        && !span_contains_comment(cx.sess().source_map(), filter_span.with_hi(expr.span.hi()))
-    {
-        span_lint_and_sugg(
+        ),
+        Some(FilterType::IsSome) => span_lint_and_sugg(
             cx,
-            ITER_FILTER_IS_OK,
+            ITER_FILTER_IS_SOME,
             filter_span.with_hi(expr.span.hi()),
-            "`filter` for `is_ok` on iterator over `Result`s",
+            "`filter` for `is_some` on iterator over `Option`",
             "consider using `flatten` instead",
             reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(),
             Applicability::HasPlaceholders,
-        );
+        ),
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs b/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs
new file mode 100644
index 00000000000..d29acd4622a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs
@@ -0,0 +1,59 @@
+use clippy_config::msrvs::{Msrv, OPTION_RESULT_IS_VARIANT_AND};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_lint::LateContext;
+use rustc_span::{sym, Span};
+
+use super::MANUAL_IS_VARIANT_AND;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'_>,
+    expr: &'tcx rustc_hir::Expr<'_>,
+    map_recv: &'tcx rustc_hir::Expr<'_>,
+    map_arg: &'tcx rustc_hir::Expr<'_>,
+    map_span: Span,
+    msrv: &Msrv,
+) {
+    // Don't lint if:
+
+    // 1. the `expr` is generated by a macro
+    if expr.span.from_expansion() {
+        return;
+    }
+
+    // 2. the caller of `map()` is neither `Option` nor `Result`
+    let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(map_recv), sym::Option);
+    let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(map_recv), sym::Result);
+    if !is_option && !is_result {
+        return;
+    }
+
+    // 3. the caller of `unwrap_or_default` is neither `Option<bool>` nor `Result<bool, _>`
+    if !cx.typeck_results().expr_ty(expr).is_bool() {
+        return;
+    }
+
+    // 4. msrv doesn't meet `OPTION_RESULT_IS_VARIANT_AND`
+    if !msrv.meets(OPTION_RESULT_IS_VARIANT_AND) {
+        return;
+    }
+
+    let lint_msg = if is_option {
+        "called `map(<f>).unwrap_or_default()` on an `Option` value"
+    } else {
+        "called `map(<f>).unwrap_or_default()` on a `Result` value"
+    };
+    let suggestion = if is_option { "is_some_and" } else { "is_ok_and" };
+
+    span_lint_and_sugg(
+        cx,
+        MANUAL_IS_VARIANT_AND,
+        expr.span.with_lo(map_span.lo()),
+        lint_msg,
+        "use",
+        format!("{}({})", suggestion, snippet(cx, map_arg.span, "..")),
+        Applicability::MachineApplicable,
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
index cc6eeaa86e5..f9f636bbbf7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -2,9 +2,10 @@ use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
-use clippy_utils::{is_diag_trait_item, peel_blocks};
+use clippy_utils::{is_diag_trait_item, match_def_path, paths, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
 use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty;
@@ -14,60 +15,110 @@ use rustc_span::{sym, Span};
 
 use super::MAP_CLONE;
 
+// If this `map` is called on an `Option` or a `Result` and the previous call is `as_ref`, we don't
+// run this lint because it would overlap with `useless_asref` which provides a better suggestion
+// in this case.
+fn should_run_lint(cx: &LateContext<'_>, e: &hir::Expr<'_>, method_id: DefId) -> bool {
+    if is_diag_trait_item(cx, method_id, sym::Iterator) {
+        return true;
+    }
+    // We check if it's an `Option` or a `Result`.
+    if let Some(id) = cx.tcx.impl_of_method(method_id) {
+        let identity = cx.tcx.type_of(id).instantiate_identity();
+        if !is_type_diagnostic_item(cx, identity, sym::Option) && !is_type_diagnostic_item(cx, identity, sym::Result) {
+            return false;
+        }
+    } else {
+        return false;
+    }
+    // We check if the previous method call is `as_ref`.
+    if let hir::ExprKind::MethodCall(path1, receiver, _, _) = &e.kind
+        && let hir::ExprKind::MethodCall(path2, _, _, _) = &receiver.kind
+    {
+        return path2.ident.name != sym::as_ref || path1.ident.name != sym::map;
+    }
+
+    true
+}
+
 pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, msrv: &Msrv) {
     if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
-        && (cx.tcx.impl_of_method(method_id).map_or(false, |id| {
-            is_type_diagnostic_item(cx, cx.tcx.type_of(id).instantiate_identity(), sym::Option)
-        }) || is_diag_trait_item(cx, method_id, sym::Iterator))
-        && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind
+        && should_run_lint(cx, e, method_id)
     {
-        let closure_body = cx.tcx.hir().body(body);
-        let closure_expr = peel_blocks(closure_body.value);
-        match closure_body.params[0].pat.kind {
-            hir::PatKind::Ref(inner, hir::Mutability::Not) => {
-                if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) = inner.kind {
-                    if ident_eq(name, closure_expr) {
-                        lint_explicit_closure(cx, e.span, recv.span, true, msrv);
-                    }
-                }
-            },
-            hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => {
-                match closure_expr.kind {
-                    hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
-                        if ident_eq(name, inner) {
-                            if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
+        match arg.kind {
+            hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
+                let closure_body = cx.tcx.hir().body(body);
+                let closure_expr = peel_blocks(closure_body.value);
+                match closure_body.params[0].pat.kind {
+                    hir::PatKind::Ref(inner, hir::Mutability::Not) => {
+                        if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) = inner.kind {
+                            if ident_eq(name, closure_expr) {
                                 lint_explicit_closure(cx, e.span, recv.span, true, msrv);
                             }
                         }
                     },
-                    hir::ExprKind::MethodCall(method, obj, [], _) => {
-                        if ident_eq(name, obj) && method.ident.name == sym::clone
-                        && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id)
-                        && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
-                        && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id)
-                        // no autoderefs
-                        && !cx.typeck_results().expr_adjustments(obj).iter()
-                            .any(|a| matches!(a.kind, Adjust::Deref(Some(..))))
-                        {
-                            let obj_ty = cx.typeck_results().expr_ty(obj);
-                            if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
-                                if matches!(mutability, Mutability::Not) {
-                                    let copy = is_copy(cx, *ty);
-                                    lint_explicit_closure(cx, e.span, recv.span, copy, msrv);
+                    hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => {
+                        match closure_expr.kind {
+                            hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
+                                if ident_eq(name, inner) {
+                                    if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
+                                        lint_explicit_closure(cx, e.span, recv.span, true, msrv);
+                                    }
                                 }
-                            } else {
-                                lint_needless_cloning(cx, e.span, recv.span);
-                            }
+                            },
+                            hir::ExprKind::MethodCall(method, obj, [], _) => {
+                                if ident_eq(name, obj) && method.ident.name == sym::clone
+                                && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id)
+                                && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+                                && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id)
+                                // no autoderefs
+                                && !cx.typeck_results().expr_adjustments(obj).iter()
+                                    .any(|a| matches!(a.kind, Adjust::Deref(Some(..))))
+                                {
+                                    let obj_ty = cx.typeck_results().expr_ty(obj);
+                                    if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
+                                        if matches!(mutability, Mutability::Not) {
+                                            let copy = is_copy(cx, *ty);
+                                            lint_explicit_closure(cx, e.span, recv.span, copy, msrv);
+                                        }
+                                    } else {
+                                        lint_needless_cloning(cx, e.span, recv.span);
+                                    }
+                                }
+                            },
+                            hir::ExprKind::Call(call, [_]) => {
+                                if let hir::ExprKind::Path(qpath) = call.kind {
+                                    handle_path(cx, call, &qpath, e, recv);
+                                }
+                            },
+                            _ => {},
                         }
                     },
                     _ => {},
                 }
             },
+            hir::ExprKind::Path(qpath) => handle_path(cx, arg, &qpath, e, recv),
             _ => {},
         }
     }
 }
 
+fn handle_path(
+    cx: &LateContext<'_>,
+    arg: &hir::Expr<'_>,
+    qpath: &hir::QPath<'_>,
+    e: &hir::Expr<'_>,
+    recv: &hir::Expr<'_>,
+) {
+    if let Some(path_def_id) = cx.qpath_res(qpath, arg.hir_id).opt_def_id()
+        && match_def_path(cx, path_def_id, &paths::CLONE_TRAIT_METHOD)
+    {
+        // FIXME: It would be better to infer the type to check if it's copyable or not
+        // to suggest to use `.copied()` instead of `.cloned()` where applicable.
+        lint_path(cx, e.span, recv.span);
+    }
+}
+
 fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool {
     if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind {
         path.segments.len() == 1 && path.segments[0].ident == name
@@ -88,6 +139,23 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
     );
 }
 
+fn lint_path(cx: &LateContext<'_>, replace: Span, root: Span) {
+    let mut applicability = Applicability::MachineApplicable;
+
+    span_lint_and_sugg(
+        cx,
+        MAP_CLONE,
+        replace,
+        "you are explicitly cloning with `.map()`",
+        "consider calling the dedicated `cloned` method",
+        format!(
+            "{}.cloned()",
+            snippet_with_applicability(cx, root, "..", &mut applicability),
+        ),
+        applicability,
+    );
+}
+
 fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: &Msrv) {
     let mut applicability = Applicability::MachineApplicable;
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index c1e126137df..89ea3597dc0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -51,6 +51,7 @@ mod iter_skip_zero;
 mod iter_with_drain;
 mod iterator_step_by_zero;
 mod join_absolute_paths;
+mod manual_is_variant_and;
 mod manual_next_back;
 mod manual_ok_or;
 mod manual_saturating_arithmetic;
@@ -70,6 +71,7 @@ mod no_effect_replace;
 mod obfuscated_if_else;
 mod ok_expect;
 mod open_options;
+mod option_as_ref_cloned;
 mod option_as_ref_deref;
 mod option_map_or_err_ok;
 mod option_map_or_none;
@@ -93,6 +95,7 @@ mod single_char_pattern;
 mod single_char_push_string;
 mod skip_while_next;
 mod stable_sort_primitive;
+mod str_split;
 mod str_splitn;
 mod string_extend_chars;
 mod string_lit_chars_any;
@@ -2589,11 +2592,11 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for usage of `x.get(0)` instead of
-    /// `x.first()`.
+    /// `x.first()` or `x.front()`.
     ///
     /// ### Why is this bad?
-    /// Using `x.first()` is easier to read and has the same
-    /// result.
+    /// Using `x.first()` for `Vec`s and slices or `x.front()`
+    /// for `VecDeque`s is easier to read and has the same result.
     ///
     /// ### Example
     /// ```no_run
@@ -2609,7 +2612,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.63.0"]
     pub GET_FIRST,
     style,
-    "Using `x.get(0)` when `x.first()` is simpler"
+    "Using `x.get(0)` when `x.first()` or `x.front()` is simpler"
 }
 
 declare_clippy_lint! {
@@ -3784,7 +3787,7 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad?
     /// This pattern is often followed by manual unwrapping of the `Option`. The simplification
-    /// results in more readable and succint code without the need for manual unwrapping.
+    /// results in more readable and succinct code without the need for manual unwrapping.
     ///
     /// ### Example
     /// ```no_run
@@ -3810,7 +3813,7 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad?
     /// This pattern is often followed by manual unwrapping of `Result`. The simplification
-    /// results in more readable and succint code without the need for manual unwrapping.
+    /// results in more readable and succinct code without the need for manual unwrapping.
     ///
     /// ### Example
     /// ```no_run
@@ -3829,6 +3832,87 @@ declare_clippy_lint! {
     "filtering an iterator over `Result`s for `Ok` can be achieved with `flatten`"
 }
 
+declare_clippy_lint! {
+    /// Checks for usage of `option.map(f).unwrap_or_default()` and `result.map(f).unwrap_or_default()` where f is a function or closure that returns the `bool` type.
+    ///
+    /// ### Why is this bad?
+    /// Readability. These can be written more concisely as `option.is_some_and(f)` and `result.is_ok_and(f)`.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// # let option = Some(1);
+    /// # let result: Result<usize, ()> = Ok(1);
+    /// option.map(|a| a > 10).unwrap_or_default();
+    /// result.map(|a| a > 10).unwrap_or_default();
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// # let option = Some(1);
+    /// # let result: Result<usize, ()> = Ok(1);
+    /// option.is_some_and(|a| a > 10);
+    /// result.is_ok_and(|a| a > 10);
+    /// ```
+    #[clippy::version = "1.76.0"]
+    pub MANUAL_IS_VARIANT_AND,
+    pedantic,
+    "using `.map(f).unwrap_or_default()`, which is more succinctly expressed as `is_some_and(f)` or `is_ok_and(f)`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for usages of `str.trim().split("\n")` and `str.trim().split("\r\n")`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Hard-coding the line endings makes the code less compatible. `str.lines` should be used instead.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// "some\ntext\nwith\nnewlines\n".trim().split('\n');
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// "some\ntext\nwith\nnewlines\n".lines();
+    /// ```
+    ///
+    /// ### Known Problems
+    ///
+    /// This lint cannot detect if the split is intentionally restricted to a single type of newline (`"\n"` or
+    /// `"\r\n"`), for example during the parsing of a specific file format in which precisely one newline type is
+    /// valid.
+    /// ```
+    #[clippy::version = "1.76.0"]
+    pub STR_SPLIT_AT_NEWLINE,
+    pedantic,
+    "splitting a trimmed string at hard-coded newlines"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `.as_ref().cloned()` and `.as_mut().cloned()` on `Option`s
+    ///
+    /// ### Why is this bad?
+    /// This can be written more concisely by cloning the `Option` directly.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// fn foo(bar: &Option<Vec<u8>>) -> Option<Vec<u8>> {
+    ///     bar.as_ref().cloned()
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// fn foo(bar: &Option<Vec<u8>>) -> Option<Vec<u8>> {
+    ///     bar.clone()
+    /// }
+    /// ```
+    #[clippy::version = "1.77.0"]
+    pub OPTION_AS_REF_CLONED,
+    pedantic,
+    "cloning an `Option` via `as_ref().cloned()`"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -3983,6 +4067,9 @@ impl_lint_pass!(Methods => [
     RESULT_FILTER_MAP,
     ITER_FILTER_IS_SOME,
     ITER_FILTER_IS_OK,
+    MANUAL_IS_VARIANT_AND,
+    STR_SPLIT_AT_NEWLINE,
+    OPTION_AS_REF_CLONED,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4230,7 +4317,10 @@ impl Methods {
                 ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
                 ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
                 ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
-                ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv),
+                ("cloned", []) => {
+                    cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv);
+                    option_as_ref_cloned::check(cx, recv, span);
+                },
                 ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => {
                     needless_collect::check(cx, span, expr, recv, call_span);
                     match method_call(recv) {
@@ -4569,6 +4659,9 @@ impl Methods {
                 ("sort_unstable_by", [arg]) => {
                     unnecessary_sort_by::check(cx, expr, recv, arg, true);
                 },
+                ("split", [arg]) => {
+                    str_split::check(cx, expr, recv, arg);
+                },
                 ("splitn" | "rsplitn", [count_arg, pat_arg]) => {
                     if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) {
                         suspicious_splitn::check(cx, name, expr, recv, count);
@@ -4664,7 +4757,13 @@ impl Methods {
                     }
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
-                ("unwrap_or_default" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => {
+                ("unwrap_or_default", []) => {
+                    if let Some(("map", m_recv, [arg], span, _)) = method_call(recv) {
+                        manual_is_variant_and::check(cx, expr, m_recv, arg, span, &self.msrv);
+                    }
+                    unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
+                },
+                ("unwrap_unchecked" | "unwrap_err_unchecked", []) => {
                     unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
                 ("unwrap_or_else", [u_arg]) => {
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
new file mode 100644
index 00000000000..d7fec360fa2
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_cloned.rs
@@ -0,0 +1,24 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_span::{sym, Span};
+
+use super::{method_call, OPTION_AS_REF_CLONED};
+
+pub(super) fn check(cx: &LateContext<'_>, cloned_recv: &Expr<'_>, cloned_ident_span: Span) {
+    if let Some((method @ ("as_ref" | "as_mut"), as_ref_recv, [], as_ref_ident_span, _)) = method_call(cloned_recv)
+        && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(as_ref_recv).peel_refs(), sym::Option)
+    {
+        span_lint_and_sugg(
+            cx,
+            OPTION_AS_REF_CLONED,
+            as_ref_ident_span.to(cloned_ident_span),
+            &format!("cloning an `Option<_>` using `.{method}().cloned()`"),
+            "this can be written more concisely by cloning the `Option<_>` directly",
+            "clone".into(),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
index 47c9438c588..624597ffca9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -72,7 +72,7 @@ pub(super) fn check<'tcx>(
         }
 
         // is_some_and is stabilised && `unwrap_or` argument is false; suggest `is_some_and` instead
-        let suggest_is_some_and = msrv.meets(msrvs::OPTION_IS_SOME_AND)
+        let suggest_is_some_and = msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND)
             && matches!(&unwrap_arg.kind, ExprKind::Lit(lit)
             if matches!(lit.node, rustc_ast::LitKind::Bool(false)));
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs b/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs
index 094ead9f4ad..29f44ec2a4d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs
@@ -33,7 +33,7 @@ pub(super) fn check(
         && path.chars().all(char::is_alphanumeric)
     {
         let mut sugg = snippet(cx, recv.span, "..").into_owned();
-        if msrv.meets(msrvs::OPTION_IS_SOME_AND) {
+        if msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) {
             let _ = write!(sugg, r#".extension().is_some_and(|ext| ext == "{path}")"#);
         } else {
             let _ = write!(sugg, r#".extension().map_or(false, |ext| ext == "{path}")"#);
diff --git a/src/tools/clippy/clippy_lints/src/methods/redundant_as_str.rs b/src/tools/clippy/clippy_lints/src/methods/redundant_as_str.rs
index 2a2feedd2b4..24de1979c63 100644
--- a/src/tools/clippy/clippy_lints/src/methods/redundant_as_str.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/redundant_as_str.rs
@@ -13,7 +13,11 @@ pub(super) fn check(
     as_str_span: Span,
     other_method_span: Span,
 ) {
-    if cx.typeck_results().expr_ty(recv).ty_adt_def().is_some_and(|adt| Some(adt.did()) == cx.tcx.lang_items().string())
+    if cx
+        .typeck_results()
+        .expr_ty(recv)
+        .ty_adt_def()
+        .is_some_and(|adt| Some(adt.did()) == cx.tcx.lang_items().string())
     {
         let mut applicability = Applicability::MachineApplicable;
         span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_split.rs b/src/tools/clippy/clippy_lints/src/methods/str_split.rs
new file mode 100644
index 00000000000..3586e11f56a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/str_split.rs
@@ -0,0 +1,38 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::visitors::is_const_evaluatable;
+use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+
+use super::STR_SPLIT_AT_NEWLINE;
+
+pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &'a Expr<'_>, split_arg: &'_ Expr<'_>) {
+    // We're looking for `A.trim().split(B)`, where the adjusted type of `A` is `&str` (e.g. an
+    // expression returning `String`), and `B` is a `Pattern` that hard-codes a newline (either `"\n"`
+    // or `"\r\n"`). There are a lot of ways to specify a pattern, and this lint only checks the most
+    // basic ones: a `'\n'`, `"\n"`, and `"\r\n"`.
+    if let ExprKind::MethodCall(trim_method_name, trim_recv, [], _) = split_recv.kind
+        && trim_method_name.ident.as_str() == "trim"
+        && cx.typeck_results().expr_ty_adjusted(trim_recv).peel_refs().is_str()
+        && !is_const_evaluatable(cx, trim_recv)
+        && let ExprKind::Lit(split_lit) = split_arg.kind
+        && (matches!(split_lit.node, LitKind::Char('\n'))
+            || matches!(split_lit.node, LitKind::Str(sym, _) if (sym.as_str() == "\n" || sym.as_str() == "\r\n")))
+    {
+        let mut app = Applicability::MaybeIncorrect;
+        span_lint_and_sugg(
+            cx,
+            STR_SPLIT_AT_NEWLINE,
+            expr.span,
+            "using `str.trim().split()` with hard-coded newlines",
+            "use `str.lines()` instead",
+            format!(
+                "{}.lines()",
+                snippet_with_context(cx, trim_recv.span, expr.span.ctxt(), "..", &mut app).0
+            ),
+            app,
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 637368e9361..64fcd9f8f45 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -3,13 +3,13 @@ use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
+use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_lang_item, peel_mid_ty_refs};
 use clippy_utils::visitors::find_all_ret_expressions;
 use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, Node};
+use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node};
 use rustc_hir_typeck::{FnCtxt, Inherited};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
@@ -246,6 +246,19 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb
         && let Some(receiver_snippet) = snippet_opt(cx, receiver.span)
         && let Some(arg_snippet) = snippet_opt(cx, argument_expr.span)
     {
+        // We may end-up here because of an expression like `x.to_string().split(…)` where the type of `x`
+        // implements `AsRef<str>` but does not implement `Deref<Target = str>`. In this case, we have to
+        // add `.as_ref()` to the suggestion.
+        let as_ref = if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String)
+            && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
+            && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, "Target")
+                != Some(cx.tcx.types.str_)
+        {
+            ".as_ref()"
+        } else {
+            ""
+        };
+
         // The next suggestion may be incorrect because the removal of the `to_owned`-like
         // function could cause the iterator to hold a reference to a resource that is used
         // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148.
@@ -255,7 +268,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb
             parent.span,
             &format!("unnecessary use of `{method_name}`"),
             "use",
-            format!("{receiver_snippet}.split({arg_snippet})"),
+            format!("{receiver_snippet}{as_ref}.split({arg_snippet})"),
             Applicability::MaybeIncorrect,
         );
         return true;
@@ -445,7 +458,10 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                 {
                     let bound_fn_sig = cx.tcx.fn_sig(callee_def_id);
                     let fn_sig = bound_fn_sig.skip_binder();
-                    if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
+                    if let Some(arg_index) = recv
+                        .into_iter()
+                        .chain(call_args)
+                        .position(|arg| arg.hir_id == expr.hir_id)
                         && let param_ty = fn_sig.input(arg_index).skip_binder()
                         && let ty::Param(ParamTy { index: param_index , ..}) = *param_ty.kind()
                         // https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index 84ee64e88a6..66727e5a29d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -1,19 +1,52 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::walk_ptrs_ty_depth;
-use clippy_utils::{get_parent_expr, is_trait_method};
+use clippy_utils::{get_parent_expr, is_diag_trait_item, match_def_path, paths, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
-use rustc_span::sym;
+use rustc_middle::ty::adjustment::Adjust;
+use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_span::{sym, Span};
+
+use core::ops::ControlFlow;
 
 use super::USELESS_ASREF;
 
+/// Returns the first type inside the `Option`/`Result` type passed as argument.
+fn get_enum_ty(enum_ty: Ty<'_>) -> Option<Ty<'_>> {
+    struct ContainsTyVisitor {
+        level: usize,
+    }
+
+    impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ContainsTyVisitor {
+        type BreakTy = Ty<'tcx>;
+
+        fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+            self.level += 1;
+            if self.level == 1 {
+                t.super_visit_with(self)
+            } else {
+                ControlFlow::Break(t)
+            }
+        }
+    }
+
+    match enum_ty.visit_with(&mut ContainsTyVisitor { level: 0 }) {
+        ControlFlow::Break(ty) => Some(ty),
+        ControlFlow::Continue(()) => None,
+    }
+}
+
 /// Checks for the `USELESS_ASREF` lint.
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) {
     // when we get here, we've already checked that the call name is "as_ref" or "as_mut"
     // check if the call is to the actual `AsRef` or `AsMut` trait
-    if is_trait_method(cx, expr, sym::AsRef) || is_trait_method(cx, expr, sym::AsMut) {
+    let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else {
+        return;
+    };
+
+    if is_diag_trait_item(cx, def_id, sym::AsRef) || is_diag_trait_item(cx, def_id, sym::AsMut) {
         // check if the type after `as_ref` or `as_mut` is the same as before
         let rcv_ty = cx.typeck_results().expr_ty(recvr);
         let res_ty = cx.typeck_results().expr_ty(expr);
@@ -39,5 +72,89 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
                 applicability,
             );
         }
+    } else if match_def_path(cx, def_id, &["core", "option", "Option", call_name])
+        || match_def_path(cx, def_id, &["core", "result", "Result", call_name])
+    {
+        let rcv_ty = cx.typeck_results().expr_ty(recvr).peel_refs();
+        let res_ty = cx.typeck_results().expr_ty(expr).peel_refs();
+
+        if let Some(rcv_ty) = get_enum_ty(rcv_ty)
+            && let Some(res_ty) = get_enum_ty(res_ty)
+            // If the only thing the `as_mut`/`as_ref` call is doing is adding references and not
+            // changing the type, then we can move forward.
+            && rcv_ty.peel_refs() == res_ty.peel_refs()
+            && let Some(parent) = get_parent_expr(cx, expr)
+            && let hir::ExprKind::MethodCall(segment, _, args, _) = parent.kind
+            && segment.ident.span != expr.span
+            // We check that the called method name is `map`.
+            && segment.ident.name == sym::map
+            // And that it only has one argument.
+            && let [arg] = args
+            && is_calling_clone(cx, arg)
+        {
+            lint_as_ref_clone(cx, expr.span.with_hi(parent.span.hi()), recvr, call_name);
+        }
+    }
+}
+
+fn check_qpath(cx: &LateContext<'_>, qpath: hir::QPath<'_>, hir_id: hir::HirId) -> bool {
+    // We check it's calling the `clone` method of the `Clone` trait.
+    if let Some(path_def_id) = cx.qpath_res(&qpath, hir_id).opt_def_id() {
+        match_def_path(cx, path_def_id, &paths::CLONE_TRAIT_METHOD)
+    } else {
+        false
     }
 }
+
+fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
+    match arg.kind {
+        hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
+            // If it's a closure, we need to check what is called.
+            let closure_body = cx.tcx.hir().body(body);
+            let closure_expr = peel_blocks(closure_body.value);
+            match closure_expr.kind {
+                hir::ExprKind::MethodCall(method, obj, [], _) => {
+                    if method.ident.name == sym::clone
+                        && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id)
+                        && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+                        // We check it's the `Clone` trait.
+                        && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id)
+                        // no autoderefs
+                        && !cx.typeck_results().expr_adjustments(obj).iter()
+                            .any(|a| matches!(a.kind, Adjust::Deref(Some(..))))
+                    {
+                        true
+                    } else {
+                        false
+                    }
+                },
+                hir::ExprKind::Call(call, [_]) => {
+                    if let hir::ExprKind::Path(qpath) = call.kind {
+                        check_qpath(cx, qpath, call.hir_id)
+                    } else {
+                        false
+                    }
+                },
+                _ => false,
+            }
+        },
+        hir::ExprKind::Path(qpath) => check_qpath(cx, qpath, arg.hir_id),
+        _ => false,
+    }
+}
+
+fn lint_as_ref_clone(cx: &LateContext<'_>, span: Span, recvr: &hir::Expr<'_>, call_name: &str) {
+    let mut applicability = Applicability::MachineApplicable;
+    span_lint_and_sugg(
+        cx,
+        USELESS_ASREF,
+        span,
+        &format!("this call to `{call_name}.map(...)` does nothing"),
+        "try",
+        format!(
+            "{}.clone()",
+            snippet_with_applicability(cx, recvr.span, "..", &mut applicability)
+        ),
+        applicability,
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index 9ad4250a141..3a0305b4d55 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -74,6 +74,7 @@ pub(super) fn get_hint_if_single_char_arg(
             match ch {
                 "'" => "\\'",
                 r"\" => "\\\\",
+                "\\\"" => "\"", // no need to escape `"` in `'"'`
                 _ => ch,
             }
         );
diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
index 0f18e943451..bbc4d0a0f9a 100644
--- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
@@ -331,7 +331,7 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnhashMap<u64, Vec<IndexEntry<'_>>
                     slice,
                 } if indexes.len() > 1 => {
                     // if we have found an `assert!`, let's also check that it's actually right
-                    // and if it convers the highest index and if not, suggest the correct length
+                    // and if it covers the highest index and if not, suggest the correct length
                     let sugg = match comparison {
                         // `v.len() < 5` and `v.len() <= 5` does nothing in terms of bounds checks.
                         // The user probably meant `v.len() > 5`
diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
index c1f6c71a63e..c6c188854fd 100644
--- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
@@ -13,21 +13,23 @@ use rustc_span::Symbol;
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for imports that do not rename the item as specified
-    /// in the `enforce-import-renames` config option.
+    /// in the `enforced-import-renames` config option.
     ///
     /// Note: Even though this lint is warn-by-default, it will only trigger if
-    /// import renames are defined in the clippy.toml file.
+    /// import renames are defined in the `clippy.toml` file.
     ///
     /// ### Why is this bad?
-    /// Consistency is important, if a project has defined import
-    /// renames they should be followed. More practically, some item names are too
-    /// vague outside of their defining scope this can enforce a more meaningful naming.
+    /// Consistency is important; if a project has defined import renames, then they should be
+    /// followed. More practically, some item names are too vague outside of their defining scope,
+    /// in which case this can enforce a more meaningful naming.
     ///
     /// ### Example
     /// An example clippy.toml configuration:
     /// ```toml
     /// # clippy.toml
-    /// enforced-import-renames = [ { path = "serde_json::Value", rename = "JsonValue" }]
+    /// enforced-import-renames = [
+    ///     { path = "serde_json::Value", rename = "JsonValue" },
+    /// ]
     /// ```
     ///
     /// ```rust,ignore
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index a23e12f7a18..4ae4fc9b096 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -6,7 +6,7 @@ use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, IntTy, Ty, UintTy};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
 
@@ -105,8 +105,28 @@ impl<'tcx> LateLintPass<'tcx> for Mutex {
 fn get_atomic_name(ty: Ty<'_>) -> Option<&'static str> {
     match ty.kind() {
         ty::Bool => Some("AtomicBool"),
-        ty::Uint(_) => Some("AtomicUsize"),
-        ty::Int(_) => Some("AtomicIsize"),
+        ty::Uint(uint_ty) => {
+            match uint_ty {
+                UintTy::U8 => Some("AtomicU8"),
+                UintTy::U16 => Some("AtomicU16"),
+                UintTy::U32 => Some("AtomicU32"),
+                UintTy::U64 => Some("AtomicU64"),
+                UintTy::Usize => Some("AtomicUsize"),
+                // There's no `AtomicU128`.
+                UintTy::U128 => None,
+            }
+        },
+        ty::Int(int_ty) => {
+            match int_ty {
+                IntTy::I8 => Some("AtomicI8"),
+                IntTy::I16 => Some("AtomicI16"),
+                IntTy::I32 => Some("AtomicI32"),
+                IntTy::I64 => Some("AtomicI64"),
+                IntTy::Isize => Some("AtomicIsize"),
+                // There's no `AtomicI128`.
+                IntTy::I128 => None,
+            }
+        },
         ty::RawPtr(_) => Some("AtomicPtr"),
         _ => None,
     }
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 5978da83199..6bbe427ea29 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -165,7 +165,7 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
 }
 
 fn is_operator_overridden(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    // It's very hard or impossable to check whether overridden operator have side-effect this lint.
+    // It's very hard or impossible to check whether overridden operator have side-effect this lint.
     // So, this function assume user-defined operator is overridden with an side-effect.
     // The definition of user-defined structure here is ADT-type,
     // Althrough this will weaken the ability of this lint, less error lint-fix happen.
diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
index 49e9e2c00cc..2701d6bdca3 100644
--- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
@@ -53,14 +53,10 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
                             && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did())))
                     && let ExprKind::Lit(_) = param.kind
                     && param.span.eq_ctxt(expr.span)
+                    && let Some(snip) = snippet_opt(cx, param.span)
+                    && !(snip.starts_with("0o") || snip.starts_with("0b"))
                 {
-                    let Some(snip) = snippet_opt(cx, param.span) else {
-                        return;
-                    };
-
-                    if !snip.starts_with("0o") {
-                        show_error(cx, param);
-                    }
+                    show_error(cx, param);
                 }
             },
             ExprKind::Call(func, [param]) => {
@@ -70,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
                     && let ExprKind::Lit(_) = param.kind
                     && param.span.eq_ctxt(expr.span)
                     && let Some(snip) = snippet_opt(cx, param.span)
-                    && !snip.starts_with("0o")
+                    && !(snip.starts_with("0o") || snip.starts_with("0b"))
                 {
                     show_error(cx, param);
                 }
diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
index 8ecb038627f..f671517c134 100644
--- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
@@ -18,82 +18,118 @@ pub(crate) fn check<'tcx>(
     right: &'tcx Expr<'_>,
 ) {
     if !is_allowed(cx, op, left, right) {
-        match op {
-            BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
-                check_op(
-                    cx,
-                    left,
-                    0,
-                    expr.span,
-                    peel_hir_expr_refs(right).0.span,
-                    needs_parenthesis(cx, expr, right),
-                );
-                check_op(
-                    cx,
-                    right,
-                    0,
-                    expr.span,
-                    peel_hir_expr_refs(left).0.span,
-                    Parens::Unneeded,
-                );
-            },
-            BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => {
-                check_op(
-                    cx,
-                    right,
-                    0,
-                    expr.span,
-                    peel_hir_expr_refs(left).0.span,
-                    Parens::Unneeded,
-                );
-            },
-            BinOpKind::Mul => {
-                check_op(
-                    cx,
-                    left,
-                    1,
-                    expr.span,
-                    peel_hir_expr_refs(right).0.span,
-                    needs_parenthesis(cx, expr, right),
-                );
-                check_op(
-                    cx,
-                    right,
-                    1,
-                    expr.span,
-                    peel_hir_expr_refs(left).0.span,
-                    Parens::Unneeded,
-                );
-            },
-            BinOpKind::Div => check_op(
+        return;
+    }
+
+    // we need to know whether a ref is coerced to a value
+    // if a ref is coerced, then the suggested lint must deref it
+    // e.g. `let _: i32 = x+0` with `x: &i32` should be replaced with `let _: i32 = *x`.
+    // we do this by checking the _kind_ of the type of the expression
+    // if it's a ref, we then check whether it is erased, and that's it.
+    let (peeled_left_span, left_is_coerced_to_value) = {
+        let expr = peel_hir_expr_refs(left).0;
+        let span = expr.span;
+        let is_coerced = expr_is_erased_ref(cx, expr);
+        (span, is_coerced)
+    };
+
+    let (peeled_right_span, right_is_coerced_to_value) = {
+        let expr = peel_hir_expr_refs(right).0;
+        let span = expr.span;
+        let is_coerced = expr_is_erased_ref(cx, expr);
+        (span, is_coerced)
+    };
+
+    match op {
+        BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
+            check_op(
+                cx,
+                left,
+                0,
+                expr.span,
+                peeled_right_span,
+                needs_parenthesis(cx, expr, right),
+                right_is_coerced_to_value,
+            );
+            check_op(
+                cx,
+                right,
+                0,
+                expr.span,
+                peeled_left_span,
+                Parens::Unneeded,
+                left_is_coerced_to_value,
+            );
+        },
+        BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => {
+            check_op(
+                cx,
+                right,
+                0,
+                expr.span,
+                peeled_left_span,
+                Parens::Unneeded,
+                left_is_coerced_to_value,
+            );
+        },
+        BinOpKind::Mul => {
+            check_op(
+                cx,
+                left,
+                1,
+                expr.span,
+                peeled_right_span,
+                needs_parenthesis(cx, expr, right),
+                right_is_coerced_to_value,
+            );
+            check_op(
                 cx,
                 right,
                 1,
                 expr.span,
-                peel_hir_expr_refs(left).0.span,
+                peeled_left_span,
                 Parens::Unneeded,
-            ),
-            BinOpKind::BitAnd => {
-                check_op(
-                    cx,
-                    left,
-                    -1,
-                    expr.span,
-                    peel_hir_expr_refs(right).0.span,
-                    needs_parenthesis(cx, expr, right),
-                );
-                check_op(
-                    cx,
-                    right,
-                    -1,
-                    expr.span,
-                    peel_hir_expr_refs(left).0.span,
-                    Parens::Unneeded,
-                );
-            },
-            BinOpKind::Rem => check_remainder(cx, left, right, expr.span, left.span),
-            _ => (),
-        }
+                left_is_coerced_to_value,
+            );
+        },
+        BinOpKind::Div => check_op(
+            cx,
+            right,
+            1,
+            expr.span,
+            peeled_left_span,
+            Parens::Unneeded,
+            left_is_coerced_to_value,
+        ),
+        BinOpKind::BitAnd => {
+            check_op(
+                cx,
+                left,
+                -1,
+                expr.span,
+                peeled_right_span,
+                needs_parenthesis(cx, expr, right),
+                right_is_coerced_to_value,
+            );
+            check_op(
+                cx,
+                right,
+                -1,
+                expr.span,
+                peeled_left_span,
+                Parens::Unneeded,
+                left_is_coerced_to_value,
+            );
+        },
+        BinOpKind::Rem => check_remainder(cx, left, right, expr.span, left.span),
+        _ => (),
+    }
+}
+
+fn expr_is_erased_ref(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    match cx.typeck_results().expr_ty(expr).kind() {
+        ty::Ref(r, ..) => r.is_erased(),
+        _ => false,
     }
 }
 
@@ -144,11 +180,11 @@ fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, right: &Expr<'_>)
 }
 
 fn is_allowed(cx: &LateContext<'_>, cmp: BinOpKind, left: &Expr<'_>, right: &Expr<'_>) -> bool {
-    // This lint applies to integers
-    !cx.typeck_results().expr_ty(left).peel_refs().is_integral()
-        || !cx.typeck_results().expr_ty(right).peel_refs().is_integral()
+    // This lint applies to integers and their references
+    cx.typeck_results().expr_ty(left).peel_refs().is_integral()
+        && cx.typeck_results().expr_ty(right).peel_refs().is_integral()
         // `1 << 0` is a common pattern in bit manipulation code
-        || (cmp == BinOpKind::Shl
+        && !(cmp == BinOpKind::Shl
             && constant_simple(cx, cx.typeck_results(), right) == Some(Constant::Int(0))
             && constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1)))
 }
@@ -161,11 +197,11 @@ fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span
         (Some(FullInt::U(lv)), Some(FullInt::U(rv))) => lv < rv,
         _ => return,
     } {
-        span_ineffective_operation(cx, span, arg, Parens::Unneeded);
+        span_ineffective_operation(cx, span, arg, Parens::Unneeded, false);
     }
 }
 
-fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens) {
+fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens, is_erased: bool) {
     if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e).map(Constant::peel_refs) {
         let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() {
             ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
@@ -178,18 +214,28 @@ fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, pa
             1 => v == 1,
             _ => unreachable!(),
         } {
-            span_ineffective_operation(cx, span, arg, parens);
+            span_ineffective_operation(cx, span, arg, parens, is_erased);
         }
     }
 }
 
-fn span_ineffective_operation(cx: &LateContext<'_>, span: Span, arg: Span, parens: Parens) {
+fn span_ineffective_operation(
+    cx: &LateContext<'_>,
+    span: Span,
+    arg: Span,
+    parens: Parens,
+    is_ref_coerced_to_val: bool,
+) {
     let mut applicability = Applicability::MachineApplicable;
     let expr_snippet = snippet_with_applicability(cx, arg, "..", &mut applicability);
-
+    let expr_snippet = if is_ref_coerced_to_val {
+        format!("*{expr_snippet}")
+    } else {
+        expr_snippet.into_owned()
+    };
     let suggestion = match parens {
         Parens::Needed => format!("({expr_snippet})"),
-        Parens::Unneeded => expr_snippet.into_owned(),
+        Parens::Unneeded => expr_snippet,
     };
 
     span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs
new file mode 100644
index 00000000000..00465ce4381
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs
@@ -0,0 +1,83 @@
+use clippy_config::types::PubUnderscoreFieldsBehaviour;
+use clippy_utils::attrs::is_doc_hidden;
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_path_lang_item;
+use rustc_hir::{FieldDef, Item, ItemKind, LangItem};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::impl_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks whether any field of the struct is prefixed with an `_` (underscore) and also marked
+    /// `pub` (public)
+    ///
+    /// ### Why is this bad?
+    /// Fields prefixed with an `_` are inferred as unused, which suggests it should not be marked
+    /// as `pub`, because marking it as `pub` infers it will be used.
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct FileHandle {
+    ///     pub _descriptor: usize,
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct FileHandle {
+    ///     _descriptor: usize,
+    /// }
+    /// ```
+    ///
+    /// OR
+    ///
+    /// ```rust
+    /// struct FileHandle {
+    ///     pub descriptor: usize,
+    /// }
+    /// ```
+    #[clippy::version = "1.77.0"]
+    pub PUB_UNDERSCORE_FIELDS,
+    pedantic,
+    "struct field prefixed with underscore and marked public"
+}
+
+pub struct PubUnderscoreFields {
+    pub behavior: PubUnderscoreFieldsBehaviour,
+}
+impl_lint_pass!(PubUnderscoreFields => [PUB_UNDERSCORE_FIELDS]);
+
+impl<'tcx> LateLintPass<'tcx> for PubUnderscoreFields {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        // This lint only pertains to structs.
+        let ItemKind::Struct(variant_data, _) = &item.kind else {
+            return;
+        };
+
+        let is_visible = |field: &FieldDef<'_>| match self.behavior {
+            PubUnderscoreFieldsBehaviour::PublicallyExported => cx.effective_visibilities.is_reachable(field.def_id),
+            PubUnderscoreFieldsBehaviour::AllPubFields => {
+                // If there is a visibility span then the field is marked pub in some way.
+                !field.vis_span.is_empty()
+            },
+        };
+
+        for field in variant_data.fields() {
+            // Only pertains to fields that start with an underscore, and are public.
+            if field.ident.as_str().starts_with('_') && is_visible(field)
+                // We ignore fields that have `#[doc(hidden)]`.
+                && !is_doc_hidden(cx.tcx.hir().attrs(field.hir_id))
+                // We ignore fields that are `PhantomData`.
+                && !is_path_lang_item(cx, field.ty, LangItem::PhantomData)
+            {
+                span_lint_and_help(
+                    cx,
+                    PUB_UNDERSCORE_FIELDS,
+                    field.vis_span.to(field.ident.span),
+                    "field marked as public but also inferred as unused because it's prefixed with `_`",
+                    None,
+                    "consider removing the underscore, or making the field private",
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index 9469888a4d4..bd3128a0f97 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -75,12 +75,7 @@ enum IfBlockType<'hir> {
     /// An `if x.is_xxx() { a } else { b } ` expression.
     ///
     /// Contains: caller (x), caller_type, call_sym (is_xxx), if_then (a), if_else (b)
-    IfIs(
-        &'hir Expr<'hir>,
-        Ty<'hir>,
-        Symbol,
-        &'hir Expr<'hir>,
-    ),
+    IfIs(&'hir Expr<'hir>, Ty<'hir>, Symbol, &'hir Expr<'hir>),
     /// An `if let Xxx(a) = b { c } else { d }` expression.
     ///
     /// Contains: let_pat_qpath (Xxx), let_pat_type, let_pat_sym (a), let_expr (b), if_then (c),
diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs
index 90834d784a5..b4278d879e5 100644
--- a/src/tools/clippy/clippy_lints/src/serde_api.rs
+++ b/src/tools/clippy/clippy_lints/src/serde_api.rs
@@ -6,7 +6,7 @@ use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for mis-uses of the serde API.
+    /// Checks for misuses of the serde API.
     ///
     /// ### Why is this bad?
     /// Serde is very finnicky about how its API should be
diff --git a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
new file mode 100644
index 00000000000..9fee4c06200
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
@@ -0,0 +1,102 @@
+use clippy_config::msrvs::Msrv;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::fn_has_unsatisfiable_preds;
+use clippy_utils::qualify_min_const_fn::is_min_const_fn;
+use clippy_utils::source::snippet;
+use rustc_errors::Applicability;
+use rustc_hir::{intravisit, ExprKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::impl_lint_pass;
+use rustc_span::sym::thread_local_macro;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Suggests to use `const` in `thread_local!` macro if possible.
+    /// ### Why is this bad?
+    ///
+    /// The `thread_local!` macro wraps static declarations and makes them thread-local.
+    /// It supports using a `const` keyword that may be used for declarations that can
+    /// be evaluated as a constant expression. This can enable a more efficient thread
+    /// local implementation that can avoid lazy initialization. For types that do not
+    /// need to be dropped, this can enable an even more efficient implementation that
+    /// does not need to track any additional state.
+    ///
+    /// https://doc.rust-lang.org/std/macro.thread_local.html
+    ///
+    /// ### Example
+    /// ```no_run
+    /// // example code where clippy issues a warning
+    /// thread_local! {
+    ///     static BUF: String = String::new();
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// // example code which does not raise clippy warning
+    /// thread_local! {
+    ///     static BUF: String = const { String::new() };
+    /// }
+    /// ```
+    #[clippy::version = "1.76.0"]
+    pub THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST,
+    perf,
+    "suggest using `const` in `thread_local!` macro"
+}
+
+pub struct ThreadLocalInitializerCanBeMadeConst {
+    msrv: Msrv,
+}
+
+impl ThreadLocalInitializerCanBeMadeConst {
+    #[must_use]
+    pub fn new(msrv: Msrv) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(ThreadLocalInitializerCanBeMadeConst => [THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST]);
+
+impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        fn_kind: rustc_hir::intravisit::FnKind<'tcx>,
+        _: &'tcx rustc_hir::FnDecl<'tcx>,
+        body: &'tcx rustc_hir::Body<'tcx>,
+        span: rustc_span::Span,
+        defid: rustc_span::def_id::LocalDefId,
+    ) {
+        if in_external_macro(cx.sess(), span)
+            && let Some(callee) = span.source_callee()
+            && let Some(macro_def_id) = callee.macro_def_id
+            && cx.tcx.is_diagnostic_item(thread_local_macro, macro_def_id)
+            && let intravisit::FnKind::ItemFn(..) = fn_kind
+            // Building MIR for `fn`s with unsatisfiable preds results in ICE.
+            && !fn_has_unsatisfiable_preds(cx, defid.to_def_id())
+            && let mir = cx.tcx.optimized_mir(defid.to_def_id())
+            && let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv)
+            // this is the `__init` function emitted by the `thread_local!` macro
+            // when the `const` keyword is not used. We avoid checking the `__init` directly
+            // as that is not a public API.
+            // we know that the function is const-qualifiable, so now we need only to get the
+            // initializer expression to span-lint it.
+            && let ExprKind::Block(block, _) = body.value.kind
+            && let Some(ret_expr) = block.expr
+            && let initializer_snippet = snippet(cx, ret_expr.span, "thread_local! { ... }")
+            && initializer_snippet != "thread_local! { ... }"
+        {
+            span_lint_and_sugg(
+                cx,
+                THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST,
+                ret_expr.span,
+                "initializer for `thread_local` value can be made `const`",
+                "replace with",
+                format!("const {{ {initializer_snippet} }}"),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
+    extract_msrv_attr!(LateContext);
+}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
index 01a23c515f5..c44f5150dd1 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_normalizable;
-use clippy_utils::{path_to_local, path_to_local_id};
+use clippy_utils::{eq_expr_value, path_to_local};
 use rustc_abi::WrappingRange;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Node};
@@ -25,6 +25,52 @@ fn range_fully_contained(from: WrappingRange, to: WrappingRange) -> bool {
     to.contains(from.start) && to.contains(from.end)
 }
 
+/// Checks if a given expression is a binary operation involving a local variable or is made up of
+/// other (nested) binary expressions involving the local. There must be at least one local
+/// reference that is the same as `local_expr`.
+///
+/// This is used as a heuristic to detect if a variable
+/// is checked to be within the valid range of a transmuted type.
+/// All of these would return true:
+/// * `x < 4`
+/// * `x < 4 && x > 1`
+/// * `x.field < 4 && x.field > 1` (given `x.field`)
+/// * `x.field < 4 && unrelated()`
+/// * `(1..=3).contains(&x)`
+fn binops_with_local(cx: &LateContext<'_>, local_expr: &Expr<'_>, expr: &Expr<'_>) -> bool {
+    match expr.kind {
+        ExprKind::Binary(_, lhs, rhs) => {
+            binops_with_local(cx, local_expr, lhs) || binops_with_local(cx, local_expr, rhs)
+        },
+        ExprKind::MethodCall(path, receiver, [arg], _)
+            if path.ident.name == sym!(contains)
+                // ... `contains` called on some kind of range
+                && let Some(receiver_adt) = cx.typeck_results().expr_ty(receiver).peel_refs().ty_adt_def()
+                && let lang_items = cx.tcx.lang_items()
+                && [
+                    lang_items.range_from_struct(),
+                    lang_items.range_inclusive_struct(),
+                    lang_items.range_struct(),
+                    lang_items.range_to_inclusive_struct(),
+                    lang_items.range_to_struct()
+                ].into_iter().any(|did| did == Some(receiver_adt.did())) =>
+        {
+            eq_expr_value(cx, local_expr, arg.peel_borrows())
+        },
+        _ => eq_expr_value(cx, local_expr, expr),
+    }
+}
+
+/// Checks if an expression is a path to a local variable (with optional projections), e.g.
+/// `x.field[0].field2` would return true.
+fn is_local_with_projections(expr: &Expr<'_>) -> bool {
+    match expr.kind {
+        ExprKind::Path(_) => path_to_local(expr).is_some(),
+        ExprKind::Field(expr, _) | ExprKind::Index(expr, ..) => is_local_with_projections(expr),
+        _ => false,
+    }
+}
+
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
@@ -36,9 +82,8 @@ pub(super) fn check<'tcx>(
         && let ExprKind::MethodCall(path, receiver, [arg], _) = then_some_call.kind
         && cx.typeck_results().expr_ty(receiver).is_bool()
         && path.ident.name == sym!(then_some)
-        && let ExprKind::Binary(_, lhs, rhs) = receiver.kind
-        && let Some(local_id) = path_to_local(transmutable)
-        && (path_to_local_id(lhs, local_id) || path_to_local_id(rhs, local_id))
+        && is_local_with_projections(transmutable)
+        && binops_with_local(cx, transmutable, receiver)
         && is_normalizable(cx, cx.param_env, from_ty)
         && is_normalizable(cx, cx.param_env, to_ty)
         // we only want to lint if the target type has a niche that is larger than the one of the source type
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index db378cfd755..a6f03c85b4f 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -37,9 +37,7 @@ pub(super) fn check<'tcx>(
                 to_ty = to_sub_ty;
                 continue;
             },
-            (ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(Some(to_sub_ty)))
-                if reduced_tys.from_fat_ptr =>
-            {
+            (ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(Some(to_sub_ty))) if reduced_tys.from_fat_ptr => {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
                 continue;
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index b1fa30aa068..e90306ded61 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -1,14 +1,21 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{get_trait_def_id, path_res};
+use clippy_utils::{expr_or_init, get_trait_def_id, path_def_id};
 use rustc_ast::BinOpKind;
-use rustc_hir::def::Res;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, Expr, ExprKind, FnDecl, Item, ItemKind, Node};
+use rustc_hir::intravisit::{walk_body, walk_expr, FnKind, Visitor};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId, Item, ItemKind, Node, QPath, TyKind};
+use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, Ty};
-use rustc_session::declare_lint_pass;
+use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt};
+use rustc_session::impl_lint_pass;
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::{sym, Span};
+use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -41,7 +48,26 @@ declare_clippy_lint! {
     "detect unconditional recursion in some traits implementation"
 }
 
-declare_lint_pass!(UnconditionalRecursion => [UNCONDITIONAL_RECURSION]);
+#[derive(Default)]
+pub struct UnconditionalRecursion {
+    /// The key is the `DefId` of the type implementing the `Default` trait and the value is the
+    /// `DefId` of the return call.
+    default_impl_for_type: FxHashMap<DefId, DefId>,
+}
+
+impl_lint_pass!(UnconditionalRecursion => [UNCONDITIONAL_RECURSION]);
+
+fn span_error(cx: &LateContext<'_>, method_span: Span, expr: &Expr<'_>) {
+    span_lint_and_then(
+        cx,
+        UNCONDITIONAL_RECURSION,
+        method_span,
+        "function cannot return without recursing",
+        |diag| {
+            diag.span_note(expr.span, "recursive call site");
+        },
+    );
+}
 
 fn get_ty_def_id(ty: Ty<'_>) -> Option<DefId> {
     match ty.peel_refs().kind() {
@@ -51,84 +77,329 @@ fn get_ty_def_id(ty: Ty<'_>) -> Option<DefId> {
     }
 }
 
-fn is_local(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    matches!(path_res(cx, expr), Res::Local(_))
+fn get_hir_ty_def_id(tcx: TyCtxt<'_>, hir_ty: rustc_hir::Ty<'_>) -> Option<DefId> {
+    let TyKind::Path(qpath) = hir_ty.kind else { return None };
+    match qpath {
+        QPath::Resolved(_, path) => path.res.opt_def_id(),
+        QPath::TypeRelative(_, _) => {
+            let ty = hir_ty_to_ty(tcx, &hir_ty);
+
+            match ty.kind() {
+                ty::Alias(ty::Projection, proj) => {
+                    Res::<HirId>::Def(DefKind::Trait, proj.trait_ref(tcx).def_id).opt_def_id()
+                },
+                _ => None,
+            }
+        },
+        QPath::LangItem(..) => None,
+    }
 }
 
-impl<'tcx> LateLintPass<'tcx> for UnconditionalRecursion {
+fn get_return_calls_in_body<'tcx>(body: &'tcx Body<'tcx>) -> Vec<&'tcx Expr<'tcx>> {
+    let mut visitor = ReturnsVisitor::default();
+
+    visitor.visit_body(body);
+    visitor.returns
+}
+
+fn has_conditional_return(body: &Body<'_>, expr: &Expr<'_>) -> bool {
+    match get_return_calls_in_body(body).as_slice() {
+        [] => false,
+        [return_expr] => return_expr.hir_id != expr.hir_id,
+        _ => true,
+    }
+}
+
+fn get_impl_trait_def_id(cx: &LateContext<'_>, method_def_id: LocalDefId) -> Option<DefId> {
+    let hir_id = cx.tcx.local_def_id_to_hir_id(method_def_id);
+    if let Some((
+        _,
+        Node::Item(Item {
+            kind: ItemKind::Impl(impl_),
+            owner_id,
+            ..
+        }),
+    )) = cx.tcx.hir().parent_iter(hir_id).next()
+        // We exclude `impl` blocks generated from rustc's proc macros.
+        && !cx.tcx.has_attr(*owner_id, sym::automatically_derived)
+        // It is a implementation of a trait.
+        && let Some(trait_) = impl_.of_trait
+    {
+        trait_.trait_def_id()
+    } else {
+        None
+    }
+}
+
+#[allow(clippy::unnecessary_def_path)]
+fn check_partial_eq(cx: &LateContext<'_>, method_span: Span, method_def_id: LocalDefId, name: Ident, expr: &Expr<'_>) {
+    let args = cx
+        .tcx
+        .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(method_def_id).skip_binder())
+        .inputs();
+    // That has two arguments.
+    if let [self_arg, other_arg] = args
+        && let Some(self_arg) = get_ty_def_id(*self_arg)
+        && let Some(other_arg) = get_ty_def_id(*other_arg)
+        // The two arguments are of the same type.
+        && self_arg == other_arg
+        && let Some(trait_def_id) = get_impl_trait_def_id(cx, method_def_id)
+        // The trait is `PartialEq`.
+        && Some(trait_def_id) == get_trait_def_id(cx, &["core", "cmp", "PartialEq"])
+    {
+        let to_check_op = if name.name == sym::eq {
+            BinOpKind::Eq
+        } else {
+            BinOpKind::Ne
+        };
+        let is_bad = match expr.kind {
+            ExprKind::Binary(op, left, right) if op.node == to_check_op => {
+                // Then we check if the left-hand element is of the same type as `self`.
+                if let Some(left_ty) = cx.typeck_results().expr_ty_opt(left)
+                    && let Some(left_id) = get_ty_def_id(left_ty)
+                    && self_arg == left_id
+                    && let Some(right_ty) = cx.typeck_results().expr_ty_opt(right)
+                    && let Some(right_id) = get_ty_def_id(right_ty)
+                    && other_arg == right_id
+                {
+                    true
+                } else {
+                    false
+                }
+            },
+            ExprKind::MethodCall(segment, _receiver, &[_arg], _) if segment.ident.name == name.name => {
+                if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+                    && trait_id == trait_def_id
+                {
+                    true
+                } else {
+                    false
+                }
+            },
+            _ => false,
+        };
+        if is_bad {
+            span_error(cx, method_span, expr);
+        }
+    }
+}
+
+#[allow(clippy::unnecessary_def_path)]
+fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: LocalDefId, name: Ident, expr: &Expr<'_>) {
+    let args = cx
+        .tcx
+        .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(method_def_id).skip_binder())
+        .inputs();
+    // That has one argument.
+    if let [_self_arg] = args
+        && let hir_id = cx.tcx.local_def_id_to_hir_id(method_def_id)
+        && let Some((
+            _,
+            Node::Item(Item {
+                kind: ItemKind::Impl(impl_),
+                owner_id,
+                ..
+            }),
+        )) = cx.tcx.hir().parent_iter(hir_id).next()
+        // We exclude `impl` blocks generated from rustc's proc macros.
+        && !cx.tcx.has_attr(*owner_id, sym::automatically_derived)
+        // It is a implementation of a trait.
+        && let Some(trait_) = impl_.of_trait
+        && let Some(trait_def_id) = trait_.trait_def_id()
+        // The trait is `ToString`.
+        && Some(trait_def_id) == get_trait_def_id(cx, &["alloc", "string", "ToString"])
+    {
+        let is_bad = match expr.kind {
+            ExprKind::MethodCall(segment, _receiver, &[_arg], _) if segment.ident.name == name.name => {
+                if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+                    && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
+                    && trait_id == trait_def_id
+                {
+                    true
+                } else {
+                    false
+                }
+            },
+            _ => false,
+        };
+        if is_bad {
+            span_error(cx, method_span, expr);
+        }
+    }
+}
+
+fn is_default_method_on_current_ty(tcx: TyCtxt<'_>, qpath: QPath<'_>, implemented_ty_id: DefId) -> bool {
+    match qpath {
+        QPath::Resolved(_, path) => match path.segments {
+            [first, .., last] => last.ident.name == kw::Default && first.res.opt_def_id() == Some(implemented_ty_id),
+            _ => false,
+        },
+        QPath::TypeRelative(ty, segment) => {
+            if segment.ident.name != kw::Default {
+                return false;
+            }
+            if matches!(
+                ty.kind,
+                TyKind::Path(QPath::Resolved(
+                    _,
+                    hir::Path {
+                        res: Res::SelfTyAlias { .. },
+                        ..
+                    },
+                ))
+            ) {
+                return true;
+            }
+            get_hir_ty_def_id(tcx, *ty) == Some(implemented_ty_id)
+        },
+        QPath::LangItem(..) => false,
+    }
+}
+
+struct CheckCalls<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    map: Map<'tcx>,
+    implemented_ty_id: DefId,
+    found_default_call: bool,
+    method_span: Span,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for CheckCalls<'a, 'tcx>
+where
+    'tcx: 'a,
+{
+    type NestedFilter = nested_filter::OnlyBodies;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.map
+    }
+
     #[allow(clippy::unnecessary_def_path)]
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        if self.found_default_call {
+            return;
+        }
+        walk_expr(self, expr);
+
+        if let ExprKind::Call(f, _) = expr.kind
+            && let ExprKind::Path(qpath) = f.kind
+            && is_default_method_on_current_ty(self.cx.tcx, qpath, self.implemented_ty_id)
+            && let Some(method_def_id) = path_def_id(self.cx, f)
+            && let Some(trait_def_id) = self.cx.tcx.trait_of_item(method_def_id)
+            && Some(trait_def_id) == get_trait_def_id(self.cx, &["core", "default", "Default"])
+        {
+            self.found_default_call = true;
+            span_error(self.cx, self.method_span, expr);
+        }
+    }
+}
+
+impl UnconditionalRecursion {
+    #[allow(clippy::unnecessary_def_path)]
+    fn init_default_impl_for_type_if_needed(&mut self, cx: &LateContext<'_>) {
+        if self.default_impl_for_type.is_empty()
+            && let Some(default_trait_id) = get_trait_def_id(cx, &["core", "default", "Default"])
+        {
+            let impls = cx.tcx.trait_impls_of(default_trait_id);
+            for (ty, impl_def_ids) in impls.non_blanket_impls() {
+                let Some(self_def_id) = ty.def() else { continue };
+                for impl_def_id in impl_def_ids {
+                    if !cx.tcx.has_attr(*impl_def_id, sym::automatically_derived) &&
+                        let Some(assoc_item) = cx
+                            .tcx
+                            .associated_items(impl_def_id)
+                            .in_definition_order()
+                            // We're not interested in foreign implementations of the `Default` trait.
+                            .find(|item| {
+                                item.kind == AssocKind::Fn && item.def_id.is_local() && item.name == kw::Default
+                            })
+                        && let Some(body_node) = cx.tcx.hir().get_if_local(assoc_item.def_id)
+                        && let Some(body_id) = body_node.body_id()
+                        && let body = cx.tcx.hir().body(body_id)
+                        // We don't want to keep it if it has conditional return.
+                        && let [return_expr] = get_return_calls_in_body(body).as_slice()
+                        && let ExprKind::Call(call_expr, _) = return_expr.kind
+                        // We need to use typeck here to infer the actual function being called.
+                        && let body_def_id = cx.tcx.hir().enclosing_body_owner(call_expr.hir_id)
+                        && let Some(body_owner) = cx.tcx.hir().maybe_body_owned_by(body_def_id)
+                        && let typeck = cx.tcx.typeck_body(body_owner)
+                        && let Some(call_def_id) = typeck.type_dependent_def_id(call_expr.hir_id)
+                    {
+                        self.default_impl_for_type.insert(self_def_id, call_def_id);
+                    }
+                }
+            }
+        }
+    }
+
+    fn check_default_new<'tcx>(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        decl: &FnDecl<'tcx>,
+        body: &'tcx Body<'tcx>,
+        method_span: Span,
+        method_def_id: LocalDefId,
+    ) {
+        // We're only interested into static methods.
+        if decl.implicit_self.has_implicit_self() {
+            return;
+        }
+        // We don't check trait implementations.
+        if get_impl_trait_def_id(cx, method_def_id).is_some() {
+            return;
+        }
+
+        let hir_id = cx.tcx.local_def_id_to_hir_id(method_def_id);
+        if let Some((
+            _,
+            Node::Item(Item {
+                kind: ItemKind::Impl(impl_),
+                ..
+            }),
+        )) = cx.tcx.hir().parent_iter(hir_id).next()
+            && let Some(implemented_ty_id) = get_hir_ty_def_id(cx.tcx, *impl_.self_ty)
+            && {
+                self.init_default_impl_for_type_if_needed(cx);
+                true
+            }
+            && let Some(return_def_id) = self.default_impl_for_type.get(&implemented_ty_id)
+            && method_def_id.to_def_id() == *return_def_id
+        {
+            let mut c = CheckCalls {
+                cx,
+                map: cx.tcx.hir(),
+                implemented_ty_id,
+                found_default_call: false,
+                method_span,
+            };
+            walk_body(&mut c, body);
+        }
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for UnconditionalRecursion {
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
         kind: FnKind<'tcx>,
-        _decl: &'tcx FnDecl<'tcx>,
+        decl: &'tcx FnDecl<'tcx>,
         body: &'tcx Body<'tcx>,
         method_span: Span,
-        def_id: LocalDefId,
+        method_def_id: LocalDefId,
     ) {
         // If the function is a method...
         if let FnKind::Method(name, _) = kind
-            // That has two arguments.
-            && let [self_arg, other_arg] = cx
-                .tcx
-                .instantiate_bound_regions_with_erased(cx.tcx.fn_sig(def_id).skip_binder())
-                .inputs()
-            && let Some(self_arg) = get_ty_def_id(*self_arg)
-            && let Some(other_arg) = get_ty_def_id(*other_arg)
-            // The two arguments are of the same type.
-            && self_arg == other_arg
-            && let hir_id = cx.tcx.local_def_id_to_hir_id(def_id)
-            && let Some((
-                _,
-                Node::Item(Item {
-                    kind: ItemKind::Impl(impl_),
-                    owner_id,
-                    ..
-                }),
-            )) = cx.tcx.hir().parent_iter(hir_id).next()
-            // We exclude `impl` blocks generated from rustc's proc macros.
-            && !cx.tcx.has_attr(*owner_id, sym::automatically_derived)
-            // It is a implementation of a trait.
-            && let Some(trait_) = impl_.of_trait
-            && let Some(trait_def_id) = trait_.trait_def_id()
-            // The trait is `PartialEq`.
-            && Some(trait_def_id) == get_trait_def_id(cx, &["core", "cmp", "PartialEq"])
+            && let expr = expr_or_init(cx, body.value).peel_blocks()
+            // Doesn't have a conditional return.
+            && !has_conditional_return(body, expr)
         {
-            let to_check_op = if name.name == sym::eq {
-                BinOpKind::Eq
-            } else {
-                BinOpKind::Ne
-            };
-            let expr = body.value.peel_blocks();
-            let is_bad = match expr.kind {
-                ExprKind::Binary(op, left, right) if op.node == to_check_op => {
-                    is_local(cx, left) && is_local(cx, right)
-                },
-                ExprKind::MethodCall(segment, receiver, &[arg], _) if segment.ident.name == name.name => {
-                    if is_local(cx, receiver)
-                        && is_local(cx, &arg)
-                        && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
-                        && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
-                        && trait_id == trait_def_id
-                    {
-                        true
-                    } else {
-                        false
-                    }
-                },
-                _ => false,
-            };
-            if is_bad {
-                span_lint_and_then(
-                    cx,
-                    UNCONDITIONAL_RECURSION,
-                    method_span,
-                    "function cannot return without recursing",
-                    |diag| {
-                        diag.span_note(expr.span, "recursive call site");
-                    },
-                );
+            if name.name == sym::eq || name.name == sym::ne {
+                check_partial_eq(cx, method_span, method_def_id, name, expr);
+            } else if name.name == sym::to_string {
+                check_to_string(cx, method_span, method_def_id, name, expr);
             }
+            self.check_default_new(cx, decl, body, method_span, method_def_id);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index e5bc3b5a25f..add4b3e5637 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -681,11 +681,19 @@ fn text_has_safety_comment(src: &str, line_starts: &[RelativeBytePos], start_pos
         .filter(|(_, text)| !text.is_empty());
 
     let (line_start, line) = lines.next()?;
+    let mut in_codeblock = false;
     // Check for a sequence of line comments.
     if line.starts_with("//") {
         let (mut line, mut line_start) = (line, line_start);
         loop {
-            if line.to_ascii_uppercase().contains("SAFETY:") {
+            // Don't lint if the safety comment is part of a codeblock in a doc comment.
+            // It may or may not be required, and we can't very easily check it (and we shouldn't, since
+            // the safety comment isn't referring to the node we're currently checking)
+            if line.trim_start_matches("///").trim_start().starts_with("```") {
+                in_codeblock = !in_codeblock;
+            }
+
+            if line.to_ascii_uppercase().contains("SAFETY:") && !in_codeblock {
                 return Some(start_pos + BytePos(u32::try_from(line_start).unwrap()));
             }
             match lines.next() {
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index ef67f4b04b5..ed0958197f8 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -13,12 +13,31 @@ use rustc_middle::ty;
 use super::LET_UNIT_VALUE;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
+    // skip `let () = { ... }`
+    if let PatKind::Tuple(fields, ..) = local.pat.kind
+        && fields.is_empty()
+    {
+        return;
+    }
+
     if let Some(init) = local.init
         && !local.pat.span.from_expansion()
         && !in_external_macro(cx.sess(), local.span)
         && !is_from_async_await(local.span)
         && cx.typeck_results().pat_ty(local.pat).is_unit()
     {
+        // skip `let awa = ()`
+        if let ExprKind::Tup([]) = init.kind {
+            return;
+        }
+
+        // skip `let _: () = { ... }`
+        if let Some(ty) = local.ty
+            && let TyKind::Tup([]) = ty.kind
+        {
+            return;
+        }
+
         if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer))
             || matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()))
             && expr_needs_inferred_result(cx, init)
@@ -34,7 +53,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
                     |diag| {
                         diag.span_suggestion(
                             local.pat.span,
-                            "use a wild (`_`) binding",
+                            "use a wildcard binding",
                             "_",
                             Applicability::MaybeIncorrect, // snippet
                         );
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 5e13c73f035..2c33c93412a 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -11,8 +11,8 @@ use clippy_utils::{get_parent_expr, higher, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, Mutability, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::{sym, DesugaringKind, Span};
 
@@ -79,7 +79,6 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
                 // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
                 && local.ty.is_none()
                 && let PatKind::Binding(_, id, ..) = local.pat.kind
-                && is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(expr.peel_borrows())))
             {
                 let only_slice_uses = for_each_local_use_after_expr(cx, id, expr.hir_id, |expr| {
                     // allow indexing into a vec and some set of allowed method calls that exist on slices, too
@@ -185,6 +184,11 @@ impl UselessVec {
         let snippet = match *vec_args {
             higher::VecArgs::Repeat(elem, len) => {
                 if let Some(Constant::Int(len_constant)) = constant(cx, cx.typeck_results(), len) {
+                    // vec![ty; N] works when ty is Clone, [ty; N] requires it to be Copy also
+                    if !is_copy(cx, cx.typeck_results().expr_ty(elem)) {
+                        return;
+                    }
+
                     #[expect(clippy::cast_possible_truncation)]
                     if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack {
                         return;
@@ -241,12 +245,3 @@ fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 {
     let ty = cx.typeck_results().expr_ty_adjusted(expr);
     cx.layout_of(ty).map_or(0, |l| l.size.bytes())
 }
-
-/// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
-fn vec_type(ty: Ty<'_>) -> Ty<'_> {
-    if let ty::Adt(_, args) = ty.kind() {
-        args.type_at(0)
-    } else {
-        panic!("The type of `vec!` is a not a struct?");
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 9b0dac6af25..b82bd1d7e7c 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -142,7 +142,7 @@ impl LateLintPass<'_> for WildcardImports {
             } else {
                 // In this case, the `use_path.span` ends right before the `::*`, so we need to
                 // extend it up to the `*`. Since it is hard to find the `*` in weird
-                // formattings like `use _ ::  *;`, we extend it up to, but not including the
+                // formatting like `use _ ::  *;`, we extend it up to, but not including the
                 // `;`. In nested imports, like `use _::{inner::*, _}` there is no `;` and we
                 // can just use the end of the item span
                 let mut span = use_path.span.with_hi(item.span.hi());
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 4e71c6483e6..6c40029a9de 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -99,7 +99,10 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
 }
 
 fn res_has_significant_drop(res: Res, cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    if let Res::Def(DefKind::Ctor(..) | DefKind::Variant, _) | Res::SelfCtor(_) = res {
+    if let Res::Def(DefKind::Ctor(..) | DefKind::Variant | DefKind::Enum | DefKind::Struct, _)
+    | Res::SelfCtor(_)
+    | Res::SelfTyAlias { .. } = res
+    {
         cx.typeck_results()
             .expr_ty(e)
             .has_significant_drop(cx.tcx, cx.param_env)
@@ -173,6 +176,13 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                     self.eagerness |= NoChange;
                     return;
                 },
+                #[expect(clippy::match_same_arms)] // arm pattern can't be merged due to `ref`, see rust#105778
+                ExprKind::Struct(path, ..) => {
+                    if res_has_significant_drop(self.cx.qpath_res(path, e.hir_id), self.cx, e) {
+                        self.eagerness = ForceNoChange;
+                        return;
+                    }
+                },
                 ExprKind::Path(ref path) => {
                     if res_has_significant_drop(self.cx.qpath_res(path, e.hir_id), self.cx, e) {
                         self.eagerness = ForceNoChange;
@@ -291,7 +301,6 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 | ExprKind::Closure { .. }
                 | ExprKind::Field(..)
                 | ExprKind::AddrOf(..)
-                | ExprKind::Struct(..)
                 | ExprKind::Repeat(..)
                 | ExprKind::Block(Block { stmts: [], .. }, _)
                 | ExprKind::OffsetOf(..) => (),
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index a23105691bf..07b72e3f570 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -865,7 +865,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
 
                 for arm in arms {
                     self.hash_pat(arm.pat);
-                    if let Some(ref e) = arm.guard {
+                    if let Some(e) = arm.guard {
                         self.hash_expr(e);
                     }
                     self.hash_expr(arm.body);
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index 46ce4ffdce5..c475e7b7c43 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -420,7 +420,7 @@ pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId)
         ast_format_args
             .get()?
             .get(&format_args_expr.span.with_parent(None))
-            .map(Rc::clone)
+            .cloned()
     })
 }
 
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
index da71fc3aaa8..adca2ca1c3e 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -38,7 +38,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
 
         ExprKind::Call(callee, args) => {
             let lhs = expr_type_certainty(cx, callee);
-            let rhs = if type_is_inferrable_from_arguments(cx, expr) {
+            let rhs = if type_is_inferable_from_arguments(cx, expr) {
                 meet(args.iter().map(|arg| expr_type_certainty(cx, arg)))
             } else {
                 Certainty::Uncertain
@@ -57,7 +57,7 @@ fn expr_type_certainty(cx: &LateContext<'_>, expr: &Expr<'_>) -> Certainty {
                 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) {
+            let rhs = if type_is_inferable_from_arguments(cx, expr) {
                 meet(
                     std::iter::once(receiver_type_certainty).chain(args.iter().map(|arg| expr_type_certainty(cx, arg))),
                 )
@@ -279,7 +279,7 @@ fn update_res(cx: &LateContext<'_>, parent_certainty: Certainty, path_segment: &
 }
 
 #[allow(clippy::cast_possible_truncation)]
-fn type_is_inferrable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+fn type_is_inferable_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);
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 5a2526fd267..2589d46e7da 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-12-28"
+channel = "nightly-2024-01-11"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/rustc_tools_util/README.md b/src/tools/clippy/rustc_tools_util/README.md
index e197ea048a0..56f62b867a6 100644
--- a/src/tools/clippy/rustc_tools_util/README.md
+++ b/src/tools/clippy/rustc_tools_util/README.md
@@ -51,7 +51,7 @@ The changelog for `rustc_tools_util` is available under:
 
 <!-- REUSE-IgnoreStart -->
 
-Copyright 2014-2022 The Rust Project Developers
+Copyright 2014-2024 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
diff --git a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/all_pub_fields/clippy.toml b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/all_pub_fields/clippy.toml
new file mode 100644
index 00000000000..95835d101b1
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/all_pub_fields/clippy.toml
@@ -0,0 +1 @@
+pub-underscore-fields-behavior = "AllPubFields"
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/exported/clippy.toml b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/exported/clippy.toml
new file mode 100644
index 00000000000..94a0d3554bc
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/exported/clippy.toml
@@ -0,0 +1 @@
+pub-underscore-fields-behavior = "PublicallyExported"
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr
new file mode 100644
index 00000000000..c6bd499fd8c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr
@@ -0,0 +1,60 @@
+error: field marked as public but also inferred as unused because it's prefixed with `_`
+  --> $DIR/pub_underscore_fields.rs:15:9
+   |
+LL |         pub _b: u8,
+   |         ^^^^^^
+   |
+   = help: consider removing the underscore, or making the field private
+   = note: `-D clippy::pub-underscore-fields` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::pub_underscore_fields)]`
+
+error: field marked as public but also inferred as unused because it's prefixed with `_`
+  --> $DIR/pub_underscore_fields.rs:23:13
+   |
+LL |             pub(in crate::inner) _f: Option<()>,
+   |             ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing the underscore, or making the field private
+
+error: field marked as public but also inferred as unused because it's prefixed with `_`
+  --> $DIR/pub_underscore_fields.rs:27:13
+   |
+LL |             pub _g: String,
+   |             ^^^^^^
+   |
+   = help: consider removing the underscore, or making the field private
+
+error: field marked as public but also inferred as unused because it's prefixed with `_`
+  --> $DIR/pub_underscore_fields.rs:34:9
+   |
+LL |         pub _a: usize,
+   |         ^^^^^^
+   |
+   = help: consider removing the underscore, or making the field private
+
+error: field marked as public but also inferred as unused because it's prefixed with `_`
+  --> $DIR/pub_underscore_fields.rs:41:9
+   |
+LL |         pub _c: i64,
+   |         ^^^^^^
+   |
+   = help: consider removing the underscore, or making the field private
+
+error: field marked as public but also inferred as unused because it's prefixed with `_`
+  --> $DIR/pub_underscore_fields.rs:44:9
+   |
+LL |         pub _e: Option<u8>,
+   |         ^^^^^^
+   |
+   = help: consider removing the underscore, or making the field private
+
+error: field marked as public but also inferred as unused because it's prefixed with `_`
+  --> $DIR/pub_underscore_fields.rs:57:9
+   |
+LL |         pub(crate) _b: Option<String>,
+   |         ^^^^^^^^^^^^^
+   |
+   = help: consider removing the underscore, or making the field private
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.exported.stderr b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.exported.stderr
new file mode 100644
index 00000000000..b76f6b3d388
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.exported.stderr
@@ -0,0 +1,12 @@
+error: field marked as public but also inferred as unused because it's prefixed with `_`
+  --> $DIR/pub_underscore_fields.rs:15:9
+   |
+LL |         pub _b: u8,
+   |         ^^^^^^
+   |
+   = help: consider removing the underscore, or making the field private
+   = note: `-D clippy::pub-underscore-fields` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::pub_underscore_fields)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs
new file mode 100644
index 00000000000..1d8fee7daad
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs
@@ -0,0 +1,66 @@
+//@revisions: exported all_pub_fields
+//@[all_pub_fields] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/pub_underscore_fields/all_pub_fields
+//@[exported] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/pub_underscore_fields/exported
+
+#![allow(unused)]
+#![warn(clippy::pub_underscore_fields)]
+
+use std::marker::PhantomData;
+
+pub mod inner {
+    use std::marker;
+
+    pub struct PubSuper {
+        pub(super) a: usize,
+        pub _b: u8,
+        _c: i32,
+        pub _mark: marker::PhantomData<u8>,
+    }
+
+    mod inner2 {
+        pub struct PubModVisibility {
+            pub(in crate::inner) e: bool,
+            pub(in crate::inner) _f: Option<()>,
+        }
+
+        struct PrivateStructPubField {
+            pub _g: String,
+        }
+    }
+}
+
+fn main() {
+    pub struct StructWithOneViolation {
+        pub _a: usize,
+    }
+
+    // should handle structs with multiple violations
+    pub struct StructWithMultipleViolations {
+        a: u8,
+        _b: usize,
+        pub _c: i64,
+        #[doc(hidden)]
+        pub d: String,
+        pub _e: Option<u8>,
+    }
+
+    // shouldn't warn on anonymous fields
+    pub struct AnonymousFields(pub usize, i32);
+
+    // don't warn on empty structs
+    pub struct Empty1;
+    pub struct Empty2();
+    pub struct Empty3 {};
+
+    pub struct PubCrate {
+        pub(crate) a: String,
+        pub(crate) _b: Option<String>,
+    }
+
+    // shouldn't warn on fields named pub
+    pub struct NamedPub {
+        r#pub: bool,
+        _pub: String,
+        pub(crate) _mark: PhantomData<u8>,
+    }
+}
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 12828cf9dec..ed4fb84df1a 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
@@ -49,6 +49,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            missing-docs-in-crate-items
            msrv
            pass-by-value-size-limit
+           pub-underscore-fields-behavior
            semicolon-inside-block-ignore-singleline
            semicolon-outside-block-ignore-multiline
            single-char-binding-names-threshold
@@ -124,6 +125,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            missing-docs-in-crate-items
            msrv
            pass-by-value-size-limit
+           pub-underscore-fields-behavior
            semicolon-inside-block-ignore-singleline
            semicolon-outside-block-ignore-multiline
            single-char-binding-names-threshold
diff --git a/src/tools/clippy/tests/ui/as_conversions.rs b/src/tools/clippy/tests/ui/as_conversions.rs
index 192eb51ea99..8499c0ac5a0 100644
--- a/src/tools/clippy/tests/ui/as_conversions.rs
+++ b/src/tools/clippy/tests/ui/as_conversions.rs
@@ -17,7 +17,7 @@ fn main() {
 with_span!(
     span
 
-    fn coverting() {
+    fn converting() {
         let x = 0u32 as u64;
     }
 );
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index 1ca18170f8a..e9476c80ccb 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -365,3 +365,52 @@ fn avoid_subtract_overflow(q: u32) {
 fn issue11426() {
     (&42u8 >> 0xa9008fb6c9d81e42_0e25730562a601c8_u128) as usize;
 }
+
+fn issue11642() {
+    fn square(x: i16) -> u32 {
+        let x = x as i32;
+        (x * x) as u32;
+        x.pow(2) as u32;
+        (-2_i32).pow(2) as u32
+    }
+
+    let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
+
+    (-2_i32).pow(3) as u32;
+    //~^ ERROR: casting `i32` to `u32` may lose the sign of the value
+
+    let x: i32 = 10;
+    (x * x) as u32;
+    (x * x * x) as u32;
+    //~^ ERROR: casting `i32` to `u32` may lose the sign of the value
+
+    let y: i16 = -2;
+    (y * y * y * y * -2) as u16;
+    //~^ ERROR: casting `i16` to `u16` may lose the sign of the value
+    (y * y * y * y * 2) as u16;
+    (y * y * y * 2) as u16;
+    //~^ ERROR: casting `i16` to `u16` may lose the sign of the value
+    (y * y * y * -2) as u16;
+    //~^ ERROR: casting `i16` to `u16` may lose the sign of the value
+
+    fn foo(a: i32, b: i32, c: i32) -> u32 {
+        (a * a * b * b * c * c) as u32;
+        (a * b * c) as u32;
+        //~^ ERROR: casting `i32` to `u32` may lose the sign of the value
+        (a * -b * c) as u32;
+        //~^ ERROR: casting `i32` to `u32` may lose the sign of the value
+        (a * b * c * c) as u32;
+        (a * -2) as u32;
+        //~^ ERROR: casting `i32` to `u32` may lose the sign of the value
+        (a * b * c * -2) as u32;
+        //~^ ERROR: casting `i32` to `u32` may lose the sign of the value
+        (a / b) as u32;
+        (a / b * c) as u32;
+        //~^ ERROR: casting `i32` to `u32` may lose the sign of the value
+        (a / b + b * c) as u32;
+        //~^ ERROR: casting `i32` to `u32` may lose the sign of the value
+        a.pow(3) as u32;
+        //~^ ERROR: casting `i32` to `u32` may lose the sign of the value
+        (a.abs() * b.pow(2) / c.abs()) as u32
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index bc74f7b728e..4e37af7f378 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -444,5 +444,77 @@ help: ... or use `try_from` and handle the error accordingly
 LL |     let c = u8::try_from(q / 1000);
    |             ~~~~~~~~~~~~~~~~~~~~~~
 
-error: aborting due to 51 previous errors
+error: casting `i32` to `u32` may lose the sign of the value
+  --> $DIR/cast.rs:379:5
+   |
+LL |     (-2_i32).pow(3) as u32;
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting `i32` to `u32` may lose the sign of the value
+  --> $DIR/cast.rs:384:5
+   |
+LL |     (x * x * x) as u32;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: casting `i16` to `u16` may lose the sign of the value
+  --> $DIR/cast.rs:388:5
+   |
+LL |     (y * y * y * y * -2) as u16;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting `i16` to `u16` may lose the sign of the value
+  --> $DIR/cast.rs:391:5
+   |
+LL |     (y * y * y * 2) as u16;
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting `i16` to `u16` may lose the sign of the value
+  --> $DIR/cast.rs:393:5
+   |
+LL |     (y * y * y * -2) as u16;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting `i32` to `u32` may lose the sign of the value
+  --> $DIR/cast.rs:398:9
+   |
+LL |         (a * b * c) as u32;
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: casting `i32` to `u32` may lose the sign of the value
+  --> $DIR/cast.rs:400:9
+   |
+LL |         (a * -b * c) as u32;
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: casting `i32` to `u32` may lose the sign of the value
+  --> $DIR/cast.rs:403:9
+   |
+LL |         (a * -2) as u32;
+   |         ^^^^^^^^^^^^^^^
+
+error: casting `i32` to `u32` may lose the sign of the value
+  --> $DIR/cast.rs:405:9
+   |
+LL |         (a * b * c * -2) as u32;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting `i32` to `u32` may lose the sign of the value
+  --> $DIR/cast.rs:408:9
+   |
+LL |         (a / b * c) as u32;
+   |         ^^^^^^^^^^^^^^^^^^
+
+error: casting `i32` to `u32` may lose the sign of the value
+  --> $DIR/cast.rs:410:9
+   |
+LL |         (a / b + b * c) as u32;
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting `i32` to `u32` may lose the sign of the value
+  --> $DIR/cast.rs:412:9
+   |
+LL |         a.pow(3) as u32;
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to 63 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-8821.fixed b/src/tools/clippy/tests/ui/crashes/ice-8821.fixed
deleted file mode 100644
index a25bb46f9ff..00000000000
--- a/src/tools/clippy/tests/ui/crashes/ice-8821.fixed
+++ /dev/null
@@ -1,10 +0,0 @@
-#![warn(clippy::let_unit_value)]
-
-fn f() {}
-static FN: fn() = f;
-
-fn main() {
-    FN();
-    //~^ ERROR: this let-binding has unit value
-    //~| NOTE: `-D clippy::let-unit-value` implied by `-D warnings`
-}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-8821.rs b/src/tools/clippy/tests/ui/crashes/ice-8821.rs
index 082f7c92646..fb87b79aeed 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-8821.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-8821.rs
@@ -5,6 +5,4 @@ static FN: fn() = f;
 
 fn main() {
     let _: () = FN();
-    //~^ ERROR: this let-binding has unit value
-    //~| NOTE: `-D clippy::let-unit-value` implied by `-D warnings`
 }
diff --git a/src/tools/clippy/tests/ui/crashes/ice-8821.stderr b/src/tools/clippy/tests/ui/crashes/ice-8821.stderr
deleted file mode 100644
index 94ebb20918e..00000000000
--- a/src/tools/clippy/tests/ui/crashes/ice-8821.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: this let-binding has unit value
-  --> $DIR/ice-8821.rs:7:5
-   |
-LL |     let _: () = FN();
-   |     ^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `FN();`
-   |
-   = note: `-D clippy::let-unit-value` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]`
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed
index 9072d233563..00f0d764434 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed
@@ -73,9 +73,7 @@ mod nested_local {
 
 mod function_def {
     fn ret_f64() -> f64 {
-        // Even though the output type is specified,
-        // this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
-        1.0_f64
+        1.
     }
 
     fn test() {
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs
index 256b94f6c05..942cedac275 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs
@@ -73,8 +73,6 @@ mod nested_local {
 
 mod function_def {
     fn ret_f64() -> f64 {
-        // Even though the output type is specified,
-        // this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
         1.
     }
 
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr
index 7ea2e3e6819..c95679c9eb8 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr
@@ -86,66 +86,60 @@ LL |             let y = 1.;
    |                     ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:78:9
-   |
-LL |         1.
-   |         ^^ help: consider adding suffix: `1.0_f64`
-
-error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:84:27
+  --> $DIR/default_numeric_fallback_f64.rs:82:27
    |
 LL |         let f = || -> _ { 1. };
    |                           ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:88:29
+  --> $DIR/default_numeric_fallback_f64.rs:86:29
    |
 LL |         let f = || -> f64 { 1. };
    |                             ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:102:21
+  --> $DIR/default_numeric_fallback_f64.rs:100:21
    |
 LL |         generic_arg(1.);
    |                     ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:105:32
+  --> $DIR/default_numeric_fallback_f64.rs:103:32
    |
 LL |         let x: _ = generic_arg(1.);
    |                                ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:123:28
+  --> $DIR/default_numeric_fallback_f64.rs:121:28
    |
 LL |         GenericStruct { x: 1. };
    |                            ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:126:36
+  --> $DIR/default_numeric_fallback_f64.rs:124:36
    |
 LL |         let _ = GenericStruct { x: 1. };
    |                                    ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:144:24
+  --> $DIR/default_numeric_fallback_f64.rs:142:24
    |
 LL |         GenericEnum::X(1.);
    |                        ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:164:23
+  --> $DIR/default_numeric_fallback_f64.rs:162:23
    |
 LL |         s.generic_arg(1.);
    |                       ^^ help: consider adding suffix: `1.0_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_f64.rs:174:25
+  --> $DIR/default_numeric_fallback_f64.rs:172:25
    |
 LL |         inline!(let x = 22.;);
    |                         ^^^ help: consider adding suffix: `22.0_f64`
    |
    = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 24 previous errors
+error: aborting due to 23 previous errors
 
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
index 920cd9f8f77..c364c683057 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed
@@ -74,9 +74,7 @@ mod nested_local {
 
 mod function_def {
     fn ret_i32() -> i32 {
-        // Even though the output type is specified,
-        // this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
-        1_i32
+        1
     }
 
     fn test() {
@@ -186,4 +184,36 @@ fn check_expect_suppression() {
     let x = 21;
 }
 
+mod type_already_inferred {
+    // Should NOT lint if bound to return type
+    fn ret_i32() -> i32 {
+        1
+    }
+
+    // Should NOT lint if bound to return type
+    fn ret_if_i32(b: bool) -> i32 {
+        if b { 100 } else { 0 }
+    }
+
+    // Should NOT lint if bound to return type
+    fn ret_i32_tuple() -> (i32, i32) {
+        (0, 1)
+    }
+
+    // Should NOT lint if bound to return type
+    fn ret_stmt(b: bool) -> (i32, i32) {
+        if b {
+            return (0, 1);
+        }
+        (0, 0)
+    }
+
+    #[allow(clippy::useless_vec)]
+    fn vec_macro() {
+        // Should NOT lint in `vec!` call if the type was already stated
+        let data_i32: Vec<i32> = vec![1, 2, 3];
+        let data_i32 = vec![1_i32, 2_i32, 3_i32];
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
index bdb7b5f47bc..ffa7b961d1c 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs
@@ -74,8 +74,6 @@ mod nested_local {
 
 mod function_def {
     fn ret_i32() -> i32 {
-        // Even though the output type is specified,
-        // this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
         1
     }
 
@@ -186,4 +184,36 @@ fn check_expect_suppression() {
     let x = 21;
 }
 
+mod type_already_inferred {
+    // Should NOT lint if bound to return type
+    fn ret_i32() -> i32 {
+        1
+    }
+
+    // Should NOT lint if bound to return type
+    fn ret_if_i32(b: bool) -> i32 {
+        if b { 100 } else { 0 }
+    }
+
+    // Should NOT lint if bound to return type
+    fn ret_i32_tuple() -> (i32, i32) {
+        (0, 1)
+    }
+
+    // Should NOT lint if bound to return type
+    fn ret_stmt(b: bool) -> (i32, i32) {
+        if b {
+            return (0, 1);
+        }
+        (0, 0)
+    }
+
+    #[allow(clippy::useless_vec)]
+    fn vec_macro() {
+        // Should NOT lint in `vec!` call if the type was already stated
+        let data_i32: Vec<i32> = vec![1, 2, 3];
+        let data_i32 = vec![1, 2, 3];
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr
index b03b8b84c33..7663977fb65 100644
--- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr
+++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr
@@ -98,66 +98,78 @@ LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:79:9
-   |
-LL |         1
-   |         ^ help: consider adding suffix: `1_i32`
-
-error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:85:27
+  --> $DIR/default_numeric_fallback_i32.rs:83:27
    |
 LL |         let f = || -> _ { 1 };
    |                           ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:89:29
+  --> $DIR/default_numeric_fallback_i32.rs:87:29
    |
 LL |         let f = || -> i32 { 1 };
    |                             ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:103:21
+  --> $DIR/default_numeric_fallback_i32.rs:101:21
    |
 LL |         generic_arg(1);
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:106:32
+  --> $DIR/default_numeric_fallback_i32.rs:104:32
    |
 LL |         let x: _ = generic_arg(1);
    |                                ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:124:28
+  --> $DIR/default_numeric_fallback_i32.rs:122:28
    |
 LL |         GenericStruct { x: 1 };
    |                            ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:127:36
+  --> $DIR/default_numeric_fallback_i32.rs:125:36
    |
 LL |         let _ = GenericStruct { x: 1 };
    |                                    ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:145:24
+  --> $DIR/default_numeric_fallback_i32.rs:143:24
    |
 LL |         GenericEnum::X(1);
    |                        ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:165:23
+  --> $DIR/default_numeric_fallback_i32.rs:163:23
    |
 LL |         s.generic_arg(1);
    |                       ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback_i32.rs:175:25
+  --> $DIR/default_numeric_fallback_i32.rs:173:25
    |
 LL |         inline!(let x = 22;);
    |                         ^^ help: consider adding suffix: `22_i32`
    |
    = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 26 previous errors
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback_i32.rs:215:29
+   |
+LL |         let data_i32 = vec![1, 2, 3];
+   |                             ^ help: consider adding suffix: `1_i32`
+
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback_i32.rs:215:32
+   |
+LL |         let data_i32 = vec![1, 2, 3];
+   |                                ^ help: consider adding suffix: `2_i32`
+
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback_i32.rs:215:35
+   |
+LL |         let data_i32 = vec![1, 2, 3];
+   |                                   ^ help: consider adding suffix: `3_i32`
+
+error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/eager_transmute.fixed b/src/tools/clippy/tests/ui/eager_transmute.fixed
index e06aa2cc9fd..bece09bba1a 100644
--- a/src/tools/clippy/tests/ui/eager_transmute.fixed
+++ b/src/tools/clippy/tests/ui/eager_transmute.fixed
@@ -12,16 +12,49 @@ enum Opcode {
     Div = 3,
 }
 
+struct Data {
+    foo: &'static [u8],
+    bar: &'static [u8],
+}
+
 fn int_to_opcode(op: u8) -> Option<Opcode> {
     (op < 4).then(|| unsafe { std::mem::transmute(op) })
 }
 
-fn f(op: u8, unrelated: u8) {
+fn f(op: u8, op2: Data, unrelated: u8) {
     true.then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
     (unrelated < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
     (op < 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
     (op > 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
     (op == 0).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
+
+    let _: Option<Opcode> = (op > 0 && op < 10).then(|| unsafe { std::mem::transmute(op) });
+    let _: Option<Opcode> = (op > 0 && op < 10 && unrelated == 0).then(|| unsafe { std::mem::transmute(op) });
+
+    // lint even when the transmutable goes through field/array accesses
+    let _: Option<Opcode> = (op2.foo[0] > 0 && op2.foo[0] < 10).then(|| unsafe { std::mem::transmute(op2.foo[0]) });
+
+    // don't lint: wrong index used in the transmute
+    let _: Option<Opcode> = (op2.foo[0] > 0 && op2.foo[0] < 10).then_some(unsafe { std::mem::transmute(op2.foo[1]) });
+
+    // don't lint: no check for the transmutable in the condition
+    let _: Option<Opcode> = (op2.foo[0] > 0 && op2.bar[1] < 10).then_some(unsafe { std::mem::transmute(op2.bar[0]) });
+
+    // don't lint: wrong variable
+    let _: Option<Opcode> = (op2.foo[0] > 0 && op2.bar[1] < 10).then_some(unsafe { std::mem::transmute(op) });
+
+    // range contains checks
+    let _: Option<Opcode> = (1..=3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
+    let _: Option<Opcode> = ((1..=3).contains(&op) || op == 4).then(|| unsafe { std::mem::transmute(op) });
+    let _: Option<Opcode> = (1..3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
+    let _: Option<Opcode> = (1..).contains(&op).then(|| unsafe { std::mem::transmute(op) });
+    let _: Option<Opcode> = (..3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
+    let _: Option<Opcode> = (..=3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
+
+    // unrelated binding in contains
+    let _: Option<Opcode> = (1..=3)
+        .contains(&unrelated)
+        .then_some(unsafe { std::mem::transmute(op) });
 }
 
 unsafe fn f2(op: u8) {
diff --git a/src/tools/clippy/tests/ui/eager_transmute.rs b/src/tools/clippy/tests/ui/eager_transmute.rs
index 89ccdf583f3..a82bd578f76 100644
--- a/src/tools/clippy/tests/ui/eager_transmute.rs
+++ b/src/tools/clippy/tests/ui/eager_transmute.rs
@@ -12,16 +12,49 @@ enum Opcode {
     Div = 3,
 }
 
+struct Data {
+    foo: &'static [u8],
+    bar: &'static [u8],
+}
+
 fn int_to_opcode(op: u8) -> Option<Opcode> {
     (op < 4).then_some(unsafe { std::mem::transmute(op) })
 }
 
-fn f(op: u8, unrelated: u8) {
+fn f(op: u8, op2: Data, unrelated: u8) {
     true.then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
     (unrelated < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
     (op < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
     (op > 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
     (op == 0).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
+
+    let _: Option<Opcode> = (op > 0 && op < 10).then_some(unsafe { std::mem::transmute(op) });
+    let _: Option<Opcode> = (op > 0 && op < 10 && unrelated == 0).then_some(unsafe { std::mem::transmute(op) });
+
+    // lint even when the transmutable goes through field/array accesses
+    let _: Option<Opcode> = (op2.foo[0] > 0 && op2.foo[0] < 10).then_some(unsafe { std::mem::transmute(op2.foo[0]) });
+
+    // don't lint: wrong index used in the transmute
+    let _: Option<Opcode> = (op2.foo[0] > 0 && op2.foo[0] < 10).then_some(unsafe { std::mem::transmute(op2.foo[1]) });
+
+    // don't lint: no check for the transmutable in the condition
+    let _: Option<Opcode> = (op2.foo[0] > 0 && op2.bar[1] < 10).then_some(unsafe { std::mem::transmute(op2.bar[0]) });
+
+    // don't lint: wrong variable
+    let _: Option<Opcode> = (op2.foo[0] > 0 && op2.bar[1] < 10).then_some(unsafe { std::mem::transmute(op) });
+
+    // range contains checks
+    let _: Option<Opcode> = (1..=3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
+    let _: Option<Opcode> = ((1..=3).contains(&op) || op == 4).then_some(unsafe { std::mem::transmute(op) });
+    let _: Option<Opcode> = (1..3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
+    let _: Option<Opcode> = (1..).contains(&op).then_some(unsafe { std::mem::transmute(op) });
+    let _: Option<Opcode> = (..3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
+    let _: Option<Opcode> = (..=3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
+
+    // unrelated binding in contains
+    let _: Option<Opcode> = (1..=3)
+        .contains(&unrelated)
+        .then_some(unsafe { std::mem::transmute(op) });
 }
 
 unsafe fn f2(op: u8) {
diff --git a/src/tools/clippy/tests/ui/eager_transmute.stderr b/src/tools/clippy/tests/ui/eager_transmute.stderr
index 5eb163c5fcb..5f42eec544f 100644
--- a/src/tools/clippy/tests/ui/eager_transmute.stderr
+++ b/src/tools/clippy/tests/ui/eager_transmute.stderr
@@ -1,5 +1,5 @@
 error: this transmute is always evaluated eagerly, even if the condition is false
-  --> $DIR/eager_transmute.rs:16:33
+  --> $DIR/eager_transmute.rs:21:33
    |
 LL |     (op < 4).then_some(unsafe { std::mem::transmute(op) })
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL |     (op < 4).then(|| unsafe { std::mem::transmute(op) })
    |              ~~~~ ++
 
 error: this transmute is always evaluated eagerly, even if the condition is false
-  --> $DIR/eager_transmute.rs:22:33
+  --> $DIR/eager_transmute.rs:27:33
    |
 LL |     (op < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL |     (op < 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
    |              ~~~~ ++
 
 error: this transmute is always evaluated eagerly, even if the condition is false
-  --> $DIR/eager_transmute.rs:23:33
+  --> $DIR/eager_transmute.rs:28:33
    |
 LL |     (op > 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -34,7 +34,7 @@ LL |     (op > 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
    |              ~~~~ ++
 
 error: this transmute is always evaluated eagerly, even if the condition is false
-  --> $DIR/eager_transmute.rs:24:34
+  --> $DIR/eager_transmute.rs:29:34
    |
 LL |     (op == 0).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -45,7 +45,106 @@ LL |     (op == 0).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
    |               ~~~~ ++
 
 error: this transmute is always evaluated eagerly, even if the condition is false
-  --> $DIR/eager_transmute.rs:28:24
+  --> $DIR/eager_transmute.rs:31:68
+   |
+LL |     let _: Option<Opcode> = (op > 0 && op < 10).then_some(unsafe { std::mem::transmute(op) });
+   |                                                                    ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     let _: Option<Opcode> = (op > 0 && op < 10).then(|| unsafe { std::mem::transmute(op) });
+   |                                                 ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:32:86
+   |
+LL |     let _: Option<Opcode> = (op > 0 && op < 10 && unrelated == 0).then_some(unsafe { std::mem::transmute(op) });
+   |                                                                                      ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     let _: Option<Opcode> = (op > 0 && op < 10 && unrelated == 0).then(|| unsafe { std::mem::transmute(op) });
+   |                                                                   ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:35:84
+   |
+LL |     let _: Option<Opcode> = (op2.foo[0] > 0 && op2.foo[0] < 10).then_some(unsafe { std::mem::transmute(op2.foo[0]) });
+   |                                                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     let _: Option<Opcode> = (op2.foo[0] > 0 && op2.foo[0] < 10).then(|| unsafe { std::mem::transmute(op2.foo[0]) });
+   |                                                                 ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:47:70
+   |
+LL |     let _: Option<Opcode> = (1..=3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
+   |                                                                      ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     let _: Option<Opcode> = (1..=3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
+   |                                                   ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:48:83
+   |
+LL |     let _: Option<Opcode> = ((1..=3).contains(&op) || op == 4).then_some(unsafe { std::mem::transmute(op) });
+   |                                                                                   ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     let _: Option<Opcode> = ((1..=3).contains(&op) || op == 4).then(|| unsafe { std::mem::transmute(op) });
+   |                                                                ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:49:69
+   |
+LL |     let _: Option<Opcode> = (1..3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
+   |                                                                     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     let _: Option<Opcode> = (1..3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
+   |                                                  ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:50:68
+   |
+LL |     let _: Option<Opcode> = (1..).contains(&op).then_some(unsafe { std::mem::transmute(op) });
+   |                                                                    ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     let _: Option<Opcode> = (1..).contains(&op).then(|| unsafe { std::mem::transmute(op) });
+   |                                                 ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:51:68
+   |
+LL |     let _: Option<Opcode> = (..3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
+   |                                                                    ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     let _: Option<Opcode> = (..3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
+   |                                                 ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:52:69
+   |
+LL |     let _: Option<Opcode> = (..=3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
+   |                                                                     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider using `bool::then` to only transmute if the condition holds
+   |
+LL |     let _: Option<Opcode> = (..=3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
+   |                                                  ~~~~ ++
+
+error: this transmute is always evaluated eagerly, even if the condition is false
+  --> $DIR/eager_transmute.rs:61:24
    |
 LL |     (op < 4).then_some(std::mem::transmute::<_, Opcode>(op));
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -56,7 +155,7 @@ LL |     (op < 4).then(|| std::mem::transmute::<_, Opcode>(op));
    |              ~~~~ ++
 
 error: this transmute is always evaluated eagerly, even if the condition is false
-  --> $DIR/eager_transmute.rs:57:60
+  --> $DIR/eager_transmute.rs:90:60
    |
 LL |     let _: Option<NonZeroU8> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) });
    |                                                            ^^^^^^^^^^^^^^^^^^^^^^^
@@ -67,7 +166,7 @@ LL |     let _: Option<NonZeroU8> = (v1 > 0).then(|| unsafe { std::mem::transmut
    |                                         ~~~~ ++
 
 error: this transmute is always evaluated eagerly, even if the condition is false
-  --> $DIR/eager_transmute.rs:63:86
+  --> $DIR/eager_transmute.rs:96:86
    |
 LL |     let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
    |                                                                                      ^^^^^^^^^^^^^^^^^^^^^^^
@@ -78,7 +177,7 @@ LL |     let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| u
    |                                                                   ~~~~ ++
 
 error: this transmute is always evaluated eagerly, even if the condition is false
-  --> $DIR/eager_transmute.rs:69:93
+  --> $DIR/eager_transmute.rs:102:93
    |
 LL |     let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
    |                                                                                             ^^^^^^^^^^^^^^^^^^^^^^^
@@ -88,5 +187,5 @@ help: consider using `bool::then` to only transmute if the condition holds
 LL |     let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
    |                                                                          ~~~~ ++
 
-error: aborting due to 8 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.fixed b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.fixed
new file mode 100644
index 00000000000..1a5e78dd47f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.fixed
@@ -0,0 +1,27 @@
+#![warn(clippy::empty_enum_variants_with_brackets)]
+#![allow(dead_code)]
+
+pub enum PublicTestEnum {
+    NonEmptyBraces { x: i32, y: i32 }, // No error
+    NonEmptyParentheses(i32, i32),     // No error
+    EmptyBraces,                    //~ ERROR: enum variant has empty brackets
+    EmptyParentheses,                //~ ERROR: enum variant has empty brackets
+}
+
+enum TestEnum {
+    NonEmptyBraces { x: i32, y: i32 }, // No error
+    NonEmptyParentheses(i32, i32),     // No error
+    EmptyBraces,                    //~ ERROR: enum variant has empty brackets
+    EmptyParentheses,                //~ ERROR: enum variant has empty brackets
+    AnotherEnum,                       // No error
+}
+
+enum TestEnumWithFeatures {
+    NonEmptyBraces {
+        #[cfg(feature = "thisisneverenabled")]
+        x: i32,
+    }, // No error
+    NonEmptyParentheses(#[cfg(feature = "thisisneverenabled")] i32), // No error
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.rs b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.rs
new file mode 100644
index 00000000000..ca20b969a24
--- /dev/null
+++ b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.rs
@@ -0,0 +1,27 @@
+#![warn(clippy::empty_enum_variants_with_brackets)]
+#![allow(dead_code)]
+
+pub enum PublicTestEnum {
+    NonEmptyBraces { x: i32, y: i32 }, // No error
+    NonEmptyParentheses(i32, i32),     // No error
+    EmptyBraces {},                    //~ ERROR: enum variant has empty brackets
+    EmptyParentheses(),                //~ ERROR: enum variant has empty brackets
+}
+
+enum TestEnum {
+    NonEmptyBraces { x: i32, y: i32 }, // No error
+    NonEmptyParentheses(i32, i32),     // No error
+    EmptyBraces {},                    //~ ERROR: enum variant has empty brackets
+    EmptyParentheses(),                //~ ERROR: enum variant has empty brackets
+    AnotherEnum,                       // No error
+}
+
+enum TestEnumWithFeatures {
+    NonEmptyBraces {
+        #[cfg(feature = "thisisneverenabled")]
+        x: i32,
+    }, // No error
+    NonEmptyParentheses(#[cfg(feature = "thisisneverenabled")] i32), // No error
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.stderr b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.stderr
new file mode 100644
index 00000000000..6b2f286147f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.stderr
@@ -0,0 +1,36 @@
+error: enum variant has empty brackets
+  --> $DIR/empty_enum_variants_with_brackets.rs:7:16
+   |
+LL |     EmptyBraces {},
+   |                ^^^
+   |
+   = note: `-D clippy::empty-enum-variants-with-brackets` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::empty_enum_variants_with_brackets)]`
+   = help: remove the brackets
+
+error: enum variant has empty brackets
+  --> $DIR/empty_enum_variants_with_brackets.rs:8:21
+   |
+LL |     EmptyParentheses(),
+   |                     ^^
+   |
+   = help: remove the brackets
+
+error: enum variant has empty brackets
+  --> $DIR/empty_enum_variants_with_brackets.rs:14:16
+   |
+LL |     EmptyBraces {},
+   |                ^^^
+   |
+   = help: remove the brackets
+
+error: enum variant has empty brackets
+  --> $DIR/empty_enum_variants_with_brackets.rs:15:21
+   |
+LL |     EmptyParentheses(),
+   |                     ^^
+   |
+   = help: remove the brackets
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/identity_op.fixed b/src/tools/clippy/tests/ui/identity_op.fixed
index f3b4b1fffa0..660e9a21b18 100644
--- a/src/tools/clippy/tests/ui/identity_op.fixed
+++ b/src/tools/clippy/tests/ui/identity_op.fixed
@@ -6,7 +6,9 @@
     clippy::unnecessary_operation,
     clippy::op_ref,
     clippy::double_parens,
-    clippy::uninlined_format_args
+    clippy::uninlined_format_args,
+    clippy::borrow_deref_ref,
+    clippy::deref_addrof
 )]
 
 use std::fmt::Write as _;
@@ -40,32 +42,45 @@ fn main() {
     let x = 0;
 
     x;
+    //~^ ERROR: this operation has no effect
     x;
+    //~^ ERROR: this operation has no effect
     x + 1;
     x;
+    //~^ ERROR: this operation has no effect
     1 + x;
     x - ZERO; //no error, as we skip lookups (for now)
     x;
+    //~^ ERROR: this operation has no effect
     ((ZERO)) | x; //no error, as we skip lookups (for now)
 
     x;
+    //~^ ERROR: this operation has no effect
     x;
+    //~^ ERROR: this operation has no effect
     x / ONE; //no error, as we skip lookups (for now)
 
     x / 2; //no false positive
 
     x & NEG_ONE; //no error, as we skip lookups (for now)
     x;
+    //~^ ERROR: this operation has no effect
 
     let u: u8 = 0;
     u;
+    //~^ ERROR: this operation has no effect
 
     1 << 0; // no error, this case is allowed, see issue 3430
     42;
+    //~^ ERROR: this operation has no effect
     1;
+    //~^ ERROR: this operation has no effect
     42;
+    //~^ ERROR: this operation has no effect
     x;
+    //~^ ERROR: this operation has no effect
     x;
+    //~^ ERROR: this operation has no effect
 
     let mut a = A(String::new());
     let b = a << 0; // no error: non-integer
@@ -73,10 +88,15 @@ fn main() {
     1 * Meter; // no error: non-integer
 
     2;
+    //~^ ERROR: this operation has no effect
     -2;
+    //~^ ERROR: this operation has no effect
     2 + x;
+    //~^ ERROR: this operation has no effect
     -2 + x;
+    //~^ ERROR: this operation has no effect
     x + 1;
+    //~^ ERROR: this operation has no effect
     (x + 1) % 3; // no error
     4 % 3; // no error
     4 % -3; // no error
@@ -85,38 +105,110 @@ fn main() {
     let a = 0;
     let b = true;
     (if b { 1 } else { 2 });
+    //~^ ERROR: this operation has no effect
     (if b { 1 } else { 2 }) + if b { 3 } else { 4 };
+    //~^ ERROR: this operation has no effect
     (match a { 0 => 10, _ => 20 });
+    //~^ ERROR: this operation has no effect
     (match a { 0 => 10, _ => 20 }) + match a { 0 => 30, _ => 40 };
+    //~^ ERROR: this operation has no effect
     (if b { 1 } else { 2 }) + match a { 0 => 30, _ => 40 };
+    //~^ ERROR: this operation has no effect
     (match a { 0 => 10, _ => 20 }) + if b { 3 } else { 4 };
+    //~^ ERROR: this operation has no effect
     (if b { 1 } else { 2 });
+    //~^ ERROR: this operation has no effect
 
     ({ a }) + 3;
+    //~^ ERROR: this operation has no effect
     ({ a } * 2);
+    //~^ ERROR: this operation has no effect
     (loop { let mut c = 0; if c == 10 { break c; } c += 1; }) + { a * 2 };
+    //~^ ERROR: this operation has no effect
 
     fn f(_: i32) {
         todo!();
     }
+
     f(a + { 8 * 5 });
+    //~^ ERROR: this operation has no effect
     f(if b { 1 } else { 2 } + 3);
+    //~^ ERROR: this operation has no effect
+    
     const _: i32 = { 2 * 4 } + 3;
+    //~^ ERROR: this operation has no effect
     const _: i32 = { 1 + 2 * 3 } + 3;
+    //~^ ERROR: this operation has no effect
 
     a as usize;
+    //~^ ERROR: this operation has no effect
     let _ = a as usize;
+    //~^ ERROR: this operation has no effect
     ({ a } as usize);
+    //~^ ERROR: this operation has no effect
 
     2 * { a };
+    //~^ ERROR: this operation has no effect
     (({ a } + 4));
+    //~^ ERROR: this operation has no effect
     1;
+    //~^ ERROR: this operation has no effect
 
     // Issue #9904
     let x = 0i32;
     let _: i32 = x;
+    //~^ ERROR: this operation has no effect
 }
 
 pub fn decide(a: bool, b: bool) -> u32 {
     (if a { 1 } else { 2 }) + if b { 3 } else { 5 }
 }
+
+/// The following tests are from / for issue #12050
+/// In short, the lint didn't work for coerced references,
+/// e.g. let x = &0; let y = x + 0;
+/// because the suggested fix was `let y = x;` but
+/// it should have been `let y = *x;`
+fn issue_12050() {
+    {
+        let x = &0i32;
+        let _: i32 = *x;
+        //~^ ERROR: this operation has no effect
+        let _: i32 = *x;
+        //~^ ERROR: this operation has no effect
+    }
+    {
+        let x = &&0i32;
+        let _: i32 = **x;
+        //~^ ERROR: this operation has no effect
+        let x = &&0i32;
+        let _: i32 = **x;
+        //~^ ERROR: this operation has no effect
+    }
+    {
+        // this is just silly
+        let x = &&&0i32;
+        let _: i32 = ***x;
+        //~^ ERROR: this operation has no effect
+        let _: i32 = ***x;
+        //~^ ERROR: this operation has no effect
+        let x = 0i32;
+        let _: i32 = *&x;
+        //~^ ERROR: this operation has no effect
+        let _: i32 = **&&x;
+        //~^ ERROR: this operation has no effect
+        let _: i32 = *&*&x;
+        //~^ ERROR: this operation has no effect
+        let _: i32 = **&&*&x;
+        //~^ ERROR: this operation has no effect
+    }
+    {
+        // this is getting ridiculous, but we should still see the same
+        // error message so let's just keep going
+        let x = &0i32;
+        let _: i32 = ***&&*&x;
+        //~^ ERROR: this operation has no effect
+        let _: i32 = ***&&*&x;
+        //~^ ERROR: this operation has no effect
+    }
+}
diff --git a/src/tools/clippy/tests/ui/identity_op.rs b/src/tools/clippy/tests/ui/identity_op.rs
index 631aa3b0215..bbef531e9dc 100644
--- a/src/tools/clippy/tests/ui/identity_op.rs
+++ b/src/tools/clippy/tests/ui/identity_op.rs
@@ -6,7 +6,9 @@
     clippy::unnecessary_operation,
     clippy::op_ref,
     clippy::double_parens,
-    clippy::uninlined_format_args
+    clippy::uninlined_format_args,
+    clippy::borrow_deref_ref,
+    clippy::deref_addrof
 )]
 
 use std::fmt::Write as _;
@@ -40,32 +42,45 @@ fn main() {
     let x = 0;
 
     x + 0;
+    //~^ ERROR: this operation has no effect
     x + (1 - 1);
+    //~^ ERROR: this operation has no effect
     x + 1;
     0 + x;
+    //~^ ERROR: this operation has no effect
     1 + x;
     x - ZERO; //no error, as we skip lookups (for now)
     x | (0);
+    //~^ ERROR: this operation has no effect
     ((ZERO)) | x; //no error, as we skip lookups (for now)
 
     x * 1;
+    //~^ ERROR: this operation has no effect
     1 * x;
+    //~^ ERROR: this operation has no effect
     x / ONE; //no error, as we skip lookups (for now)
 
     x / 2; //no false positive
 
     x & NEG_ONE; //no error, as we skip lookups (for now)
     -1 & x;
+    //~^ ERROR: this operation has no effect
 
     let u: u8 = 0;
     u & 255;
+    //~^ ERROR: this operation has no effect
 
     1 << 0; // no error, this case is allowed, see issue 3430
     42 << 0;
+    //~^ ERROR: this operation has no effect
     1 >> 0;
+    //~^ ERROR: this operation has no effect
     42 >> 0;
+    //~^ ERROR: this operation has no effect
     &x >> 0;
+    //~^ ERROR: this operation has no effect
     x >> &0;
+    //~^ ERROR: this operation has no effect
 
     let mut a = A(String::new());
     let b = a << 0; // no error: non-integer
@@ -73,10 +88,15 @@ fn main() {
     1 * Meter; // no error: non-integer
 
     2 % 3;
+    //~^ ERROR: this operation has no effect
     -2 % 3;
+    //~^ ERROR: this operation has no effect
     2 % -3 + x;
+    //~^ ERROR: this operation has no effect
     -2 % -3 + x;
+    //~^ ERROR: this operation has no effect
     x + 1 % 3;
+    //~^ ERROR: this operation has no effect
     (x + 1) % 3; // no error
     4 % 3; // no error
     4 % -3; // no error
@@ -85,38 +105,110 @@ fn main() {
     let a = 0;
     let b = true;
     0 + if b { 1 } else { 2 };
+    //~^ ERROR: this operation has no effect
     0 + if b { 1 } else { 2 } + if b { 3 } else { 4 };
+    //~^ ERROR: this operation has no effect
     0 + match a { 0 => 10, _ => 20 };
+    //~^ ERROR: this operation has no effect
     0 + match a { 0 => 10, _ => 20 } + match a { 0 => 30, _ => 40 };
+    //~^ ERROR: this operation has no effect
     0 + if b { 1 } else { 2 } + match a { 0 => 30, _ => 40 };
+    //~^ ERROR: this operation has no effect
     0 + match a { 0 => 10, _ => 20 } + if b { 3 } else { 4 };
+    //~^ ERROR: this operation has no effect
     (if b { 1 } else { 2 }) + 0;
+    //~^ ERROR: this operation has no effect
 
     0 + { a } + 3;
+    //~^ ERROR: this operation has no effect
     0 + { a } * 2;
+    //~^ ERROR: this operation has no effect
     0 + loop { let mut c = 0; if c == 10 { break c; } c += 1; } + { a * 2 };
+    //~^ ERROR: this operation has no effect
 
     fn f(_: i32) {
         todo!();
     }
+
     f(1 * a + { 8 * 5 });
+    //~^ ERROR: this operation has no effect
     f(0 + if b { 1 } else { 2 } + 3);
+    //~^ ERROR: this operation has no effect
+    
     const _: i32 = { 2 * 4 } + 0 + 3;
+    //~^ ERROR: this operation has no effect
     const _: i32 = 0 + { 1 + 2 * 3 } + 3;
+    //~^ ERROR: this operation has no effect
 
     0 + a as usize;
+    //~^ ERROR: this operation has no effect
     let _ = 0 + a as usize;
+    //~^ ERROR: this operation has no effect
     0 + { a } as usize;
+    //~^ ERROR: this operation has no effect
 
     2 * (0 + { a });
+    //~^ ERROR: this operation has no effect
     1 * ({ a } + 4);
+    //~^ ERROR: this operation has no effect
     1 * 1;
+    //~^ ERROR: this operation has no effect
 
     // Issue #9904
     let x = 0i32;
     let _: i32 = &x + 0;
+    //~^ ERROR: this operation has no effect
 }
 
 pub fn decide(a: bool, b: bool) -> u32 {
     0 + if a { 1 } else { 2 } + if b { 3 } else { 5 }
 }
+
+/// The following tests are from / for issue #12050
+/// In short, the lint didn't work for coerced references,
+/// e.g. let x = &0; let y = x + 0;
+/// because the suggested fix was `let y = x;` but
+/// it should have been `let y = *x;`
+fn issue_12050() {
+    {
+        let x = &0i32;
+        let _: i32 = *x + 0;
+        //~^ ERROR: this operation has no effect
+        let _: i32 = x + 0;
+        //~^ ERROR: this operation has no effect
+    }
+    {
+        let x = &&0i32;
+        let _: i32 = **x + 0;
+        //~^ ERROR: this operation has no effect
+        let x = &&0i32;
+        let _: i32 = *x + 0;
+        //~^ ERROR: this operation has no effect
+    }
+    {
+        // this is just silly
+        let x = &&&0i32;
+        let _: i32 = ***x + 0;
+        //~^ ERROR: this operation has no effect
+        let _: i32 = **x + 0;
+        //~^ ERROR: this operation has no effect
+        let x = 0i32;
+        let _: i32 = *&x + 0;
+        //~^ ERROR: this operation has no effect
+        let _: i32 = **&&x + 0;
+        //~^ ERROR: this operation has no effect
+        let _: i32 = *&*&x + 0;
+        //~^ ERROR: this operation has no effect
+        let _: i32 = **&&*&x + 0;
+        //~^ ERROR: this operation has no effect
+    }
+    {
+        // this is getting ridiculous, but we should still see the same
+        // error message so let's just keep going
+        let x = &0i32;
+        let _: i32 = **&&*&x + 0;
+        //~^ ERROR: this operation has no effect
+        let _: i32 = **&&*&x + 0;
+        //~^ ERROR: this operation has no effect
+    }
+}
diff --git a/src/tools/clippy/tests/ui/identity_op.stderr b/src/tools/clippy/tests/ui/identity_op.stderr
index 2a61327f15f..6bb980035c1 100644
--- a/src/tools/clippy/tests/ui/identity_op.stderr
+++ b/src/tools/clippy/tests/ui/identity_op.stderr
@@ -1,5 +1,5 @@
 error: this operation has no effect
-  --> $DIR/identity_op.rs:42:5
+  --> $DIR/identity_op.rs:44:5
    |
 LL |     x + 0;
    |     ^^^^^ help: consider reducing it to: `x`
@@ -8,238 +8,310 @@ LL |     x + 0;
    = help: to override `-D warnings` add `#[allow(clippy::identity_op)]`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:43:5
+  --> $DIR/identity_op.rs:46:5
    |
 LL |     x + (1 - 1);
    |     ^^^^^^^^^^^ help: consider reducing it to: `x`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:45:5
+  --> $DIR/identity_op.rs:49:5
    |
 LL |     0 + x;
    |     ^^^^^ help: consider reducing it to: `x`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:48:5
+  --> $DIR/identity_op.rs:53:5
    |
 LL |     x | (0);
    |     ^^^^^^^ help: consider reducing it to: `x`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:51:5
+  --> $DIR/identity_op.rs:57:5
    |
 LL |     x * 1;
    |     ^^^^^ help: consider reducing it to: `x`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:52:5
+  --> $DIR/identity_op.rs:59:5
    |
 LL |     1 * x;
    |     ^^^^^ help: consider reducing it to: `x`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:58:5
+  --> $DIR/identity_op.rs:66:5
    |
 LL |     -1 & x;
    |     ^^^^^^ help: consider reducing it to: `x`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:61:5
+  --> $DIR/identity_op.rs:70:5
    |
 LL |     u & 255;
    |     ^^^^^^^ help: consider reducing it to: `u`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:64:5
+  --> $DIR/identity_op.rs:74:5
    |
 LL |     42 << 0;
    |     ^^^^^^^ help: consider reducing it to: `42`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:65:5
+  --> $DIR/identity_op.rs:76:5
    |
 LL |     1 >> 0;
    |     ^^^^^^ help: consider reducing it to: `1`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:66:5
+  --> $DIR/identity_op.rs:78:5
    |
 LL |     42 >> 0;
    |     ^^^^^^^ help: consider reducing it to: `42`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:67:5
+  --> $DIR/identity_op.rs:80:5
    |
 LL |     &x >> 0;
    |     ^^^^^^^ help: consider reducing it to: `x`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:68:5
+  --> $DIR/identity_op.rs:82:5
    |
 LL |     x >> &0;
    |     ^^^^^^^ help: consider reducing it to: `x`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:75:5
+  --> $DIR/identity_op.rs:90:5
    |
 LL |     2 % 3;
    |     ^^^^^ help: consider reducing it to: `2`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:76:5
+  --> $DIR/identity_op.rs:92:5
    |
 LL |     -2 % 3;
    |     ^^^^^^ help: consider reducing it to: `-2`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:77:5
+  --> $DIR/identity_op.rs:94:5
    |
 LL |     2 % -3 + x;
    |     ^^^^^^ help: consider reducing it to: `2`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:78:5
+  --> $DIR/identity_op.rs:96:5
    |
 LL |     -2 % -3 + x;
    |     ^^^^^^^ help: consider reducing it to: `-2`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:79:9
+  --> $DIR/identity_op.rs:98:9
    |
 LL |     x + 1 % 3;
    |         ^^^^^ help: consider reducing it to: `1`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:87:5
+  --> $DIR/identity_op.rs:107:5
    |
 LL |     0 + if b { 1 } else { 2 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:88:5
+  --> $DIR/identity_op.rs:109:5
    |
 LL |     0 + if b { 1 } else { 2 } + if b { 3 } else { 4 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:89:5
+  --> $DIR/identity_op.rs:111:5
    |
 LL |     0 + match a { 0 => 10, _ => 20 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:90:5
+  --> $DIR/identity_op.rs:113:5
    |
 LL |     0 + match a { 0 => 10, _ => 20 } + match a { 0 => 30, _ => 40 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:91:5
+  --> $DIR/identity_op.rs:115:5
    |
 LL |     0 + if b { 1 } else { 2 } + match a { 0 => 30, _ => 40 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:92:5
+  --> $DIR/identity_op.rs:117:5
    |
 LL |     0 + match a { 0 => 10, _ => 20 } + if b { 3 } else { 4 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:93:5
+  --> $DIR/identity_op.rs:119:5
    |
 LL |     (if b { 1 } else { 2 }) + 0;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:95:5
+  --> $DIR/identity_op.rs:122:5
    |
 LL |     0 + { a } + 3;
    |     ^^^^^^^^^ help: consider reducing it to: `({ a })`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:96:5
+  --> $DIR/identity_op.rs:124:5
    |
 LL |     0 + { a } * 2;
    |     ^^^^^^^^^^^^^ help: consider reducing it to: `({ a } * 2)`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:97:5
+  --> $DIR/identity_op.rs:126:5
    |
 LL |     0 + loop { let mut c = 0; if c == 10 { break c; } c += 1; } + { a * 2 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(loop { let mut c = 0; if c == 10 { break c; } c += 1; })`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:102:7
+  --> $DIR/identity_op.rs:133:7
    |
 LL |     f(1 * a + { 8 * 5 });
    |       ^^^^^ help: consider reducing it to: `a`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:103:7
+  --> $DIR/identity_op.rs:135:7
    |
 LL |     f(0 + if b { 1 } else { 2 } + 3);
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `if b { 1 } else { 2 }`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:104:20
+  --> $DIR/identity_op.rs:138:20
    |
 LL |     const _: i32 = { 2 * 4 } + 0 + 3;
    |                    ^^^^^^^^^^^^^ help: consider reducing it to: `{ 2 * 4 }`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:105:20
+  --> $DIR/identity_op.rs:140:20
    |
 LL |     const _: i32 = 0 + { 1 + 2 * 3 } + 3;
    |                    ^^^^^^^^^^^^^^^^^ help: consider reducing it to: `{ 1 + 2 * 3 }`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:107:5
+  --> $DIR/identity_op.rs:143:5
    |
 LL |     0 + a as usize;
    |     ^^^^^^^^^^^^^^ help: consider reducing it to: `a as usize`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:108:13
+  --> $DIR/identity_op.rs:145:13
    |
 LL |     let _ = 0 + a as usize;
    |             ^^^^^^^^^^^^^^ help: consider reducing it to: `a as usize`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:109:5
+  --> $DIR/identity_op.rs:147:5
    |
 LL |     0 + { a } as usize;
    |     ^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `({ a } as usize)`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:111:9
+  --> $DIR/identity_op.rs:150:9
    |
 LL |     2 * (0 + { a });
    |         ^^^^^^^^^^^ help: consider reducing it to: `{ a }`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:112:5
+  --> $DIR/identity_op.rs:152:5
    |
 LL |     1 * ({ a } + 4);
    |     ^^^^^^^^^^^^^^^ help: consider reducing it to: `(({ a } + 4))`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:113:5
+  --> $DIR/identity_op.rs:154:5
    |
 LL |     1 * 1;
    |     ^^^^^ help: consider reducing it to: `1`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:117:18
+  --> $DIR/identity_op.rs:159:18
    |
 LL |     let _: i32 = &x + 0;
    |                  ^^^^^^ help: consider reducing it to: `x`
 
 error: this operation has no effect
-  --> $DIR/identity_op.rs:121:5
+  --> $DIR/identity_op.rs:164:5
    |
 LL |     0 + if a { 1 } else { 2 } + if b { 3 } else { 5 }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if a { 1 } else { 2 })`
 
-error: aborting due to 40 previous errors
+error: this operation has no effect
+  --> $DIR/identity_op.rs:175:22
+   |
+LL |         let _: i32 = *x + 0;
+   |                      ^^^^^^ help: consider reducing it to: `*x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:177:22
+   |
+LL |         let _: i32 = x + 0;
+   |                      ^^^^^ help: consider reducing it to: `*x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:182:22
+   |
+LL |         let _: i32 = **x + 0;
+   |                      ^^^^^^^ help: consider reducing it to: `**x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:185:22
+   |
+LL |         let _: i32 = *x + 0;
+   |                      ^^^^^^ help: consider reducing it to: `**x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:191:22
+   |
+LL |         let _: i32 = ***x + 0;
+   |                      ^^^^^^^^ help: consider reducing it to: `***x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:193:22
+   |
+LL |         let _: i32 = **x + 0;
+   |                      ^^^^^^^ help: consider reducing it to: `***x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:196:22
+   |
+LL |         let _: i32 = *&x + 0;
+   |                      ^^^^^^^ help: consider reducing it to: `*&x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:198:22
+   |
+LL |         let _: i32 = **&&x + 0;
+   |                      ^^^^^^^^^ help: consider reducing it to: `**&&x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:200:22
+   |
+LL |         let _: i32 = *&*&x + 0;
+   |                      ^^^^^^^^^ help: consider reducing it to: `*&*&x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:202:22
+   |
+LL |         let _: i32 = **&&*&x + 0;
+   |                      ^^^^^^^^^^^ help: consider reducing it to: `**&&*&x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:209:22
+   |
+LL |         let _: i32 = **&&*&x + 0;
+   |                      ^^^^^^^^^^^ help: consider reducing it to: `***&&*&x`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:211:22
+   |
+LL |         let _: i32 = **&&*&x + 0;
+   |                      ^^^^^^^^^^^ help: consider reducing it to: `***&&*&x`
+
+error: aborting due to 52 previous errors
 
diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.rs b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
index abc92459148..ccde154bd56 100644
--- a/src/tools/clippy/tests/ui/if_then_some_else_none.rs
+++ b/src/tools/clippy/tests/ui/if_then_some_else_none.rs
@@ -130,3 +130,8 @@ fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> {
 
     Ok(())
 }
+
+const fn issue12103(x: u32) -> Option<u32> {
+    // Should not issue an error in `const` context
+    if x > 42 { Some(150) } else { None }
+}
diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.rs b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
index 448d0114dff..c8b9076041a 100644
--- a/src/tools/clippy/tests/ui/into_iter_without_iter.rs
+++ b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
@@ -1,5 +1,7 @@
 //@no-rustfix
+//@aux-build:proc_macros.rs
 #![warn(clippy::into_iter_without_iter)]
+extern crate proc_macros;
 
 use std::iter::IntoIterator;
 
@@ -111,6 +113,43 @@ impl IntoIterator for &Alias {
     }
 }
 
+// Fine to lint, the impls comes from a local macro.
+pub struct Issue12037;
+macro_rules! generate_impl {
+    () => {
+        impl<'a> IntoIterator for &'a Issue12037 {
+            type IntoIter = std::slice::Iter<'a, u8>;
+            type Item = &'a u8;
+            fn into_iter(self) -> Self::IntoIter {
+                todo!()
+            }
+        }
+    };
+}
+generate_impl!();
+
+// Impl comes from an external crate
+proc_macros::external! {
+    pub struct ImplWithForeignSpan;
+    impl<'a> IntoIterator for &'a ImplWithForeignSpan {
+        type IntoIter = std::slice::Iter<'a, u8>;
+        type Item = &'a u8;
+        fn into_iter(self) -> Self::IntoIter {
+            todo!()
+        }
+    }
+}
+
+pub struct Allowed;
+#[allow(clippy::into_iter_without_iter)]
+impl<'a> IntoIterator for &'a Allowed {
+    type IntoIter = std::slice::Iter<'a, u8>;
+    type Item = &'a u8;
+    fn into_iter(self) -> Self::IntoIter {
+        todo!()
+    }
+}
+
 fn main() {}
 
 pub mod issue11635 {
diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.stderr b/src/tools/clippy/tests/ui/into_iter_without_iter.stderr
index 70f3f82a936..a232c7cecc5 100644
--- a/src/tools/clippy/tests/ui/into_iter_without_iter.stderr
+++ b/src/tools/clippy/tests/ui/into_iter_without_iter.stderr
@@ -1,5 +1,5 @@
 error: `IntoIterator` implemented for a reference type without an `iter` method
-  --> $DIR/into_iter_without_iter.rs:7:1
+  --> $DIR/into_iter_without_iter.rs:9:1
    |
 LL | / impl<'a> IntoIterator for &'a S1 {
 LL | |
@@ -23,7 +23,7 @@ LL + }
    |
 
 error: `IntoIterator` implemented for a reference type without an `iter_mut` method
-  --> $DIR/into_iter_without_iter.rs:15:1
+  --> $DIR/into_iter_without_iter.rs:17:1
    |
 LL | / impl<'a> IntoIterator for &'a mut S1 {
 LL | |
@@ -45,7 +45,7 @@ LL + }
    |
 
 error: `IntoIterator` implemented for a reference type without an `iter` method
-  --> $DIR/into_iter_without_iter.rs:25:1
+  --> $DIR/into_iter_without_iter.rs:27:1
    |
 LL | / impl<'a, T> IntoIterator for &'a S2<T> {
 LL | |
@@ -67,7 +67,7 @@ LL + }
    |
 
 error: `IntoIterator` implemented for a reference type without an `iter_mut` method
-  --> $DIR/into_iter_without_iter.rs:33:1
+  --> $DIR/into_iter_without_iter.rs:35:1
    |
 LL | / impl<'a, T> IntoIterator for &'a mut S2<T> {
 LL | |
@@ -89,7 +89,7 @@ LL + }
    |
 
 error: `IntoIterator` implemented for a reference type without an `iter_mut` method
-  --> $DIR/into_iter_without_iter.rs:84:1
+  --> $DIR/into_iter_without_iter.rs:86:1
    |
 LL | / impl<'a, T> IntoIterator for &mut S4<'a, T> {
 LL | |
@@ -110,5 +110,31 @@ LL +     }
 LL + }
    |
 
-error: aborting due to 5 previous errors
+error: `IntoIterator` implemented for a reference type without an `iter` method
+  --> $DIR/into_iter_without_iter.rs:120:9
+   |
+LL | /         impl<'a> IntoIterator for &'a Issue12037 {
+LL | |             type IntoIter = std::slice::Iter<'a, u8>;
+LL | |             type Item = &'a u8;
+LL | |             fn into_iter(self) -> Self::IntoIter {
+LL | |                 todo!()
+LL | |             }
+LL | |         }
+   | |_________^
+...
+LL |   generate_impl!();
+   |   ---------------- in this macro invocation
+   |
+   = note: this error originates in the macro `generate_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider implementing `iter`
+   |
+LL ~         
+LL + impl Issue12037 {
+LL +     fn iter(&self) -> std::slice::Iter<'a, u8> {
+LL +         <&Self as IntoIterator>::into_iter(self)
+LL +     }
+LL + }
+   |
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_filter_is_ok.fixed b/src/tools/clippy/tests/ui/iter_filter_is_ok.fixed
index a5ca41528af..80db8b29c18 100644
--- a/src/tools/clippy/tests/ui/iter_filter_is_ok.fixed
+++ b/src/tools/clippy/tests/ui/iter_filter_is_ok.fixed
@@ -1,21 +1,72 @@
 #![warn(clippy::iter_filter_is_ok)]
+#![allow(
+    clippy::map_identity,
+    clippy::result_filter_map,
+    clippy::needless_borrow,
+    clippy::redundant_closure
+)]
 
 fn main() {
-    let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
-    //~^ HELP: consider using `flatten` instead
-    let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
-    //~^ HELP: consider using `flatten` instead
+    {
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+        #[rustfmt::skip]
+        let _ = vec![Ok(1), Err(2)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+    }
 
-    #[rustfmt::skip]
-    let _ = vec![Ok(1), Err(2)].into_iter().flatten();
-    //~^ HELP: consider using `flatten` instead
+    {
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
 
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+
+        #[rustfmt::skip]
+        let _ = vec![Ok(1), Err(2)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+    }
+
+    {
+        let _ = vec![Ok(1), Err(2), Ok(3)]
+            .into_iter()
+            .flatten();
+        //~^ HELP: consider using `flatten` instead
+
+        let _ = vec![Ok(1), Err(2), Ok(3)]
+            .into_iter()
+            .flatten();
+        //~^ HELP: consider using `flatten` instead
+        #[rustfmt::skip]
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+    }
+
+    {
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+
+        #[rustfmt::skip]
+        let _ = vec![Ok(1), Err(2)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+    }
+}
+
+fn avoid_linting_when_filter_has_side_effects() {
     // Don't lint below
     let mut counter = 0;
     let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
         counter += 1;
         o.is_ok()
     });
+}
+
+fn avoid_linting_when_commented() {
     let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
         // Roses are red,
         // Violets are blue,
@@ -24,3 +75,131 @@ fn main() {
         o.is_ok()
     });
 }
+
+fn ice_12058() {
+    // check that checking the parent node doesn't cause an ICE
+    // by indexing the parameters of a closure without parameters
+    Some(1).or_else(|| {
+        vec![Ok(1), Err(())].into_iter().filter(|z| *z != Ok(2));
+        None
+    });
+}
+
+fn avoid_linting_map() {
+    // should not lint
+    let _ = vec![Ok(1), Err(())]
+        .into_iter()
+        .filter(|o| o.is_ok())
+        .map(|o| o.unwrap());
+
+    // should not lint
+    let _ = vec![Ok(1), Err(())].into_iter().filter(|o| o.is_ok()).map(|o| o);
+}
+
+fn avoid_false_positive_due_to_is_ok_and_iterator_impl() {
+    #[derive(Default, Clone)]
+    struct Foo {}
+
+    impl Foo {
+        fn is_ok(&self) -> bool {
+            true
+        }
+    }
+
+    impl Iterator for Foo {
+        type Item = Foo;
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(Foo::default())
+        }
+    }
+
+    let data = vec![Foo::default()];
+    // should not lint
+    let _ = data.clone().into_iter().filter(Foo::is_ok);
+    // should not lint
+    let _ = data.clone().into_iter().filter(|f| f.is_ok());
+}
+
+fn avoid_false_positive_due_to_is_ok_and_into_iterator_impl() {
+    #[derive(Default, Clone)]
+    struct Foo {}
+
+    impl Foo {
+        fn is_ok(&self) -> bool {
+            true
+        }
+    }
+
+    let data = vec![Foo::default()];
+    // should not lint
+    let _ = data.clone().into_iter().filter(Foo::is_ok);
+    // should not lint
+    let _ = data.clone().into_iter().filter(|f| f.is_ok());
+}
+
+fn avoid_fp_for_trivial() {
+    let _ = vec![Ok(1), Err(()), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| (Err(()) as Result<i32, ()>).is_ok());
+}
+
+fn avoid_false_positive_due_to_method_name() {
+    fn is_ok(x: &Result<i32, i32>) -> bool {
+        x.is_ok()
+    }
+
+    vec![Ok(1), Err(2), Ok(3)].into_iter().filter(is_ok);
+    // should not lint
+}
+
+fn avoid_fp_due_to_trait_type() {
+    struct Foo {
+        bar: i32,
+    }
+    impl Foo {
+        fn is_ok(obj: &Result<i32, i32>) -> bool {
+            obj.is_ok()
+        }
+    }
+    vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Foo::is_ok);
+    // should not lint
+}
+
+fn avoid_fp_with_call_to_outside_var() {
+    let outside: Result<i32, ()> = Ok(1);
+
+    let _ = vec![Ok(1), Err(2), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| outside.is_ok());
+
+    let _ = vec![Ok(1), Err(2), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| Result::is_ok(&outside));
+
+    let _ = vec![Ok(1), Err(2), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| std::result::Result::is_ok(&outside));
+}
+
+fn avoid_fp_with_call_to_outside_var_mix_match_types() {
+    let outside = Some(1);
+
+    let _ = vec![Ok(1), Err(2), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| outside.is_some());
+
+    let _ = vec![Ok(1), Err(2), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| Option::is_some(&outside));
+
+    let _ = vec![Ok(1), Err(2), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| std::option::Option::is_some(&outside));
+}
diff --git a/src/tools/clippy/tests/ui/iter_filter_is_ok.rs b/src/tools/clippy/tests/ui/iter_filter_is_ok.rs
index e4e73f5ada1..89b083b84f3 100644
--- a/src/tools/clippy/tests/ui/iter_filter_is_ok.rs
+++ b/src/tools/clippy/tests/ui/iter_filter_is_ok.rs
@@ -1,21 +1,72 @@
 #![warn(clippy::iter_filter_is_ok)]
+#![allow(
+    clippy::map_identity,
+    clippy::result_filter_map,
+    clippy::needless_borrow,
+    clippy::redundant_closure
+)]
 
 fn main() {
-    let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok);
-    //~^ HELP: consider using `flatten` instead
-    let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok());
-    //~^ HELP: consider using `flatten` instead
+    {
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok);
+        //~^ HELP: consider using `flatten` instead
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok());
+        //~^ HELP: consider using `flatten` instead
+        #[rustfmt::skip]
+        let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() });
+        //~^ HELP: consider using `flatten` instead
+    }
 
-    #[rustfmt::skip]
-    let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() });
-    //~^ HELP: consider using `flatten` instead
+    {
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|&a| a.is_ok());
+        //~^ HELP: consider using `flatten` instead
 
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|&a| a.is_ok());
+        //~^ HELP: consider using `flatten` instead
+
+        #[rustfmt::skip]
+        let _ = vec![Ok(1), Err(2)].into_iter().filter(|&o| { o.is_ok() });
+        //~^ HELP: consider using `flatten` instead
+    }
+
+    {
+        let _ = vec![Ok(1), Err(2), Ok(3)]
+            .into_iter()
+            .filter(std::result::Result::is_ok);
+        //~^ HELP: consider using `flatten` instead
+
+        let _ = vec![Ok(1), Err(2), Ok(3)]
+            .into_iter()
+            .filter(|a| std::result::Result::is_ok(a));
+        //~^ HELP: consider using `flatten` instead
+        #[rustfmt::skip]
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| { std::result::Result::is_ok(a) });
+        //~^ HELP: consider using `flatten` instead
+    }
+
+    {
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|ref a| a.is_ok());
+        //~^ HELP: consider using `flatten` instead
+
+        let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|ref a| a.is_ok());
+        //~^ HELP: consider using `flatten` instead
+
+        #[rustfmt::skip]
+        let _ = vec![Ok(1), Err(2)].into_iter().filter(|ref o| { o.is_ok() });
+        //~^ HELP: consider using `flatten` instead
+    }
+}
+
+fn avoid_linting_when_filter_has_side_effects() {
     // Don't lint below
     let mut counter = 0;
     let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
         counter += 1;
         o.is_ok()
     });
+}
+
+fn avoid_linting_when_commented() {
     let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
         // Roses are red,
         // Violets are blue,
@@ -24,3 +75,131 @@ fn main() {
         o.is_ok()
     });
 }
+
+fn ice_12058() {
+    // check that checking the parent node doesn't cause an ICE
+    // by indexing the parameters of a closure without parameters
+    Some(1).or_else(|| {
+        vec![Ok(1), Err(())].into_iter().filter(|z| *z != Ok(2));
+        None
+    });
+}
+
+fn avoid_linting_map() {
+    // should not lint
+    let _ = vec![Ok(1), Err(())]
+        .into_iter()
+        .filter(|o| o.is_ok())
+        .map(|o| o.unwrap());
+
+    // should not lint
+    let _ = vec![Ok(1), Err(())].into_iter().filter(|o| o.is_ok()).map(|o| o);
+}
+
+fn avoid_false_positive_due_to_is_ok_and_iterator_impl() {
+    #[derive(Default, Clone)]
+    struct Foo {}
+
+    impl Foo {
+        fn is_ok(&self) -> bool {
+            true
+        }
+    }
+
+    impl Iterator for Foo {
+        type Item = Foo;
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(Foo::default())
+        }
+    }
+
+    let data = vec![Foo::default()];
+    // should not lint
+    let _ = data.clone().into_iter().filter(Foo::is_ok);
+    // should not lint
+    let _ = data.clone().into_iter().filter(|f| f.is_ok());
+}
+
+fn avoid_false_positive_due_to_is_ok_and_into_iterator_impl() {
+    #[derive(Default, Clone)]
+    struct Foo {}
+
+    impl Foo {
+        fn is_ok(&self) -> bool {
+            true
+        }
+    }
+
+    let data = vec![Foo::default()];
+    // should not lint
+    let _ = data.clone().into_iter().filter(Foo::is_ok);
+    // should not lint
+    let _ = data.clone().into_iter().filter(|f| f.is_ok());
+}
+
+fn avoid_fp_for_trivial() {
+    let _ = vec![Ok(1), Err(()), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| (Err(()) as Result<i32, ()>).is_ok());
+}
+
+fn avoid_false_positive_due_to_method_name() {
+    fn is_ok(x: &Result<i32, i32>) -> bool {
+        x.is_ok()
+    }
+
+    vec![Ok(1), Err(2), Ok(3)].into_iter().filter(is_ok);
+    // should not lint
+}
+
+fn avoid_fp_due_to_trait_type() {
+    struct Foo {
+        bar: i32,
+    }
+    impl Foo {
+        fn is_ok(obj: &Result<i32, i32>) -> bool {
+            obj.is_ok()
+        }
+    }
+    vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Foo::is_ok);
+    // should not lint
+}
+
+fn avoid_fp_with_call_to_outside_var() {
+    let outside: Result<i32, ()> = Ok(1);
+
+    let _ = vec![Ok(1), Err(2), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| outside.is_ok());
+
+    let _ = vec![Ok(1), Err(2), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| Result::is_ok(&outside));
+
+    let _ = vec![Ok(1), Err(2), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| std::result::Result::is_ok(&outside));
+}
+
+fn avoid_fp_with_call_to_outside_var_mix_match_types() {
+    let outside = Some(1);
+
+    let _ = vec![Ok(1), Err(2), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| outside.is_some());
+
+    let _ = vec![Ok(1), Err(2), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| Option::is_some(&outside));
+
+    let _ = vec![Ok(1), Err(2), Ok(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| std::option::Option::is_some(&outside));
+}
diff --git a/src/tools/clippy/tests/ui/iter_filter_is_ok.stderr b/src/tools/clippy/tests/ui/iter_filter_is_ok.stderr
index f3acbe38d8a..d99e2e0446d 100644
--- a/src/tools/clippy/tests/ui/iter_filter_is_ok.stderr
+++ b/src/tools/clippy/tests/ui/iter_filter_is_ok.stderr
@@ -1,23 +1,77 @@
 error: `filter` for `is_ok` on iterator over `Result`s
-  --> $DIR/iter_filter_is_ok.rs:4:52
+  --> $DIR/iter_filter_is_ok.rs:11:56
    |
-LL |     let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok);
-   |                                                    ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+LL |         let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok);
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
    |
    = note: `-D clippy::iter-filter-is-ok` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_ok)]`
 
 error: `filter` for `is_ok` on iterator over `Result`s
-  --> $DIR/iter_filter_is_ok.rs:6:52
+  --> $DIR/iter_filter_is_ok.rs:13:56
    |
-LL |     let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok());
-   |                                                    ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+LL |         let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok());
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
 
 error: `filter` for `is_ok` on iterator over `Result`s
-  --> $DIR/iter_filter_is_ok.rs:10:45
+  --> $DIR/iter_filter_is_ok.rs:16:49
    |
-LL |     let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() });
-   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+LL |         let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() });
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
 
-error: aborting due to 3 previous errors
+error: `filter` for `is_ok` on iterator over `Result`s
+  --> $DIR/iter_filter_is_ok.rs:21:56
+   |
+LL |         let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|&a| a.is_ok());
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_ok` on iterator over `Result`s
+  --> $DIR/iter_filter_is_ok.rs:24:56
+   |
+LL |         let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|&a| a.is_ok());
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_ok` on iterator over `Result`s
+  --> $DIR/iter_filter_is_ok.rs:28:49
+   |
+LL |         let _ = vec![Ok(1), Err(2)].into_iter().filter(|&o| { o.is_ok() });
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_ok` on iterator over `Result`s
+  --> $DIR/iter_filter_is_ok.rs:35:14
+   |
+LL |             .filter(std::result::Result::is_ok);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_ok` on iterator over `Result`s
+  --> $DIR/iter_filter_is_ok.rs:40:14
+   |
+LL |             .filter(|a| std::result::Result::is_ok(a));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_ok` on iterator over `Result`s
+  --> $DIR/iter_filter_is_ok.rs:43:56
+   |
+LL |         let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| { std::result::Result::is_ok(a) });
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_ok` on iterator over `Result`s
+  --> $DIR/iter_filter_is_ok.rs:48:56
+   |
+LL |         let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|ref a| a.is_ok());
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_ok` on iterator over `Result`s
+  --> $DIR/iter_filter_is_ok.rs:51:56
+   |
+LL |         let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|ref a| a.is_ok());
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_ok` on iterator over `Result`s
+  --> $DIR/iter_filter_is_ok.rs:55:49
+   |
+LL |         let _ = vec![Ok(1), Err(2)].into_iter().filter(|ref o| { o.is_ok() });
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_filter_is_some.fixed b/src/tools/clippy/tests/ui/iter_filter_is_some.fixed
index c3fa93f0ab2..abc3a47fa46 100644
--- a/src/tools/clippy/tests/ui/iter_filter_is_some.fixed
+++ b/src/tools/clippy/tests/ui/iter_filter_is_some.fixed
@@ -1,23 +1,70 @@
 #![warn(clippy::iter_filter_is_some)]
+#![allow(
+    clippy::map_identity,
+    clippy::result_filter_map,
+    clippy::needless_borrow,
+    clippy::option_filter_map,
+    clippy::redundant_closure
+)]
+
+use std::collections::HashMap;
 
 fn main() {
-    let _ = vec![Some(1)].into_iter().flatten();
-    //~^ HELP: consider using `flatten` instead
-    let _ = vec![Some(1)].into_iter().flatten();
-    //~^ HELP: consider using `flatten` instead
+    {
+        let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+        let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+        #[rustfmt::skip]
+        let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+    }
+
+    {
+        let _ = vec![Some(1), None, Some(3)]
+            .into_iter()
+            .flatten();
+        //~^ HELP: consider using `flatten` instead
+
+        let _ = vec![Some(1), None, Some(3)]
+            .into_iter()
+            .flatten();
+        //~^ HELP: consider using `flatten` instead
+        #[rustfmt::skip]
+        let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+    }
+
+    {
+        let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+
+        #[rustfmt::skip]
+        let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+    }
+
+    {
+        let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
 
-    #[rustfmt::skip]
-    let _ = vec![Some(1)].into_iter().flatten();
-    //~^ HELP: consider using `flatten` instead
+        #[rustfmt::skip]
+        let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
+        //~^ HELP: consider using `flatten` instead
+    }
+}
 
+fn avoid_linting_when_filter_has_side_effects() {
     // Don't lint below
     let mut counter = 0;
-    let _ = vec![Some(1)].into_iter().filter(|o| {
+    let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| {
         counter += 1;
         o.is_some()
     });
+}
 
-    let _ = vec![Some(1)].into_iter().filter(|o| {
+fn avoid_linting_when_commented() {
+    let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| {
         // Roses are red,
         // Violets are blue,
         // `Err` is not an `Option`,
@@ -25,3 +72,169 @@ fn main() {
         o.is_some()
     });
 }
+
+fn ice_12058() {
+    // check that checking the parent node doesn't cause an ICE
+    // by indexing the parameters of a closure without parameters
+    Some(1).or_else(|| {
+        vec![Some(1), None, Some(3)].into_iter().filter(|z| *z != Some(2));
+        None
+    });
+}
+
+fn avoid_linting_map() {
+    // should not lint
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        .filter(|o| o.is_some())
+        .map(|o| o.unwrap());
+
+    // should not lint
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        .filter(|o| o.is_some())
+        .map(|o| o);
+}
+
+fn avoid_false_positive_due_to_is_some_and_iterator_impl() {
+    #[derive(Default, Clone)]
+    struct Foo {}
+
+    impl Foo {
+        fn is_some(&self) -> bool {
+            true
+        }
+    }
+
+    impl Iterator for Foo {
+        type Item = Foo;
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(Foo::default())
+        }
+    }
+
+    let data = vec![Foo::default()];
+    // should not lint
+    let _ = data.clone().into_iter().filter(Foo::is_some);
+    // should not lint
+    let _ = data.clone().into_iter().filter(|f| f.is_some());
+}
+
+fn avoid_false_positive_due_to_is_some_and_into_iterator_impl() {
+    #[derive(Default, Clone)]
+    struct Foo {}
+
+    impl Foo {
+        fn is_some(&self) -> bool {
+            true
+        }
+    }
+
+    let data = vec![Foo::default()];
+    // should not lint
+    let _ = data.clone().into_iter().filter(Foo::is_some);
+    // should not lint
+    let _ = data.clone().into_iter().filter(|f| f.is_some());
+}
+
+fn avoid_unpack_fp() {
+    let _ = vec![(Some(1), None), (None, Some(3))]
+        .into_iter()
+        // should not lint
+        .filter(|(a, _)| a.is_some());
+    let _ = vec![(Some(1), None), (None, Some(3))]
+        .into_iter()
+        // should not lint
+        .filter(|(a, _)| a.is_some())
+        .collect::<Vec<_>>();
+
+    let m = HashMap::from([(1, 1)]);
+    let _ = vec![1, 2, 4].into_iter().filter(|a| m.get(a).is_some());
+    // should not lint
+}
+
+fn avoid_fp_for_external() {
+    let value = HashMap::from([(1, 1)]);
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| value.get(&1).is_some());
+
+    let value = Option::Some(1);
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| value.is_some());
+}
+
+fn avoid_fp_for_trivial() {
+    let value = HashMap::from([(1, 1)]);
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| Some(1).is_some());
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| None::<i32>.is_some());
+}
+
+fn avoid_false_positive_due_to_method_name() {
+    fn is_some(x: &Option<i32>) -> bool {
+        x.is_some()
+    }
+
+    vec![Some(1), None, Some(3)].into_iter().filter(is_some);
+    // should not lint
+}
+
+fn avoid_fp_due_to_trait_type() {
+    struct Foo {
+        bar: i32,
+    }
+    impl Foo {
+        fn is_some(obj: &Option<i32>) -> bool {
+            obj.is_some()
+        }
+    }
+    vec![Some(1), None, Some(3)].into_iter().filter(Foo::is_some);
+    // should not lint
+}
+
+fn avoid_fp_with_call_to_outside_var() {
+    let outside = Some(1);
+
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| outside.is_some());
+
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| Option::is_some(&outside));
+
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| std::option::Option::is_some(&outside));
+}
+
+fn avoid_fp_with_call_to_outside_var_mix_match_types() {
+    let outside: Result<i32, ()> = Ok(1);
+
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| outside.is_ok());
+
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| Result::is_ok(&outside));
+
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| std::result::Result::is_ok(&outside));
+}
diff --git a/src/tools/clippy/tests/ui/iter_filter_is_some.rs b/src/tools/clippy/tests/ui/iter_filter_is_some.rs
index b023776abe4..c74775a82ba 100644
--- a/src/tools/clippy/tests/ui/iter_filter_is_some.rs
+++ b/src/tools/clippy/tests/ui/iter_filter_is_some.rs
@@ -1,23 +1,70 @@
 #![warn(clippy::iter_filter_is_some)]
+#![allow(
+    clippy::map_identity,
+    clippy::result_filter_map,
+    clippy::needless_borrow,
+    clippy::option_filter_map,
+    clippy::redundant_closure
+)]
+
+use std::collections::HashMap;
 
 fn main() {
-    let _ = vec![Some(1)].into_iter().filter(Option::is_some);
-    //~^ HELP: consider using `flatten` instead
-    let _ = vec![Some(1)].into_iter().filter(|o| o.is_some());
-    //~^ HELP: consider using `flatten` instead
+    {
+        let _ = vec![Some(1), None, Some(3)].into_iter().filter(Option::is_some);
+        //~^ HELP: consider using `flatten` instead
+        let _ = vec![Some(1), None, Some(3)].into_iter().filter(|a| a.is_some());
+        //~^ HELP: consider using `flatten` instead
+        #[rustfmt::skip]
+        let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| { o.is_some() });
+        //~^ HELP: consider using `flatten` instead
+    }
+
+    {
+        let _ = vec![Some(1), None, Some(3)]
+            .into_iter()
+            .filter(std::option::Option::is_some);
+        //~^ HELP: consider using `flatten` instead
+
+        let _ = vec![Some(1), None, Some(3)]
+            .into_iter()
+            .filter(|a| std::option::Option::is_some(a));
+        //~^ HELP: consider using `flatten` instead
+        #[rustfmt::skip]
+        let _ = vec![Some(1), None, Some(3)].into_iter().filter(|a| { std::option::Option::is_some(a) });
+        //~^ HELP: consider using `flatten` instead
+    }
+
+    {
+        let _ = vec![Some(1), None, Some(3)].into_iter().filter(|&a| a.is_some());
+        //~^ HELP: consider using `flatten` instead
+
+        #[rustfmt::skip]
+        let _ = vec![Some(1), None, Some(3)].into_iter().filter(|&o| { o.is_some() });
+        //~^ HELP: consider using `flatten` instead
+    }
+
+    {
+        let _ = vec![Some(1), None, Some(3)].into_iter().filter(|ref a| a.is_some());
+        //~^ HELP: consider using `flatten` instead
 
-    #[rustfmt::skip]
-    let _ = vec![Some(1)].into_iter().filter(|o| { o.is_some() });
-    //~^ HELP: consider using `flatten` instead
+        #[rustfmt::skip]
+        let _ = vec![Some(1), None, Some(3)].into_iter().filter(|ref o| { o.is_some() });
+        //~^ HELP: consider using `flatten` instead
+    }
+}
 
+fn avoid_linting_when_filter_has_side_effects() {
     // Don't lint below
     let mut counter = 0;
-    let _ = vec![Some(1)].into_iter().filter(|o| {
+    let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| {
         counter += 1;
         o.is_some()
     });
+}
 
-    let _ = vec![Some(1)].into_iter().filter(|o| {
+fn avoid_linting_when_commented() {
+    let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| {
         // Roses are red,
         // Violets are blue,
         // `Err` is not an `Option`,
@@ -25,3 +72,169 @@ fn main() {
         o.is_some()
     });
 }
+
+fn ice_12058() {
+    // check that checking the parent node doesn't cause an ICE
+    // by indexing the parameters of a closure without parameters
+    Some(1).or_else(|| {
+        vec![Some(1), None, Some(3)].into_iter().filter(|z| *z != Some(2));
+        None
+    });
+}
+
+fn avoid_linting_map() {
+    // should not lint
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        .filter(|o| o.is_some())
+        .map(|o| o.unwrap());
+
+    // should not lint
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        .filter(|o| o.is_some())
+        .map(|o| o);
+}
+
+fn avoid_false_positive_due_to_is_some_and_iterator_impl() {
+    #[derive(Default, Clone)]
+    struct Foo {}
+
+    impl Foo {
+        fn is_some(&self) -> bool {
+            true
+        }
+    }
+
+    impl Iterator for Foo {
+        type Item = Foo;
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(Foo::default())
+        }
+    }
+
+    let data = vec![Foo::default()];
+    // should not lint
+    let _ = data.clone().into_iter().filter(Foo::is_some);
+    // should not lint
+    let _ = data.clone().into_iter().filter(|f| f.is_some());
+}
+
+fn avoid_false_positive_due_to_is_some_and_into_iterator_impl() {
+    #[derive(Default, Clone)]
+    struct Foo {}
+
+    impl Foo {
+        fn is_some(&self) -> bool {
+            true
+        }
+    }
+
+    let data = vec![Foo::default()];
+    // should not lint
+    let _ = data.clone().into_iter().filter(Foo::is_some);
+    // should not lint
+    let _ = data.clone().into_iter().filter(|f| f.is_some());
+}
+
+fn avoid_unpack_fp() {
+    let _ = vec![(Some(1), None), (None, Some(3))]
+        .into_iter()
+        // should not lint
+        .filter(|(a, _)| a.is_some());
+    let _ = vec![(Some(1), None), (None, Some(3))]
+        .into_iter()
+        // should not lint
+        .filter(|(a, _)| a.is_some())
+        .collect::<Vec<_>>();
+
+    let m = HashMap::from([(1, 1)]);
+    let _ = vec![1, 2, 4].into_iter().filter(|a| m.get(a).is_some());
+    // should not lint
+}
+
+fn avoid_fp_for_external() {
+    let value = HashMap::from([(1, 1)]);
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| value.get(&1).is_some());
+
+    let value = Option::Some(1);
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| value.is_some());
+}
+
+fn avoid_fp_for_trivial() {
+    let value = HashMap::from([(1, 1)]);
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| Some(1).is_some());
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| None::<i32>.is_some());
+}
+
+fn avoid_false_positive_due_to_method_name() {
+    fn is_some(x: &Option<i32>) -> bool {
+        x.is_some()
+    }
+
+    vec![Some(1), None, Some(3)].into_iter().filter(is_some);
+    // should not lint
+}
+
+fn avoid_fp_due_to_trait_type() {
+    struct Foo {
+        bar: i32,
+    }
+    impl Foo {
+        fn is_some(obj: &Option<i32>) -> bool {
+            obj.is_some()
+        }
+    }
+    vec![Some(1), None, Some(3)].into_iter().filter(Foo::is_some);
+    // should not lint
+}
+
+fn avoid_fp_with_call_to_outside_var() {
+    let outside = Some(1);
+
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| outside.is_some());
+
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| Option::is_some(&outside));
+
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| std::option::Option::is_some(&outside));
+}
+
+fn avoid_fp_with_call_to_outside_var_mix_match_types() {
+    let outside: Result<i32, ()> = Ok(1);
+
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| outside.is_ok());
+
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| Result::is_ok(&outside));
+
+    let _ = vec![Some(1), None, Some(3)]
+        .into_iter()
+        // should not lint
+        .filter(|o| std::result::Result::is_ok(&outside));
+}
diff --git a/src/tools/clippy/tests/ui/iter_filter_is_some.stderr b/src/tools/clippy/tests/ui/iter_filter_is_some.stderr
index 1f2b10036fe..2eb00633e88 100644
--- a/src/tools/clippy/tests/ui/iter_filter_is_some.stderr
+++ b/src/tools/clippy/tests/ui/iter_filter_is_some.stderr
@@ -1,23 +1,65 @@
 error: `filter` for `is_some` on iterator over `Option`
-  --> $DIR/iter_filter_is_some.rs:4:39
+  --> $DIR/iter_filter_is_some.rs:14:58
    |
-LL |     let _ = vec![Some(1)].into_iter().filter(Option::is_some);
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+LL |         let _ = vec![Some(1), None, Some(3)].into_iter().filter(Option::is_some);
+   |                                                          ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
    |
    = note: `-D clippy::iter-filter-is-some` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_some)]`
 
 error: `filter` for `is_some` on iterator over `Option`
-  --> $DIR/iter_filter_is_some.rs:6:39
+  --> $DIR/iter_filter_is_some.rs:16:58
    |
-LL |     let _ = vec![Some(1)].into_iter().filter(|o| o.is_some());
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+LL |         let _ = vec![Some(1), None, Some(3)].into_iter().filter(|a| a.is_some());
+   |                                                          ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
 
 error: `filter` for `is_some` on iterator over `Option`
-  --> $DIR/iter_filter_is_some.rs:10:39
+  --> $DIR/iter_filter_is_some.rs:19:58
    |
-LL |     let _ = vec![Some(1)].into_iter().filter(|o| { o.is_some() });
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+LL |         let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| { o.is_some() });
+   |                                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
 
-error: aborting due to 3 previous errors
+error: `filter` for `is_some` on iterator over `Option`
+  --> $DIR/iter_filter_is_some.rs:26:14
+   |
+LL |             .filter(std::option::Option::is_some);
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_some` on iterator over `Option`
+  --> $DIR/iter_filter_is_some.rs:31:14
+   |
+LL |             .filter(|a| std::option::Option::is_some(a));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_some` on iterator over `Option`
+  --> $DIR/iter_filter_is_some.rs:34:58
+   |
+LL |         let _ = vec![Some(1), None, Some(3)].into_iter().filter(|a| { std::option::Option::is_some(a) });
+   |                                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_some` on iterator over `Option`
+  --> $DIR/iter_filter_is_some.rs:39:58
+   |
+LL |         let _ = vec![Some(1), None, Some(3)].into_iter().filter(|&a| a.is_some());
+   |                                                          ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_some` on iterator over `Option`
+  --> $DIR/iter_filter_is_some.rs:43:58
+   |
+LL |         let _ = vec![Some(1), None, Some(3)].into_iter().filter(|&o| { o.is_some() });
+   |                                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_some` on iterator over `Option`
+  --> $DIR/iter_filter_is_some.rs:48:58
+   |
+LL |         let _ = vec![Some(1), None, Some(3)].into_iter().filter(|ref a| a.is_some());
+   |                                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: `filter` for `is_some` on iterator over `Option`
+  --> $DIR/iter_filter_is_some.rs:52:58
+   |
+LL |         let _ = vec![Some(1), None, Some(3)].into_iter().filter(|ref o| { o.is_some() });
+   |                                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_without_into_iter.rs b/src/tools/clippy/tests/ui/iter_without_into_iter.rs
index 29f526b455c..3054d848efb 100644
--- a/src/tools/clippy/tests/ui/iter_without_into_iter.rs
+++ b/src/tools/clippy/tests/ui/iter_without_into_iter.rs
@@ -1,5 +1,7 @@
 //@no-rustfix
+//@aux-build:proc_macros.rs
 #![warn(clippy::iter_without_into_iter)]
+extern crate proc_macros;
 
 pub struct S1;
 impl S1 {
@@ -121,4 +123,33 @@ impl S12 {
     }
 }
 
+pub struct Issue12037;
+macro_rules! generate_impl {
+    () => {
+        impl Issue12037 {
+            fn iter(&self) -> std::slice::Iter<'_, u8> {
+                todo!()
+            }
+        }
+    };
+}
+generate_impl!();
+
+proc_macros::external! {
+    pub struct ImplWithForeignSpan;
+    impl ImplWithForeignSpan {
+        fn iter(&self) -> std::slice::Iter<'_, u8> {
+            todo!()
+        }
+    }
+}
+
+pub struct Allowed;
+impl Allowed {
+    #[allow(clippy::iter_without_into_iter)]
+    pub fn iter(&self) -> std::slice::Iter<'_, u8> {
+        todo!()
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/iter_without_into_iter.stderr b/src/tools/clippy/tests/ui/iter_without_into_iter.stderr
index af5afd47bfc..4cf20e2aa56 100644
--- a/src/tools/clippy/tests/ui/iter_without_into_iter.stderr
+++ b/src/tools/clippy/tests/ui/iter_without_into_iter.stderr
@@ -1,5 +1,5 @@
 error: `iter` method without an `IntoIterator` impl for `&S1`
-  --> $DIR/iter_without_into_iter.rs:6:5
+  --> $DIR/iter_without_into_iter.rs:8:5
    |
 LL | /     pub fn iter(&self) -> std::slice::Iter<'_, u8> {
 LL | |
@@ -22,7 +22,7 @@ LL + }
    |
 
 error: `iter_mut` method without an `IntoIterator` impl for `&mut S1`
-  --> $DIR/iter_without_into_iter.rs:10:5
+  --> $DIR/iter_without_into_iter.rs:12:5
    |
 LL | /     pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
 LL | |
@@ -43,7 +43,7 @@ LL + }
    |
 
 error: `iter` method without an `IntoIterator` impl for `&S3<'a>`
-  --> $DIR/iter_without_into_iter.rs:26:5
+  --> $DIR/iter_without_into_iter.rs:28:5
    |
 LL | /     pub fn iter(&self) -> std::slice::Iter<'_, u8> {
 LL | |
@@ -64,7 +64,7 @@ LL + }
    |
 
 error: `iter_mut` method without an `IntoIterator` impl for `&mut S3<'a>`
-  --> $DIR/iter_without_into_iter.rs:30:5
+  --> $DIR/iter_without_into_iter.rs:32:5
    |
 LL | /     pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
 LL | |
@@ -85,7 +85,7 @@ LL + }
    |
 
 error: `iter` method without an `IntoIterator` impl for `&S8<T>`
-  --> $DIR/iter_without_into_iter.rs:67:5
+  --> $DIR/iter_without_into_iter.rs:69:5
    |
 LL | /     pub fn iter(&self) -> std::slice::Iter<'static, T> {
 LL | |         todo!()
@@ -105,7 +105,7 @@ LL + }
    |
 
 error: `iter` method without an `IntoIterator` impl for `&S9<T>`
-  --> $DIR/iter_without_into_iter.rs:75:5
+  --> $DIR/iter_without_into_iter.rs:77:5
    |
 LL | /     pub fn iter(&self) -> std::slice::Iter<'_, T> {
 LL | |
@@ -126,7 +126,7 @@ LL + }
    |
 
 error: `iter_mut` method without an `IntoIterator` impl for `&mut S9<T>`
-  --> $DIR/iter_without_into_iter.rs:79:5
+  --> $DIR/iter_without_into_iter.rs:81:5
    |
 LL | /     pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
 LL | |
@@ -146,5 +146,29 @@ LL +     }
 LL + }
    |
 
-error: aborting due to 7 previous errors
+error: `iter` method without an `IntoIterator` impl for `&Issue12037`
+  --> $DIR/iter_without_into_iter.rs:130:13
+   |
+LL | /             fn iter(&self) -> std::slice::Iter<'_, u8> {
+LL | |                 todo!()
+LL | |             }
+   | |_____________^
+...
+LL |   generate_impl!();
+   |   ---------------- in this macro invocation
+   |
+   = note: this error originates in the macro `generate_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider implementing `IntoIterator` for `&Issue12037`
+   |
+LL ~         
+LL + impl IntoIterator for &Issue12037 {
+LL +     type IntoIter = std::slice::Iter<'_, u8>;
+LL +     type Item = &u8;
+LL +     fn into_iter(self) -> Self::IntoIter {
+LL +         self.iter()
+LL +     }
+LL + }
+   |
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/let_unit.fixed b/src/tools/clippy/tests/ui/let_unit.fixed
index f98ce9d50a9..4d41b5e5e50 100644
--- a/src/tools/clippy/tests/ui/let_unit.fixed
+++ b/src/tools/clippy/tests/ui/let_unit.fixed
@@ -13,7 +13,14 @@ fn main() {
     let _y = 1; // this is fine
     let _z = ((), 1); // this as well
     if true {
-        ();
+        // do not lint this, since () is explicit
+        let _a = ();
+        let () = dummy();
+        let () = ();
+        () = dummy();
+        () = ();
+        let _a: () = ();
+        let _a: () = dummy();
     }
 
     consume_units_with_for_loop(); // should be fine as well
@@ -23,6 +30,8 @@ fn main() {
     let_and_return!(()) // should be fine
 }
 
+fn dummy() {}
+
 // Related to issue #1964
 fn consume_units_with_for_loop() {
     // `for_let_unit` lint should not be triggered by consuming them using for loop.
@@ -74,40 +83,29 @@ fn _returns_generic() {
         x.then(|| T::default())
     }
 
-    let _: () = f(); // Ok
-    let _: () = f(); // Lint.
+    let _: () = f();
+    let x: () = f();
 
-    let _: () = f2(0i32); // Ok
-    let _: () = f2(0i32); // Lint.
+    let _: () = f2(0i32);
+    let x: () = f2(0i32);
 
-    f3(()); // Lint
-    f3(()); // Lint
+    let _: () = f3(());
+    let x: () = f3(());
 
-    // Should lint:
-    // fn f4<T>(mut x: Vec<T>) -> T {
-    //    x.pop().unwrap()
-    // }
-    // let _: () = f4(vec![()]);
-    // let x: () = f4(vec![()]);
+    fn f4<T>(mut x: Vec<T>) -> T {
+        x.pop().unwrap()
+    }
+    let _: () = f4(vec![()]);
+    let x: () = f4(vec![()]);
 
-    // Ok
     let _: () = {
         let x = 5;
         f2(x)
     };
 
-    let _: () = if true { f() } else { f2(0) }; // Ok
-    let _: () = if true { f() } else { f2(0) }; // Lint
-
-    // Ok
-    let _: () = match Some(0) {
-        None => f2(1),
-        Some(0) => f(),
-        Some(1) => f2(3),
-        Some(_) => f2('x'),
-    };
+    let _: () = if true { f() } else { f2(0) };
+    let x: () = if true { f() } else { f2(0) };
 
-    // Lint
     match Some(0) {
         None => f2(1),
         Some(0) => f(),
@@ -155,7 +153,7 @@ fn _returns_generic() {
         {
             let _: () = x;
             let _: () = y;
-            z;
+            let _: () = z;
             let _: () = x1;
             let _: () = x2;
             let _: () = opt;
diff --git a/src/tools/clippy/tests/ui/let_unit.rs b/src/tools/clippy/tests/ui/let_unit.rs
index 6d942ca8908..daa660be25e 100644
--- a/src/tools/clippy/tests/ui/let_unit.rs
+++ b/src/tools/clippy/tests/ui/let_unit.rs
@@ -13,7 +13,14 @@ fn main() {
     let _y = 1; // this is fine
     let _z = ((), 1); // this as well
     if true {
+        // do not lint this, since () is explicit
         let _a = ();
+        let () = dummy();
+        let () = ();
+        () = dummy();
+        () = ();
+        let _a: () = ();
+        let _a: () = dummy();
     }
 
     consume_units_with_for_loop(); // should be fine as well
@@ -23,6 +30,8 @@ fn main() {
     let_and_return!(()) // should be fine
 }
 
+fn dummy() {}
+
 // Related to issue #1964
 fn consume_units_with_for_loop() {
     // `for_let_unit` lint should not be triggered by consuming them using for loop.
@@ -74,41 +83,30 @@ fn _returns_generic() {
         x.then(|| T::default())
     }
 
-    let _: () = f(); // Ok
-    let x: () = f(); // Lint.
+    let _: () = f();
+    let x: () = f();
 
-    let _: () = f2(0i32); // Ok
-    let x: () = f2(0i32); // Lint.
+    let _: () = f2(0i32);
+    let x: () = f2(0i32);
 
-    let _: () = f3(()); // Lint
-    let x: () = f3(()); // Lint
+    let _: () = f3(());
+    let x: () = f3(());
 
-    // Should lint:
-    // fn f4<T>(mut x: Vec<T>) -> T {
-    //    x.pop().unwrap()
-    // }
-    // let _: () = f4(vec![()]);
-    // let x: () = f4(vec![()]);
+    fn f4<T>(mut x: Vec<T>) -> T {
+        x.pop().unwrap()
+    }
+    let _: () = f4(vec![()]);
+    let x: () = f4(vec![()]);
 
-    // Ok
     let _: () = {
         let x = 5;
         f2(x)
     };
 
-    let _: () = if true { f() } else { f2(0) }; // Ok
-    let x: () = if true { f() } else { f2(0) }; // Lint
-
-    // Ok
-    let _: () = match Some(0) {
-        None => f2(1),
-        Some(0) => f(),
-        Some(1) => f2(3),
-        Some(_) => f2('x'),
-    };
+    let _: () = if true { f() } else { f2(0) };
+    let x: () = if true { f() } else { f2(0) };
 
-    // Lint
-    let _: () = match Some(0) {
+    let x = match Some(0) {
         None => f2(1),
         Some(0) => f(),
         Some(1) => f2(3),
diff --git a/src/tools/clippy/tests/ui/let_unit.stderr b/src/tools/clippy/tests/ui/let_unit.stderr
index de106f50e0e..00a3c439ba0 100644
--- a/src/tools/clippy/tests/ui/let_unit.stderr
+++ b/src/tools/clippy/tests/ui/let_unit.stderr
@@ -8,13 +8,7 @@ LL |     let _x = println!("x");
    = help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]`
 
 error: this let-binding has unit value
-  --> $DIR/let_unit.rs:16:9
-   |
-LL |         let _a = ();
-   |         ^^^^^^^^^^^^ help: omit the `let` binding: `();`
-
-error: this let-binding has unit value
-  --> $DIR/let_unit.rs:51:5
+  --> $DIR/let_unit.rs:60:5
    |
 LL | /     let _ = v
 LL | |         .into_iter()
@@ -37,45 +31,9 @@ LL +         .unwrap();
    |
 
 error: this let-binding has unit value
-  --> $DIR/let_unit.rs:78:5
-   |
-LL |     let x: () = f(); // Lint.
-   |     ^^^^-^^^^^^^^^^^
-   |         |
-   |         help: use a wild (`_`) binding: `_`
-
-error: this let-binding has unit value
-  --> $DIR/let_unit.rs:81:5
+  --> $DIR/let_unit.rs:109:5
    |
-LL |     let x: () = f2(0i32); // Lint.
-   |     ^^^^-^^^^^^^^^^^^^^^^
-   |         |
-   |         help: use a wild (`_`) binding: `_`
-
-error: this let-binding has unit value
-  --> $DIR/let_unit.rs:83:5
-   |
-LL |     let _: () = f3(()); // Lint
-   |     ^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `f3(());`
-
-error: this let-binding has unit value
-  --> $DIR/let_unit.rs:84:5
-   |
-LL |     let x: () = f3(()); // Lint
-   |     ^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `f3(());`
-
-error: this let-binding has unit value
-  --> $DIR/let_unit.rs:100:5
-   |
-LL |     let x: () = if true { f() } else { f2(0) }; // Lint
-   |     ^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         help: use a wild (`_`) binding: `_`
-
-error: this let-binding has unit value
-  --> $DIR/let_unit.rs:111:5
-   |
-LL | /     let _: () = match Some(0) {
+LL | /     let x = match Some(0) {
 LL | |         None => f2(1),
 LL | |         Some(0) => f(),
 LL | |         Some(1) => f2(3),
@@ -93,11 +51,5 @@ LL +         Some(_) => (),
 LL +     };
    |
 
-error: this let-binding has unit value
-  --> $DIR/let_unit.rs:158:13
-   |
-LL |             let _: () = z;
-   |             ^^^^^^^^^^^^^^ help: omit the `let` binding: `z;`
-
-error: aborting due to 10 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.fixed b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed
new file mode 100644
index 00000000000..8c34b51103c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed
@@ -0,0 +1,51 @@
+//@aux-build:option_helpers.rs
+#![warn(clippy::manual_is_variant_and)]
+
+#[macro_use]
+extern crate option_helpers;
+
+#[rustfmt::skip]
+fn option_methods() {
+    let opt = Some(1);
+
+    // Check for `option.map(_).unwrap_or_default()` use.
+    // Single line case.
+    let _ = opt.is_some_and(|x| x > 1);
+    // Multi-line cases.
+    let _ = opt.is_some_and(|x| {
+        x > 1
+    });
+    let _ = opt.is_some_and(|x| x > 1);
+    let _ = opt
+        .is_some_and(|x| x > 1);
+
+    // won't fix because the return type of the closure is not `bool`
+    let _ = opt.map(|x| x + 1).unwrap_or_default();
+
+    let opt2 = Some('a');
+    let _ = opt2.is_some_and(char::is_alphanumeric); // should lint
+    let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint
+}
+
+#[rustfmt::skip]
+fn result_methods() {
+    let res: Result<i32, ()> = Ok(1);
+
+    // multi line cases
+    let _ = res.is_ok_and(|x| {
+        x > 1
+    });
+    let _ = res.is_ok_and(|x| x > 1);
+
+    // won't fix because the return type of the closure is not `bool`
+    let _ = res.map(|x| x + 1).unwrap_or_default();
+
+    let res2: Result<char, ()> = Ok('a');
+    let _ = res2.is_ok_and(char::is_alphanumeric); // should lint
+    let _ = opt_map!(res2, |x| x == 'a').unwrap_or_default(); // should not lint
+}
+
+fn main() {
+    option_methods();
+    result_methods();
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.rs b/src/tools/clippy/tests/ui/manual_is_variant_and.rs
new file mode 100644
index 00000000000..25b2489d942
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_is_variant_and.rs
@@ -0,0 +1,57 @@
+//@aux-build:option_helpers.rs
+#![warn(clippy::manual_is_variant_and)]
+
+#[macro_use]
+extern crate option_helpers;
+
+#[rustfmt::skip]
+fn option_methods() {
+    let opt = Some(1);
+
+    // Check for `option.map(_).unwrap_or_default()` use.
+    // Single line case.
+    let _ = opt.map(|x| x > 1)
+        // Should lint even though this call is on a separate line.
+        .unwrap_or_default();
+    // Multi-line cases.
+    let _ = opt.map(|x| {
+        x > 1
+    }
+    ).unwrap_or_default();
+    let _ = opt.map(|x| x > 1).unwrap_or_default();
+    let _ = opt
+        .map(|x| x > 1)
+        .unwrap_or_default();
+
+    // won't fix because the return type of the closure is not `bool`
+    let _ = opt.map(|x| x + 1).unwrap_or_default();
+
+    let opt2 = Some('a');
+    let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
+    let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint
+}
+
+#[rustfmt::skip]
+fn result_methods() {
+    let res: Result<i32, ()> = Ok(1);
+
+    // multi line cases
+    let _ = res.map(|x| {
+        x > 1
+    }
+    ).unwrap_or_default();
+    let _ = res.map(|x| x > 1)
+        .unwrap_or_default();
+
+    // won't fix because the return type of the closure is not `bool`
+    let _ = res.map(|x| x + 1).unwrap_or_default();
+
+    let res2: Result<char, ()> = Ok('a');
+    let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
+    let _ = opt_map!(res2, |x| x == 'a').unwrap_or_default(); // should not lint
+}
+
+fn main() {
+    option_methods();
+    result_methods();
+}
diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.stderr b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr
new file mode 100644
index 00000000000..c243de098dc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr
@@ -0,0 +1,82 @@
+error: called `map(<f>).unwrap_or_default()` on an `Option` value
+  --> $DIR/manual_is_variant_and.rs:13:17
+   |
+LL |       let _ = opt.map(|x| x > 1)
+   |  _________________^
+LL | |         // Should lint even though this call is on a separate line.
+LL | |         .unwrap_or_default();
+   | |____________________________^ help: use: `is_some_and(|x| x > 1)`
+   |
+   = note: `-D clippy::manual-is-variant-and` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::manual_is_variant_and)]`
+
+error: called `map(<f>).unwrap_or_default()` on an `Option` value
+  --> $DIR/manual_is_variant_and.rs:17:17
+   |
+LL |       let _ = opt.map(|x| {
+   |  _________________^
+LL | |         x > 1
+LL | |     }
+LL | |     ).unwrap_or_default();
+   | |_________________________^
+   |
+help: use
+   |
+LL ~     let _ = opt.is_some_and(|x| {
+LL +         x > 1
+LL ~     });
+   |
+
+error: called `map(<f>).unwrap_or_default()` on an `Option` value
+  --> $DIR/manual_is_variant_and.rs:21:17
+   |
+LL |     let _ = opt.map(|x| x > 1).unwrap_or_default();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(|x| x > 1)`
+
+error: called `map(<f>).unwrap_or_default()` on an `Option` value
+  --> $DIR/manual_is_variant_and.rs:23:10
+   |
+LL |           .map(|x| x > 1)
+   |  __________^
+LL | |         .unwrap_or_default();
+   | |____________________________^ help: use: `is_some_and(|x| x > 1)`
+
+error: called `map(<f>).unwrap_or_default()` on an `Option` value
+  --> $DIR/manual_is_variant_and.rs:30:18
+   |
+LL |     let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(char::is_alphanumeric)`
+
+error: called `map(<f>).unwrap_or_default()` on a `Result` value
+  --> $DIR/manual_is_variant_and.rs:39:17
+   |
+LL |       let _ = res.map(|x| {
+   |  _________________^
+LL | |         x > 1
+LL | |     }
+LL | |     ).unwrap_or_default();
+   | |_________________________^
+   |
+help: use
+   |
+LL ~     let _ = res.is_ok_and(|x| {
+LL +         x > 1
+LL ~     });
+   |
+
+error: called `map(<f>).unwrap_or_default()` on a `Result` value
+  --> $DIR/manual_is_variant_and.rs:43:17
+   |
+LL |       let _ = res.map(|x| x > 1)
+   |  _________________^
+LL | |         .unwrap_or_default();
+   | |____________________________^ help: use: `is_ok_and(|x| x > 1)`
+
+error: called `map(<f>).unwrap_or_default()` on a `Result` value
+  --> $DIR/manual_is_variant_and.rs:50:18
+   |
+LL |     let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_ok_and(char::is_alphanumeric)`
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/map_clone.fixed b/src/tools/clippy/tests/ui/map_clone.fixed
index dd979013d3c..08b155a1aea 100644
--- a/src/tools/clippy/tests/ui/map_clone.fixed
+++ b/src/tools/clippy/tests/ui/map_clone.fixed
@@ -4,6 +4,8 @@
     clippy::iter_cloned_collect,
     clippy::many_single_char_names,
     clippy::redundant_clone,
+    clippy::redundant_closure,
+    clippy::useless_asref,
     clippy::useless_vec
 )]
 
@@ -60,4 +62,26 @@ fn main() {
 
         let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone());
     }
+
+    let x = Some(String::new());
+    let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint.
+    let y = x.cloned();
+    //~^ ERROR: you are explicitly cloning with `.map()`
+    let y = x.cloned();
+    //~^ ERROR: you are explicitly cloning with `.map()`
+    let y = x.cloned();
+    //~^ ERROR: you are explicitly cloning with `.map()`
+
+    // Testing with `Result` now.
+    let x: Result<String, ()> = Ok(String::new());
+    let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint.
+    let y = x.cloned();
+    //~^ ERROR: you are explicitly cloning with `.map()`
+    let y = x.cloned();
+
+    // We ensure that no warning is emitted here because `useless_asref` is taking over.
+    let x = Some(String::new());
+    let y = x.as_ref().map(|x| String::clone(x));
+    let x: Result<String, ()> = Ok(String::new());
+    let y = x.as_ref().map(|x| String::clone(x));
 }
diff --git a/src/tools/clippy/tests/ui/map_clone.rs b/src/tools/clippy/tests/ui/map_clone.rs
index 96cba71965f..901d9b278b4 100644
--- a/src/tools/clippy/tests/ui/map_clone.rs
+++ b/src/tools/clippy/tests/ui/map_clone.rs
@@ -4,6 +4,8 @@
     clippy::iter_cloned_collect,
     clippy::many_single_char_names,
     clippy::redundant_clone,
+    clippy::redundant_closure,
+    clippy::useless_asref,
     clippy::useless_vec
 )]
 
@@ -60,4 +62,26 @@ fn main() {
 
         let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone());
     }
+
+    let x = Some(String::new());
+    let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint.
+    let y = x.map(|x| String::clone(x));
+    //~^ ERROR: you are explicitly cloning with `.map()`
+    let y = x.map(Clone::clone);
+    //~^ ERROR: you are explicitly cloning with `.map()`
+    let y = x.map(String::clone);
+    //~^ ERROR: you are explicitly cloning with `.map()`
+
+    // Testing with `Result` now.
+    let x: Result<String, ()> = Ok(String::new());
+    let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint.
+    let y = x.map(|x| String::clone(x));
+    //~^ ERROR: you are explicitly cloning with `.map()`
+    let y = x.map(|x| String::clone(x));
+
+    // We ensure that no warning is emitted here because `useless_asref` is taking over.
+    let x = Some(String::new());
+    let y = x.as_ref().map(|x| String::clone(x));
+    let x: Result<String, ()> = Ok(String::new());
+    let y = x.as_ref().map(|x| String::clone(x));
 }
diff --git a/src/tools/clippy/tests/ui/map_clone.stderr b/src/tools/clippy/tests/ui/map_clone.stderr
index eb11f084887..9d7e9317b58 100644
--- a/src/tools/clippy/tests/ui/map_clone.stderr
+++ b/src/tools/clippy/tests/ui/map_clone.stderr
@@ -1,5 +1,5 @@
 error: you are using an explicit closure for copying elements
-  --> $DIR/map_clone.rs:11:22
+  --> $DIR/map_clone.rs:13:22
    |
 LL |     let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()`
@@ -8,34 +8,64 @@ LL |     let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
    = help: to override `-D warnings` add `#[allow(clippy::map_clone)]`
 
 error: you are using an explicit closure for cloning elements
-  --> $DIR/map_clone.rs:12:26
+  --> $DIR/map_clone.rs:14:26
    |
 LL |     let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()`
 
 error: you are using an explicit closure for copying elements
-  --> $DIR/map_clone.rs:13:23
+  --> $DIR/map_clone.rs:15:23
    |
 LL |     let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()`
 
 error: you are using an explicit closure for copying elements
-  --> $DIR/map_clone.rs:15:26
+  --> $DIR/map_clone.rs:17:26
    |
 LL |     let _: Option<u64> = Some(&16).map(|b| *b);
    |                          ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()`
 
 error: you are using an explicit closure for copying elements
-  --> $DIR/map_clone.rs:16:25
+  --> $DIR/map_clone.rs:18:25
    |
 LL |     let _: Option<u8> = Some(&1).map(|x| x.clone());
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()`
 
 error: you are needlessly cloning iterator elements
-  --> $DIR/map_clone.rs:27:29
+  --> $DIR/map_clone.rs:29:29
    |
 LL |     let _ = std::env::args().map(|v| v.clone());
    |                             ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call
 
-error: aborting due to 6 previous errors
+error: you are explicitly cloning with `.map()`
+  --> $DIR/map_clone.rs:68:13
+   |
+LL |     let y = x.map(|x| String::clone(x));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
+
+error: you are explicitly cloning with `.map()`
+  --> $DIR/map_clone.rs:70:13
+   |
+LL |     let y = x.map(Clone::clone);
+   |             ^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
+
+error: you are explicitly cloning with `.map()`
+  --> $DIR/map_clone.rs:72:13
+   |
+LL |     let y = x.map(String::clone);
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
+
+error: you are explicitly cloning with `.map()`
+  --> $DIR/map_clone.rs:78:13
+   |
+LL |     let y = x.map(|x| String::clone(x));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
+
+error: you are explicitly cloning with `.map()`
+  --> $DIR/map_clone.rs:80:13
+   |
+LL |     let y = x.map(|x| String::clone(x));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed
index db20ba29f3d..c057eba4aca 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.fixed
+++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed
@@ -1,9 +1,5 @@
 #![feature(never_type)]
-#![allow(
-    unused_mut,
-    clippy::redundant_allocation,
-    clippy::needless_pass_by_ref_mut
-)]
+#![allow(unused_mut, clippy::redundant_allocation, clippy::needless_pass_by_ref_mut)]
 #![warn(clippy::must_use_candidate)]
 use std::rc::Rc;
 use std::sync::atomic::{AtomicBool, Ordering};
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs
index d7e56130245..36019652006 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.rs
+++ b/src/tools/clippy/tests/ui/must_use_candidates.rs
@@ -1,9 +1,5 @@
 #![feature(never_type)]
-#![allow(
-    unused_mut,
-    clippy::redundant_allocation,
-    clippy::needless_pass_by_ref_mut
-)]
+#![allow(unused_mut, clippy::redundant_allocation, clippy::needless_pass_by_ref_mut)]
 #![warn(clippy::must_use_candidate)]
 use std::rc::Rc;
 use std::sync::atomic::{AtomicBool, Ordering};
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.stderr b/src/tools/clippy/tests/ui/must_use_candidates.stderr
index 39446bf6cd9..98175dbd458 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.stderr
+++ b/src/tools/clippy/tests/ui/must_use_candidates.stderr
@@ -1,5 +1,5 @@
 error: this function could have a `#[must_use]` attribute
-  --> $DIR/must_use_candidates.rs:15:1
+  --> $DIR/must_use_candidates.rs:11:1
    |
 LL | pub fn pure(i: u8) -> u8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8`
@@ -8,25 +8,25 @@ LL | pub fn pure(i: u8) -> u8 {
    = help: to override `-D warnings` add `#[allow(clippy::must_use_candidate)]`
 
 error: this method could have a `#[must_use]` attribute
-  --> $DIR/must_use_candidates.rs:20:5
+  --> $DIR/must_use_candidates.rs:16:5
    |
 LL |     pub fn inherent_pure(&self) -> u8 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8`
 
 error: this function could have a `#[must_use]` attribute
-  --> $DIR/must_use_candidates.rs:51:1
+  --> $DIR/must_use_candidates.rs:47:1
    |
 LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool`
 
 error: this function could have a `#[must_use]` attribute
-  --> $DIR/must_use_candidates.rs:63:1
+  --> $DIR/must_use_candidates.rs:59:1
    |
 LL | pub fn rcd(_x: Rc<u32>) -> bool {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc<u32>) -> bool`
 
 error: this function could have a `#[must_use]` attribute
-  --> $DIR/must_use_candidates.rs:71:1
+  --> $DIR/must_use_candidates.rs:67:1
    |
 LL | pub fn arcd(_x: Arc<u32>) -> bool {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc<u32>) -> bool`
diff --git a/src/tools/clippy/tests/ui/mutex_atomic.rs b/src/tools/clippy/tests/ui/mutex_atomic.rs
index 198b95d8c94..3a51538b742 100644
--- a/src/tools/clippy/tests/ui/mutex_atomic.rs
+++ b/src/tools/clippy/tests/ui/mutex_atomic.rs
@@ -18,9 +18,24 @@ fn main() {
     Mutex::new(&mut x as *mut u32);
     //~^ ERROR: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want
     Mutex::new(0u32);
-    //~^ ERROR: consider using an `AtomicUsize` instead of a `Mutex` here; if you just wan
+    //~^ ERROR: consider using an `AtomicU32` instead of a `Mutex` here; if you just wan
     //~| NOTE: `-D clippy::mutex-integer` implied by `-D warnings`
     Mutex::new(0i32);
-    //~^ ERROR: consider using an `AtomicIsize` instead of a `Mutex` here; if you just wan
+    //~^ ERROR: consider using an `AtomicI32` instead of a `Mutex` here; if you just wan
     Mutex::new(0f32); // there are no float atomics, so this should not lint
+    Mutex::new(0u8);
+    //~^ ERROR: consider using an `AtomicU8` instead of a `Mutex` here; if you just wan
+    Mutex::new(0i16);
+    //~^ ERROR: consider using an `AtomicI16` instead of a `Mutex` here; if you just wan
+    let _x: Mutex<i8> = Mutex::new(0);
+    //~^ ERROR: consider using an `AtomicI8` instead of a `Mutex` here; if you just wan
+    const X: i64 = 0;
+    Mutex::new(X);
+    //~^ ERROR: consider using an `AtomicI64` instead of a `Mutex` here; if you just wan
+
+    // there are no 128 atomics, so these two should not lint
+    {
+        Mutex::new(0u128);
+        let _x: Mutex<i128> = Mutex::new(0);
+    }
 }
diff --git a/src/tools/clippy/tests/ui/mutex_atomic.stderr b/src/tools/clippy/tests/ui/mutex_atomic.stderr
index 483e1ce15f6..91f73d30b53 100644
--- a/src/tools/clippy/tests/ui/mutex_atomic.stderr
+++ b/src/tools/clippy/tests/ui/mutex_atomic.stderr
@@ -31,7 +31,7 @@ error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want
 LL |     Mutex::new(&mut x as *mut u32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+error: consider using an `AtomicU32` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
   --> $DIR/mutex_atomic.rs:20:5
    |
 LL |     Mutex::new(0u32);
@@ -40,11 +40,35 @@ LL |     Mutex::new(0u32);
    = note: `-D clippy::mutex-integer` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::mutex_integer)]`
 
-error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+error: consider using an `AtomicI32` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
   --> $DIR/mutex_atomic.rs:23:5
    |
 LL |     Mutex::new(0i32);
    |     ^^^^^^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error: consider using an `AtomicU8` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+  --> $DIR/mutex_atomic.rs:26:5
+   |
+LL |     Mutex::new(0u8);
+   |     ^^^^^^^^^^^^^^^
+
+error: consider using an `AtomicI16` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+  --> $DIR/mutex_atomic.rs:28:5
+   |
+LL |     Mutex::new(0i16);
+   |     ^^^^^^^^^^^^^^^^
+
+error: consider using an `AtomicI8` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+  --> $DIR/mutex_atomic.rs:30:25
+   |
+LL |     let _x: Mutex<i8> = Mutex::new(0);
+   |                         ^^^^^^^^^^^^^
+
+error: consider using an `AtomicI64` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
+  --> $DIR/mutex_atomic.rs:33:5
+   |
+LL |     Mutex::new(X);
+   |     ^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed b/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed
index 245d36cb734..237f5f5b97a 100644
--- a/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed
+++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed
@@ -25,9 +25,13 @@ fn main() {
 
     permissions.set_mode(0o644);
     permissions.set_mode(0o704);
+    // no error
+    permissions.set_mode(0b111_000_100);
 
     // DirBuilderExt::mode
     let mut builder = DirBuilder::new();
     builder.mode(0o755);
     builder.mode(0o406);
+    // no error
+    permissions.set_mode(0b111000100);
 }
diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs b/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs
index d1559cba554..c8da5dbcec2 100644
--- a/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs
+++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs
@@ -25,9 +25,13 @@ fn main() {
 
     permissions.set_mode(644);
     permissions.set_mode(0o704);
+    // no error
+    permissions.set_mode(0b111_000_100);
 
     // DirBuilderExt::mode
     let mut builder = DirBuilder::new();
     builder.mode(755);
     builder.mode(0o406);
+    // no error
+    permissions.set_mode(0b111000100);
 }
diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr b/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr
index 78c8f1a2fcf..83688c1b451 100644
--- a/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr
+++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr
@@ -20,7 +20,7 @@ LL |     permissions.set_mode(644);
    |                          ^^^ help: consider using an octal literal instead: `0o644`
 
 error: using a non-octal value to set unix file permissions
-  --> $DIR/non_octal_unix_permissions.rs:31:18
+  --> $DIR/non_octal_unix_permissions.rs:33:18
    |
 LL |     builder.mode(755);
    |                  ^^^ help: consider using an octal literal instead: `0o755`
diff --git a/src/tools/clippy/tests/ui/option_as_ref_cloned.fixed b/src/tools/clippy/tests/ui/option_as_ref_cloned.fixed
new file mode 100644
index 00000000000..394dad219f7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_as_ref_cloned.fixed
@@ -0,0 +1,21 @@
+#![warn(clippy::option_as_ref_cloned)]
+#![allow(clippy::clone_on_copy)]
+
+fn main() {
+    let mut x = Some(String::new());
+
+    let _: Option<String> = x.clone();
+    let _: Option<String> = x.clone();
+
+    let y = x.as_ref();
+    let _: Option<&String> = y.clone();
+
+    macro_rules! cloned_recv {
+        () => {
+            x.as_ref()
+        };
+    }
+
+    // Don't lint when part of the expression is from a macro
+    let _: Option<String> = cloned_recv!().cloned();
+}
diff --git a/src/tools/clippy/tests/ui/option_as_ref_cloned.rs b/src/tools/clippy/tests/ui/option_as_ref_cloned.rs
new file mode 100644
index 00000000000..7243957927b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_as_ref_cloned.rs
@@ -0,0 +1,21 @@
+#![warn(clippy::option_as_ref_cloned)]
+#![allow(clippy::clone_on_copy)]
+
+fn main() {
+    let mut x = Some(String::new());
+
+    let _: Option<String> = x.as_ref().cloned();
+    let _: Option<String> = x.as_mut().cloned();
+
+    let y = x.as_ref();
+    let _: Option<&String> = y.as_ref().cloned();
+
+    macro_rules! cloned_recv {
+        () => {
+            x.as_ref()
+        };
+    }
+
+    // Don't lint when part of the expression is from a macro
+    let _: Option<String> = cloned_recv!().cloned();
+}
diff --git a/src/tools/clippy/tests/ui/option_as_ref_cloned.stderr b/src/tools/clippy/tests/ui/option_as_ref_cloned.stderr
new file mode 100644
index 00000000000..ea03da3b69f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/option_as_ref_cloned.stderr
@@ -0,0 +1,37 @@
+error: cloning an `Option<_>` using `.as_ref().cloned()`
+  --> $DIR/option_as_ref_cloned.rs:7:31
+   |
+LL |     let _: Option<String> = x.as_ref().cloned();
+   |                               ^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::option-as-ref-cloned` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::option_as_ref_cloned)]`
+help: this can be written more concisely by cloning the `Option<_>` directly
+   |
+LL |     let _: Option<String> = x.clone();
+   |                               ~~~~~
+
+error: cloning an `Option<_>` using `.as_mut().cloned()`
+  --> $DIR/option_as_ref_cloned.rs:8:31
+   |
+LL |     let _: Option<String> = x.as_mut().cloned();
+   |                               ^^^^^^^^^^^^^^^
+   |
+help: this can be written more concisely by cloning the `Option<_>` directly
+   |
+LL |     let _: Option<String> = x.clone();
+   |                               ~~~~~
+
+error: cloning an `Option<_>` using `.as_ref().cloned()`
+  --> $DIR/option_as_ref_cloned.rs:11:32
+   |
+LL |     let _: Option<&String> = y.as_ref().cloned();
+   |                                ^^^^^^^^^^^^^^^
+   |
+help: this can be written more concisely by cloning the `Option<_>` directly
+   |
+LL |     let _: Option<&String> = y.clone();
+   |                                ~~~~~
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_as_str.fixed b/src/tools/clippy/tests/ui/redundant_as_str.fixed
index a38523a7c79..4185b402226 100644
--- a/src/tools/clippy/tests/ui/redundant_as_str.fixed
+++ b/src/tools/clippy/tests/ui/redundant_as_str.fixed
@@ -11,7 +11,7 @@ fn main() {
     let _no_as_str = string.as_bytes();
     let _no_as_str = string.is_empty();
 
-    // These methods are not redundant, and are equivelant to
+    // These methods are not redundant, and are equivalent to
     // doing dereferencing the string and applying the method
     let _not_redundant = string.as_str().escape_unicode();
     let _not_redundant = string.as_str().trim();
diff --git a/src/tools/clippy/tests/ui/redundant_as_str.rs b/src/tools/clippy/tests/ui/redundant_as_str.rs
index 33adb609996..7a74d8a55de 100644
--- a/src/tools/clippy/tests/ui/redundant_as_str.rs
+++ b/src/tools/clippy/tests/ui/redundant_as_str.rs
@@ -11,7 +11,7 @@ fn main() {
     let _no_as_str = string.as_bytes();
     let _no_as_str = string.is_empty();
 
-    // These methods are not redundant, and are equivelant to
+    // These methods are not redundant, and are equivalent to
     // doing dereferencing the string and applying the method
     let _not_redundant = string.as_str().escape_unicode();
     let _not_redundant = string.as_str().trim();
diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs
index 1ea0d65bf1e..4fb6c08bb44 100644
--- a/src/tools/clippy/tests/ui/regex.rs
+++ b/src/tools/clippy/tests/ui/regex.rs
@@ -113,7 +113,7 @@ fn trivial_regex() {
     // #6005: unicode classes in bytes::Regex
     let a_byte_of_unicode = BRegex::new(r"\p{C}");
 
-    // start and end word boundry, introduced in regex 0.10
+    // start and end word boundary, introduced in regex 0.10
     let _ = BRegex::new(r"\<word\>");
     let _ = BRegex::new(r"\b{start}word\b{end}");
 }
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.fixed b/src/tools/clippy/tests/ui/single_char_pattern.fixed
index 79e7eda4070..9573fdbcfde 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.fixed
+++ b/src/tools/clippy/tests/ui/single_char_pattern.fixed
@@ -42,6 +42,8 @@ fn main() {
     x.split('\n');
     x.split('\'');
     x.split('\'');
+    // Issue #11973: Don't escape `"` in `'"'`
+    x.split('"');
 
     let h = HashSet::<String>::new();
     h.contains("X"); // should not warn
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.rs b/src/tools/clippy/tests/ui/single_char_pattern.rs
index 81962c0a6e9..8a04480dbc6 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.rs
+++ b/src/tools/clippy/tests/ui/single_char_pattern.rs
@@ -42,6 +42,8 @@ fn main() {
     x.split("\n");
     x.split("'");
     x.split("\'");
+    // Issue #11973: Don't escape `"` in `'"'`
+    x.split("\"");
 
     let h = HashSet::<String>::new();
     h.contains("X"); // should not warn
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr
index 6e57ab3489f..781ab316d9d 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.stderr
+++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr
@@ -182,58 +182,64 @@ LL |     x.split("\'");
    |             ^^^^ help: try using a `char` instead: `'\''`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:49:31
+  --> $DIR/single_char_pattern.rs:46:13
+   |
+LL |     x.split("\"");
+   |             ^^^^ help: try using a `char` instead: `'"'`
+
+error: single-character string constant used as pattern
+  --> $DIR/single_char_pattern.rs:51:31
    |
 LL |     x.replace(';', ",").split(","); // issue #2978
    |                               ^^^ help: try using a `char` instead: `','`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:50:19
+  --> $DIR/single_char_pattern.rs:52:19
    |
 LL |     x.starts_with("\x03"); // issue #2996
    |                   ^^^^^^ help: try using a `char` instead: `'\x03'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:57:13
+  --> $DIR/single_char_pattern.rs:59:13
    |
 LL |     x.split(r"a");
    |             ^^^^ help: try using a `char` instead: `'a'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:58:13
+  --> $DIR/single_char_pattern.rs:60:13
    |
 LL |     x.split(r#"a"#);
    |             ^^^^^^ help: try using a `char` instead: `'a'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:59:13
+  --> $DIR/single_char_pattern.rs:61:13
    |
 LL |     x.split(r###"a"###);
    |             ^^^^^^^^^^ help: try using a `char` instead: `'a'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:60:13
+  --> $DIR/single_char_pattern.rs:62:13
    |
 LL |     x.split(r###"'"###);
    |             ^^^^^^^^^^ help: try using a `char` instead: `'\''`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:61:13
+  --> $DIR/single_char_pattern.rs:63:13
    |
 LL |     x.split(r###"#"###);
    |             ^^^^^^^^^^ help: try using a `char` instead: `'#'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:63:13
+  --> $DIR/single_char_pattern.rs:65:13
    |
 LL |     x.split(r#"\"#);
    |             ^^^^^^ help: try using a `char` instead: `'\\'`
 
 error: single-character string constant used as pattern
-  --> $DIR/single_char_pattern.rs:64:13
+  --> $DIR/single_char_pattern.rs:66:13
    |
 LL |     x.split(r"\");
    |             ^^^^ help: try using a `char` instead: `'\\'`
 
-error: aborting due to 39 previous errors
+error: aborting due to 40 previous errors
 
diff --git a/src/tools/clippy/tests/ui/str_split.fixed b/src/tools/clippy/tests/ui/str_split.fixed
new file mode 100644
index 00000000000..4f33241da7a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/str_split.fixed
@@ -0,0 +1,145 @@
+#![warn(clippy::str_split_at_newline)]
+
+use core::str::Split;
+use std::ops::Deref;
+
+struct NotStr<'a> {
+    s: &'a str,
+}
+
+impl<'a> NotStr<'a> {
+    fn trim(&'a self) -> &'a str {
+        self.s
+    }
+}
+
+struct DerefsIntoNotStr<'a> {
+    not_str: &'a NotStr<'a>,
+}
+
+impl<'a> Deref for DerefsIntoNotStr<'a> {
+    type Target = NotStr<'a>;
+
+    fn deref(&self) -> &Self::Target {
+        self.not_str
+    }
+}
+
+struct DerefsIntoStr<'a> {
+    s: &'a str,
+}
+
+impl<'a> Deref for DerefsIntoStr<'a> {
+    type Target = str;
+
+    fn deref(&self) -> &Self::Target {
+        self.s
+    }
+}
+
+macro_rules! trim_split {
+    ( $x:expr, $y:expr ) => {
+        $x.trim().split($y);
+    };
+}
+
+macro_rules! make_str {
+    ( $x: expr ) => {
+        format!("x={}", $x)
+    };
+}
+
+fn main() {
+    let s1 = "hello\nworld\n";
+    let s2 = s1.to_owned();
+
+    // CASES THAT SHOULD EMIT A LINT
+
+    // Splitting a `str` variable at "\n" or "\r\n" after trimming should warn
+    let _ = s1.lines();
+    #[allow(clippy::single_char_pattern)]
+    let _ = s1.lines();
+    let _ = s1.lines();
+
+    // Splitting a `String` variable at "\n" or "\r\n" after trimming should warn
+    let _ = s2.lines();
+    #[allow(clippy::single_char_pattern)]
+    let _ = s2.lines();
+    let _ = s2.lines();
+
+    // Splitting a variable that derefs into `str` at "\n" or "\r\n" after trimming should warn.
+    let s3 = DerefsIntoStr { s: s1 };
+    let _ = s3.lines();
+    #[allow(clippy::single_char_pattern)]
+    let _ = s3.lines();
+    let _ = s3.lines();
+
+    // If the `&str` is generated by a macro then the macro should not be expanded in the suggested fix.
+    let _ = make_str!(s1).lines();
+
+    // CASES THAT SHOULD NOT EMIT A LINT
+
+    // Splitting a `str` constant at "\n" or "\r\n" after trimming should not warn
+    let _ = "hello\nworld\n".trim().split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = "hello\nworld\n".trim().split("\n");
+    let _ = "hello\nworld\n".trim().split("\r\n");
+
+    // Splitting a `str` variable at "\n" or "\r\n" without trimming should not warn, since it is not
+    // equivalent
+    let _ = s1.split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s1.split("\n");
+    let _ = s1.split("\r\n");
+
+    // Splitting a `String` variable at "\n" or "\r\n" without trimming should not warn.
+    let _ = s2.split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s2.split("\n");
+
+    // Splitting a variable that derefs into `str` at "\n" or "\r\n" without trimming should not warn.
+    let _ = s3.split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s3.split("\n");
+    let _ = s3.split("\r\n");
+    let _ = s2.split("\r\n");
+
+    // Splitting a `str` variable at other separators should not warn
+    let _ = s1.trim().split('\r');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s1.trim().split("\r");
+    let _ = s1.trim().split("\n\r");
+    let _ = s1.trim().split("\r \n");
+
+    // Splitting a `String` variable at other separators should not warn
+    let _ = s2.trim().split('\r');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s2.trim().split("\r");
+    let _ = s2.trim().split("\n\r");
+
+    // Splitting a variable that derefs into `str` at other separators should not warn
+    let _ = s3.trim().split('\r');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s3.trim().split("\r");
+    let _ = s3.trim().split("\n\r");
+    let _ = s3.trim().split("\r \n");
+    let _ = s2.trim().split("\r \n");
+
+    // Using `trim` and `split` on other types should not warn
+    let not_str = NotStr { s: s1 };
+    let _ = not_str.trim().split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = not_str.trim().split("\n");
+    let _ = not_str.trim().split("\r\n");
+    let derefs_into_not_str = DerefsIntoNotStr { not_str: &not_str };
+    let _ = derefs_into_not_str.trim().split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = derefs_into_not_str.trim().split("\n");
+    let _ = derefs_into_not_str.trim().split("\r\n");
+
+    // Code generated by macros should not create a warning
+    trim_split!(s1, "\r\n");
+    trim_split!("hello\nworld\n", "\r\n");
+    trim_split!(s2, "\r\n");
+    trim_split!(s3, "\r\n");
+}
diff --git a/src/tools/clippy/tests/ui/str_split.rs b/src/tools/clippy/tests/ui/str_split.rs
new file mode 100644
index 00000000000..f24caa61c30
--- /dev/null
+++ b/src/tools/clippy/tests/ui/str_split.rs
@@ -0,0 +1,145 @@
+#![warn(clippy::str_split_at_newline)]
+
+use core::str::Split;
+use std::ops::Deref;
+
+struct NotStr<'a> {
+    s: &'a str,
+}
+
+impl<'a> NotStr<'a> {
+    fn trim(&'a self) -> &'a str {
+        self.s
+    }
+}
+
+struct DerefsIntoNotStr<'a> {
+    not_str: &'a NotStr<'a>,
+}
+
+impl<'a> Deref for DerefsIntoNotStr<'a> {
+    type Target = NotStr<'a>;
+
+    fn deref(&self) -> &Self::Target {
+        self.not_str
+    }
+}
+
+struct DerefsIntoStr<'a> {
+    s: &'a str,
+}
+
+impl<'a> Deref for DerefsIntoStr<'a> {
+    type Target = str;
+
+    fn deref(&self) -> &Self::Target {
+        self.s
+    }
+}
+
+macro_rules! trim_split {
+    ( $x:expr, $y:expr ) => {
+        $x.trim().split($y);
+    };
+}
+
+macro_rules! make_str {
+    ( $x: expr ) => {
+        format!("x={}", $x)
+    };
+}
+
+fn main() {
+    let s1 = "hello\nworld\n";
+    let s2 = s1.to_owned();
+
+    // CASES THAT SHOULD EMIT A LINT
+
+    // Splitting a `str` variable at "\n" or "\r\n" after trimming should warn
+    let _ = s1.trim().split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s1.trim().split("\n");
+    let _ = s1.trim().split("\r\n");
+
+    // Splitting a `String` variable at "\n" or "\r\n" after trimming should warn
+    let _ = s2.trim().split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s2.trim().split("\n");
+    let _ = s2.trim().split("\r\n");
+
+    // Splitting a variable that derefs into `str` at "\n" or "\r\n" after trimming should warn.
+    let s3 = DerefsIntoStr { s: s1 };
+    let _ = s3.trim().split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s3.trim().split("\n");
+    let _ = s3.trim().split("\r\n");
+
+    // If the `&str` is generated by a macro then the macro should not be expanded in the suggested fix.
+    let _ = make_str!(s1).trim().split('\n');
+
+    // CASES THAT SHOULD NOT EMIT A LINT
+
+    // Splitting a `str` constant at "\n" or "\r\n" after trimming should not warn
+    let _ = "hello\nworld\n".trim().split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = "hello\nworld\n".trim().split("\n");
+    let _ = "hello\nworld\n".trim().split("\r\n");
+
+    // Splitting a `str` variable at "\n" or "\r\n" without trimming should not warn, since it is not
+    // equivalent
+    let _ = s1.split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s1.split("\n");
+    let _ = s1.split("\r\n");
+
+    // Splitting a `String` variable at "\n" or "\r\n" without trimming should not warn.
+    let _ = s2.split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s2.split("\n");
+
+    // Splitting a variable that derefs into `str` at "\n" or "\r\n" without trimming should not warn.
+    let _ = s3.split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s3.split("\n");
+    let _ = s3.split("\r\n");
+    let _ = s2.split("\r\n");
+
+    // Splitting a `str` variable at other separators should not warn
+    let _ = s1.trim().split('\r');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s1.trim().split("\r");
+    let _ = s1.trim().split("\n\r");
+    let _ = s1.trim().split("\r \n");
+
+    // Splitting a `String` variable at other separators should not warn
+    let _ = s2.trim().split('\r');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s2.trim().split("\r");
+    let _ = s2.trim().split("\n\r");
+
+    // Splitting a variable that derefs into `str` at other separators should not warn
+    let _ = s3.trim().split('\r');
+    #[allow(clippy::single_char_pattern)]
+    let _ = s3.trim().split("\r");
+    let _ = s3.trim().split("\n\r");
+    let _ = s3.trim().split("\r \n");
+    let _ = s2.trim().split("\r \n");
+
+    // Using `trim` and `split` on other types should not warn
+    let not_str = NotStr { s: s1 };
+    let _ = not_str.trim().split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = not_str.trim().split("\n");
+    let _ = not_str.trim().split("\r\n");
+    let derefs_into_not_str = DerefsIntoNotStr { not_str: &not_str };
+    let _ = derefs_into_not_str.trim().split('\n');
+    #[allow(clippy::single_char_pattern)]
+    let _ = derefs_into_not_str.trim().split("\n");
+    let _ = derefs_into_not_str.trim().split("\r\n");
+
+    // Code generated by macros should not create a warning
+    trim_split!(s1, "\r\n");
+    trim_split!("hello\nworld\n", "\r\n");
+    trim_split!(s2, "\r\n");
+    trim_split!(s3, "\r\n");
+}
diff --git a/src/tools/clippy/tests/ui/str_split.stderr b/src/tools/clippy/tests/ui/str_split.stderr
new file mode 100644
index 00000000000..ee0a9653711
--- /dev/null
+++ b/src/tools/clippy/tests/ui/str_split.stderr
@@ -0,0 +1,65 @@
+error: using `str.trim().split()` with hard-coded newlines
+  --> $DIR/str_split.rs:59:13
+   |
+LL |     let _ = s1.trim().split('\n');
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()`
+   |
+   = note: `-D clippy::str-split-at-newline` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::str_split_at_newline)]`
+
+error: using `str.trim().split()` with hard-coded newlines
+  --> $DIR/str_split.rs:61:13
+   |
+LL |     let _ = s1.trim().split("\n");
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()`
+
+error: using `str.trim().split()` with hard-coded newlines
+  --> $DIR/str_split.rs:62:13
+   |
+LL |     let _ = s1.trim().split("\r\n");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()`
+
+error: using `str.trim().split()` with hard-coded newlines
+  --> $DIR/str_split.rs:65:13
+   |
+LL |     let _ = s2.trim().split('\n');
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()`
+
+error: using `str.trim().split()` with hard-coded newlines
+  --> $DIR/str_split.rs:67:13
+   |
+LL |     let _ = s2.trim().split("\n");
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()`
+
+error: using `str.trim().split()` with hard-coded newlines
+  --> $DIR/str_split.rs:68:13
+   |
+LL |     let _ = s2.trim().split("\r\n");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()`
+
+error: using `str.trim().split()` with hard-coded newlines
+  --> $DIR/str_split.rs:72:13
+   |
+LL |     let _ = s3.trim().split('\n');
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()`
+
+error: using `str.trim().split()` with hard-coded newlines
+  --> $DIR/str_split.rs:74:13
+   |
+LL |     let _ = s3.trim().split("\n");
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()`
+
+error: using `str.trim().split()` with hard-coded newlines
+  --> $DIR/str_split.rs:75:13
+   |
+LL |     let _ = s3.trim().split("\r\n");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()`
+
+error: using `str.trim().split()` with hard-coded newlines
+  --> $DIR/str_split.rs:78:13
+   |
+LL |     let _ = make_str!(s1).trim().split('\n');
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `make_str!(s1).lines()`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/struct_fields.rs b/src/tools/clippy/tests/ui/struct_fields.rs
index 8b1a1446e3c..7c9e9d8ed26 100644
--- a/src/tools/clippy/tests/ui/struct_fields.rs
+++ b/src/tools/clippy/tests/ui/struct_fields.rs
@@ -39,14 +39,14 @@ struct DataStruct {
 struct DoublePrefix {
     //~^ ERROR: all fields have the same prefix: `some_data`
     some_data_a: bool,
-    some_data_b: bool,
+    some_data_b: i8,
     some_data_c: bool,
 }
 
 struct DoublePostfix {
     //~^ ERROR: all fields have the same postfix: `some_data`
     a_some_data: bool,
-    b_some_data: bool,
+    b_some_data: i8,
     c_some_data: bool,
 }
 
@@ -54,18 +54,18 @@ struct DoublePostfix {
 struct NotSnakeCase {
     //~^ ERROR: all fields have the same postfix: `someData`
     a_someData: bool,
-    b_someData: bool,
+    b_someData: i8,
     c_someData: bool,
 }
 #[allow(non_snake_case)]
 struct NotSnakeCase2 {
     //~^ ERROR: all fields have the same prefix: `someData`
     someData_c: bool,
-    someData_b: bool,
+    someData_b: i8,
     someData_a_b: bool,
 }
 
-// no error, threshold is 3 fiels by default
+// no error, threshold is 3 fields by default
 struct Fooo {
     foo: u8,
     bar: u8,
@@ -328,4 +328,18 @@ external! {
 
 }
 
+// Should not warn
+struct Config {
+    use_foo: bool,
+    use_bar: bool,
+    use_baz: bool,
+}
+
+struct Use {
+    use_foo: bool,
+    //~^ ERROR: field name starts with the struct's name
+    use_bar: bool,
+    use_baz: bool,
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/struct_fields.stderr b/src/tools/clippy/tests/ui/struct_fields.stderr
index 4ca57715b18..d2bdbd17d5c 100644
--- a/src/tools/clippy/tests/ui/struct_fields.stderr
+++ b/src/tools/clippy/tests/ui/struct_fields.stderr
@@ -45,7 +45,7 @@ error: all fields have the same prefix: `some_data`
 LL | / struct DoublePrefix {
 LL | |
 LL | |     some_data_a: bool,
-LL | |     some_data_b: bool,
+LL | |     some_data_b: i8,
 LL | |     some_data_c: bool,
 LL | | }
    | |_^
@@ -58,7 +58,7 @@ error: all fields have the same postfix: `some_data`
 LL | / struct DoublePostfix {
 LL | |
 LL | |     a_some_data: bool,
-LL | |     b_some_data: bool,
+LL | |     b_some_data: i8,
 LL | |     c_some_data: bool,
 LL | | }
    | |_^
@@ -71,7 +71,7 @@ error: all fields have the same postfix: `someData`
 LL | / struct NotSnakeCase {
 LL | |
 LL | |     a_someData: bool,
-LL | |     b_someData: bool,
+LL | |     b_someData: i8,
 LL | |     c_someData: bool,
 LL | | }
    | |_^
@@ -84,7 +84,7 @@ error: all fields have the same prefix: `someData`
 LL | / struct NotSnakeCase2 {
 LL | |
 LL | |     someData_c: bool,
-LL | |     someData_b: bool,
+LL | |     someData_b: i8,
 LL | |     someData_a_b: bool,
 LL | | }
    | |_^
@@ -261,5 +261,23 @@ LL |       mk_struct_full_def!(PrefixData, some_data, some_meta, some_other);
    = help: remove the prefixes
    = note: this error originates in the macro `mk_struct_full_def` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 21 previous errors
+error: field name starts with the struct's name
+  --> $DIR/struct_fields.rs:339:5
+   |
+LL |     use_foo: bool,
+   |     ^^^^^^^^^^^^^
+
+error: field name starts with the struct's name
+  --> $DIR/struct_fields.rs:341:5
+   |
+LL |     use_bar: bool,
+   |     ^^^^^^^^^^^^^
+
+error: field name starts with the struct's name
+  --> $DIR/struct_fields.rs:342:5
+   |
+LL |     use_baz: bool,
+   |     ^^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors
 
diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed
new file mode 100644
index 00000000000..bbde25b0a88
--- /dev/null
+++ b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.fixed
@@ -0,0 +1,30 @@
+#![warn(clippy::thread_local_initializer_can_be_made_const)]
+
+use std::cell::RefCell;
+
+fn main() {
+    // lint and suggest const
+    thread_local! {
+        static BUF_1: RefCell<String> = const { RefCell::new(String::new()) };
+    }
+    //~^^ ERROR: initializer for `thread_local` value can be made `const`
+
+    // don't lint
+    thread_local! {
+        static BUF_2: RefCell<String> = const { RefCell::new(String::new()) };
+    }
+
+    thread_local! {
+        static SIMPLE:i32 = const { 1 };
+    }
+    //~^^ ERROR: initializer for `thread_local` value can be made `const`
+
+    // lint and suggest const for all non const items
+    thread_local! {
+        static BUF_3_CAN_BE_MADE_CONST: RefCell<String> = const { RefCell::new(String::new()) };
+        static CONST_MIXED_WITH:i32 = const { 1 };
+        static BUF_4_CAN_BE_MADE_CONST: RefCell<String> = const { RefCell::new(String::new()) };
+    }
+    //~^^^^ ERROR: initializer for `thread_local` value can be made `const`
+    //~^^^ ERROR: initializer for `thread_local` value can be made `const`
+}
diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs
new file mode 100644
index 00000000000..3d7aacf2f09
--- /dev/null
+++ b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.rs
@@ -0,0 +1,30 @@
+#![warn(clippy::thread_local_initializer_can_be_made_const)]
+
+use std::cell::RefCell;
+
+fn main() {
+    // lint and suggest const
+    thread_local! {
+        static BUF_1: RefCell<String> = RefCell::new(String::new());
+    }
+    //~^^ ERROR: initializer for `thread_local` value can be made `const`
+
+    // don't lint
+    thread_local! {
+        static BUF_2: RefCell<String> = const { RefCell::new(String::new()) };
+    }
+
+    thread_local! {
+        static SIMPLE:i32 = 1;
+    }
+    //~^^ ERROR: initializer for `thread_local` value can be made `const`
+
+    // lint and suggest const for all non const items
+    thread_local! {
+        static BUF_3_CAN_BE_MADE_CONST: RefCell<String> = RefCell::new(String::new());
+        static CONST_MIXED_WITH:i32 = const { 1 };
+        static BUF_4_CAN_BE_MADE_CONST: RefCell<String> = RefCell::new(String::new());
+    }
+    //~^^^^ ERROR: initializer for `thread_local` value can be made `const`
+    //~^^^ ERROR: initializer for `thread_local` value can be made `const`
+}
diff --git a/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr
new file mode 100644
index 00000000000..b35bd306b52
--- /dev/null
+++ b/src/tools/clippy/tests/ui/thread_local_initializer_can_be_made_const.stderr
@@ -0,0 +1,29 @@
+error: initializer for `thread_local` value can be made `const`
+  --> $DIR/thread_local_initializer_can_be_made_const.rs:8:41
+   |
+LL |         static BUF_1: RefCell<String> = RefCell::new(String::new());
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }`
+   |
+   = note: `-D clippy::thread-local-initializer-can-be-made-const` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::thread_local_initializer_can_be_made_const)]`
+
+error: initializer for `thread_local` value can be made `const`
+  --> $DIR/thread_local_initializer_can_be_made_const.rs:18:29
+   |
+LL |         static SIMPLE:i32 = 1;
+   |                             ^ help: replace with: `const { 1 }`
+
+error: initializer for `thread_local` value can be made `const`
+  --> $DIR/thread_local_initializer_can_be_made_const.rs:24:59
+   |
+LL |         static BUF_3_CAN_BE_MADE_CONST: RefCell<String> = RefCell::new(String::new());
+   |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }`
+
+error: initializer for `thread_local` value can be made `const`
+  --> $DIR/thread_local_initializer_can_be_made_const.rs:26:59
+   |
+LL |         static BUF_4_CAN_BE_MADE_CONST: RefCell<String> = RefCell::new(String::new());
+   |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.rs b/src/tools/clippy/tests/ui/unconditional_recursion.rs
index 1169118de83..e1a2d6a90b8 100644
--- a/src/tools/clippy/tests/ui/unconditional_recursion.rs
+++ b/src/tools/clippy/tests/ui/unconditional_recursion.rs
@@ -1,7 +1,7 @@
 //@no-rustfix
 
 #![warn(clippy::unconditional_recursion)]
-#![allow(clippy::partialeq_ne_impl)]
+#![allow(clippy::partialeq_ne_impl, clippy::default_constructed_unit_structs)]
 
 enum Foo {
     A,
@@ -158,6 +158,112 @@ struct S5;
 impl_partial_eq!(S5);
 //~^ ERROR: function cannot return without recursing
 
+struct S6 {
+    field: String,
+}
+
+impl PartialEq for S6 {
+    fn eq(&self, other: &Self) -> bool {
+        let mine = &self.field;
+        let theirs = &other.field;
+        mine == theirs // Should not warn!
+    }
+}
+
+struct S7<'a> {
+    field: &'a S7<'a>,
+}
+
+impl<'a> PartialEq for S7<'a> {
+    fn eq(&self, other: &Self) -> bool {
+        //~^ ERROR: function cannot return without recursing
+        let mine = &self.field;
+        let theirs = &other.field;
+        mine == theirs
+    }
+}
+
+struct S8 {
+    num: i32,
+    field: Option<Box<S8>>,
+}
+
+impl PartialEq for S8 {
+    fn eq(&self, other: &Self) -> bool {
+        if self.num != other.num {
+            return false;
+        }
+
+        let (this, other) = match (self.field.as_deref(), other.field.as_deref()) {
+            (Some(x1), Some(x2)) => (x1, x2),
+            (None, None) => return true,
+            _ => return false,
+        };
+
+        this == other
+    }
+}
+
+struct S9;
+
+impl std::string::ToString for S9 {
+    fn to_string(&self) -> String {
+        //~^ ERROR: function cannot return without recursing
+        self.to_string()
+    }
+}
+
+struct S10;
+
+impl std::string::ToString for S10 {
+    fn to_string(&self) -> String {
+        //~^ ERROR: function cannot return without recursing
+        let x = self;
+        x.to_string()
+    }
+}
+
+struct S11;
+
+impl std::string::ToString for S11 {
+    fn to_string(&self) -> String {
+        //~^ ERROR: function cannot return without recursing
+        (self as &Self).to_string()
+    }
+}
+
+struct S12;
+
+impl std::default::Default for S12 {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl S12 {
+    fn new() -> Self {
+        //~^ ERROR: function cannot return without recursing
+        Self::default()
+    }
+
+    fn bar() -> Self {
+        // Should not warn!
+        Self::default()
+    }
+}
+
+#[derive(Default)]
+struct S13 {
+    f: u32,
+}
+
+impl S13 {
+    fn new() -> Self {
+        // Shoud not warn!
+        Self::default()
+    }
+}
+
 fn main() {
     // test code goes here
 }
diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.stderr b/src/tools/clippy/tests/ui/unconditional_recursion.stderr
index 1fb01c00f19..5d82e2a9f31 100644
--- a/src/tools/clippy/tests/ui/unconditional_recursion.stderr
+++ b/src/tools/clippy/tests/ui/unconditional_recursion.stderr
@@ -23,6 +23,39 @@ LL |         self.eq(other)
    = help: a `loop` may express intention better if this is on purpose
 
 error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:210:5
+   |
+LL |     fn to_string(&self) -> String {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL |         self.to_string()
+   |         ---------------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:219:5
+   |
+LL |     fn to_string(&self) -> String {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+...
+LL |         x.to_string()
+   |         ------------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:229:5
+   |
+LL |     fn to_string(&self) -> String {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL |         (self as &Self).to_string()
+   |         --------------------------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+error: function cannot return without recursing
   --> $DIR/unconditional_recursion.rs:12:5
    |
 LL | /     fn ne(&self, other: &Self) -> bool {
@@ -55,6 +88,34 @@ LL |         self == other
    |         ^^^^^^^^^^^^^
 
 error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:28:5
+   |
+LL | /     fn ne(&self, other: &Self) -> bool {
+LL | |         self != &Foo2::B // no error here
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:29:9
+   |
+LL |         self != &Foo2::B // no error here
+   |         ^^^^^^^^^^^^^^^^
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:31:5
+   |
+LL | /     fn eq(&self, other: &Self) -> bool {
+LL | |         self == &Foo2::B // no error here
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:32:9
+   |
+LL |         self == &Foo2::B // no error here
+   |         ^^^^^^^^^^^^^^^^
+
+error: function cannot return without recursing
   --> $DIR/unconditional_recursion.rs:42:5
    |
 LL | /     fn ne(&self, other: &Self) -> bool {
@@ -247,5 +308,37 @@ LL | impl_partial_eq!(S5);
    | -------------------- in this macro invocation
    = note: this error originates in the macro `impl_partial_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 19 previous errors
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:178:5
+   |
+LL | /     fn eq(&self, other: &Self) -> bool {
+LL | |
+LL | |         let mine = &self.field;
+LL | |         let theirs = &other.field;
+LL | |         mine == theirs
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:182:9
+   |
+LL |         mine == theirs
+   |         ^^^^^^^^^^^^^^
+
+error: function cannot return without recursing
+  --> $DIR/unconditional_recursion.rs:244:5
+   |
+LL | /     fn new() -> Self {
+LL | |
+LL | |         Self::default()
+LL | |     }
+   | |_____^
+   |
+note: recursive call site
+  --> $DIR/unconditional_recursion.rs:246:9
+   |
+LL |         Self::default()
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to 26 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
index 66598f89208..d8031c484e5 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
@@ -47,6 +47,18 @@ impl Drop for Issue9427FollowUp {
     }
 }
 
+struct Issue9427Followup2 {
+    ptr: *const (),
+}
+impl Issue9427Followup2 {
+    fn from_owned(ptr: *const ()) -> Option<Self> {
+        (!ptr.is_null()).then(|| Self { ptr })
+    }
+}
+impl Drop for Issue9427Followup2 {
+    fn drop(&mut self) {}
+}
+
 struct Issue10437;
 impl Deref for Issue10437 {
     type Target = u32;
@@ -128,6 +140,7 @@ fn main() {
     // Should not lint - bool
     let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop
     let _ = false.then(|| Issue9427FollowUp); // Issue9427FollowUp has a significant drop
+    let _ = false.then(|| Issue9427Followup2 { ptr: std::ptr::null() });
 
     // should not lint, bind_instead_of_map takes priority
     let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
index 5045fcd790e..ea55b1d9a90 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
@@ -47,6 +47,18 @@ impl Drop for Issue9427FollowUp {
     }
 }
 
+struct Issue9427Followup2 {
+    ptr: *const (),
+}
+impl Issue9427Followup2 {
+    fn from_owned(ptr: *const ()) -> Option<Self> {
+        (!ptr.is_null()).then(|| Self { ptr })
+    }
+}
+impl Drop for Issue9427Followup2 {
+    fn drop(&mut self) {}
+}
+
 struct Issue10437;
 impl Deref for Issue10437 {
     type Target = u32;
@@ -128,6 +140,7 @@ fn main() {
     // Should not lint - bool
     let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop
     let _ = false.then(|| Issue9427FollowUp); // Issue9427FollowUp has a significant drop
+    let _ = false.then(|| Issue9427Followup2 { ptr: std::ptr::null() });
 
     // should not lint, bind_instead_of_map takes priority
     let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
index 466664aee6c..6ff2691a461 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
@@ -1,5 +1,5 @@
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:71:13
+  --> $DIR/unnecessary_lazy_eval.rs:83:13
    |
 LL |     let _ = opt.unwrap_or_else(|| 2);
    |             ^^^^--------------------
@@ -10,7 +10,7 @@ LL |     let _ = opt.unwrap_or_else(|| 2);
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:72:13
+  --> $DIR/unnecessary_lazy_eval.rs:84:13
    |
 LL |     let _ = opt.unwrap_or_else(|| astronomers_pi);
    |             ^^^^---------------------------------
@@ -18,7 +18,7 @@ LL |     let _ = opt.unwrap_or_else(|| astronomers_pi);
    |                 help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:73:13
+  --> $DIR/unnecessary_lazy_eval.rs:85:13
    |
 LL |     let _ = opt.unwrap_or_else(|| ext_str.some_field);
    |             ^^^^-------------------------------------
@@ -26,7 +26,7 @@ LL |     let _ = opt.unwrap_or_else(|| ext_str.some_field);
    |                 help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:75:13
+  --> $DIR/unnecessary_lazy_eval.rs:87:13
    |
 LL |     let _ = opt.and_then(|_| ext_opt);
    |             ^^^^---------------------
@@ -34,7 +34,7 @@ LL |     let _ = opt.and_then(|_| ext_opt);
    |                 help: use `and(..)` instead: `and(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:76:13
+  --> $DIR/unnecessary_lazy_eval.rs:88:13
    |
 LL |     let _ = opt.or_else(|| ext_opt);
    |             ^^^^-------------------
@@ -42,7 +42,7 @@ LL |     let _ = opt.or_else(|| ext_opt);
    |                 help: use `or(..)` instead: `or(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:77:13
+  --> $DIR/unnecessary_lazy_eval.rs:89:13
    |
 LL |     let _ = opt.or_else(|| None);
    |             ^^^^----------------
@@ -50,7 +50,7 @@ LL |     let _ = opt.or_else(|| None);
    |                 help: use `or(..)` instead: `or(None)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:78:13
+  --> $DIR/unnecessary_lazy_eval.rs:90:13
    |
 LL |     let _ = opt.get_or_insert_with(|| 2);
    |             ^^^^------------------------
@@ -58,7 +58,7 @@ LL |     let _ = opt.get_or_insert_with(|| 2);
    |                 help: use `get_or_insert(..)` instead: `get_or_insert(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:79:13
+  --> $DIR/unnecessary_lazy_eval.rs:91:13
    |
 LL |     let _ = opt.ok_or_else(|| 2);
    |             ^^^^----------------
@@ -66,7 +66,7 @@ LL |     let _ = opt.ok_or_else(|| 2);
    |                 help: use `ok_or(..)` instead: `ok_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:80:13
+  --> $DIR/unnecessary_lazy_eval.rs:92:13
    |
 LL |     let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
    |             ^^^^^^^^^^^^^^^^^-------------------------------
@@ -74,7 +74,7 @@ LL |     let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
    |                              help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:81:13
+  --> $DIR/unnecessary_lazy_eval.rs:93:13
    |
 LL |     let _ = cond.then(|| astronomers_pi);
    |             ^^^^^-----------------------
@@ -82,7 +82,7 @@ LL |     let _ = cond.then(|| astronomers_pi);
    |                  help: use `then_some(..)` instead: `then_some(astronomers_pi)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:82:13
+  --> $DIR/unnecessary_lazy_eval.rs:94:13
    |
 LL |     let _ = true.then(|| -> _ {});
    |             ^^^^^----------------
@@ -90,7 +90,7 @@ LL |     let _ = true.then(|| -> _ {});
    |                  help: use `then_some(..)` instead: `then_some({})`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:83:13
+  --> $DIR/unnecessary_lazy_eval.rs:95:13
    |
 LL |     let _ = true.then(|| {});
    |             ^^^^^-----------
@@ -98,7 +98,7 @@ LL |     let _ = true.then(|| {});
    |                  help: use `then_some(..)` instead: `then_some({})`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:87:13
+  --> $DIR/unnecessary_lazy_eval.rs:99:13
    |
 LL |     let _ = Some(1).unwrap_or_else(|| *r);
    |             ^^^^^^^^---------------------
@@ -106,7 +106,7 @@ LL |     let _ = Some(1).unwrap_or_else(|| *r);
    |                     help: use `unwrap_or(..)` instead: `unwrap_or(*r)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:89:13
+  --> $DIR/unnecessary_lazy_eval.rs:101:13
    |
 LL |     let _ = Some(1).unwrap_or_else(|| *b);
    |             ^^^^^^^^---------------------
@@ -114,7 +114,7 @@ LL |     let _ = Some(1).unwrap_or_else(|| *b);
    |                     help: use `unwrap_or(..)` instead: `unwrap_or(*b)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:91:13
+  --> $DIR/unnecessary_lazy_eval.rs:103:13
    |
 LL |     let _ = Some(1).as_ref().unwrap_or_else(|| &r);
    |             ^^^^^^^^^^^^^^^^^---------------------
@@ -122,7 +122,7 @@ LL |     let _ = Some(1).as_ref().unwrap_or_else(|| &r);
    |                              help: use `unwrap_or(..)` instead: `unwrap_or(&r)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:92:13
+  --> $DIR/unnecessary_lazy_eval.rs:104:13
    |
 LL |     let _ = Some(1).as_ref().unwrap_or_else(|| &b);
    |             ^^^^^^^^^^^^^^^^^---------------------
@@ -130,7 +130,7 @@ LL |     let _ = Some(1).as_ref().unwrap_or_else(|| &b);
    |                              help: use `unwrap_or(..)` instead: `unwrap_or(&b)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:95:13
+  --> $DIR/unnecessary_lazy_eval.rs:107:13
    |
 LL |     let _ = Some(10).unwrap_or_else(|| 2);
    |             ^^^^^^^^^--------------------
@@ -138,7 +138,7 @@ LL |     let _ = Some(10).unwrap_or_else(|| 2);
    |                      help: use `unwrap_or(..)` instead: `unwrap_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:96:13
+  --> $DIR/unnecessary_lazy_eval.rs:108:13
    |
 LL |     let _ = Some(10).and_then(|_| ext_opt);
    |             ^^^^^^^^^---------------------
@@ -146,7 +146,7 @@ LL |     let _ = Some(10).and_then(|_| ext_opt);
    |                      help: use `and(..)` instead: `and(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:97:28
+  --> $DIR/unnecessary_lazy_eval.rs:109:28
    |
 LL |     let _: Option<usize> = None.or_else(|| ext_opt);
    |                            ^^^^^-------------------
@@ -154,7 +154,7 @@ LL |     let _: Option<usize> = None.or_else(|| ext_opt);
    |                                 help: use `or(..)` instead: `or(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:98:13
+  --> $DIR/unnecessary_lazy_eval.rs:110:13
    |
 LL |     let _ = None.get_or_insert_with(|| 2);
    |             ^^^^^------------------------
@@ -162,7 +162,7 @@ LL |     let _ = None.get_or_insert_with(|| 2);
    |                  help: use `get_or_insert(..)` instead: `get_or_insert(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:99:35
+  --> $DIR/unnecessary_lazy_eval.rs:111:35
    |
 LL |     let _: Result<usize, usize> = None.ok_or_else(|| 2);
    |                                   ^^^^^----------------
@@ -170,7 +170,7 @@ LL |     let _: Result<usize, usize> = None.ok_or_else(|| 2);
    |                                        help: use `ok_or(..)` instead: `ok_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:100:28
+  --> $DIR/unnecessary_lazy_eval.rs:112:28
    |
 LL |     let _: Option<usize> = None.or_else(|| None);
    |                            ^^^^^----------------
@@ -178,7 +178,7 @@ LL |     let _: Option<usize> = None.or_else(|| None);
    |                                 help: use `or(..)` instead: `or(None)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:103:13
+  --> $DIR/unnecessary_lazy_eval.rs:115:13
    |
 LL |     let _ = deep.0.unwrap_or_else(|| 2);
    |             ^^^^^^^--------------------
@@ -186,7 +186,7 @@ LL |     let _ = deep.0.unwrap_or_else(|| 2);
    |                    help: use `unwrap_or(..)` instead: `unwrap_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:104:13
+  --> $DIR/unnecessary_lazy_eval.rs:116:13
    |
 LL |     let _ = deep.0.and_then(|_| ext_opt);
    |             ^^^^^^^---------------------
@@ -194,7 +194,7 @@ LL |     let _ = deep.0.and_then(|_| ext_opt);
    |                    help: use `and(..)` instead: `and(ext_opt)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:105:13
+  --> $DIR/unnecessary_lazy_eval.rs:117:13
    |
 LL |     let _ = deep.0.or_else(|| None);
    |             ^^^^^^^----------------
@@ -202,7 +202,7 @@ LL |     let _ = deep.0.or_else(|| None);
    |                    help: use `or(..)` instead: `or(None)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:106:13
+  --> $DIR/unnecessary_lazy_eval.rs:118:13
    |
 LL |     let _ = deep.0.get_or_insert_with(|| 2);
    |             ^^^^^^^------------------------
@@ -210,7 +210,7 @@ LL |     let _ = deep.0.get_or_insert_with(|| 2);
    |                    help: use `get_or_insert(..)` instead: `get_or_insert(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:107:13
+  --> $DIR/unnecessary_lazy_eval.rs:119:13
    |
 LL |     let _ = deep.0.ok_or_else(|| 2);
    |             ^^^^^^^----------------
@@ -218,7 +218,7 @@ LL |     let _ = deep.0.ok_or_else(|| 2);
    |                    help: use `ok_or(..)` instead: `ok_or(2)`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:137:28
+  --> $DIR/unnecessary_lazy_eval.rs:150:28
    |
 LL |     let _: Option<usize> = None.or_else(|| Some(3));
    |                            ^^^^^-------------------
@@ -226,7 +226,7 @@ LL |     let _: Option<usize> = None.or_else(|| Some(3));
    |                                 help: use `or(..)` instead: `or(Some(3))`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:138:13
+  --> $DIR/unnecessary_lazy_eval.rs:151:13
    |
 LL |     let _ = deep.0.or_else(|| Some(3));
    |             ^^^^^^^-------------------
@@ -234,7 +234,7 @@ LL |     let _ = deep.0.or_else(|| Some(3));
    |                    help: use `or(..)` instead: `or(Some(3))`
 
 error: unnecessary closure used to substitute value for `Option::None`
-  --> $DIR/unnecessary_lazy_eval.rs:139:13
+  --> $DIR/unnecessary_lazy_eval.rs:152:13
    |
 LL |     let _ = opt.or_else(|| Some(3));
    |             ^^^^-------------------
@@ -242,7 +242,7 @@ LL |     let _ = opt.or_else(|| Some(3));
    |                 help: use `or(..)` instead: `or(Some(3))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:145:13
+  --> $DIR/unnecessary_lazy_eval.rs:158:13
    |
 LL |     let _ = res2.unwrap_or_else(|_| 2);
    |             ^^^^^---------------------
@@ -250,7 +250,7 @@ LL |     let _ = res2.unwrap_or_else(|_| 2);
    |                  help: use `unwrap_or(..)` instead: `unwrap_or(2)`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:146:13
+  --> $DIR/unnecessary_lazy_eval.rs:159:13
    |
 LL |     let _ = res2.unwrap_or_else(|_| astronomers_pi);
    |             ^^^^^----------------------------------
@@ -258,7 +258,7 @@ LL |     let _ = res2.unwrap_or_else(|_| astronomers_pi);
    |                  help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:147:13
+  --> $DIR/unnecessary_lazy_eval.rs:160:13
    |
 LL |     let _ = res2.unwrap_or_else(|_| ext_str.some_field);
    |             ^^^^^--------------------------------------
@@ -266,7 +266,7 @@ LL |     let _ = res2.unwrap_or_else(|_| ext_str.some_field);
    |                  help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:169:35
+  --> $DIR/unnecessary_lazy_eval.rs:182:35
    |
 LL |     let _: Result<usize, usize> = res.and_then(|_| Err(2));
    |                                   ^^^^--------------------
@@ -274,7 +274,7 @@ LL |     let _: Result<usize, usize> = res.and_then(|_| Err(2));
    |                                       help: use `and(..)` instead: `and(Err(2))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:170:35
+  --> $DIR/unnecessary_lazy_eval.rs:183:35
    |
 LL |     let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
    |                                   ^^^^---------------------------------
@@ -282,7 +282,7 @@ LL |     let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
    |                                       help: use `and(..)` instead: `and(Err(astronomers_pi))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:171:35
+  --> $DIR/unnecessary_lazy_eval.rs:184:35
    |
 LL |     let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
    |                                   ^^^^-------------------------------------
@@ -290,7 +290,7 @@ LL |     let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field))
    |                                       help: use `and(..)` instead: `and(Err(ext_str.some_field))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:173:35
+  --> $DIR/unnecessary_lazy_eval.rs:186:35
    |
 LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(2));
    |                                   ^^^^------------------
@@ -298,7 +298,7 @@ LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(2));
    |                                       help: use `or(..)` instead: `or(Ok(2))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:174:35
+  --> $DIR/unnecessary_lazy_eval.rs:187:35
    |
 LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
    |                                   ^^^^-------------------------------
@@ -306,7 +306,7 @@ LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
    |                                       help: use `or(..)` instead: `or(Ok(astronomers_pi))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:175:35
+  --> $DIR/unnecessary_lazy_eval.rs:188:35
    |
 LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
    |                                   ^^^^-----------------------------------
@@ -314,7 +314,7 @@ LL |     let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
    |                                       help: use `or(..)` instead: `or(Ok(ext_str.some_field))`
 
 error: unnecessary closure used to substitute value for `Result::Err`
-  --> $DIR/unnecessary_lazy_eval.rs:176:35
+  --> $DIR/unnecessary_lazy_eval.rs:189:35
    |
 LL |       let _: Result<usize, usize> = res.
    |  ___________________________________^
@@ -329,7 +329,7 @@ LL | |     or_else(|_| Ok(ext_str.some_field));
    |       help: use `or(..)` instead: `or(Ok(ext_str.some_field))`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:206:14
+  --> $DIR/unnecessary_lazy_eval.rs:219:14
    |
 LL |     let _x = false.then(|| i32::MAX + 1);
    |              ^^^^^^---------------------
@@ -337,7 +337,7 @@ LL |     let _x = false.then(|| i32::MAX + 1);
    |                    help: use `then_some(..)` instead: `then_some(i32::MAX + 1)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:208:14
+  --> $DIR/unnecessary_lazy_eval.rs:221:14
    |
 LL |     let _x = false.then(|| i32::MAX * 2);
    |              ^^^^^^---------------------
@@ -345,7 +345,7 @@ LL |     let _x = false.then(|| i32::MAX * 2);
    |                    help: use `then_some(..)` instead: `then_some(i32::MAX * 2)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:210:14
+  --> $DIR/unnecessary_lazy_eval.rs:223:14
    |
 LL |     let _x = false.then(|| i32::MAX - 1);
    |              ^^^^^^---------------------
@@ -353,7 +353,7 @@ LL |     let _x = false.then(|| i32::MAX - 1);
    |                    help: use `then_some(..)` instead: `then_some(i32::MAX - 1)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:212:14
+  --> $DIR/unnecessary_lazy_eval.rs:225:14
    |
 LL |     let _x = false.then(|| i32::MIN - 1);
    |              ^^^^^^---------------------
@@ -361,7 +361,7 @@ LL |     let _x = false.then(|| i32::MIN - 1);
    |                    help: use `then_some(..)` instead: `then_some(i32::MIN - 1)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:214:14
+  --> $DIR/unnecessary_lazy_eval.rs:227:14
    |
 LL |     let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2);
    |              ^^^^^^-------------------------------------
@@ -369,7 +369,7 @@ LL |     let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2);
    |                    help: use `then_some(..)` instead: `then_some((1 + 2 * 3 - 2 / 3 + 9) << 2)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:216:14
+  --> $DIR/unnecessary_lazy_eval.rs:229:14
    |
 LL |     let _x = false.then(|| 255u8 << 7);
    |              ^^^^^^-------------------
@@ -377,7 +377,7 @@ LL |     let _x = false.then(|| 255u8 << 7);
    |                    help: use `then_some(..)` instead: `then_some(255u8 << 7)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:218:14
+  --> $DIR/unnecessary_lazy_eval.rs:231:14
    |
 LL |     let _x = false.then(|| 255u8 << 8);
    |              ^^^^^^-------------------
@@ -385,7 +385,7 @@ LL |     let _x = false.then(|| 255u8 << 8);
    |                    help: use `then_some(..)` instead: `then_some(255u8 << 8)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:220:14
+  --> $DIR/unnecessary_lazy_eval.rs:233:14
    |
 LL |     let _x = false.then(|| 255u8 >> 8);
    |              ^^^^^^-------------------
@@ -393,7 +393,7 @@ LL |     let _x = false.then(|| 255u8 >> 8);
    |                    help: use `then_some(..)` instead: `then_some(255u8 >> 8)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:223:14
+  --> $DIR/unnecessary_lazy_eval.rs:236:14
    |
 LL |     let _x = false.then(|| i32::MAX + -1);
    |              ^^^^^^----------------------
@@ -401,7 +401,7 @@ LL |     let _x = false.then(|| i32::MAX + -1);
    |                    help: use `then_some(..)` instead: `then_some(i32::MAX + -1)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:225:14
+  --> $DIR/unnecessary_lazy_eval.rs:238:14
    |
 LL |     let _x = false.then(|| -i32::MAX);
    |              ^^^^^^------------------
@@ -409,7 +409,7 @@ LL |     let _x = false.then(|| -i32::MAX);
    |                    help: use `then_some(..)` instead: `then_some(-i32::MAX)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:227:14
+  --> $DIR/unnecessary_lazy_eval.rs:240:14
    |
 LL |     let _x = false.then(|| -i32::MIN);
    |              ^^^^^^------------------
@@ -417,7 +417,7 @@ LL |     let _x = false.then(|| -i32::MIN);
    |                    help: use `then_some(..)` instead: `then_some(-i32::MIN)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:230:14
+  --> $DIR/unnecessary_lazy_eval.rs:243:14
    |
 LL |     let _x = false.then(|| 255 >> -7);
    |              ^^^^^^------------------
@@ -425,7 +425,7 @@ LL |     let _x = false.then(|| 255 >> -7);
    |                    help: use `then_some(..)` instead: `then_some(255 >> -7)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:232:14
+  --> $DIR/unnecessary_lazy_eval.rs:245:14
    |
 LL |     let _x = false.then(|| 255 << -1);
    |              ^^^^^^------------------
@@ -433,7 +433,7 @@ LL |     let _x = false.then(|| 255 << -1);
    |                    help: use `then_some(..)` instead: `then_some(255 << -1)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:234:14
+  --> $DIR/unnecessary_lazy_eval.rs:247:14
    |
 LL |     let _x = false.then(|| 1 / 0);
    |              ^^^^^^--------------
@@ -441,7 +441,7 @@ LL |     let _x = false.then(|| 1 / 0);
    |                    help: use `then_some(..)` instead: `then_some(1 / 0)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:236:14
+  --> $DIR/unnecessary_lazy_eval.rs:249:14
    |
 LL |     let _x = false.then(|| x << -1);
    |              ^^^^^^----------------
@@ -449,7 +449,7 @@ LL |     let _x = false.then(|| x << -1);
    |                    help: use `then_some(..)` instead: `then_some(x << -1)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:238:14
+  --> $DIR/unnecessary_lazy_eval.rs:251:14
    |
 LL |     let _x = false.then(|| x << 2);
    |              ^^^^^^---------------
@@ -457,7 +457,7 @@ LL |     let _x = false.then(|| x << 2);
    |                    help: use `then_some(..)` instead: `then_some(x << 2)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:248:14
+  --> $DIR/unnecessary_lazy_eval.rs:261:14
    |
 LL |     let _x = false.then(|| x / 0);
    |              ^^^^^^--------------
@@ -465,7 +465,7 @@ LL |     let _x = false.then(|| x / 0);
    |                    help: use `then_some(..)` instead: `then_some(x / 0)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:250:14
+  --> $DIR/unnecessary_lazy_eval.rs:263:14
    |
 LL |     let _x = false.then(|| x % 0);
    |              ^^^^^^--------------
@@ -473,7 +473,7 @@ LL |     let _x = false.then(|| x % 0);
    |                    help: use `then_some(..)` instead: `then_some(x % 0)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:253:14
+  --> $DIR/unnecessary_lazy_eval.rs:266:14
    |
 LL |     let _x = false.then(|| 1 / -1);
    |              ^^^^^^---------------
@@ -481,7 +481,7 @@ LL |     let _x = false.then(|| 1 / -1);
    |                    help: use `then_some(..)` instead: `then_some(1 / -1)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:255:14
+  --> $DIR/unnecessary_lazy_eval.rs:268:14
    |
 LL |     let _x = false.then(|| i32::MIN / -1);
    |              ^^^^^^----------------------
@@ -489,7 +489,7 @@ LL |     let _x = false.then(|| i32::MIN / -1);
    |                    help: use `then_some(..)` instead: `then_some(i32::MIN / -1)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:258:14
+  --> $DIR/unnecessary_lazy_eval.rs:271:14
    |
 LL |     let _x = false.then(|| i32::MIN / 0);
    |              ^^^^^^---------------------
@@ -497,7 +497,7 @@ LL |     let _x = false.then(|| i32::MIN / 0);
    |                    help: use `then_some(..)` instead: `then_some(i32::MIN / 0)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:260:14
+  --> $DIR/unnecessary_lazy_eval.rs:273:14
    |
 LL |     let _x = false.then(|| 4 / 2);
    |              ^^^^^^--------------
@@ -505,7 +505,7 @@ LL |     let _x = false.then(|| 4 / 2);
    |                    help: use `then_some(..)` instead: `then_some(4 / 2)`
 
 error: unnecessary closure used with `bool::then`
-  --> $DIR/unnecessary_lazy_eval.rs:268:14
+  --> $DIR/unnecessary_lazy_eval.rs:281:14
    |
 LL |     let _x = false.then(|| f1 + f2);
    |              ^^^^^^----------------
diff --git a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs
index d9a7ad8e56c..bdc6fa0f46b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs
@@ -73,4 +73,25 @@ mod issue_10084 {
     }
 }
 
+mod issue_12048 {
+    pub const X: u8 = 0;
+
+    /// Returns a pointer to five.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use foo::point_to_five;
+    ///
+    /// let five_pointer = point_to_five();
+    /// // Safety: this pointer always points to a valid five.
+    /// let five = unsafe { *five_pointer };
+    /// assert_eq!(five, 5);
+    /// ```
+    pub fn point_to_five() -> *const u8 {
+        static FIVE: u8 = 5;
+        &FIVE
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed
index 53dc3c43e2f..f87c898f9b7 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed
@@ -1,4 +1,18 @@
-#[allow(clippy::single_char_pattern)]
+#![allow(clippy::single_char_pattern)]
+
+struct Issue12068;
+
+impl AsRef<str> for Issue12068 {
+    fn as_ref(&self) -> &str {
+        ""
+    }
+}
+
+impl ToString for Issue12068 {
+    fn to_string(&self) -> String {
+        String::new()
+    }
+}
 
 fn main() {
     let _ = "a".split('a').next().unwrap();
@@ -9,6 +23,8 @@ fn main() {
     //~^ ERROR: unnecessary use of `to_owned`
     let _ = "a".split("a").next().unwrap();
     //~^ ERROR: unnecessary use of `to_owned`
+    let _ = Issue12068.as_ref().split('a').next().unwrap();
+    //~^ ERROR: unnecessary use of `to_string`
 
     let _ = [1].split(|x| *x == 2).next().unwrap();
     //~^ ERROR: unnecessary use of `to_vec`
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs
index 62400e7eee1..db5719e5880 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs
@@ -1,4 +1,18 @@
-#[allow(clippy::single_char_pattern)]
+#![allow(clippy::single_char_pattern)]
+
+struct Issue12068;
+
+impl AsRef<str> for Issue12068 {
+    fn as_ref(&self) -> &str {
+        ""
+    }
+}
+
+impl ToString for Issue12068 {
+    fn to_string(&self) -> String {
+        String::new()
+    }
+}
 
 fn main() {
     let _ = "a".to_string().split('a').next().unwrap();
@@ -9,6 +23,8 @@ fn main() {
     //~^ ERROR: unnecessary use of `to_owned`
     let _ = "a".to_owned().split("a").next().unwrap();
     //~^ ERROR: unnecessary use of `to_owned`
+    let _ = Issue12068.to_string().split('a').next().unwrap();
+    //~^ ERROR: unnecessary use of `to_string`
 
     let _ = [1].to_vec().split(|x| *x == 2).next().unwrap();
     //~^ ERROR: unnecessary use of `to_vec`
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr
index cfb3766d15e..4cfaeed3384 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr
@@ -1,5 +1,5 @@
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned_on_split.rs:4:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:18:13
    |
 LL |     let _ = "a".to_string().split('a').next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split('a')`
@@ -8,46 +8,52 @@ LL |     let _ = "a".to_string().split('a').next().unwrap();
    = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]`
 
 error: unnecessary use of `to_string`
-  --> $DIR/unnecessary_to_owned_on_split.rs:6:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:20:13
    |
 LL |     let _ = "a".to_string().split("a").next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split("a")`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned_on_split.rs:8:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:22:13
    |
 LL |     let _ = "a".to_owned().split('a').next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split('a')`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned_on_split.rs:10:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:24:13
    |
 LL |     let _ = "a".to_owned().split("a").next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split("a")`
 
+error: unnecessary use of `to_string`
+  --> $DIR/unnecessary_to_owned_on_split.rs:26:13
+   |
+LL |     let _ = Issue12068.to_string().split('a').next().unwrap();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Issue12068.as_ref().split('a')`
+
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned_on_split.rs:13:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:29:13
    |
 LL |     let _ = [1].to_vec().split(|x| *x == 2).next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
 
 error: unnecessary use of `to_vec`
-  --> $DIR/unnecessary_to_owned_on_split.rs:15:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:31:13
    |
 LL |     let _ = [1].to_vec().split(|x| *x == 2).next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned_on_split.rs:17:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:33:13
    |
 LL |     let _ = [1].to_owned().split(|x| *x == 2).next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
 
 error: unnecessary use of `to_owned`
-  --> $DIR/unnecessary_to_owned_on_split.rs:19:13
+  --> $DIR/unnecessary_to_owned_on_split.rs:35:13
    |
 LL |     let _ = [1].to_owned().split(|x| *x == 2).next().unwrap();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed
index f6770558bd8..88b95095bc0 100644
--- a/src/tools/clippy/tests/ui/useless_asref.fixed
+++ b/src/tools/clippy/tests/ui/useless_asref.fixed
@@ -2,7 +2,9 @@
 #![allow(
     clippy::explicit_auto_deref,
     clippy::uninlined_format_args,
-    clippy::needless_pass_by_ref_mut
+    clippy::map_clone,
+    clippy::needless_pass_by_ref_mut,
+    clippy::redundant_closure
 )]
 
 use std::fmt::Debug;
@@ -132,6 +134,16 @@ fn generic_ok<U: AsMut<T> + AsRef<T> + ?Sized, T: Debug + ?Sized>(mru: &mut U) {
     foo_rt(mru.as_ref());
 }
 
+fn foo() {
+    let x = Some(String::new());
+    let z = x.clone();
+    //~^ ERROR: this call to `as_ref.map(...)` does nothing
+    let z = x.clone();
+    //~^ ERROR: this call to `as_ref.map(...)` does nothing
+    let z = x.clone();
+    //~^ ERROR: this call to `as_ref.map(...)` does nothing
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs
index 0996218076b..504dc1f5cbf 100644
--- a/src/tools/clippy/tests/ui/useless_asref.rs
+++ b/src/tools/clippy/tests/ui/useless_asref.rs
@@ -2,7 +2,9 @@
 #![allow(
     clippy::explicit_auto_deref,
     clippy::uninlined_format_args,
-    clippy::needless_pass_by_ref_mut
+    clippy::map_clone,
+    clippy::needless_pass_by_ref_mut,
+    clippy::redundant_closure
 )]
 
 use std::fmt::Debug;
@@ -132,6 +134,16 @@ fn generic_ok<U: AsMut<T> + AsRef<T> + ?Sized, T: Debug + ?Sized>(mru: &mut U) {
     foo_rt(mru.as_ref());
 }
 
+fn foo() {
+    let x = Some(String::new());
+    let z = x.as_ref().map(String::clone);
+    //~^ ERROR: this call to `as_ref.map(...)` does nothing
+    let z = x.as_ref().map(|z| z.clone());
+    //~^ ERROR: this call to `as_ref.map(...)` does nothing
+    let z = x.as_ref().map(|z| String::clone(z));
+    //~^ ERROR: this call to `as_ref.map(...)` does nothing
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/src/tools/clippy/tests/ui/useless_asref.stderr b/src/tools/clippy/tests/ui/useless_asref.stderr
index 163eb7b1437..deb5d90f2f6 100644
--- a/src/tools/clippy/tests/ui/useless_asref.stderr
+++ b/src/tools/clippy/tests/ui/useless_asref.stderr
@@ -1,5 +1,5 @@
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:46:18
+  --> $DIR/useless_asref.rs:48:18
    |
 LL |         foo_rstr(rstr.as_ref());
    |                  ^^^^^^^^^^^^^ help: try: `rstr`
@@ -11,64 +11,82 @@ LL | #![deny(clippy::useless_asref)]
    |         ^^^^^^^^^^^^^^^^^^^^^
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:48:20
+  --> $DIR/useless_asref.rs:50:20
    |
 LL |         foo_rslice(rslice.as_ref());
    |                    ^^^^^^^^^^^^^^^ help: try: `rslice`
 
 error: this call to `as_mut` does nothing
-  --> $DIR/useless_asref.rs:52:21
+  --> $DIR/useless_asref.rs:54:21
    |
 LL |         foo_mrslice(mrslice.as_mut());
    |                     ^^^^^^^^^^^^^^^^ help: try: `mrslice`
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:54:20
+  --> $DIR/useless_asref.rs:56:20
    |
 LL |         foo_rslice(mrslice.as_ref());
    |                    ^^^^^^^^^^^^^^^^ help: try: `mrslice`
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:61:20
+  --> $DIR/useless_asref.rs:63:20
    |
 LL |         foo_rslice(rrrrrslice.as_ref());
    |                    ^^^^^^^^^^^^^^^^^^^ help: try: `rrrrrslice`
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:63:18
+  --> $DIR/useless_asref.rs:65:18
    |
 LL |         foo_rstr(rrrrrstr.as_ref());
    |                  ^^^^^^^^^^^^^^^^^ help: try: `rrrrrstr`
 
 error: this call to `as_mut` does nothing
-  --> $DIR/useless_asref.rs:68:21
+  --> $DIR/useless_asref.rs:70:21
    |
 LL |         foo_mrslice(mrrrrrslice.as_mut());
    |                     ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice`
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:70:20
+  --> $DIR/useless_asref.rs:72:20
    |
 LL |         foo_rslice(mrrrrrslice.as_ref());
    |                    ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice`
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:74:16
+  --> $DIR/useless_asref.rs:76:16
    |
 LL |     foo_rrrrmr((&&&&MoreRef).as_ref());
    |                ^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&&&&MoreRef)`
 
 error: this call to `as_mut` does nothing
-  --> $DIR/useless_asref.rs:124:13
+  --> $DIR/useless_asref.rs:126:13
    |
 LL |     foo_mrt(mrt.as_mut());
    |             ^^^^^^^^^^^^ help: try: `mrt`
 
 error: this call to `as_ref` does nothing
-  --> $DIR/useless_asref.rs:126:12
+  --> $DIR/useless_asref.rs:128:12
    |
 LL |     foo_rt(mrt.as_ref());
    |            ^^^^^^^^^^^^ help: try: `mrt`
 
-error: aborting due to 11 previous errors
+error: this call to `as_ref.map(...)` does nothing
+  --> $DIR/useless_asref.rs:139:13
+   |
+LL |     let z = x.as_ref().map(String::clone);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()`
+
+error: this call to `as_ref.map(...)` does nothing
+  --> $DIR/useless_asref.rs:141:13
+   |
+LL |     let z = x.as_ref().map(|z| z.clone());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()`
+
+error: this call to `as_ref.map(...)` does nothing
+  --> $DIR/useless_asref.rs:143:13
+   |
+LL |     let z = x.as_ref().map(|z| String::clone(z));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()`
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed
index ed8387b7eb2..ce00fde2f99 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.fixed
+++ b/src/tools/clippy/tests/ui/useless_conversion.fixed
@@ -241,7 +241,7 @@ mod issue11300 {
         foo2::<(), _>([1, 2, 3].into_iter());
 
         // This should lint. Removing the `.into_iter()` means that `I` gets substituted with `[i32; 3]`,
-        // and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unncessary.
+        // and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unnecessary.
         foo3([1, 2, 3]);
     }
 
@@ -253,7 +253,7 @@ mod issue11300 {
 
         S1.foo([1, 2]);
 
-        // ICE that occured in itertools
+        // ICE that occurred in itertools
         trait Itertools {
             fn interleave_shortest<J>(self, other: J)
             where
diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs
index 991a7762fc6..39979619586 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.rs
+++ b/src/tools/clippy/tests/ui/useless_conversion.rs
@@ -241,7 +241,7 @@ mod issue11300 {
         foo2::<(), _>([1, 2, 3].into_iter());
 
         // This should lint. Removing the `.into_iter()` means that `I` gets substituted with `[i32; 3]`,
-        // and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unncessary.
+        // and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unnecessary.
         foo3([1, 2, 3].into_iter());
     }
 
@@ -253,7 +253,7 @@ mod issue11300 {
 
         S1.foo([1, 2].into_iter());
 
-        // ICE that occured in itertools
+        // ICE that occurred in itertools
         trait Itertools {
             fn interleave_shortest<J>(self, other: J)
             where
diff --git a/src/tools/clippy/tests/ui/vec.fixed b/src/tools/clippy/tests/ui/vec.fixed
index 81b8bd7da77..b318fd42f7c 100644
--- a/src/tools/clippy/tests/ui/vec.fixed
+++ b/src/tools/clippy/tests/ui/vec.fixed
@@ -210,3 +210,10 @@ fn issue11861() {
     // should not lint
     m!(vec![1]);
 }
+
+fn issue_11958() {
+    fn f(_s: &[String]) {}
+
+    // should not lint, `String` is not `Copy`
+    f(&vec!["test".to_owned(); 2]);
+}
diff --git a/src/tools/clippy/tests/ui/vec.rs b/src/tools/clippy/tests/ui/vec.rs
index 5aca9b2925c..08ad6efa37f 100644
--- a/src/tools/clippy/tests/ui/vec.rs
+++ b/src/tools/clippy/tests/ui/vec.rs
@@ -210,3 +210,10 @@ fn issue11861() {
     // should not lint
     m!(vec![1]);
 }
+
+fn issue_11958() {
+    fn f(_s: &[String]) {}
+
+    // should not lint, `String` is not `Copy`
+    f(&vec!["test".to_owned(); 2]);
+}
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index 96085bcf9ee..a05765b3981 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -28,7 +28,6 @@ users_on_vacation = ["blyxyas"]
 "*" = [
     "@Manishearth",
     "@llogiq",
-    "@giraffate",
     "@xFrednet",
     "@Alexendoo",
     "@dswij",