about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2022-06-04 12:53:27 +0200
committerPhilipp Krones <hello@philkrones.com>2022-06-04 12:53:27 +0200
commit7f402b15c78d32b8a536960816fa4f1d7f75ac4a (patch)
tree0080c24f0e524afd66958a148f29deb4d604de36
parent57304823dbd1c246d1166e85c156e694d2f7a184 (diff)
parent8ef490871c0cc0a3aff00976c6f00c7eab6d90c7 (diff)
downloadrust-7f402b15c78d32b8a536960816fa4f1d7f75ac4a.tar.gz
rust-7f402b15c78d32b8a536960816fa4f1d7f75ac4a.zip
Merge remote-tracking branch 'upstream/master' into rustup
-rw-r--r--CHANGELOG.md10
-rw-r--r--Cargo.toml5
-rw-r--r--clippy_dev/Cargo.toml2
-rw-r--r--clippy_dev/src/main.rs156
-rw-r--r--clippy_dev/src/serve.rs10
-rw-r--r--clippy_lints/src/almost_complete_letter_range.rs100
-rw-r--r--clippy_lints/src/approx_const.rs2
-rw-r--r--clippy_lints/src/as_conversions.rs9
-rw-r--r--clippy_lints/src/as_underscore.rs74
-rw-r--r--clippy_lints/src/assign_ops.rs10
-rw-r--r--clippy_lints/src/attrs.rs59
-rw-r--r--clippy_lints/src/blocks_in_if_conditions.rs12
-rw-r--r--clippy_lints/src/booleans.rs19
-rw-r--r--clippy_lints/src/borrow_deref_ref.rs118
-rw-r--r--clippy_lints/src/bytecount.rs8
-rw-r--r--clippy_lints/src/casts/cast_abs_to_unsigned.rs46
-rw-r--r--clippy_lints/src/checked_conversions.rs4
-rw-r--r--clippy_lints/src/cognitive_complexity.rs2
-rw-r--r--clippy_lints/src/collapsible_if.rs2
-rw-r--r--clippy_lints/src/comparison_chain.rs2
-rw-r--r--clippy_lints/src/copies.rs2
-rw-r--r--clippy_lints/src/crate_in_macro_def.rs4
-rw-r--r--clippy_lints/src/dbg_macro.rs21
-rw-r--r--clippy_lints/src/derivable_impls.rs2
-rw-r--r--clippy_lints/src/derive.rs47
-rw-r--r--clippy_lints/src/doc_link_with_quotes.rs60
-rw-r--r--clippy_lints/src/double_comparison.rs2
-rw-r--r--clippy_lints/src/double_parens.rs14
-rw-r--r--clippy_lints/src/duration_subsec.rs18
-rw-r--r--clippy_lints/src/else_if_without_else.rs2
-rw-r--r--clippy_lints/src/empty_enum.rs3
-rw-r--r--clippy_lints/src/entry.rs2
-rw-r--r--clippy_lints/src/enum_variants.rs2
-rw-r--r--clippy_lints/src/eq_op.rs6
-rw-r--r--clippy_lints/src/equatable_if_let.rs2
-rw-r--r--clippy_lints/src/escape.rs6
-rw-r--r--clippy_lints/src/excessive_bools.rs3
-rw-r--r--clippy_lints/src/explicit_write.rs10
-rw-r--r--clippy_lints/src/fallible_impl_from.rs3
-rw-r--r--clippy_lints/src/float_literal.rs5
-rw-r--r--clippy_lints/src/floating_point_arithmetic.rs3
-rw-r--r--clippy_lints/src/format.rs7
-rw-r--r--clippy_lints/src/formatting.rs16
-rw-r--r--clippy_lints/src/get_first.rs69
-rw-r--r--clippy_lints/src/get_last_with_len.rs107
-rw-r--r--clippy_lints/src/identity_op.rs125
-rw-r--r--clippy_lints/src/large_enum_variant.rs88
-rw-r--r--clippy_lints/src/let_if_seq.rs2
-rw-r--r--clippy_lints/src/lib.register_all.rs18
-rw-r--r--clippy_lints/src/lib.register_complexity.rs6
-rw-r--r--clippy_lints/src/lib.register_correctness.rs2
-rw-r--r--clippy_lints/src/lib.register_lints.rs29
-rw-r--r--clippy_lints/src/lib.register_nursery.rs5
-rw-r--r--clippy_lints/src/lib.register_pedantic.rs6
-rw-r--r--clippy_lints/src/lib.register_restriction.rs7
-rw-r--r--clippy_lints/src/lib.register_style.rs5
-rw-r--r--clippy_lints/src/lib.register_suspicious.rs5
-rw-r--r--clippy_lints/src/lib.rs39
-rw-r--r--clippy_lints/src/loops/mod.rs15
-rw-r--r--clippy_lints/src/loops/needless_range_loop.rs57
-rw-r--r--clippy_lints/src/loops/never_loop.rs2
-rw-r--r--clippy_lints/src/macro_use.rs3
-rw-r--r--clippy_lints/src/manual_map.rs316
-rw-r--r--clippy_lints/src/manual_non_exhaustive.rs2
-rw-r--r--clippy_lints/src/manual_unwrap_or.rs123
-rw-r--r--clippy_lints/src/match_on_vec_items.rs104
-rw-r--r--clippy_lints/src/matches/collapsible_match.rs (renamed from clippy_lints/src/collapsible_match.rs)70
-rw-r--r--clippy_lints/src/matches/manual_map.rs306
-rw-r--r--clippy_lints/src/matches/manual_unwrap_or.rs83
-rw-r--r--clippy_lints/src/matches/match_bool.rs4
-rw-r--r--clippy_lints/src/matches/match_like_matches.rs34
-rw-r--r--clippy_lints/src/matches/match_on_vec_items.rs61
-rw-r--r--clippy_lints/src/matches/match_str_case_mismatch.rs (renamed from clippy_lints/src/match_str_case_mismatch.rs)75
-rw-r--r--clippy_lints/src/matches/mod.rs351
-rw-r--r--clippy_lints/src/matches/needless_match.rs30
-rw-r--r--clippy_lints/src/matches/redundant_pattern_match.rs20
-rw-r--r--clippy_lints/src/matches/significant_drop_in_scrutinee.rs (renamed from clippy_lints/src/significant_drop_in_scrutinee.rs)216
-rw-r--r--clippy_lints/src/matches/try_err.rs145
-rw-r--r--clippy_lints/src/methods/get_last_with_len.rs55
-rw-r--r--clippy_lints/src/methods/iter_next_slice.rs9
-rw-r--r--clippy_lints/src/methods/mod.rs157
-rw-r--r--clippy_lints/src/methods/no_effect_replace.rs47
-rw-r--r--clippy_lints/src/methods/option_map_or_none.rs4
-rw-r--r--clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--clippy_lints/src/minmax.rs8
-rw-r--r--clippy_lints/src/misc.rs14
-rw-r--r--clippy_lints/src/mismatching_type_param_order.rs116
-rw-r--r--clippy_lints/src/missing_doc.rs21
-rw-r--r--clippy_lints/src/mixed_read_write_in_expression.rs2
-rw-r--r--clippy_lints/src/mut_key.rs2
-rw-r--r--clippy_lints/src/mutable_debug_assertion.rs11
-rw-r--r--clippy_lints/src/needless_late_init.rs13
-rw-r--r--clippy_lints/src/numeric_arithmetic.rs (renamed from clippy_lints/src/arithmetic.rs)6
-rw-r--r--clippy_lints/src/panic_in_result_fn.rs2
-rw-r--r--clippy_lints/src/pass_by_ref_or_value.rs2
-rw-r--r--clippy_lints/src/ranges.rs20
-rw-r--r--clippy_lints/src/rc_clone_in_vec_init.rs56
-rw-r--r--clippy_lints/src/redundant_clone.rs6
-rw-r--r--clippy_lints/src/redundant_static_lifetimes.rs9
-rw-r--r--clippy_lints/src/returns.rs14
-rw-r--r--clippy_lints/src/same_name_method.rs10
-rw-r--r--clippy_lints/src/shadow.rs53
-rw-r--r--clippy_lints/src/size_of_in_element_count.rs2
-rw-r--r--clippy_lints/src/swap_ptr_to_ref.rs80
-rw-r--r--clippy_lints/src/trait_bounds.rs14
-rw-r--r--clippy_lints/src/transmute/mod.rs2
-rw-r--r--clippy_lints/src/transmute/useless_transmute.rs47
-rw-r--r--clippy_lints/src/try_err.rs186
-rw-r--r--clippy_lints/src/unused_rounding.rs69
-rw-r--r--clippy_lints/src/use_self.rs18
-rw-r--r--clippy_lints/src/utils/conf.rs4
-rw-r--r--clippy_lints/src/utils/internal_lints.rs8
-rw-r--r--clippy_lints/src/utils/internal_lints/metadata_collector.rs58
-rw-r--r--clippy_utils/src/consts.rs2
-rw-r--r--clippy_utils/src/diagnostics.rs12
-rw-r--r--clippy_utils/src/higher.rs2
-rw-r--r--clippy_utils/src/hir_utils.rs6
-rw-r--r--clippy_utils/src/lib.rs19
-rw-r--r--clippy_utils/src/msrvs.rs1
-rw-r--r--clippy_utils/src/paths.rs2
-rw-r--r--clippy_utils/src/qualify_min_const_fn.rs21
-rw-r--r--clippy_utils/src/source.rs23
-rw-r--r--clippy_utils/src/ty.rs22
-rw-r--r--doc/adding_lints.md11
-rw-r--r--doc/common_tools_writing_lints.md3
-rw-r--r--lintcheck/Cargo.toml2
-rw-r--r--lintcheck/src/config.rs22
-rw-r--r--tests/compile-test.rs95
-rw-r--r--tests/ui-internal/unnecessary_symbol_str.fixed1
-rw-r--r--tests/ui-internal/unnecessary_symbol_str.rs1
-rw-r--r--tests/ui-internal/unnecessary_symbol_str.stderr10
-rw-r--r--tests/ui-toml/dbg_macro/clippy.toml1
-rw-r--r--tests/ui-toml/dbg_macro/dbg_macro.rs39
-rw-r--r--tests/ui-toml/dbg_macro/dbg_macro.stderr102
-rw-r--r--tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr1
-rw-r--r--tests/ui-toml/unwrap_used/unwrap_used.rs2
-rw-r--r--tests/ui/almost_complete_letter_range.fixed66
-rw-r--r--tests/ui/almost_complete_letter_range.rs66
-rw-r--r--tests/ui/almost_complete_letter_range.stderr100
-rw-r--r--tests/ui/as_underscore.fixed13
-rw-r--r--tests/ui/as_underscore.rs13
-rw-r--r--tests/ui/as_underscore.stderr20
-rw-r--r--tests/ui/bind_instead_of_map_multipart.fixed62
-rw-r--r--tests/ui/bind_instead_of_map_multipart.rs1
-rw-r--r--tests/ui/bind_instead_of_map_multipart.stderr12
-rw-r--r--tests/ui/borrow_deref_ref.fixed59
-rw-r--r--tests/ui/borrow_deref_ref.rs59
-rw-r--r--tests/ui/borrow_deref_ref.stderr22
-rw-r--r--tests/ui/borrow_deref_ref_unfixable.rs10
-rw-r--r--tests/ui/borrow_deref_ref_unfixable.stderr18
-rw-r--r--tests/ui/cast_abs_to_unsigned.fixed21
-rw-r--r--tests/ui/cast_abs_to_unsigned.rs21
-rw-r--r--tests/ui/cast_abs_to_unsigned.stderr92
-rw-r--r--tests/ui/collapsible_match2.rs2
-rw-r--r--tests/ui/collapsible_match2.stderr4
-rw-r--r--tests/ui/crashes/ice-8850.rs27
-rw-r--r--tests/ui/crashes/ice-8850.stderr45
-rw-r--r--tests/ui/dbg_macro.stderr35
-rw-r--r--tests/ui/debug_assert_with_mut_call.rs2
-rw-r--r--tests/ui/deref_by_slicing.fixed1
-rw-r--r--tests/ui/deref_by_slicing.rs1
-rw-r--r--tests/ui/deref_by_slicing.stderr18
-rw-r--r--tests/ui/derive_partial_eq_without_eq.fixed6
-rw-r--r--tests/ui/derive_partial_eq_without_eq.rs6
-rw-r--r--tests/ui/doc_link_with_quotes.rs12
-rw-r--r--tests/ui/doc_link_with_quotes.stderr10
-rw-r--r--tests/ui/empty_line_after_outer_attribute.rs10
-rw-r--r--tests/ui/empty_line_after_outer_attribute.stderr12
-rw-r--r--tests/ui/expect_tool_lint_rfc_2383.rs12
-rw-r--r--tests/ui/explicit_deref_methods.fixed7
-rw-r--r--tests/ui/explicit_deref_methods.rs7
-rw-r--r--tests/ui/explicit_deref_methods.stderr24
-rw-r--r--tests/ui/forget_ref.rs1
-rw-r--r--tests/ui/forget_ref.stderr36
-rw-r--r--tests/ui/get_first.fixed42
-rw-r--r--tests/ui/get_first.rs42
-rw-r--r--tests/ui/get_first.stderr22
-rw-r--r--tests/ui/get_last_with_len.fixed28
-rw-r--r--tests/ui/get_last_with_len.rs28
-rw-r--r--tests/ui/get_last_with_len.stderr36
-rw-r--r--tests/ui/get_unwrap.fixed2
-rw-r--r--tests/ui/get_unwrap.rs2
-rw-r--r--tests/ui/identity_op.fixed119
-rw-r--r--tests/ui/identity_op.rs63
-rw-r--r--tests/ui/identity_op.stderr260
-rw-r--r--tests/ui/implicit_clone.fixed118
-rw-r--r--tests/ui/implicit_clone.rs3
-rw-r--r--tests/ui/implicit_clone.stderr24
-rw-r--r--tests/ui/issue_2356.fixed26
-rw-r--r--tests/ui/issue_2356.rs2
-rw-r--r--tests/ui/issue_2356.stderr4
-rw-r--r--tests/ui/iter_next_slice.fixed8
-rw-r--r--tests/ui/iter_next_slice.rs4
-rw-r--r--tests/ui/iter_next_slice.stderr4
-rw-r--r--tests/ui/large_enum_variant.rs32
-rw-r--r--tests/ui/large_enum_variant.stderr68
-rw-r--r--tests/ui/map_flatten_fixable.fixed37
-rw-r--r--tests/ui/map_flatten_fixable.rs36
-rw-r--r--tests/ui/map_flatten_fixable.stderr28
-rw-r--r--tests/ui/match_ref_pats.fixed118
-rw-r--r--tests/ui/match_ref_pats.rs3
-rw-r--r--tests/ui/match_ref_pats.stderr10
-rw-r--r--tests/ui/match_str_case_mismatch.fixed186
-rw-r--r--tests/ui/match_str_case_mismatch.rs2
-rw-r--r--tests/ui/match_str_case_mismatch.stderr14
-rw-r--r--tests/ui/mismatching_type_param_order.rs60
-rw-r--r--tests/ui/mismatching_type_param_order.stderr83
-rw-r--r--tests/ui/modulo_one.rs2
-rw-r--r--tests/ui/modulo_one.stderr10
-rw-r--r--tests/ui/needless_late_init.fixed273
-rw-r--r--tests/ui/needless_late_init.rs44
-rw-r--r--tests/ui/needless_late_init.stderr93
-rw-r--r--tests/ui/needless_late_init_fixable.fixed19
-rw-r--r--tests/ui/needless_late_init_fixable.rs19
-rw-r--r--tests/ui/needless_late_init_fixable.stderr70
-rw-r--r--tests/ui/needless_lifetimes.rs3
-rw-r--r--tests/ui/needless_lifetimes.stderr62
-rw-r--r--tests/ui/needless_return.fixed10
-rw-r--r--tests/ui/needless_return.rs6
-rw-r--r--tests/ui/needless_return.stderr20
-rw-r--r--tests/ui/no_effect_replace.rs51
-rw-r--r--tests/ui/no_effect_replace.stderr52
-rw-r--r--tests/ui/nonminimal_bool_methods.fixed111
-rw-r--r--tests/ui/nonminimal_bool_methods.rs1
-rw-r--r--tests/ui/nonminimal_bool_methods.stderr26
-rw-r--r--tests/ui/range_contains.fixed7
-rw-r--r--tests/ui/range_contains.rs7
-rw-r--r--tests/ui/range_contains.stderr26
-rw-r--r--tests/ui/rc_buffer.fixed28
-rw-r--r--tests/ui/rc_buffer.rs2
-rw-r--r--tests/ui/rc_buffer.stderr16
-rw-r--r--tests/ui/rc_buffer_arc.fixed27
-rw-r--r--tests/ui/rc_buffer_arc.rs2
-rw-r--r--tests/ui/rc_buffer_arc.stderr16
-rw-r--r--tests/ui/rc_clone_in_vec_init/arc.stderr16
-rw-r--r--tests/ui/rc_clone_in_vec_init/rc.stderr16
-rw-r--r--tests/ui/rc_clone_in_vec_init/weak.rs83
-rw-r--r--tests/ui/rc_clone_in_vec_init/weak.stderr201
-rw-r--r--tests/ui/recursive_format_impl.rs3
-rw-r--r--tests/ui/recursive_format_impl.stderr20
-rw-r--r--tests/ui/shadow.rs7
-rw-r--r--tests/ui/significant_drop_in_scrutinee.rs39
-rw-r--r--tests/ui/significant_drop_in_scrutinee.stderr60
-rw-r--r--tests/ui/suspicious_operation_groupings.fixed209
-rw-r--r--tests/ui/suspicious_operation_groupings.rs3
-rw-r--r--tests/ui/suspicious_operation_groupings.stderr52
-rw-r--r--tests/ui/swap_ptr_to_ref.fixed24
-rw-r--r--tests/ui/swap_ptr_to_ref.rs24
-rw-r--r--tests/ui/swap_ptr_to_ref.stderr28
-rw-r--r--tests/ui/swap_ptr_to_ref_unfixable.rs18
-rw-r--r--tests/ui/swap_ptr_to_ref_unfixable.stderr22
-rw-r--r--tests/ui/temporary_assignment.rs1
-rw-r--r--tests/ui/temporary_assignment.stderr8
-rw-r--r--tests/ui/transmute.rs19
-rw-r--r--tests/ui/transmute.stderr88
-rw-r--r--tests/ui/transmute_undefined_repr.rs2
-rw-r--r--tests/ui/unicode.fixed36
-rw-r--r--tests/ui/unicode.rs1
-rw-r--r--tests/ui/unicode.stderr14
-rw-r--r--tests/ui/unit_arg_empty_blocks.fixed30
-rw-r--r--tests/ui/unit_arg_empty_blocks.rs1
-rw-r--r--tests/ui/unit_arg_empty_blocks.stderr8
-rw-r--r--tests/ui/unnecessary_cast.fixed91
-rw-r--r--tests/ui/unnecessary_cast.rs54
-rw-r--r--tests/ui/unnecessary_cast.stderr120
-rw-r--r--tests/ui/unnecessary_cast_fixable.fixed50
-rw-r--r--tests/ui/unnecessary_cast_fixable.rs50
-rw-r--r--tests/ui/unnecessary_cast_fixable.stderr106
-rw-r--r--tests/ui/unused_rounding.fixed9
-rw-r--r--tests/ui/unused_rounding.rs9
-rw-r--r--tests/ui/unused_rounding.stderr22
-rw-r--r--tests/ui/use_self.fixed66
-rw-r--r--tests/ui/use_self.rs66
-rw-r--r--tests/ui/use_self.stderr62
-rw-r--r--util/gh-pages/script.js37
275 files changed, 7507 insertions, 2665 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10ef00fcbaf..6ef338b819d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3276,9 +3276,11 @@ Released 2018-09-13
 <!-- begin autogenerated links to lint list -->
 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
 [`allow_attributes_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#allow_attributes_without_reason
+[`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range
 [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
 [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
 [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
+[`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore
 [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
 [`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern
 [`assign_ops`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_ops
@@ -3296,6 +3298,7 @@ Released 2018-09-13
 [`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison
 [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
 [`borrow_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr
+[`borrow_deref_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_deref_ref
 [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
 [`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
 [`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection
@@ -3362,6 +3365,7 @@ Released 2018-09-13
 [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
 [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
+[`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
 [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
@@ -3435,6 +3439,7 @@ Released 2018-09-13
 [`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
 [`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
 [`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send
+[`get_first`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_first
 [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len
 [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap
 [`identity_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_conversion
@@ -3556,6 +3561,7 @@ Released 2018-09-13
 [`min_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_max
 [`misaligned_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#misaligned_transmute
 [`mismatched_target_os`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatched_target_os
+[`mismatching_type_param_order`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatching_type_param_order
 [`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op
 [`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
 [`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
@@ -3613,6 +3619,7 @@ Released 2018-09-13
 [`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
 [`new_without_default_derive`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default_derive
 [`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
+[`no_effect_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_replace
 [`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
 [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
 [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
@@ -3729,7 +3736,6 @@ Released 2018-09-13
 [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next
 [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization
 [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive
-[`significant_drop_in_scrutinee`]: https://rust-lang.github.io/rust-clippy/master/index.html#significant_drop_in_scrutinee
 [`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
@@ -3750,6 +3756,7 @@ Released 2018-09-13
 [`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings
 [`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
 [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
+[`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref
 [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
 [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
 [`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
@@ -3820,6 +3827,7 @@ Released 2018-09-13
 [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
 [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 [`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
+[`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding
 [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
 [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
 [`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
diff --git a/Cargo.toml b/Cargo.toml
index 373e720b0d5..d23d681df00 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -28,7 +28,7 @@ tempfile = { version = "3.2", optional = true }
 termize = "0.1"
 
 [dev-dependencies]
-compiletest_rs = { version = "0.7.1", features = ["tmp"] }
+compiletest_rs = { version = "0.8", features = ["tmp"] }
 tester = "0.9"
 regex = "1.5"
 # This is used by the `collect-metadata` alias.
@@ -40,6 +40,7 @@ filetime = "0.2"
 rustc-workspace-hack = "1.0"
 
 # UI test dependencies
+clap = { version = "3.1", features = ["derive"] }
 clippy_utils = { path = "clippy_utils" }
 derive-new = "0.5"
 if_chain = "1.0"
@@ -48,7 +49,7 @@ quote = "1.0"
 serde = { version = "1.0.125", features = ["derive"] }
 syn = { version = "1.0", features = ["full"] }
 futures = "0.3"
-parking_lot = "0.11.2"
+parking_lot = "0.12"
 tokio = { version = "1", features = ["io-util"] }
 rustc-semver = "1.1"
 
diff --git a/clippy_dev/Cargo.toml b/clippy_dev/Cargo.toml
index 2cfbcea5034..b0d470a2124 100644
--- a/clippy_dev/Cargo.toml
+++ b/clippy_dev/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 
 [dependencies]
 aho-corasick = "0.7"
-clap = "2.33"
+clap = "3.1"
 indoc = "1.0"
 itertools = "0.10.1"
 opener = "0.5"
diff --git a/clippy_dev/src/main.rs b/clippy_dev/src/main.rs
index d5cd7ca96c0..ee535b1d3be 100644
--- a/clippy_dev/src/main.rs
+++ b/clippy_dev/src/main.rs
@@ -2,20 +2,20 @@
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
+use clap::{Arg, ArgMatches, Command};
 use clippy_dev::{bless, fmt, lint, new_lint, serve, setup, update_lints};
 use indoc::indoc;
 fn main() {
     let matches = get_clap_config();
 
     match matches.subcommand() {
-        ("bless", Some(matches)) => {
+        Some(("bless", matches)) => {
             bless::bless(matches.is_present("ignore-timestamp"));
         },
-        ("fmt", Some(matches)) => {
+        Some(("fmt", matches)) => {
             fmt::run(matches.is_present("check"), matches.is_present("verbose"));
         },
-        ("update_lints", Some(matches)) => {
+        Some(("update_lints", matches)) => {
             if matches.is_present("print-only") {
                 update_lints::print_lints();
             } else if matches.is_present("check") {
@@ -24,7 +24,7 @@ fn main() {
                 update_lints::update(update_lints::UpdateMode::Change);
             }
         },
-        ("new_lint", Some(matches)) => {
+        Some(("new_lint", matches)) => {
             match new_lint::create(
                 matches.value_of("pass"),
                 matches.value_of("name"),
@@ -35,8 +35,8 @@ fn main() {
                 Err(e) => eprintln!("Unable to create lint: {}", e),
             }
         },
-        ("setup", Some(sub_command)) => match sub_command.subcommand() {
-            ("intellij", Some(matches)) => {
+        Some(("setup", sub_command)) => match sub_command.subcommand() {
+            Some(("intellij", matches)) => {
                 if matches.is_present("remove") {
                     setup::intellij::remove_rustc_src();
                 } else {
@@ -47,14 +47,14 @@ fn main() {
                     );
                 }
             },
-            ("git-hook", Some(matches)) => {
+            Some(("git-hook", matches)) => {
                 if matches.is_present("remove") {
                     setup::git_hook::remove_hook();
                 } else {
                     setup::git_hook::install_hook(matches.is_present("force-override"));
                 }
             },
-            ("vscode-tasks", Some(matches)) => {
+            Some(("vscode-tasks", matches)) => {
                 if matches.is_present("remove") {
                     setup::vscode::remove_tasks();
                 } else {
@@ -63,23 +63,23 @@ fn main() {
             },
             _ => {},
         },
-        ("remove", Some(sub_command)) => match sub_command.subcommand() {
-            ("git-hook", Some(_)) => setup::git_hook::remove_hook(),
-            ("intellij", Some(_)) => setup::intellij::remove_rustc_src(),
-            ("vscode-tasks", Some(_)) => setup::vscode::remove_tasks(),
+        Some(("remove", sub_command)) => match sub_command.subcommand() {
+            Some(("git-hook", _)) => setup::git_hook::remove_hook(),
+            Some(("intellij", _)) => setup::intellij::remove_rustc_src(),
+            Some(("vscode-tasks", _)) => setup::vscode::remove_tasks(),
             _ => {},
         },
-        ("serve", Some(matches)) => {
+        Some(("serve", matches)) => {
             let port = matches.value_of("port").unwrap().parse().unwrap();
             let lint = matches.value_of("lint");
             serve::run(port, lint);
         },
-        ("lint", Some(matches)) => {
+        Some(("lint", matches)) => {
             let path = matches.value_of("path").unwrap();
             let args = matches.values_of("args").into_iter().flatten();
             lint::run(path, args);
         },
-        ("rename_lint", Some(matches)) => {
+        Some(("rename_lint", matches)) => {
             let old_name = matches.value_of("old_name").unwrap();
             let new_name = matches.value_of("new_name").unwrap_or(old_name);
             let uplift = matches.is_present("uplift");
@@ -89,35 +89,24 @@ fn main() {
     }
 }
 
-fn get_clap_config<'a>() -> ArgMatches<'a> {
-    App::new("Clippy developer tooling")
-        .setting(AppSettings::ArgRequiredElseHelp)
+fn get_clap_config() -> ArgMatches {
+    Command::new("Clippy developer tooling")
+        .arg_required_else_help(true)
         .subcommand(
-            SubCommand::with_name("bless")
-                .about("bless the test output changes")
-                .arg(
-                    Arg::with_name("ignore-timestamp")
-                        .long("ignore-timestamp")
-                        .help("Include files updated before clippy was built"),
-                ),
+            Command::new("bless").about("bless the test output changes").arg(
+                Arg::new("ignore-timestamp")
+                    .long("ignore-timestamp")
+                    .help("Include files updated before clippy was built"),
+            ),
         )
         .subcommand(
-            SubCommand::with_name("fmt")
+            Command::new("fmt")
                 .about("Run rustfmt on all projects and tests")
-                .arg(
-                    Arg::with_name("check")
-                        .long("check")
-                        .help("Use the rustfmt --check option"),
-                )
-                .arg(
-                    Arg::with_name("verbose")
-                        .short("v")
-                        .long("verbose")
-                        .help("Echo commands run"),
-                ),
+                .arg(Arg::new("check").long("check").help("Use the rustfmt --check option"))
+                .arg(Arg::new("verbose").short('v').long("verbose").help("Echo commands run")),
         )
         .subcommand(
-            SubCommand::with_name("update_lints")
+            Command::new("update_lints")
                 .about("Updates lint registration and information from the source code")
                 .long_about(
                     "Makes sure that:\n \
@@ -127,23 +116,23 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
                  * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
                  * all lints are registered in the lint store",
                 )
-                .arg(Arg::with_name("print-only").long("print-only").help(
+                .arg(Arg::new("print-only").long("print-only").help(
                     "Print a table of lints to STDOUT. \
                  This does not include deprecated and internal lints. \
                  (Does not modify any files)",
                 ))
                 .arg(
-                    Arg::with_name("check")
+                    Arg::new("check")
                         .long("check")
                         .help("Checks that `cargo dev update_lints` has been run. Used on CI."),
                 ),
         )
         .subcommand(
-            SubCommand::with_name("new_lint")
+            Command::new("new_lint")
                 .about("Create new lint and run `cargo dev update_lints`")
                 .arg(
-                    Arg::with_name("pass")
-                        .short("p")
+                    Arg::new("pass")
+                        .short('p')
                         .long("pass")
                         .help("Specify whether the lint runs during the early or late pass")
                         .takes_value(true)
@@ -151,16 +140,16 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
                         .required(true),
                 )
                 .arg(
-                    Arg::with_name("name")
-                        .short("n")
+                    Arg::new("name")
+                        .short('n')
                         .long("name")
                         .help("Name of the new lint in snake case, ex: fn_too_long")
                         .takes_value(true)
                         .required(true),
                 )
                 .arg(
-                    Arg::with_name("category")
-                        .short("c")
+                    Arg::new("category")
+                        .short('c')
                         .long("category")
                         .help("What category the lint belongs to")
                         .default_value("nursery")
@@ -179,29 +168,25 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
                         ])
                         .takes_value(true),
                 )
-                .arg(
-                    Arg::with_name("msrv")
-                        .long("msrv")
-                        .help("Add MSRV config code to the lint"),
-                ),
+                .arg(Arg::new("msrv").long("msrv").help("Add MSRV config code to the lint")),
         )
         .subcommand(
-            SubCommand::with_name("setup")
+            Command::new("setup")
                 .about("Support for setting up your personal development environment")
-                .setting(AppSettings::ArgRequiredElseHelp)
+                .arg_required_else_help(true)
                 .subcommand(
-                    SubCommand::with_name("intellij")
+                    Command::new("intellij")
                         .about("Alter dependencies so Intellij Rust can find rustc internals")
                         .arg(
-                            Arg::with_name("remove")
+                            Arg::new("remove")
                                 .long("remove")
                                 .help("Remove the dependencies added with 'cargo dev setup intellij'")
                                 .required(false),
                         )
                         .arg(
-                            Arg::with_name("rustc-repo-path")
+                            Arg::new("rustc-repo-path")
                                 .long("repo-path")
-                                .short("r")
+                                .short('r')
                                 .help("The path to a rustc repo that will be used for setting the dependencies")
                                 .takes_value(true)
                                 .value_name("path")
@@ -210,66 +195,65 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
                         ),
                 )
                 .subcommand(
-                    SubCommand::with_name("git-hook")
+                    Command::new("git-hook")
                         .about("Add a pre-commit git hook that formats your code to make it look pretty")
                         .arg(
-                            Arg::with_name("remove")
+                            Arg::new("remove")
                                 .long("remove")
                                 .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'")
                                 .required(false),
                         )
                         .arg(
-                            Arg::with_name("force-override")
+                            Arg::new("force-override")
                                 .long("force-override")
-                                .short("f")
+                                .short('f')
                                 .help("Forces the override of an existing git pre-commit hook")
                                 .required(false),
                         ),
                 )
                 .subcommand(
-                    SubCommand::with_name("vscode-tasks")
+                    Command::new("vscode-tasks")
                         .about("Add several tasks to vscode for formatting, validation and testing")
                         .arg(
-                            Arg::with_name("remove")
+                            Arg::new("remove")
                                 .long("remove")
                                 .help("Remove the tasks added with 'cargo dev setup vscode-tasks'")
                                 .required(false),
                         )
                         .arg(
-                            Arg::with_name("force-override")
+                            Arg::new("force-override")
                                 .long("force-override")
-                                .short("f")
+                                .short('f')
                                 .help("Forces the override of existing vscode tasks")
                                 .required(false),
                         ),
                 ),
         )
         .subcommand(
-            SubCommand::with_name("remove")
+            Command::new("remove")
                 .about("Support for undoing changes done by the setup command")
-                .setting(AppSettings::ArgRequiredElseHelp)
-                .subcommand(SubCommand::with_name("git-hook").about("Remove any existing pre-commit git hook"))
-                .subcommand(SubCommand::with_name("vscode-tasks").about("Remove any existing vscode tasks"))
+                .arg_required_else_help(true)
+                .subcommand(Command::new("git-hook").about("Remove any existing pre-commit git hook"))
+                .subcommand(Command::new("vscode-tasks").about("Remove any existing vscode tasks"))
                 .subcommand(
-                    SubCommand::with_name("intellij")
-                        .about("Removes rustc source paths added via `cargo dev setup intellij`"),
+                    Command::new("intellij").about("Removes rustc source paths added via `cargo dev setup intellij`"),
                 ),
         )
         .subcommand(
-            SubCommand::with_name("serve")
+            Command::new("serve")
                 .about("Launch a local 'ALL the Clippy Lints' website in a browser")
                 .arg(
-                    Arg::with_name("port")
+                    Arg::new("port")
                         .long("port")
-                        .short("p")
+                        .short('p')
                         .help("Local port for the http server")
                         .default_value("8000")
                         .validator_os(serve::validate_port),
                 )
-                .arg(Arg::with_name("lint").help("Which lint's page to load initially (optional)")),
+                .arg(Arg::new("lint").help("Which lint's page to load initially (optional)")),
         )
         .subcommand(
-            SubCommand::with_name("lint")
+            Command::new("lint")
                 .about("Manually run clippy on a file or package")
                 .after_help(indoc! {"
                     EXAMPLES
@@ -288,33 +272,33 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
                             cargo dev lint ~/my-project -- -- -W clippy::pedantic
                 "})
                 .arg(
-                    Arg::with_name("path")
+                    Arg::new("path")
                         .required(true)
                         .help("The path to a file or package directory to lint"),
                 )
                 .arg(
-                    Arg::with_name("args")
-                        .multiple(true)
+                    Arg::new("args")
+                        .multiple_occurrences(true)
                         .help("Pass extra arguments to cargo/clippy-driver"),
                 ),
         )
         .subcommand(
-            SubCommand::with_name("rename_lint")
+            Command::new("rename_lint")
                 .about("Renames the given lint")
                 .arg(
-                    Arg::with_name("old_name")
+                    Arg::new("old_name")
                         .index(1)
                         .required(true)
                         .help("The name of the lint to rename"),
                 )
                 .arg(
-                    Arg::with_name("new_name")
+                    Arg::new("new_name")
                         .index(2)
-                        .required_unless("uplift")
+                        .required_unless_present("uplift")
                         .help("The new name of the lint"),
                 )
                 .arg(
-                    Arg::with_name("uplift")
+                    Arg::new("uplift")
                         .long("uplift")
                         .help("This lint will be uplifted into rustc"),
                 ),
diff --git a/clippy_dev/src/serve.rs b/clippy_dev/src/serve.rs
index b36e2a28ee4..d55b1a354d0 100644
--- a/clippy_dev/src/serve.rs
+++ b/clippy_dev/src/serve.rs
@@ -1,4 +1,5 @@
-use std::ffi::{OsStr, OsString};
+use std::ffi::OsStr;
+use std::num::ParseIntError;
 use std::path::Path;
 use std::process::Command;
 use std::thread;
@@ -59,9 +60,6 @@ fn mtime(path: impl AsRef<Path>) -> SystemTime {
 }
 
 #[allow(clippy::missing_errors_doc)]
-pub fn validate_port(arg: &OsStr) -> Result<(), OsString> {
-    match arg.to_string_lossy().parse::<u16>() {
-        Ok(_port) => Ok(()),
-        Err(err) => Err(OsString::from(err.to_string())),
-    }
+pub fn validate_port(arg: &OsStr) -> Result<(), ParseIntError> {
+    arg.to_string_lossy().parse::<u16>().map(|_| ())
 }
diff --git a/clippy_lints/src/almost_complete_letter_range.rs b/clippy_lints/src/almost_complete_letter_range.rs
new file mode 100644
index 00000000000..b364a370efa
--- /dev/null
+++ b/clippy_lints/src/almost_complete_letter_range.rs
@@ -0,0 +1,100 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::{trim_span, walk_span_to_context};
+use clippy_utils::{meets_msrv, msrvs};
+use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for ranges which almost include the entire range of letters from 'a' to 'z', but
+    /// don't because they're a half open range.
+    ///
+    /// ### Why is this bad?
+    /// This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let _ = 'a'..'z';
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let _ = 'a'..='z';
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub ALMOST_COMPLETE_LETTER_RANGE,
+    suspicious,
+    "almost complete letter range"
+}
+impl_lint_pass!(AlmostCompleteLetterRange => [ALMOST_COMPLETE_LETTER_RANGE]);
+
+pub struct AlmostCompleteLetterRange {
+    msrv: Option<RustcVersion>,
+}
+impl AlmostCompleteLetterRange {
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+impl EarlyLintPass for AlmostCompleteLetterRange {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
+        if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind {
+            let ctxt = e.span.ctxt();
+            let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt)
+                && let Some(end) = walk_span_to_context(end.span, ctxt)
+                && meets_msrv(self.msrv, msrvs::RANGE_INCLUSIVE)
+            {
+                Some((trim_span(cx.sess().source_map(), start.between(end)), "..="))
+            } else {
+                None
+            };
+            check_range(cx, e.span, start, end, sugg);
+        }
+    }
+
+    fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &Pat) {
+        if let PatKind::Range(Some(start), Some(end), kind) = &p.kind
+            && matches!(kind.node, RangeEnd::Excluded)
+        {
+            let sugg = if meets_msrv(self.msrv, msrvs::RANGE_INCLUSIVE) {
+                "..="
+            } else {
+                "..."
+            };
+            check_range(cx, p.span, start, end, Some((kind.span, sugg)));
+        }
+    }
+
+    extract_msrv_attr!(EarlyContext);
+}
+
+fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) {
+    if let ExprKind::Lit(start_lit) = &start.peel_parens().kind
+        && let ExprKind::Lit(end_lit) = &end.peel_parens().kind
+        && matches!(
+            (&start_lit.kind, &end_lit.kind),
+            (LitKind::Byte(b'a') | LitKind::Char('a'), LitKind::Byte(b'z') | LitKind::Char('z'))
+            | (LitKind::Byte(b'A') | LitKind::Char('A'), LitKind::Byte(b'Z') | LitKind::Char('Z'))
+        )
+    {
+        span_lint_and_then(
+            cx,
+            ALMOST_COMPLETE_LETTER_RANGE,
+            span,
+            "almost complete ascii letter range",
+            |diag| {
+                if let Some((span, sugg)) = sugg {
+                    diag.span_suggestion(
+                        span,
+                        "use an inclusive range",
+                        sugg.to_owned(),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        );
+    }
+}
diff --git a/clippy_lints/src/approx_const.rs b/clippy_lints/src/approx_const.rs
index da1b646f477..159f3b0cd01 100644
--- a/clippy_lints/src/approx_const.rs
+++ b/clippy_lints/src/approx_const.rs
@@ -28,7 +28,7 @@ declare_clippy_lint! {
     /// let x = 3.14;
     /// let y = 1_f64 / x;
     /// ```
-    /// Use predefined constants instead:
+    /// Use instead:
     /// ```rust
     /// let x = std::f32::consts::PI;
     /// let y = std::f64::consts::FRAC_1_PI;
diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs
index 88b91d58907..6e5c8f44581 100644
--- a/clippy_lints/src/as_conversions.rs
+++ b/clippy_lints/src/as_conversions.rs
@@ -29,15 +29,14 @@ declare_clippy_lint! {
     /// f(a as u16);
     /// ```
     ///
-    /// Usually better represents the semantics you expect:
+    /// Use instead:
     /// ```rust,ignore
     /// f(a.try_into()?);
-    /// ```
-    /// or
-    /// ```rust,ignore
+    ///
+    /// // or
+    ///
     /// f(a.try_into().expect("Unexpected u16 overflow in f"));
     /// ```
-    ///
     #[clippy::version = "1.41.0"]
     pub AS_CONVERSIONS,
     restriction,
diff --git a/clippy_lints/src/as_underscore.rs b/clippy_lints/src/as_underscore.rs
new file mode 100644
index 00000000000..464be4218dd
--- /dev/null
+++ b/clippy_lints/src/as_underscore.rs
@@ -0,0 +1,74 @@
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, TyKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Check for the usage of `as _` conversion using inferred type.
+    ///
+    /// ### Why is this bad?
+    /// The conversion might include lossy conversion and dangerous cast that might go
+    /// undetected du to the type being inferred.
+    ///
+    /// The lint is allowed by default as using `_` is less wordy than always specifying the type.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn foo(n: usize) {}
+    /// let n: u16 = 256;
+    /// foo(n as _);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn foo(n: usize) {}
+    /// let n: u16 = 256;
+    /// foo(n as usize);
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub AS_UNDERSCORE,
+    restriction,
+    "detects `as _` conversion"
+}
+declare_lint_pass!(AsUnderscore => [AS_UNDERSCORE]);
+
+impl<'tcx> LateLintPass<'tcx> for AsUnderscore {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        if in_external_macro(cx.sess(), expr.span) {
+            return;
+        }
+
+        if let ExprKind::Cast(_, ty) = expr.kind && let TyKind::Infer = ty.kind {
+
+            let ty_resolved = cx.typeck_results().expr_ty(expr);
+            if let ty::Error(_) = ty_resolved.kind() {
+                span_lint_and_help(
+                    cx,
+                AS_UNDERSCORE,
+                expr.span,
+                "using `as _` conversion",
+                None,
+                "consider giving the type explicitly",
+                );
+            } else {
+            span_lint_and_then(
+                cx,
+                AS_UNDERSCORE,
+                expr.span,
+                "using `as _` conversion",
+                |diag| {
+                    diag.span_suggestion(
+                        ty.span,
+                        "consider giving the type explicitly",
+                        format!("{}", ty_resolved),
+                        Applicability::MachineApplicable,
+                    );
+            }
+            );
+        }
+        }
+    }
+}
diff --git a/clippy_lints/src/assign_ops.rs b/clippy_lints/src/assign_ops.rs
index 4c2d3366483..f81da2d4223 100644
--- a/clippy_lints/src/assign_ops.rs
+++ b/clippy_lints/src/assign_ops.rs
@@ -27,10 +27,16 @@ declare_clippy_lint! {
     /// let mut a = 5;
     /// let b = 0;
     /// // ...
-    /// // Bad
+    ///
     /// a = a + b;
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// let mut a = 5;
+    /// let b = 0;
+    /// // ...
     ///
-    /// // Good
     /// a += b;
     /// ```
     #[clippy::version = "pre 1.29.0"]
diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index 3de91f3d24a..770cb6a3d7b 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -89,13 +89,14 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```ignore
-    /// // Bad
     /// #[deny(dead_code)]
     /// extern crate foo;
     /// #[forbid(dead_code)]
     /// use foo::bar;
+    /// ```
     ///
-    /// // Ok
+    /// Use instead:
+    /// ```rust,ignore
     /// #[allow(unused_imports)]
     /// use foo::baz;
     /// #[allow(unused_imports)]
@@ -146,15 +147,19 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```rust
+    /// #[allow(dead_code)]
+    ///
+    /// fn not_quite_good_code() { }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
     /// // Good (as inner attribute)
     /// #![allow(dead_code)]
     ///
     /// fn this_is_fine() { }
     ///
-    /// // Bad
-    /// #[allow(dead_code)]
-    ///
-    /// fn not_quite_good_code() { }
+    /// // or
     ///
     /// // Good (as outer attribute)
     /// #[allow(dead_code)]
@@ -175,12 +180,11 @@ declare_clippy_lint! {
     /// These lints should only be enabled on a lint-by-lint basis and with careful consideration.
     ///
     /// ### Example
-    /// Bad:
     /// ```rust
     /// #![deny(clippy::restriction)]
     /// ```
     ///
-    /// Good:
+    /// Use instead:
     /// ```rust
     /// #![deny(clippy::as_conversions)]
     /// ```
@@ -205,13 +209,12 @@ declare_clippy_lint! {
     /// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765)
     ///
     /// ### Example
-    /// Bad:
     /// ```rust
     /// #[cfg_attr(rustfmt, rustfmt_skip)]
     /// fn main() { }
     /// ```
     ///
-    /// Good:
+    /// Use instead:
     /// ```rust
     /// #[rustfmt::skip]
     /// fn main() { }
@@ -231,20 +234,20 @@ declare_clippy_lint! {
     /// by the conditional compilation engine.
     ///
     /// ### Example
-    /// Bad:
     /// ```rust
     /// #[cfg(linux)]
     /// fn conditional() { }
     /// ```
     ///
-    /// Good:
+    /// Use instead:
     /// ```rust
+    /// # mod hidden {
     /// #[cfg(target_os = "linux")]
     /// fn conditional() { }
-    /// ```
+    /// # }
+    ///
+    /// // or
     ///
-    /// Or:
-    /// ```rust
     /// #[cfg(unix)]
     /// fn conditional() { }
     /// ```
@@ -266,14 +269,13 @@ declare_clippy_lint! {
     /// ensure that others understand the reasoning
     ///
     /// ### Example
-    /// Bad:
     /// ```rust
     /// #![feature(lint_reasons)]
     ///
     /// #![allow(clippy::some_lint)]
     /// ```
     ///
-    /// Good:
+    /// Use instead:
     /// ```rust
     /// #![feature(lint_reasons)]
     ///
@@ -585,15 +587,21 @@ impl EarlyLintPass for EarlyAttributes {
 }
 
 fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
-    for attr in &item.attrs {
+    let mut iter = item.attrs.iter().peekable();
+    while let Some(attr) = iter.next() {
         if matches!(attr.kind, AttrKind::Normal(..))
             && attr.style == AttrStyle::Outer
             && is_present_in_source(cx, attr.span)
         {
             let begin_of_attr_to_item = Span::new(attr.span.lo(), item.span.lo(), item.span.ctxt(), item.span.parent());
-            let end_of_attr_to_item = Span::new(attr.span.hi(), item.span.lo(), item.span.ctxt(), item.span.parent());
+            let end_of_attr_to_next_attr_or_item = Span::new(
+                attr.span.hi(),
+                iter.peek().map_or(item.span.lo(), |next_attr| next_attr.span.lo()),
+                item.span.ctxt(),
+                item.span.parent(),
+            );
 
-            if let Some(snippet) = snippet_opt(cx, end_of_attr_to_item) {
+            if let Some(snippet) = snippet_opt(cx, end_of_attr_to_next_attr_or_item) {
                 let lines = snippet.split('\n').collect::<Vec<_>>();
                 let lines = without_block_comments(lines);
 
@@ -623,8 +631,15 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Opti
         if feature_item.has_name(sym::rustfmt);
         // check for `rustfmt_skip` and `rustfmt::skip`
         if let Some(skip_item) = &items[1].meta_item();
-        if skip_item.has_name(sym!(rustfmt_skip)) ||
-            skip_item.path.segments.last().expect("empty path in attribute").ident.name == sym::skip;
+        if skip_item.has_name(sym!(rustfmt_skip))
+            || skip_item
+                .path
+                .segments
+                .last()
+                .expect("empty path in attribute")
+                .ident
+                .name
+                == sym::skip;
         // Only lint outer attributes, because custom inner attributes are unstable
         // Tracking issue: https://github.com/rust-lang/rust/issues/54726
         if attr.style == AttrStyle::Outer;
diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs
index 4c4dd85d518..5bd7a342389 100644
--- a/clippy_lints/src/blocks_in_if_conditions.rs
+++ b/clippy_lints/src/blocks_in_if_conditions.rs
@@ -22,21 +22,17 @@ declare_clippy_lint! {
     ///
     /// ### Examples
     /// ```rust
-    /// // Bad
+    /// # fn somefunc() -> bool { true };
     /// if { true } { /* ... */ }
     ///
-    /// // Good
-    /// if true { /* ... */ }
+    /// if { let x = somefunc(); x } { /* ... */ }
     /// ```
     ///
-    /// // or
-    ///
+    /// Use instead:
     /// ```rust
     /// # fn somefunc() -> bool { true };
-    /// // Bad
-    /// if { let x = somefunc(); x } { /* ... */ }
+    /// if true { /* ... */ }
     ///
-    /// // Good
     /// let res = { let x = somefunc(); x };
     /// if res { /* ... */ }
     /// ```
diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs
index 0adb6327164..e4e122ba6eb 100644
--- a/clippy_lints/src/booleans.rs
+++ b/clippy_lints/src/booleans.rs
@@ -27,8 +27,14 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```ignore
-    /// if a && true  // should be: if a
-    /// if !(a == b)  // should be: if a != b
+    /// if a && true {}
+    /// if !(a == b) {}
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// if a {}
+    /// if a != b {}
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub NONMINIMAL_BOOL,
@@ -48,10 +54,15 @@ declare_clippy_lint! {
     /// Ignores short circuiting behavior.
     ///
     /// ### Example
-    /// ```ignore
+    /// ```rust,ignore
+    /// // The `b` is unnecessary, the expression is equivalent to `if a`.
     /// if a && b || a { ... }
     /// ```
-    /// The `b` is unnecessary, the expression is equivalent to `if a`.
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// if a {}
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub LOGIC_BUG,
     correctness,
diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs
new file mode 100644
index 00000000000..ec2f31cf673
--- /dev/null
+++ b/clippy_lints/src/borrow_deref_ref.rs
@@ -0,0 +1,118 @@
+use crate::reference::DEREF_ADDROF;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{get_parent_expr, is_lint_allowed};
+use rustc_errors::Applicability;
+use rustc_hir::{ExprKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::mir::Mutability;
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `&*(&T)`.
+    ///
+    /// ### Why is this bad?
+    /// Dereferencing and then borrowing a reference value has no effect in most cases.
+    ///
+    /// ### Known problems
+    /// false negative on such code:
+    /// ```
+    /// let x = &12;
+    /// let addr_x = &x as *const _ as usize;
+    /// let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggerd.
+    ///                                         // But if we fix it, assert will fail.
+    /// assert_ne!(addr_x, addr_y);
+    /// ```
+    ///
+    /// ### Example
+    /// ```rust
+    /// let s = &String::new();
+    ///
+    /// // Bad
+    /// let a: &String = &* s;
+    /// foo(&*s);
+    ///
+    /// // Good
+    /// let a: &String = s;
+    /// foo(&**s);
+    ///
+    /// fn foo(_: &str){ }
+    /// ```
+    #[clippy::version = "1.59.0"]
+    pub BORROW_DEREF_REF,
+    complexity,
+    "deref on an immutable reference returns the same type as itself"
+}
+
+declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]);
+
+impl LateLintPass<'_> for BorrowDerefRef {
+    fn check_expr(&mut self, cx: &LateContext<'_>, e: &rustc_hir::Expr<'_>) {
+        if_chain! {
+            if !e.span.from_expansion();
+            if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind;
+            if !addrof_target.span.from_expansion();
+            if let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind;
+            if !deref_target.span.from_expansion();
+            if !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..) );
+            let ref_ty = cx.typeck_results().expr_ty(deref_target);
+            if let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind();
+            then{
+
+                if let Some(parent_expr) = get_parent_expr(cx, e){
+                    if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) &&
+                       !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) {
+                        return;
+                    }
+
+                    // modification to `&mut &*x` is different from `&mut x`
+                    if matches!(deref_target.kind, ExprKind::Path(..)
+                                             | ExprKind::Field(..)
+                                             | ExprKind::Index(..)
+                                             | ExprKind::Unary(UnOp::Deref, ..))
+                     && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) {
+                       return;
+                    }
+                }
+
+                span_lint_and_then(
+                    cx,
+                    BORROW_DEREF_REF,
+                    e.span,
+                    "deref on an immutable reference",
+                    |diag| {
+                        diag.span_suggestion(
+                            e.span,
+                            "if you would like to reborrow, try removing `&*`",
+                            snippet_opt(cx, deref_target.span).unwrap(),
+                            Applicability::MachineApplicable
+                        );
+
+                        // has deref trait -> give 2 help
+                        // doesn't have deref trait -> give 1 help
+                        if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait(){
+                            if !implements_trait(cx, *inner_ty, deref_trait_id, &[]) {
+                                return;
+                            }
+                        }
+
+                        diag.span_suggestion(
+                            e.span,
+                            "if you would like to deref, try using `&**`",
+                            format!(
+                                "&**{}",
+                                &snippet_opt(cx, deref_target.span).unwrap(),
+                             ),
+                            Applicability::MaybeIncorrect
+                        );
+
+                    }
+                );
+
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs
index 02d97bf43df..bfdbaf2413a 100644
--- a/clippy_lints/src/bytecount.rs
+++ b/clippy_lints/src/bytecount.rs
@@ -28,7 +28,13 @@ declare_clippy_lint! {
     /// ### Example
     /// ```rust
     /// # let vec = vec![1_u8];
-    /// &vec.iter().filter(|x| **x == 0u8).count(); // use bytecount::count instead
+    /// let count = vec.iter().filter(|x| **x == 0u8).count();
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust,ignore
+    /// # let vec = vec![1_u8];
+    /// let count = bytecount::count(&vec, 0u8);
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub NAIVE_BYTECOUNT,
diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index 6bac6bf83f8..64ea326b75a 100644
--- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -1,11 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{meets_msrv, msrvs};
-use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_semver::RustcVersion;
 
 use super::CAST_ABS_TO_UNSIGNED;
@@ -18,25 +17,28 @@ pub(super) fn check(
     cast_to: Ty<'_>,
     msrv: Option<RustcVersion>,
 ) {
-    if_chain! {
-        if meets_msrv(msrv, msrvs::UNSIGNED_ABS);
-        if cast_from.is_integral();
-        if cast_to.is_integral();
-        if cast_from.is_signed();
-        if !cast_to.is_signed();
-        if let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind;
-        if let method_name = method_path.ident.name.as_str();
-        if method_name == "abs";
-        then {
-            span_lint_and_sugg(
-                cx,
-                CAST_ABS_TO_UNSIGNED,
-                expr.span,
-                &format!("casting the result of `{}::{}()` to {}", cast_from, method_name, cast_to),
-                "replace with",
-                format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
-                Applicability::MachineApplicable,
-            );
-        }
+    if meets_msrv(msrv, msrvs::UNSIGNED_ABS)
+        && let ty::Int(from) = cast_from.kind()
+        && let ty::Uint(to) = cast_to.kind()
+        && let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind
+        && method_path.ident.name.as_str() == "abs"
+    {
+        let span = if from.bit_width() == to.bit_width() {
+            expr.span
+        } else {
+            // if the result of `.unsigned_abs` would be a different type, keep the cast
+            // e.g. `i64 -> usize`, `i16 -> u8`
+            cast_expr.span
+        };
+
+        span_lint_and_sugg(
+            cx,
+            CAST_ABS_TO_UNSIGNED,
+            span,
+            &format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
+            "replace with",
+            format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
+            Applicability::MachineApplicable,
+        );
     }
 }
diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs
index 7eeaaa01921..1010340c712 100644
--- a/clippy_lints/src/checked_conversions.rs
+++ b/clippy_lints/src/checked_conversions.rs
@@ -318,7 +318,7 @@ fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function:
         if let QPath::TypeRelative(ty, path) = &path;
         if path.ident.name.as_str() == function;
         if let TyKind::Path(QPath::Resolved(None, tp)) = &ty.kind;
-        if let [int] = &*tp.segments;
+        if let [int] = tp.segments;
         then {
             let name = int.ident.name.as_str();
             candidates.iter().find(|c| &name == *c).copied()
@@ -332,7 +332,7 @@ fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function:
 fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> {
     if_chain! {
         if let QPath::Resolved(_, path) = *path;
-        if let [ty] = &*path.segments;
+        if let [ty] = path.segments;
         then {
             let name = ty.ident.name.as_str();
             INTS.iter().find(|c| &name == *c).copied()
diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs
index 317c4bfb322..33c44f8b2db 100644
--- a/clippy_lints/src/cognitive_complexity.rs
+++ b/clippy_lints/src/cognitive_complexity.rs
@@ -25,7 +25,7 @@ declare_clippy_lint! {
     /// complexity.
     ///
     /// ### Example
-    /// No. You'll see it when you get the warning.
+    /// You'll see it when you get the warning.
     #[clippy::version = "1.35.0"]
     pub COGNITIVE_COMPLEXITY,
     nursery,
diff --git a/clippy_lints/src/collapsible_if.rs b/clippy_lints/src/collapsible_if.rs
index 3227e6e86af..3eceb848822 100644
--- a/clippy_lints/src/collapsible_if.rs
+++ b/clippy_lints/src/collapsible_if.rs
@@ -41,7 +41,7 @@ declare_clippy_lint! {
     ///
     /// ```
     ///
-    /// Should be written:
+    /// Use instead:
     ///
     /// ```rust,ignore
     /// if x && y {
diff --git a/clippy_lints/src/comparison_chain.rs b/clippy_lints/src/comparison_chain.rs
index 399d11472b0..913e081af3b 100644
--- a/clippy_lints/src/comparison_chain.rs
+++ b/clippy_lints/src/comparison_chain.rs
@@ -34,7 +34,7 @@ declare_clippy_lint! {
     /// }
     /// ```
     ///
-    /// Could be written:
+    /// Use instead:
     ///
     /// ```rust,ignore
     /// use std::cmp::Ordering;
diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs
index e6a0162fd02..1e9a1153011 100644
--- a/clippy_lints/src/copies.rs
+++ b/clippy_lints/src/copies.rs
@@ -141,7 +141,7 @@ declare_clippy_lint! {
     /// };
     /// ```
     ///
-    /// Could be written as:
+    /// Use instead:
     /// ```ignore
     /// println!("Hello World");
     /// let foo = if … {
diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs
index fc141b4a6e3..9b8a481b6ea 100644
--- a/clippy_lints/src/crate_in_macro_def.rs
+++ b/clippy_lints/src/crate_in_macro_def.rs
@@ -90,7 +90,7 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option<Span> {
     while let Some(curr) = cursor.next() {
         if_chain! {
             if !prev_is_dollar;
-            if let Some(span) = is_crate_keyword(&curr);
+            if let Some(span) = is_crate_keyword(curr);
             if let Some(next) = cursor.look_ahead(0);
             if is_token(next, &TokenKind::ModSep);
             then {
@@ -103,7 +103,7 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option<Span> {
                 return span;
             }
         }
-        prev_is_dollar = is_token(&curr, &TokenKind::Dollar);
+        prev_is_dollar = is_token(curr, &TokenKind::Dollar);
     }
     None
 }
diff --git a/clippy_lints/src/dbg_macro.rs b/clippy_lints/src/dbg_macro.rs
index f99d793c201..17deccf8c39 100644
--- a/clippy_lints/src/dbg_macro.rs
+++ b/clippy_lints/src/dbg_macro.rs
@@ -5,7 +5,7 @@ use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::sym;
 
 declare_clippy_lint! {
@@ -30,14 +30,27 @@ declare_clippy_lint! {
     "`dbg!` macro is intended as a debugging tool"
 }
 
-declare_lint_pass!(DbgMacro => [DBG_MACRO]);
+#[derive(Copy, Clone)]
+pub struct DbgMacro {
+    allow_dbg_in_tests: bool,
+}
+
+impl_lint_pass!(DbgMacro => [DBG_MACRO]);
+
+impl DbgMacro {
+    pub fn new(allow_dbg_in_tests: bool) -> Self {
+        DbgMacro { allow_dbg_in_tests }
+    }
+}
 
 impl LateLintPass<'_> for DbgMacro {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
         if cx.tcx.is_diagnostic_item(sym::dbg_macro, macro_call.def_id) {
-            // we make an exception for test code
-            if is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id) {
+            // allows `dbg!` in test code if allow-dbg-in-test is set to true in clippy.toml
+            if self.allow_dbg_in_tests
+                && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id))
+            {
                 return;
             }
             let mut applicability = Applicability::MachineApplicable;
diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs
index 34a5f8444de..e98691fd5bb 100644
--- a/clippy_lints/src/derivable_impls.rs
+++ b/clippy_lints/src/derivable_impls.rs
@@ -21,7 +21,7 @@ declare_clippy_lint! {
     ///     bar: bool
     /// }
     ///
-    /// impl std::default::Default for Foo {
+    /// impl Default for Foo {
     ///     fn default() -> Self {
     ///         Self {
     ///             bar: false
diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs
index fe99f4a8d55..99347ebadc6 100644
--- a/clippy_lints/src/derive.rs
+++ b/clippy_lints/src/derive.rs
@@ -1,16 +1,17 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::paths;
-use clippy_utils::ty::{implements_trait, is_copy};
+use clippy_utils::ty::{implements_trait, implements_trait_with_env, is_copy};
 use clippy_utils::{is_lint_allowed, match_def_path};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
 use rustc_hir::{
-    BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety,
+    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, UnsafeSource, Unsafety,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::subst::GenericArg;
+use rustc_middle::ty::{self, BoundConstness, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, TraitRef, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::sym;
@@ -224,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
 fn check_hash_peq<'tcx>(
     cx: &LateContext<'tcx>,
     span: Span,
-    trait_ref: &TraitRef<'_>,
+    trait_ref: &hir::TraitRef<'_>,
     ty: Ty<'tcx>,
     hash_is_automatically_derived: bool,
 ) {
@@ -277,7 +278,7 @@ fn check_hash_peq<'tcx>(
 fn check_ord_partial_ord<'tcx>(
     cx: &LateContext<'tcx>,
     span: Span,
-    trait_ref: &TraitRef<'_>,
+    trait_ref: &hir::TraitRef<'_>,
     ty: Ty<'tcx>,
     ord_is_automatically_derived: bool,
 ) {
@@ -328,7 +329,7 @@ fn check_ord_partial_ord<'tcx>(
 }
 
 /// Implementation of the `EXPL_IMPL_CLONE_ON_COPY` lint.
-fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &TraitRef<'_>, ty: Ty<'tcx>) {
+fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
     let clone_id = match cx.tcx.lang_items().clone_trait() {
         Some(id) if trait_ref.trait_def_id() == Some(id) => id,
         _ => return,
@@ -378,7 +379,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &T
 fn check_unsafe_derive_deserialize<'tcx>(
     cx: &LateContext<'tcx>,
     item: &Item<'_>,
-    trait_ref: &TraitRef<'_>,
+    trait_ref: &hir::TraitRef<'_>,
     ty: Ty<'tcx>,
 ) {
     fn has_unsafe<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>) -> bool {
@@ -455,13 +456,41 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
 }
 
 /// Implementation of the `DERIVE_PARTIAL_EQ_WITHOUT_EQ` lint.
-fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &TraitRef<'_>, ty: Ty<'tcx>) {
+fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) {
     if_chain! {
         if let ty::Adt(adt, substs) = ty.kind();
         if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq);
+        if let Some(peq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::PartialEq);
         if let Some(def_id) = trait_ref.trait_def_id();
         if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id);
-        if !implements_trait(cx, ty, eq_trait_def_id, substs);
+        // New `ParamEnv` replacing `T: PartialEq` with `T: Eq`
+        let param_env = ParamEnv::new(
+            cx.tcx.mk_predicates(cx.param_env.caller_bounds().iter().map(|p| {
+                let kind = p.kind();
+                match kind.skip_binder() {
+                    PredicateKind::Trait(p)
+                        if p.trait_ref.def_id == peq_trait_def_id
+                            && p.trait_ref.substs.get(0) == p.trait_ref.substs.get(1)
+                            && matches!(p.trait_ref.self_ty().kind(), ty::Param(_))
+                            && p.constness == BoundConstness::NotConst
+                            && p.polarity == ImplPolarity::Positive =>
+                    {
+                        cx.tcx.mk_predicate(kind.rebind(PredicateKind::Trait(TraitPredicate {
+                            trait_ref: TraitRef::new(
+                                eq_trait_def_id,
+                                cx.tcx.mk_substs([GenericArg::from(p.trait_ref.self_ty())].into_iter()),
+                            ),
+                            constness: BoundConstness::NotConst,
+                            polarity: ImplPolarity::Positive,
+                        })))
+                    },
+                    _ => p,
+                }
+            })),
+            cx.param_env.reveal(),
+            cx.param_env.constness(),
+        );
+        if !implements_trait_with_env(cx.tcx, param_env, ty, eq_trait_def_id, substs);
         then {
             // If all of our fields implement `Eq`, we can implement `Eq` too
             for variant in adt.variants() {
diff --git a/clippy_lints/src/doc_link_with_quotes.rs b/clippy_lints/src/doc_link_with_quotes.rs
new file mode 100644
index 00000000000..cb07f57e870
--- /dev/null
+++ b/clippy_lints/src/doc_link_with_quotes.rs
@@ -0,0 +1,60 @@
+use clippy_utils::diagnostics::span_lint;
+use itertools::Itertools;
+use rustc_ast::{AttrKind, Attribute};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks)
+    /// outside of code blocks
+    /// ### Why is this bad?
+    /// It is likely a typo when defining an intra-doc link
+    ///
+    /// ### Example
+    /// ```rust
+    /// /// See also: ['foo']
+    /// fn bar() {}
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// /// See also: [`foo`]
+    /// fn bar() {}
+    /// ```
+    #[clippy::version = "1.60.0"]
+    pub DOC_LINK_WITH_QUOTES,
+    pedantic,
+    "possible typo for an intra-doc link"
+}
+declare_lint_pass!(DocLinkWithQuotes => [DOC_LINK_WITH_QUOTES]);
+
+impl EarlyLintPass for DocLinkWithQuotes {
+    fn check_attribute(&mut self, ctx: &EarlyContext<'_>, attr: &Attribute) {
+        if let AttrKind::DocComment(_, symbol) = attr.kind {
+            if contains_quote_link(symbol.as_str()) {
+                span_lint(
+                    ctx,
+                    DOC_LINK_WITH_QUOTES,
+                    attr.span,
+                    "possible intra-doc link using quotes instead of backticks",
+                );
+            }
+        }
+    }
+}
+
+fn contains_quote_link(s: &str) -> bool {
+    let mut in_backticks = false;
+    let mut found_opening = false;
+
+    for c in s.chars().tuple_windows::<(char, char)>() {
+        match c {
+            ('`', _) => in_backticks = !in_backticks,
+            ('[', '\'') if !in_backticks => found_opening = true,
+            ('\'', ']') if !in_backticks && found_opening => return true,
+            _ => {},
+        }
+    }
+
+    false
+}
diff --git a/clippy_lints/src/double_comparison.rs b/clippy_lints/src/double_comparison.rs
index be95375789d..ee0440e52ff 100644
--- a/clippy_lints/src/double_comparison.rs
+++ b/clippy_lints/src/double_comparison.rs
@@ -24,7 +24,7 @@ declare_clippy_lint! {
     /// if x == y || x < y {}
     /// ```
     ///
-    /// Could be written as:
+    /// Use instead:
     ///
     /// ```rust
     /// # let x = 1;
diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs
index e10f740d24a..a33ef5ce6e3 100644
--- a/clippy_lints/src/double_parens.rs
+++ b/clippy_lints/src/double_parens.rs
@@ -13,23 +13,21 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```rust
-    /// // Bad
     /// fn simple_double_parens() -> i32 {
     ///     ((0))
     /// }
     ///
-    /// // Good
+    /// # fn foo(bar: usize) {}
+    /// foo((0));
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
     /// fn simple_no_parens() -> i32 {
     ///     0
     /// }
     ///
-    /// // or
-    ///
     /// # fn foo(bar: usize) {}
-    /// // Bad
-    /// foo((0));
-    ///
-    /// // Good
     /// foo(0);
     /// ```
     #[clippy::version = "pre 1.29.0"]
diff --git a/clippy_lints/src/duration_subsec.rs b/clippy_lints/src/duration_subsec.rs
index 09318f74527..d85ace3a279 100644
--- a/clippy_lints/src/duration_subsec.rs
+++ b/clippy_lints/src/duration_subsec.rs
@@ -22,15 +22,17 @@ declare_clippy_lint! {
     /// ### Example
     /// ```rust
     /// # use std::time::Duration;
-    /// let dur = Duration::new(5, 0);
-    ///
-    /// // Bad
-    /// let _micros = dur.subsec_nanos() / 1_000;
-    /// let _millis = dur.subsec_nanos() / 1_000_000;
+    /// # let duration = Duration::new(5, 0);
+    /// let micros = duration.subsec_nanos() / 1_000;
+    /// let millis = duration.subsec_nanos() / 1_000_000;
+    /// ```
     ///
-    /// // Good
-    /// let _micros = dur.subsec_micros();
-    /// let _millis = dur.subsec_millis();
+    /// Use instead:
+    /// ```rust
+    /// # use std::time::Duration;
+    /// # let duration = Duration::new(5, 0);
+    /// let micros = duration.subsec_micros();
+    /// let millis = duration.subsec_millis();
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub DURATION_SUBSEC,
diff --git a/clippy_lints/src/else_if_without_else.rs b/clippy_lints/src/else_if_without_else.rs
index 0b9f54231c5..bf4488570ea 100644
--- a/clippy_lints/src/else_if_without_else.rs
+++ b/clippy_lints/src/else_if_without_else.rs
@@ -26,7 +26,7 @@ declare_clippy_lint! {
     /// }
     /// ```
     ///
-    /// Could be written:
+    /// Use instead:
     ///
     /// ```rust
     /// # fn a() {}
diff --git a/clippy_lints/src/empty_enum.rs b/clippy_lints/src/empty_enum.rs
index b5d6b3c7524..bbebc024414 100644
--- a/clippy_lints/src/empty_enum.rs
+++ b/clippy_lints/src/empty_enum.rs
@@ -23,12 +23,11 @@ declare_clippy_lint! {
     ///
     ///
     /// ### Example
-    /// Bad:
     /// ```rust
     /// enum Test {}
     /// ```
     ///
-    /// Good:
+    /// Use instead:
     /// ```rust
     /// #![feature(never_type)]
     ///
diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs
index c5a987842c3..27743a0ebec 100644
--- a/clippy_lints/src/entry.rs
+++ b/clippy_lints/src/entry.rs
@@ -46,7 +46,7 @@ declare_clippy_lint! {
     ///     map.insert(k, v);
     /// }
     /// ```
-    /// can both be rewritten as:
+    /// Use instead:
     /// ```rust
     /// # use std::collections::HashMap;
     /// # let mut map = HashMap::new();
diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs
index e029b8e8537..263a5b573c9 100644
--- a/clippy_lints/src/enum_variants.rs
+++ b/clippy_lints/src/enum_variants.rs
@@ -32,7 +32,7 @@ declare_clippy_lint! {
     ///     BattenbergCake,
     /// }
     /// ```
-    /// Could be written as:
+    /// Use instead:
     /// ```rust
     /// enum Cake {
     ///     BlackForest,
diff --git a/clippy_lints/src/eq_op.rs b/clippy_lints/src/eq_op.rs
index afb5d32f953..c3176d987c6 100644
--- a/clippy_lints/src/eq_op.rs
+++ b/clippy_lints/src/eq_op.rs
@@ -30,9 +30,9 @@ declare_clippy_lint! {
     /// ```rust
     /// # let x = 1;
     /// if x + 1 == x + 1 {}
-    /// ```
-    /// or
-    /// ```rust
+    ///
+    /// // or
+    ///
     /// # let a = 3;
     /// # let b = 4;
     /// assert_eq!(a, a);
diff --git a/clippy_lints/src/equatable_if_let.rs b/clippy_lints/src/equatable_if_let.rs
index cf47e581ccb..ef1216358dd 100644
--- a/clippy_lints/src/equatable_if_let.rs
+++ b/clippy_lints/src/equatable_if_let.rs
@@ -26,7 +26,7 @@ declare_clippy_lint! {
     ///     do_thing();
     /// }
     /// ```
-    /// Should be written
+    /// Use instead:
     /// ```rust,ignore
     /// if x == Some(2) {
     ///     do_thing();
diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs
index 807ecd2ddd1..9d21dd71e0e 100644
--- a/clippy_lints/src/escape.rs
+++ b/clippy_lints/src/escape.rs
@@ -31,12 +31,14 @@ declare_clippy_lint! {
     /// ### Example
     /// ```rust
     /// # fn foo(bar: usize) {}
-    /// // Bad
     /// let x = Box::new(1);
     /// foo(*x);
     /// println!("{}", *x);
+    /// ```
     ///
-    /// // Good
+    /// Use instead:
+    /// ```rust
+    /// # fn foo(bar: usize) {}
     /// let x = 1;
     /// foo(x);
     /// println!("{}", x);
diff --git a/clippy_lints/src/excessive_bools.rs b/clippy_lints/src/excessive_bools.rs
index 7a81fb37e84..a2af10e2ba5 100644
--- a/clippy_lints/src/excessive_bools.rs
+++ b/clippy_lints/src/excessive_bools.rs
@@ -18,7 +18,6 @@ declare_clippy_lint! {
     /// readability and API.
     ///
     /// ### Example
-    /// Bad:
     /// ```rust
     /// struct S {
     ///     is_pending: bool,
@@ -27,7 +26,7 @@ declare_clippy_lint! {
     /// }
     /// ```
     ///
-    /// Good:
+    /// Use instead:
     /// ```rust
     /// enum S {
     ///     Pending,
diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs
index d8f765b288a..12d636cf410 100644
--- a/clippy_lints/src/explicit_write.rs
+++ b/clippy_lints/src/explicit_write.rs
@@ -22,8 +22,16 @@ declare_clippy_lint! {
     /// ```rust
     /// # use std::io::Write;
     /// # let bar = "furchtbar";
-    /// // this would be clearer as `eprintln!("foo: {:?}", bar);`
     /// writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap();
+    /// writeln!(&mut std::io::stdout(), "foo: {:?}", bar).unwrap();
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// # use std::io::Write;
+    /// # let bar = "furchtbar";
+    /// eprintln!("foo: {:?}", bar);
+    /// println!("foo: {:?}", bar);
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub EXPLICIT_WRITE,
diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs
index 9f868df3ad0..b88e53aeca6 100644
--- a/clippy_lints/src/fallible_impl_from.rs
+++ b/clippy_lints/src/fallible_impl_from.rs
@@ -20,7 +20,6 @@ declare_clippy_lint! {
     /// ```rust
     /// struct Foo(i32);
     ///
-    /// // Bad
     /// impl From<String> for Foo {
     ///     fn from(s: String) -> Self {
     ///         Foo(s.parse().unwrap())
@@ -28,8 +27,8 @@ declare_clippy_lint! {
     /// }
     /// ```
     ///
+    /// Use instead:
     /// ```rust
-    /// // Good
     /// struct Foo(i32);
     ///
     /// impl TryFrom<String> for Foo {
diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs
index 7a4397a7b74..f850ea31f4d 100644
--- a/clippy_lints/src/float_literal.rs
+++ b/clippy_lints/src/float_literal.rs
@@ -19,11 +19,12 @@ declare_clippy_lint! {
     ///
     /// ### Example
     /// ```rust
-    /// // Bad
     /// let v: f32 = 0.123_456_789_9;
     /// println!("{}", v); //  0.123_456_789
+    /// ```
     ///
-    /// // Good
+    /// Use instead:
+    /// ```rust
     /// let v: f64 = 0.123_456_789_9;
     /// println!("{}", v); //  0.123_456_789_9
     /// ```
diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs
index 42503c26de1..df9b41d2c98 100644
--- a/clippy_lints/src/floating_point_arithmetic.rs
+++ b/clippy_lints/src/floating_point_arithmetic.rs
@@ -35,8 +35,7 @@ declare_clippy_lint! {
     /// let _ = a.exp() - 1.0;
     /// ```
     ///
-    /// is better expressed as
-    ///
+    /// Use instead:
     /// ```rust
     /// let a = 3f32;
     /// let _ = a.cbrt();
diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs
index 64c41b56587..3084c70589f 100644
--- a/clippy_lints/src/format.rs
+++ b/clippy_lints/src/format.rs
@@ -25,12 +25,13 @@ declare_clippy_lint! {
     ///
     /// ### Examples
     /// ```rust
-    ///
-    /// // Bad
     /// let foo = "foo";
     /// format!("{}", foo);
+    /// ```
     ///
-    /// // Good
+    /// Use instead:
+    /// ```rust
+    /// let foo = "foo";
     /// foo.to_owned();
     /// ```
     #[clippy::version = "pre 1.29.0"]
diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs
index 57964b8d48e..db0166da57f 100644
--- a/clippy_lints/src/formatting.rs
+++ b/clippy_lints/src/formatting.rs
@@ -36,12 +36,18 @@ declare_clippy_lint! {
     /// This is either a typo in the binary operator or confusing.
     ///
     /// ### Example
-    /// ```rust,ignore
-    /// if foo <- 30 { // this should be `foo < -30` but looks like a different operator
-    /// }
+    /// ```rust
+    /// # let foo = true;
+    /// # let bar = false;
+    /// // &&! looks like a different operator
+    /// if foo &&! bar {}
+    /// ```
     ///
-    /// if foo &&! bar { // this should be `foo && !bar` but looks like a different operator
-    /// }
+    /// Use instead:
+    /// ```rust
+    /// # let foo = true;
+    /// # let bar = false;
+    /// if foo && !bar {}
     /// ```
     #[clippy::version = "1.40.0"]
     pub SUSPICIOUS_UNARY_OP_FORMATTING,
diff --git a/clippy_lints/src/get_first.rs b/clippy_lints/src/get_first.rs
new file mode 100644
index 00000000000..0748ab45252
--- /dev/null
+++ b/clippy_lints/src/get_first.rs
@@ -0,0 +1,69 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{is_slice_of_primitives, match_def_path, paths};
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Spanned;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for using `x.get(0)` instead of
+    /// `x.first()`.
+    ///
+    /// ### Why is this bad?
+    /// Using `x.first()` is easier to read and has the same
+    /// result.
+    ///
+    /// ### Example
+    /// ```rust
+    /// // Bad
+    /// let x = vec![2, 3, 5];
+    /// let first_element = x.get(0);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// // Good
+    /// let x = vec![2, 3, 5];
+    /// let first_element = x.first();
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub GET_FIRST,
+    style,
+    "Using `x.get(0)` when `x.first()` is simpler"
+}
+declare_lint_pass!(GetFirst => [GET_FIRST]);
+
+impl<'tcx> LateLintPass<'tcx> for GetFirst {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if_chain! {
+            if let hir::ExprKind::MethodCall(_, [struct_calling_on, method_arg], _) = &expr.kind;
+            if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+            if match_def_path(cx, expr_def_id, &paths::SLICE_GET);
+
+            if let Some(_) = is_slice_of_primitives(cx, struct_calling_on);
+            if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = method_arg.kind;
+
+            then {
+                let mut applicability = Applicability::MachineApplicable;
+                let slice_name = snippet_with_applicability(
+                    cx,
+                    struct_calling_on.span, "..",
+                    &mut applicability,
+                );
+                span_lint_and_sugg(
+                    cx,
+                    GET_FIRST,
+                    expr.span,
+                    &format!("accessing first element with `{0}.get(0)`", slice_name),
+                    "try",
+                    format!("{}.first()", slice_name),
+                    applicability,
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/get_last_with_len.rs b/clippy_lints/src/get_last_with_len.rs
deleted file mode 100644
index df29d9308e7..00000000000
--- a/clippy_lints/src/get_last_with_len.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-//! lint on using `x.get(x.len() - 1)` instead of `x.last()`
-
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::SpanlessEq;
-use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
-use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Spanned;
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for using `x.get(x.len() - 1)` instead of
-    /// `x.last()`.
-    ///
-    /// ### Why is this bad?
-    /// Using `x.last()` is easier to read and has the same
-    /// result.
-    ///
-    /// Note that using `x[x.len() - 1]` is semantically different from
-    /// `x.last()`.  Indexing into the array will panic on out-of-bounds
-    /// accesses, while `x.get()` and `x.last()` will return `None`.
-    ///
-    /// There is another lint (get_unwrap) that covers the case of using
-    /// `x.get(index).unwrap()` instead of `x[index]`.
-    ///
-    /// ### Example
-    /// ```rust
-    /// // Bad
-    /// let x = vec![2, 3, 5];
-    /// let last_element = x.get(x.len() - 1);
-    ///
-    /// // Good
-    /// let x = vec![2, 3, 5];
-    /// let last_element = x.last();
-    /// ```
-    #[clippy::version = "1.37.0"]
-    pub GET_LAST_WITH_LEN,
-    complexity,
-    "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler"
-}
-
-declare_lint_pass!(GetLastWithLen => [GET_LAST_WITH_LEN]);
-
-impl<'tcx> LateLintPass<'tcx> for GetLastWithLen {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            // Is a method call
-            if let ExprKind::MethodCall(path, args, _) = expr.kind;
-
-            // Method name is "get"
-            if path.ident.name == sym!(get);
-
-            // Argument 0 (the struct we're calling the method on) is a vector
-            if let Some(struct_calling_on) = args.get(0);
-            let struct_ty = cx.typeck_results().expr_ty(struct_calling_on);
-            if is_type_diagnostic_item(cx, struct_ty, sym::Vec);
-
-            // Argument to "get" is a subtraction
-            if let Some(get_index_arg) = args.get(1);
-            if let ExprKind::Binary(
-                Spanned {
-                    node: BinOpKind::Sub,
-                    ..
-                },
-                lhs,
-                rhs,
-            ) = &get_index_arg.kind;
-
-            // LHS of subtraction is "x.len()"
-            if let ExprKind::MethodCall(arg_lhs_path, lhs_args, _) = &lhs.kind;
-            if arg_lhs_path.ident.name == sym::len;
-            if let Some(arg_lhs_struct) = lhs_args.get(0);
-
-            // The two vectors referenced (x in x.get(...) and in x.len())
-            if SpanlessEq::new(cx).eq_expr(struct_calling_on, arg_lhs_struct);
-
-            // RHS of subtraction is 1
-            if let ExprKind::Lit(rhs_lit) = &rhs.kind;
-            if let LitKind::Int(1, ..) = rhs_lit.node;
-
-            then {
-                let mut applicability = Applicability::MachineApplicable;
-                let vec_name = snippet_with_applicability(
-                    cx,
-                    struct_calling_on.span, "vec",
-                    &mut applicability,
-                );
-
-                span_lint_and_sugg(
-                    cx,
-                    GET_LAST_WITH_LEN,
-                    expr.span,
-                    &format!("accessing last element with `{0}.get({0}.len() - 1)`", vec_name),
-                    "try",
-                    format!("{}.last()", vec_name),
-                    applicability,
-                );
-            }
-        }
-    }
-}
diff --git a/clippy_lints/src/identity_op.rs b/clippy_lints/src/identity_op.rs
index 40cc5cd4bcf..419ea5a6811 100644
--- a/clippy_lints/src/identity_op.rs
+++ b/clippy_lints/src/identity_op.rs
@@ -1,15 +1,14 @@
-use clippy_utils::get_parent_expr;
-use clippy_utils::source::snippet;
-use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind};
+use clippy_utils::consts::{constant_full_int, constant_simple, Constant, FullInt};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{clip, unsext};
+use rustc_errors::Applicability;
+use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 
-use clippy_utils::consts::{constant_full_int, constant_simple, Constant, FullInt};
-use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{clip, unsext};
-
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for identity operations, e.g., `x + 0`.
@@ -23,11 +22,6 @@ declare_clippy_lint! {
     /// # let x = 1;
     /// x / 1 + 0 * 1 - 0 | 0;
     /// ```
-    ///
-    /// ### Known problems
-    /// False negatives: `f(0 + if b { 1 } else { 2 } + 3);` is reducible to
-    /// `f(if b { 1 } else { 2 } + 3);`. But the lint doesn't trigger for the code.
-    /// See [#8724](https://github.com/rust-lang/rust-clippy/issues/8724)
     #[clippy::version = "pre 1.29.0"]
     pub IDENTITY_OP,
     complexity,
@@ -45,31 +39,22 @@ impl<'tcx> LateLintPass<'tcx> for IdentityOp {
             if !is_allowed(cx, *cmp, left, right) {
                 match cmp.node {
                     BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
-                        if reducible_to_right(cx, expr, right) {
-                            check(cx, left, 0, expr.span, right.span);
-                        }
-                        check(cx, right, 0, expr.span, left.span);
+                        check(cx, left, 0, expr.span, right.span, needs_parenthesis(cx, expr, right));
+                        check(cx, right, 0, expr.span, left.span, Parens::Unneeded);
                     },
                     BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => {
-                        check(cx, right, 0, expr.span, left.span);
+                        check(cx, right, 0, expr.span, left.span, Parens::Unneeded);
                     },
                     BinOpKind::Mul => {
-                        if reducible_to_right(cx, expr, right) {
-                            check(cx, left, 1, expr.span, right.span);
-                        }
-                        check(cx, right, 1, expr.span, left.span);
+                        check(cx, left, 1, expr.span, right.span, needs_parenthesis(cx, expr, right));
+                        check(cx, right, 1, expr.span, left.span, Parens::Unneeded);
                     },
-                    BinOpKind::Div => check(cx, right, 1, expr.span, left.span),
+                    BinOpKind::Div => check(cx, right, 1, expr.span, left.span, Parens::Unneeded),
                     BinOpKind::BitAnd => {
-                        if reducible_to_right(cx, expr, right) {
-                            check(cx, left, -1, expr.span, right.span);
-                        }
-                        check(cx, right, -1, expr.span, left.span);
-                    },
-                    BinOpKind::Rem => {
-                        // Don't call reducible_to_right because N % N is always reducible to 1
-                        check_remainder(cx, left, right, expr.span, left.span);
+                        check(cx, left, -1, expr.span, right.span, needs_parenthesis(cx, expr, right));
+                        check(cx, right, -1, expr.span, left.span, Parens::Unneeded);
                     },
+                    BinOpKind::Rem => check_remainder(cx, left, right, expr.span, left.span),
                     _ => (),
                 }
             }
@@ -77,24 +62,50 @@ impl<'tcx> LateLintPass<'tcx> for IdentityOp {
     }
 }
 
-/// Checks if `left op ..right` can be actually reduced to `right`
-/// e.g. `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }`
-/// cannot be reduced to `if b { 1 } else { 2 } +  if b { 3 } else { 4 }`
+#[derive(Copy, Clone)]
+enum Parens {
+    Needed,
+    Unneeded,
+}
+
+/// Checks if `left op right` needs parenthesis when reduced to `right`
+/// e.g. `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }` cannot be reduced
+/// to `if b { 1 } else { 2 } + if b { 3 } else { 4 }` where the `if` could be
+/// interpreted as a statement
+///
 /// See #8724
-fn reducible_to_right(cx: &LateContext<'_>, binary: &Expr<'_>, right: &Expr<'_>) -> bool {
-    if let ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Block(..) | ExprKind::Loop(..) = right.kind {
-        is_toplevel_binary(cx, binary)
-    } else {
-        true
+fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, right: &Expr<'_>) -> Parens {
+    match right.kind {
+        ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) => {
+            // ensure we're checking against the leftmost expression of `right`
+            //
+            //     ~~~ `lhs`
+            // 0 + {4} * 2
+            //     ~~~~~~~ `right`
+            return needs_parenthesis(cx, binary, lhs);
+        },
+        ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Block(..) | ExprKind::Loop(..) => {},
+        _ => return Parens::Unneeded,
     }
-}
 
-fn is_toplevel_binary(cx: &LateContext<'_>, must_be_binary: &Expr<'_>) -> bool {
-    if let Some(parent) = get_parent_expr(cx, must_be_binary) && let ExprKind::Binary(..) = &parent.kind {
-        false
-    } else {
-        true
+    let mut prev_id = binary.hir_id;
+    for (_, node) in cx.tcx.hir().parent_iter(binary.hir_id) {
+        if let Node::Expr(expr) = node
+            && let ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) = expr.kind
+            && lhs.hir_id == prev_id
+        {
+            // keep going until we find a node that encompasses left of `binary`
+            prev_id = expr.hir_id;
+            continue;
+        }
+
+        match node {
+            Node::Block(_) | Node::Stmt(_) => break,
+            _ => return Parens::Unneeded,
+        };
     }
+
+    Parens::Needed
 }
 
 fn is_allowed(cx: &LateContext<'_>, cmp: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> bool {
@@ -115,11 +126,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);
+        span_ineffective_operation(cx, span, arg, Parens::Unneeded);
     }
 }
 
-fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
+fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens) {
     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),
@@ -132,19 +143,27 @@ fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
             1 => v == 1,
             _ => unreachable!(),
         } {
-            span_ineffective_operation(cx, span, arg);
+            span_ineffective_operation(cx, span, arg, parens);
         }
     }
 }
 
-fn span_ineffective_operation(cx: &LateContext<'_>, span: Span, arg: Span) {
-    span_lint(
+fn span_ineffective_operation(cx: &LateContext<'_>, span: Span, arg: Span, parens: Parens) {
+    let mut applicability = Applicability::MachineApplicable;
+    let expr_snippet = snippet_with_applicability(cx, arg, "..", &mut applicability);
+
+    let suggestion = match parens {
+        Parens::Needed => format!("({expr_snippet})"),
+        Parens::Unneeded => expr_snippet.into_owned(),
+    };
+
+    span_lint_and_sugg(
         cx,
         IDENTITY_OP,
         span,
-        &format!(
-            "the operation is ineffective. Consider reducing it to `{}`",
-            snippet(cx, arg, "..")
-        ),
+        "this operation has no effect",
+        "consider reducing it to",
+        suggestion,
+        applicability,
     );
 }
diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs
index 0f3889a2936..63ac092dfaf 100644
--- a/clippy_lints/src/large_enum_variant.rs
+++ b/clippy_lints/src/large_enum_variant.rs
@@ -1,12 +1,13 @@
 //! lint when there is a large size difference between variants on an enum
 
-use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{diagnostics::span_lint_and_then, ty::is_copy};
 use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::{Adt, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 
@@ -26,6 +27,15 @@ declare_clippy_lint! {
     /// the overhead is negligible and the boxing is counter-productive. Always
     /// measure the change this lint suggests.
     ///
+    /// For types that implement `Copy`, the suggestion to `Box` a variant's
+    /// data would require removing the trait impl. The types can of course
+    /// still be `Clone`, but that is worse ergonomically. Depending on the
+    /// use case it may be possible to store the large data in an auxillary
+    /// structure (e.g. Arena or ECS).
+    ///
+    /// The lint will ignore generic types if the layout depends on the
+    /// generics, even if the size difference will be large anyway.
+    ///
     /// ### Example
     /// ```rust
     /// // Bad
@@ -74,7 +84,7 @@ struct VariantInfo {
 impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
-    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
         if in_external_macro(cx.tcx.sess, item.span) {
             return;
         }
@@ -132,37 +142,43 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
                         let fields = def.variants[variants_size[0].ind].data.fields();
                         variants_size[0].fields_size.sort_by(|a, b| (a.size.cmp(&b.size)));
                         let mut applicability = Applicability::MaybeIncorrect;
-                        let sugg: Vec<(Span, String)> = variants_size[0]
-                            .fields_size
-                            .iter()
-                            .rev()
-                            .map_while(|val| {
-                                if difference > self.maximum_size_difference_allowed {
-                                    difference = difference.saturating_sub(val.size);
-                                    Some((
-                                        fields[val.ind].ty.span,
-                                        format!(
-                                            "Box<{}>",
-                                            snippet_with_applicability(
-                                                cx,
-                                                fields[val.ind].ty.span,
-                                                "..",
-                                                &mut applicability
-                                            )
-                                            .into_owned()
-                                        ),
-                                    ))
-                                } else {
-                                    None
-                                }
-                            })
-                            .collect();
+                        if is_copy(cx, ty) || maybe_copy(cx, ty) {
+                            diag.span_note(
+                                item.ident.span,
+                                "boxing a variant would require the type no longer be `Copy`",
+                            );
+                        } else {
+                            let sugg: Vec<(Span, String)> = variants_size[0]
+                                .fields_size
+                                .iter()
+                                .rev()
+                                .map_while(|val| {
+                                    if difference > self.maximum_size_difference_allowed {
+                                        difference = difference.saturating_sub(val.size);
+                                        Some((
+                                            fields[val.ind].ty.span,
+                                            format!(
+                                                "Box<{}>",
+                                                snippet_with_applicability(
+                                                    cx,
+                                                    fields[val.ind].ty.span,
+                                                    "..",
+                                                    &mut applicability
+                                                )
+                                                .into_owned()
+                                            ),
+                                        ))
+                                    } else {
+                                        None
+                                    }
+                                })
+                                .collect();
 
-                        if !sugg.is_empty() {
-                            diag.multipart_suggestion(help_text, sugg, Applicability::MaybeIncorrect);
-                            return;
+                            if !sugg.is_empty() {
+                                diag.multipart_suggestion(help_text, sugg, Applicability::MaybeIncorrect);
+                                return;
+                            }
                         }
-
                         diag.span_help(def.variants[variants_size[0].ind].span, help_text);
                     },
                 );
@@ -170,3 +186,13 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
         }
     }
 }
+
+fn maybe_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    if let Adt(_def, substs) = ty.kind()
+        && substs.types().next().is_some()
+        && let Some(copy_trait) = cx.tcx.lang_items().copy_trait()
+    {
+        return cx.tcx.non_blanket_impls_for_ty(copy_trait, ty).next().is_some();
+    }
+    false
+}
diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs
index db09d00d730..56bbbbbc819 100644
--- a/clippy_lints/src/let_if_seq.rs
+++ b/clippy_lints/src/let_if_seq.rs
@@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
                 if let hir::ExprKind::If(hir::Expr { kind: hir::ExprKind::DropTemps(cond), ..}, then, else_) = if_.kind;
                 if !is_local_used(cx, *cond, canonical_id);
                 if let hir::ExprKind::Block(then, _) = then.kind;
-                if let Some(value) = check_assign(cx, canonical_id, &*then);
+                if let Some(value) = check_assign(cx, canonical_id, then);
                 if !is_local_used(cx, value, canonical_id);
                 then {
                     let span = stmt.span.to(if_.span);
diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs
index be5c478900f..d4ec046d0bb 100644
--- a/clippy_lints/src/lib.register_all.rs
+++ b/clippy_lints/src/lib.register_all.rs
@@ -4,6 +4,7 @@
 
 store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS),
+    LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE),
     LintId::of(approx_const::APPROX_CONSTANT),
     LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
     LintId::of(assign_ops::ASSIGN_OP_PATTERN),
@@ -24,6 +25,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
     LintId::of(booleans::LOGIC_BUG),
     LintId::of(booleans::NONMINIMAL_BOOL),
+    LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
     LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
     LintId::of(casts::CAST_ABS_TO_UNSIGNED),
     LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
@@ -36,7 +38,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(casts::UNNECESSARY_CAST),
     LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
     LintId::of(collapsible_if::COLLAPSIBLE_IF),
-    LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
     LintId::of(comparison_chain::COMPARISON_CHAIN),
     LintId::of(copies::IFS_SAME_COND),
     LintId::of(copies::IF_SAME_THEN_ELSE),
@@ -91,7 +92,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF),
     LintId::of(functions::RESULT_UNIT_ERR),
     LintId::of(functions::TOO_MANY_ARGUMENTS),
-    LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
+    LintId::of(get_first::GET_FIRST),
     LintId::of(identity_op::IDENTITY_OP),
     LintId::of(if_let_mutex::IF_LET_MUTEX),
     LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
@@ -132,23 +133,25 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(main_recursion::MAIN_RECURSION),
     LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
     LintId::of(manual_bits::MANUAL_BITS),
-    LintId::of(manual_map::MANUAL_MAP),
     LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
     LintId::of(manual_strip::MANUAL_STRIP),
-    LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
     LintId::of(map_clone::MAP_CLONE),
     LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
     LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
     LintId::of(match_result_ok::MATCH_RESULT_OK),
-    LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
+    LintId::of(matches::COLLAPSIBLE_MATCH),
     LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
+    LintId::of(matches::MANUAL_MAP),
+    LintId::of(matches::MANUAL_UNWRAP_OR),
     LintId::of(matches::MATCH_AS_REF),
     LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
     LintId::of(matches::MATCH_OVERLAPPING_ARM),
     LintId::of(matches::MATCH_REF_PATS),
     LintId::of(matches::MATCH_SINGLE_BINDING),
+    LintId::of(matches::MATCH_STR_CASE_MISMATCH),
     LintId::of(matches::NEEDLESS_MATCH),
     LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
+    LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(matches::SINGLE_MATCH),
     LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
     LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
@@ -166,6 +169,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(methods::FILTER_MAP_IDENTITY),
     LintId::of(methods::FILTER_NEXT),
     LintId::of(methods::FLAT_MAP_IDENTITY),
+    LintId::of(methods::GET_LAST_WITH_LEN),
     LintId::of(methods::INSPECT_FOR_EACH),
     LintId::of(methods::INTO_ITER_ON_REF),
     LintId::of(methods::IS_DIGIT_ASCII_RADIX),
@@ -189,6 +193,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(methods::NEEDLESS_OPTION_TAKE),
     LintId::of(methods::NEEDLESS_SPLITN),
     LintId::of(methods::NEW_RET_NO_SELF),
+    LintId::of(methods::NO_EFFECT_REPLACE),
     LintId::of(methods::OK_EXPECT),
     LintId::of(methods::OPTION_AS_REF_DEREF),
     LintId::of(methods::OPTION_FILTER_MAP),
@@ -278,7 +283,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(self_assignment::SELF_ASSIGNMENT),
     LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS),
     LintId::of(serde_api::SERDE_API_MISUSE),
-    LintId::of(significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
     LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
     LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
@@ -289,6 +293,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
     LintId::of(swap::ALMOST_SWAPPED),
     LintId::of(swap::MANUAL_SWAP),
+    LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF),
     LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
     LintId::of(temporary_assignment::TEMPORARY_ASSIGNMENT),
     LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
@@ -302,6 +307,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
     LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
     LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
+    LintId::of(transmute::USELESS_TRANSMUTE),
     LintId::of(transmute::WRONG_TRANSMUTE),
     LintId::of(transmuting_null::TRANSMUTING_NULL),
     LintId::of(types::BORROWED_BOX),
diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs
index b15c979d0c7..4f1c3673f85 100644
--- a/clippy_lints/src/lib.register_complexity.rs
+++ b/clippy_lints/src/lib.register_complexity.rs
@@ -5,6 +5,7 @@
 store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec![
     LintId::of(attrs::DEPRECATED_CFG_ATTR),
     LintId::of(booleans::NONMINIMAL_BOOL),
+    LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
     LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
     LintId::of(casts::CHAR_LIT_AS_U8),
     LintId::of(casts::UNNECESSARY_CAST),
@@ -15,7 +16,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(explicit_write::EXPLICIT_WRITE),
     LintId::of(format::USELESS_FORMAT),
     LintId::of(functions::TOO_MANY_ARGUMENTS),
-    LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
     LintId::of(identity_op::IDENTITY_OP),
     LintId::of(int_plus_one::INT_PLUS_ONE),
     LintId::of(lifetimes::EXTRA_UNUSED_LIFETIMES),
@@ -25,9 +25,9 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(loops::SINGLE_ELEMENT_LOOP),
     LintId::of(loops::WHILE_LET_LOOP),
     LintId::of(manual_strip::MANUAL_STRIP),
-    LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
     LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
     LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
+    LintId::of(matches::MANUAL_UNWRAP_OR),
     LintId::of(matches::MATCH_AS_REF),
     LintId::of(matches::MATCH_SINGLE_BINDING),
     LintId::of(matches::NEEDLESS_MATCH),
@@ -37,6 +37,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(methods::FILTER_MAP_IDENTITY),
     LintId::of(methods::FILTER_NEXT),
     LintId::of(methods::FLAT_MAP_IDENTITY),
+    LintId::of(methods::GET_LAST_WITH_LEN),
     LintId::of(methods::INSPECT_FOR_EACH),
     LintId::of(methods::ITER_COUNT),
     LintId::of(methods::MANUAL_FILTER_MAP),
@@ -90,6 +91,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
     LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
     LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
+    LintId::of(transmute::USELESS_TRANSMUTE),
     LintId::of(types::BORROWED_BOX),
     LintId::of(types::TYPE_COMPLEXITY),
     LintId::of(types::VEC_BOX),
diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs
index 6bf2c4bbaed..50cdd0af923 100644
--- a/clippy_lints/src/lib.register_correctness.rs
+++ b/clippy_lints/src/lib.register_correctness.rs
@@ -39,7 +39,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
     LintId::of(loops::ITER_NEXT_LOOP),
     LintId::of(loops::NEVER_LOOP),
     LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
-    LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
+    LintId::of(matches::MATCH_STR_CASE_MISMATCH),
     LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
     LintId::of(methods::CLONE_DOUBLE_REF),
     LintId::of(methods::ITERATOR_STEP_BY_ZERO),
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index 5552ea8aa80..b927ba3b17c 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -34,10 +34,10 @@ store.register_lints(&[
     #[cfg(feature = "internal")]
     utils::internal_lints::UNNECESSARY_SYMBOL_STR,
     absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS,
+    almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE,
     approx_const::APPROX_CONSTANT,
-    arithmetic::FLOAT_ARITHMETIC,
-    arithmetic::INTEGER_ARITHMETIC,
     as_conversions::AS_CONVERSIONS,
+    as_underscore::AS_UNDERSCORE,
     asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
     asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
     assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
@@ -64,6 +64,7 @@ store.register_lints(&[
     booleans::LOGIC_BUG,
     booleans::NONMINIMAL_BOOL,
     borrow_as_ptr::BORROW_AS_PTR,
+    borrow_deref_ref::BORROW_DEREF_REF,
     bytecount::NAIVE_BYTECOUNT,
     bytes_count_to_len::BYTES_COUNT_TO_LEN,
     cargo::CARGO_COMMON_METADATA,
@@ -93,7 +94,6 @@ store.register_lints(&[
     cognitive_complexity::COGNITIVE_COMPLEXITY,
     collapsible_if::COLLAPSIBLE_ELSE_IF,
     collapsible_if::COLLAPSIBLE_IF,
-    collapsible_match::COLLAPSIBLE_MATCH,
     comparison_chain::COMPARISON_CHAIN,
     copies::BRANCHES_SHARING_CODE,
     copies::IFS_SAME_COND,
@@ -124,6 +124,7 @@ store.register_lints(&[
     doc::MISSING_PANICS_DOC,
     doc::MISSING_SAFETY_DOC,
     doc::NEEDLESS_DOCTEST_MAIN,
+    doc_link_with_quotes::DOC_LINK_WITH_QUOTES,
     double_comparison::DOUBLE_COMPARISONS,
     double_parens::DOUBLE_PARENS,
     drop_forget_ref::DROP_COPY,
@@ -183,7 +184,7 @@ store.register_lints(&[
     functions::TOO_MANY_ARGUMENTS,
     functions::TOO_MANY_LINES,
     future_not_send::FUTURE_NOT_SEND,
-    get_last_with_len::GET_LAST_WITH_LEN,
+    get_first::GET_FIRST,
     identity_op::IDENTITY_OP,
     if_let_mutex::IF_LET_MUTEX,
     if_not_else::IF_NOT_ELSE,
@@ -250,33 +251,36 @@ store.register_lints(&[
     manual_assert::MANUAL_ASSERT,
     manual_async_fn::MANUAL_ASYNC_FN,
     manual_bits::MANUAL_BITS,
-    manual_map::MANUAL_MAP,
     manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
     manual_ok_or::MANUAL_OK_OR,
     manual_strip::MANUAL_STRIP,
-    manual_unwrap_or::MANUAL_UNWRAP_OR,
     map_clone::MAP_CLONE,
     map_err_ignore::MAP_ERR_IGNORE,
     map_unit_fn::OPTION_MAP_UNIT_FN,
     map_unit_fn::RESULT_MAP_UNIT_FN,
-    match_on_vec_items::MATCH_ON_VEC_ITEMS,
     match_result_ok::MATCH_RESULT_OK,
-    match_str_case_mismatch::MATCH_STR_CASE_MISMATCH,
+    matches::COLLAPSIBLE_MATCH,
     matches::INFALLIBLE_DESTRUCTURING_MATCH,
+    matches::MANUAL_MAP,
+    matches::MANUAL_UNWRAP_OR,
     matches::MATCH_AS_REF,
     matches::MATCH_BOOL,
     matches::MATCH_LIKE_MATCHES_MACRO,
+    matches::MATCH_ON_VEC_ITEMS,
     matches::MATCH_OVERLAPPING_ARM,
     matches::MATCH_REF_PATS,
     matches::MATCH_SAME_ARMS,
     matches::MATCH_SINGLE_BINDING,
+    matches::MATCH_STR_CASE_MISMATCH,
     matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
     matches::MATCH_WILD_ERR_ARM,
     matches::NEEDLESS_MATCH,
     matches::REDUNDANT_PATTERN_MATCHING,
     matches::REST_PAT_IN_FULLY_BOUND_STRUCTS,
+    matches::SIGNIFICANT_DROP_IN_SCRUTINEE,
     matches::SINGLE_MATCH,
     matches::SINGLE_MATCH_ELSE,
+    matches::TRY_ERR,
     matches::WILDCARD_ENUM_MATCH_ARM,
     matches::WILDCARD_IN_OR_PATTERNS,
     mem_forget::MEM_FORGET,
@@ -302,6 +306,7 @@ store.register_lints(&[
     methods::FLAT_MAP_IDENTITY,
     methods::FLAT_MAP_OPTION,
     methods::FROM_ITER_INSTEAD_OF_COLLECT,
+    methods::GET_LAST_WITH_LEN,
     methods::GET_UNWRAP,
     methods::IMPLICIT_CLONE,
     methods::INEFFICIENT_TO_STRING,
@@ -330,6 +335,7 @@ store.register_lints(&[
     methods::NEEDLESS_OPTION_TAKE,
     methods::NEEDLESS_SPLITN,
     methods::NEW_RET_NO_SELF,
+    methods::NO_EFFECT_REPLACE,
     methods::OK_EXPECT,
     methods::OPTION_AS_REF_DEREF,
     methods::OPTION_FILTER_MAP,
@@ -377,6 +383,7 @@ store.register_lints(&[
     misc_early::UNNEEDED_WILDCARD_PATTERN,
     misc_early::UNSEPARATED_LITERAL_SUFFIX,
     misc_early::ZERO_PREFIXED_LITERAL,
+    mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER,
     missing_const_for_fn::MISSING_CONST_FOR_FN,
     missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS,
     missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES,
@@ -418,6 +425,8 @@ store.register_lints(&[
     non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS,
     non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY,
     nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES,
+    numeric_arithmetic::FLOAT_ARITHMETIC,
+    numeric_arithmetic::INTEGER_ARITHMETIC,
     octal_escapes::OCTAL_ESCAPES,
     only_used_in_recursion::ONLY_USED_IN_RECURSION,
     open_options::NONSENSICAL_OPEN_OPTIONS,
@@ -473,7 +482,6 @@ store.register_lints(&[
     shadow::SHADOW_REUSE,
     shadow::SHADOW_SAME,
     shadow::SHADOW_UNRELATED,
-    significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE,
     single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES,
     single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
     size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
@@ -493,6 +501,7 @@ store.register_lints(&[
     suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
     swap::ALMOST_SWAPPED,
     swap::MANUAL_SWAP,
+    swap_ptr_to_ref::SWAP_PTR_TO_REF,
     tabs_in_doc_comments::TABS_IN_DOC_COMMENTS,
     temporary_assignment::TEMPORARY_ASSIGNMENT,
     to_digit_is_some::TO_DIGIT_IS_SOME,
@@ -514,7 +523,6 @@ store.register_lints(&[
     transmute::USELESS_TRANSMUTE,
     transmute::WRONG_TRANSMUTE,
     transmuting_null::TRANSMUTING_NULL,
-    try_err::TRY_ERR,
     types::BORROWED_BOX,
     types::BOX_COLLECTION,
     types::LINKEDLIST,
@@ -544,6 +552,7 @@ store.register_lints(&[
     unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
     unused_async::UNUSED_ASYNC,
     unused_io_amount::UNUSED_IO_AMOUNT,
+    unused_rounding::UNUSED_ROUNDING,
     unused_self::UNUSED_SELF,
     unused_unit::UNUSED_UNIT,
     unwrap::PANICKING_UNWRAP,
diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs
index 34d1555049d..f961952991f 100644
--- a/clippy_lints/src/lib.register_nursery.rs
+++ b/clippy_lints/src/lib.register_nursery.rs
@@ -25,11 +25,12 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
     LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
     LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
     LintId::of(regex::TRIVIAL_REGEX),
-    LintId::of(significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(strings::STRING_LIT_AS_BYTES),
     LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
     LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
+    LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
+    LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
     LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR),
-    LintId::of(transmute::USELESS_TRANSMUTE),
+    LintId::of(unused_rounding::UNUSED_ROUNDING),
     LintId::of(use_self::USE_SELF),
 ])
diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs
index 63232fd4113..a8b6c5a5d63 100644
--- a/clippy_lints/src/lib.register_pedantic.rs
+++ b/clippy_lints/src/lib.register_pedantic.rs
@@ -26,6 +26,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(doc::DOC_MARKDOWN),
     LintId::of(doc::MISSING_ERRORS_DOC),
     LintId::of(doc::MISSING_PANICS_DOC),
+    LintId::of(doc_link_with_quotes::DOC_LINK_WITH_QUOTES),
     LintId::of(empty_enum::EMPTY_ENUM),
     LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
     LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
@@ -50,8 +51,8 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(macro_use::MACRO_USE_IMPORTS),
     LintId::of(manual_assert::MANUAL_ASSERT),
     LintId::of(manual_ok_or::MANUAL_OK_OR),
-    LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
     LintId::of(matches::MATCH_BOOL),
+    LintId::of(matches::MATCH_ON_VEC_ITEMS),
     LintId::of(matches::MATCH_SAME_ARMS),
     LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS),
     LintId::of(matches::MATCH_WILD_ERR_ARM),
@@ -66,6 +67,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(methods::UNNECESSARY_JOIN),
     LintId::of(misc::FLOAT_CMP),
     LintId::of(misc::USED_UNDERSCORE_BINDING),
+    LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER),
     LintId::of(mut_mut::MUT_MUT),
     LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
     LintId::of(needless_continue::NEEDLESS_CONTINUE),
@@ -84,8 +86,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
     LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
     LintId::of(strings::STRING_ADD_ASSIGN),
-    LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
-    LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS),
     LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
     LintId::of(types::LINKEDLIST),
     LintId::of(types::OPTION_OPTION),
diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs
index a6d3a06dc16..3695012f552 100644
--- a/clippy_lints/src/lib.register_restriction.rs
+++ b/clippy_lints/src/lib.register_restriction.rs
@@ -3,9 +3,8 @@
 // Manual edits will be overwritten.
 
 store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
-    LintId::of(arithmetic::FLOAT_ARITHMETIC),
-    LintId::of(arithmetic::INTEGER_ARITHMETIC),
     LintId::of(as_conversions::AS_CONVERSIONS),
+    LintId::of(as_underscore::AS_UNDERSCORE),
     LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
     LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
     LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON),
@@ -32,6 +31,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
     LintId::of(map_err_ignore::MAP_ERR_IGNORE),
     LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
+    LintId::of(matches::TRY_ERR),
     LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
     LintId::of(mem_forget::MEM_FORGET),
     LintId::of(methods::CLONE_ON_REF_PTR),
@@ -50,6 +50,8 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(module_style::MOD_MODULE_FILES),
     LintId::of(module_style::SELF_NAMED_MODULE_FILES),
     LintId::of(modulo_arithmetic::MODULO_ARITHMETIC),
+    LintId::of(numeric_arithmetic::FLOAT_ARITHMETIC),
+    LintId::of(numeric_arithmetic::INTEGER_ARITHMETIC),
     LintId::of(panic_in_result_fn::PANIC_IN_RESULT_FN),
     LintId::of(panic_unimplemented::PANIC),
     LintId::of(panic_unimplemented::TODO),
@@ -67,7 +69,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(strings::STRING_SLICE),
     LintId::of(strings::STRING_TO_STRING),
     LintId::of(strings::STR_TO_STRING),
-    LintId::of(try_err::TRY_ERR),
     LintId::of(types::RC_BUFFER),
     LintId::of(types::RC_MUTEX),
     LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs
index 62f26d821a0..35575351784 100644
--- a/clippy_lints/src/lib.register_style.rs
+++ b/clippy_lints/src/lib.register_style.rs
@@ -12,7 +12,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
     LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF),
     LintId::of(collapsible_if::COLLAPSIBLE_IF),
-    LintId::of(collapsible_match::COLLAPSIBLE_MATCH),
     LintId::of(comparison_chain::COMPARISON_CHAIN),
     LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
     LintId::of(dereference::NEEDLESS_BORROW),
@@ -31,6 +30,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(functions::DOUBLE_MUST_USE),
     LintId::of(functions::MUST_USE_UNIT),
     LintId::of(functions::RESULT_UNIT_ERR),
+    LintId::of(get_first::GET_FIRST),
     LintId::of(inherent_to_string::INHERENT_TO_STRING),
     LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS),
     LintId::of(len_zero::COMPARISON_TO_EMPTY),
@@ -45,11 +45,12 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(main_recursion::MAIN_RECURSION),
     LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
     LintId::of(manual_bits::MANUAL_BITS),
-    LintId::of(manual_map::MANUAL_MAP),
     LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
     LintId::of(map_clone::MAP_CLONE),
     LintId::of(match_result_ok::MATCH_RESULT_OK),
+    LintId::of(matches::COLLAPSIBLE_MATCH),
     LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
+    LintId::of(matches::MANUAL_MAP),
     LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
     LintId::of(matches::MATCH_OVERLAPPING_ARM),
     LintId::of(matches::MATCH_REF_PATS),
diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs
index 2de49f1624a..7b13713c36e 100644
--- a/clippy_lints/src/lib.register_suspicious.rs
+++ b/clippy_lints/src/lib.register_suspicious.rs
@@ -3,6 +3,7 @@
 // Manual edits will be overwritten.
 
 store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec![
+    LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE),
     LintId::of(assign_ops::MISREFACTORED_ASSIGN_OP),
     LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
     LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
@@ -23,11 +24,13 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
     LintId::of(loops::EMPTY_LOOP),
     LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
     LintId::of(loops::MUT_RANGE_BOUND),
+    LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
+    LintId::of(methods::NO_EFFECT_REPLACE),
     LintId::of(methods::SUSPICIOUS_MAP),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
     LintId::of(octal_escapes::OCTAL_ESCAPES),
     LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT),
-    LintId::of(significant_drop_in_scrutinee::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
+    LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF),
 ])
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 4ac834f7240..ee0416fc0ff 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -168,9 +168,10 @@ mod renamed_lints;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
 mod absurd_extreme_comparisons;
+mod almost_complete_letter_range;
 mod approx_const;
-mod arithmetic;
 mod as_conversions;
+mod as_underscore;
 mod asm_syntax;
 mod assertions_on_constants;
 mod assign_ops;
@@ -183,6 +184,7 @@ mod blocks_in_if_conditions;
 mod bool_assert_comparison;
 mod booleans;
 mod borrow_as_ptr;
+mod borrow_deref_ref;
 mod bytecount;
 mod bytes_count_to_len;
 mod cargo;
@@ -191,7 +193,6 @@ mod casts;
 mod checked_conversions;
 mod cognitive_complexity;
 mod collapsible_if;
-mod collapsible_match;
 mod comparison_chain;
 mod copies;
 mod copy_iterator;
@@ -208,6 +209,7 @@ mod disallowed_methods;
 mod disallowed_script_idents;
 mod disallowed_types;
 mod doc;
+mod doc_link_with_quotes;
 mod double_comparison;
 mod double_parens;
 mod drop_forget_ref;
@@ -242,7 +244,7 @@ mod from_over_into;
 mod from_str_radix_10;
 mod functions;
 mod future_not_send;
-mod get_last_with_len;
+mod get_first;
 mod identity_op;
 mod if_let_mutex;
 mod if_not_else;
@@ -278,17 +280,13 @@ mod main_recursion;
 mod manual_assert;
 mod manual_async_fn;
 mod manual_bits;
-mod manual_map;
 mod manual_non_exhaustive;
 mod manual_ok_or;
 mod manual_strip;
-mod manual_unwrap_or;
 mod map_clone;
 mod map_err_ignore;
 mod map_unit_fn;
-mod match_on_vec_items;
 mod match_result_ok;
-mod match_str_case_mismatch;
 mod matches;
 mod mem_forget;
 mod mem_replace;
@@ -296,6 +294,7 @@ mod methods;
 mod minmax;
 mod misc;
 mod misc_early;
+mod mismatching_type_param_order;
 mod missing_const_for_fn;
 mod missing_doc;
 mod missing_enforced_import_rename;
@@ -328,6 +327,7 @@ mod non_expressive_names;
 mod non_octal_unix_permissions;
 mod non_send_fields_in_send_ty;
 mod nonstandard_macro_braces;
+mod numeric_arithmetic;
 mod octal_escapes;
 mod only_used_in_recursion;
 mod open_options;
@@ -367,7 +367,6 @@ mod self_named_constructors;
 mod semicolon_if_nothing_returned;
 mod serde_api;
 mod shadow;
-mod significant_drop_in_scrutinee;
 mod single_char_lifetime_names;
 mod single_component_path_imports;
 mod size_of_in_element_count;
@@ -378,6 +377,7 @@ mod strlen_on_c_strings;
 mod suspicious_operation_groupings;
 mod suspicious_trait_impl;
 mod swap;
+mod swap_ptr_to_ref;
 mod tabs_in_doc_comments;
 mod temporary_assignment;
 mod to_digit_is_some;
@@ -385,7 +385,6 @@ mod trailing_empty_array;
 mod trait_bounds;
 mod transmute;
 mod transmuting_null;
-mod try_err;
 mod types;
 mod undocumented_unsafe_blocks;
 mod unicode;
@@ -402,6 +401,7 @@ mod unnested_or_patterns;
 mod unsafe_removed_from_name;
 mod unused_async;
 mod unused_io_amount;
+mod unused_rounding;
 mod unused_self;
 mod unused_unit;
 mod unwrap;
@@ -562,7 +562,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(len_zero::LenZero));
     store.register_late_pass(|| Box::new(attrs::Attributes));
     store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
-    store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch));
     store.register_late_pass(|| Box::new(unicode::Unicode));
     store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
     store.register_late_pass(|| Box::new(unit_hash::UnitHash));
@@ -636,6 +635,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(mutex_atomic::Mutex));
     store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate));
     store.register_late_pass(|| Box::new(needless_borrowed_ref::NeedlessBorrowedRef));
+    store.register_late_pass(|| Box::new(borrow_deref_ref::BorrowDerefRef));
     store.register_late_pass(|| Box::new(no_effect::NoEffect));
     store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment));
     store.register_late_pass(|| Box::new(transmute::Transmute));
@@ -652,7 +652,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(strings::StringLitAsBytes));
     store.register_late_pass(|| Box::new(derive::Derive));
     store.register_late_pass(|| Box::new(derivable_impls::DerivableImpls));
-    store.register_late_pass(|| Box::new(get_last_with_len::GetLastWithLen));
     store.register_late_pass(|| Box::new(drop_forget_ref::DropForgetRef));
     store.register_late_pass(|| Box::new(empty_enum::EmptyEnum));
     store.register_late_pass(|| Box::new(absurd_extreme_comparisons::AbsurdExtremeComparisons));
@@ -678,7 +677,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
     store.register_late_pass(|| Box::new(neg_multiply::NegMultiply));
     store.register_late_pass(|| Box::new(mem_forget::MemForget));
-    store.register_late_pass(|| Box::new(arithmetic::Arithmetic::default()));
+    store.register_late_pass(|| Box::new(numeric_arithmetic::NumericArithmetic::default()));
     store.register_late_pass(|| Box::new(assign_ops::AssignOps));
     store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq));
     store.register_late_pass(|| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
@@ -700,7 +699,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     );
     store.register_late_pass(move || Box::new(pass_by_ref_or_value));
     store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef));
-    store.register_late_pass(|| Box::new(try_err::TryErr));
     store.register_late_pass(|| Box::new(bytecount::ByteCount));
     store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter));
     store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody));
@@ -812,7 +810,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(if_not_else::IfNotElse));
     store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
     store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock));
-    store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems));
     store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn));
     store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero));
     store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn));
@@ -830,7 +827,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(repeat_once::RepeatOnce));
     store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult));
     store.register_late_pass(|| Box::new(self_assignment::SelfAssignment));
-    store.register_late_pass(|| Box::new(manual_unwrap_or::ManualUnwrapOr));
     store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr));
     store.register_late_pass(|| Box::new(float_equality_without_abs::FloatEqualityWithoutAbs));
     store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
@@ -849,7 +845,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing));
     store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10));
-    store.register_late_pass(|| Box::new(manual_map::ManualMap));
     store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv)));
     store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison));
     store.register_early_pass(move || Box::new(module_style::ModStyle));
@@ -875,7 +870,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         ))
     });
     store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
-    store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
     store.register_late_pass(move || Box::new(format_args::FormatArgs));
     store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
     store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
@@ -886,9 +880,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv)));
     store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv)));
     store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation));
+    store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes));
     store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion));
-    store.register_late_pass(|| Box::new(significant_drop_in_scrutinee::SignificantDropInScrutinee));
-    store.register_late_pass(|| Box::new(dbg_macro::DbgMacro));
+    let allow_dbg_in_tests = conf.allow_dbg_in_tests;
+    store.register_late_pass(move || Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
     let cargo_ignore_publish = conf.cargo_ignore_publish;
     store.register_late_pass(move || {
         Box::new(cargo::Cargo {
@@ -906,6 +901,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace));
     store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
     store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default()));
+    store.register_late_pass(|| Box::new(get_first::GetFirst));
+    store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding));
+    store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv)));
+    store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef));
+    store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch));
+    store.register_late_pass(|| Box::new(as_underscore::AsUnderscore));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs
index 75d771f992a..d61be78895f 100644
--- a/clippy_lints/src/loops/mod.rs
+++ b/clippy_lints/src/loops/mod.rs
@@ -180,29 +180,24 @@ declare_clippy_lint! {
     /// ### Example
     /// ```rust
     /// # let opt = Some(1);
-    ///
-    /// // Bad
+    /// # let res: Result<i32, std::io::Error> = Ok(1);
     /// for x in opt {
     ///     // ..
     /// }
     ///
-    /// // Good
-    /// if let Some(x) = opt {
+    /// for x in &res {
     ///     // ..
     /// }
     /// ```
     ///
-    /// // or
-    ///
+    /// Use instead:
     /// ```rust
+    /// # let opt = Some(1);
     /// # let res: Result<i32, std::io::Error> = Ok(1);
-    ///
-    /// // Bad
-    /// for x in &res {
+    /// if let Some(x) = opt {
     ///     // ..
     /// }
     ///
-    /// // Good
     /// if let Ok(x) = res {
     ///     // ..
     /// }
diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs
index 4f85364965b..a348bb465c8 100644
--- a/clippy_lints/src/loops/needless_range_loop.rs
+++ b/clippy_lints/src/loops/needless_range_loop.rs
@@ -3,9 +3,7 @@ use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::has_iter_method;
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{
-    contains_name, higher, is_integer_const, match_trait_method, paths, sugg, SpanlessEq,
-};
+use clippy_utils::{contains_name, higher, is_integer_const, match_trait_method, paths, sugg, SpanlessEq};
 use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -29,7 +27,12 @@ pub(super) fn check<'tcx>(
     body: &'tcx Expr<'_>,
     expr: &'tcx Expr<'_>,
 ) {
-    if let Some(higher::Range { start: Some(start), ref end, limits }) = higher::Range::hir(arg) {
+    if let Some(higher::Range {
+        start: Some(start),
+        ref end,
+        limits,
+    }) = higher::Range::hir(arg)
+    {
         // the var must be a single name
         if let PatKind::Binding(_, canonical_id, ident, _) = pat.kind {
             let mut visitor = VarVisitor {
@@ -104,22 +107,19 @@ pub(super) fn check<'tcx>(
                         }
                     }
 
-                    if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty)
-                    {
+                    if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
                         String::new()
-                    } else if visitor.indexed_mut.contains(&indexed)
-                        && contains_name(indexed, take_expr)
-                    {
+                    } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) {
                         return;
                     } else {
                         match limits {
                             ast::RangeLimits::Closed => {
                                 let take_expr = sugg::Sugg::hir(cx, take_expr, "<count>");
                                 format!(".take({})", take_expr + sugg::ONE)
-                            }
+                            },
                             ast::RangeLimits::HalfOpen => {
                                 format!(".take({})", snippet(cx, take_expr.span, ".."))
-                            }
+                            },
                         }
                     }
                 } else {
@@ -145,10 +145,7 @@ pub(super) fn check<'tcx>(
                         cx,
                         NEEDLESS_RANGE_LOOP,
                         arg.span,
-                        &format!(
-                            "the loop variable `{}` is used to index `{}`",
-                            ident.name, indexed
-                        ),
+                        &format!("the loop variable `{}` is used to index `{}`", ident.name, indexed),
                         |diag| {
                             multispan_sugg(
                                 diag,
@@ -157,10 +154,7 @@ pub(super) fn check<'tcx>(
                                     (pat.span, format!("({}, <item>)", ident.name)),
                                     (
                                         arg.span,
-                                        format!(
-                                            "{}.{}().enumerate(){}{}",
-                                            indexed, method, method_1, method_2
-                                        ),
+                                        format!("{}.{}().enumerate(){}{}", indexed, method, method_1, method_2),
                                     ),
                                 ],
                             );
@@ -177,10 +171,7 @@ pub(super) fn check<'tcx>(
                         cx,
                         NEEDLESS_RANGE_LOOP,
                         arg.span,
-                        &format!(
-                            "the loop variable `{}` is only used to index `{}`",
-                            ident.name, indexed
-                        ),
+                        &format!("the loop variable `{}` is only used to index `{}`", ident.name, indexed),
                         |diag| {
                             multispan_sugg(
                                 diag,
@@ -257,12 +248,7 @@ struct VarVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
-    fn check(
-        &mut self,
-        idx: &'tcx Expr<'_>,
-        seqexpr: &'tcx Expr<'_>,
-        expr: &'tcx Expr<'_>,
-    ) -> bool {
+    fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) -> bool {
         if_chain! {
             // the indexed container is referenced by a name
             if let ExprKind::Path(ref seqpath) = seqexpr.kind;
@@ -351,13 +337,13 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
                 self.visit_expr(lhs);
                 self.prefer_mutable = false;
                 self.visit_expr(rhs);
-            }
+            },
             ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => {
                 if mutbl == Mutability::Mut {
                     self.prefer_mutable = true;
                 }
                 self.visit_expr(expr);
-            }
+            },
             ExprKind::Call(f, args) => {
                 self.visit_expr(f);
                 for expr in args {
@@ -370,11 +356,10 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
                     }
                     self.visit_expr(expr);
                 }
-            }
+            },
             ExprKind::MethodCall(_, args, _) => {
                 let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
-                for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args)
-                {
+                for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) {
                     self.prefer_mutable = false;
                     if let ty::Ref(_, _, mutbl) = *ty.kind() {
                         if mutbl == Mutability::Mut {
@@ -383,11 +368,11 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
                     }
                     self.visit_expr(expr);
                 }
-            }
+            },
             ExprKind::Closure(_, _, body_id, ..) => {
                 let body = self.cx.tcx.hir().body(body_id);
                 self.visit_expr(&body.value);
-            }
+            },
             _ => walk_expr(self, expr),
         }
         self.prefer_mutable = old;
diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs
index 70a118d6b35..c025f5972d5 100644
--- a/clippy_lints/src/loops/never_loop.rs
+++ b/clippy_lints/src/loops/never_loop.rs
@@ -146,7 +146,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
             if arms.is_empty() {
                 e
             } else {
-                let arms = never_loop_expr_branch(&mut arms.iter().map(|a| &*a.body), main_loop_id);
+                let arms = never_loop_expr_branch(&mut arms.iter().map(|a| a.body), main_loop_id);
                 combine_seq(e, arms)
             }
         },
diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs
index 753469c603d..da806918be0 100644
--- a/clippy_lints/src/macro_use.rs
+++ b/clippy_lints/src/macro_use.rs
@@ -35,7 +35,8 @@ struct PathAndSpan {
     span: Span,
 }
 
-/// `MacroRefData` includes the name of the macro.
+/// `MacroRefData` includes the name of the macro
+/// and the path from `SourceMap::span_to_filename`.
 #[derive(Debug, Clone)]
 pub struct MacroRefData {
     name: String,
diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs
deleted file mode 100644
index 230ae029ed9..00000000000
--- a/clippy_lints/src/manual_map.rs
+++ /dev/null
@@ -1,316 +0,0 @@
-use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF};
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher::IfLetOrMatch;
-use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
-use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
-use clippy_utils::{
-    can_move_expr_to_closure, in_constant, is_else_clause, is_lang_ctor, is_lint_allowed, path_to_local_id,
-    peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
-};
-use rustc_ast::util::parser::PREC_POSTFIX;
-use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionNone, OptionSome};
-use rustc_hir::{
-    def::Res, Arm, BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path,
-    QPath, UnsafeSource,
-};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{sym, SyntaxContext};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for usages of `match` which could be implemented using `map`
-    ///
-    /// ### Why is this bad?
-    /// Using the `map` method is clearer and more concise.
-    ///
-    /// ### Example
-    /// ```rust
-    /// match Some(0) {
-    ///     Some(x) => Some(x + 1),
-    ///     None => None,
-    /// };
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// Some(0).map(|x| x + 1);
-    /// ```
-    #[clippy::version = "1.52.0"]
-    pub MANUAL_MAP,
-    style,
-    "reimplementation of `map`"
-}
-
-declare_lint_pass!(ManualMap => [MANUAL_MAP]);
-
-impl<'tcx> LateLintPass<'tcx> for ManualMap {
-    #[expect(clippy::too_many_lines)]
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let (scrutinee, then_pat, then_body, else_pat, else_body) = match IfLetOrMatch::parse(cx, expr) {
-            Some(IfLetOrMatch::IfLet(scrutinee, pat, body, Some(r#else))) => (scrutinee, pat, body, None, r#else),
-            Some(IfLetOrMatch::Match(
-                scrutinee,
-                [arm1 @ Arm { guard: None, .. }, arm2 @ Arm { guard: None, .. }],
-                _,
-            )) => (scrutinee, arm1.pat, arm1.body, Some(arm2.pat), arm2.body),
-            _ => return,
-        };
-        if in_external_macro(cx.sess(), expr.span) || in_constant(cx, expr.hir_id) {
-            return;
-        }
-
-        let (scrutinee_ty, ty_ref_count, ty_mutability) =
-            peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee));
-        if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::Option)
-            && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Option))
-        {
-            return;
-        }
-
-        let expr_ctxt = expr.span.ctxt();
-        let (some_expr, some_pat, pat_ref_count, is_wild_none) = match (
-            try_parse_pattern(cx, then_pat, expr_ctxt),
-            else_pat.map_or(Some(OptionPat::Wild), |p| try_parse_pattern(cx, p, expr_ctxt)),
-        ) {
-            (Some(OptionPat::Wild), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => {
-                (else_body, pattern, ref_count, true)
-            },
-            (Some(OptionPat::None), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => {
-                (else_body, pattern, ref_count, false)
-            },
-            (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::Wild)) if is_none_expr(cx, else_body) => {
-                (then_body, pattern, ref_count, true)
-            },
-            (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::None)) if is_none_expr(cx, else_body) => {
-                (then_body, pattern, ref_count, false)
-            },
-            _ => return,
-        };
-
-        // Top level or patterns aren't allowed in closures.
-        if matches!(some_pat.kind, PatKind::Or(_)) {
-            return;
-        }
-
-        let some_expr = match get_some_expr(cx, some_expr, false, expr_ctxt) {
-            Some(expr) => expr,
-            None => return,
-        };
-
-        // These two lints will go back and forth with each other.
-        if cx.typeck_results().expr_ty(some_expr.expr) == cx.tcx.types.unit
-            && !is_lint_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id)
-        {
-            return;
-        }
-
-        // `map` won't perform any adjustments.
-        if !cx.typeck_results().expr_adjustments(some_expr.expr).is_empty() {
-            return;
-        }
-
-        // Determine which binding mode to use.
-        let explicit_ref = some_pat.contains_explicit_ref_binding();
-        let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then(|| ty_mutability));
-
-        let as_ref_str = match binding_ref {
-            Some(Mutability::Mut) => ".as_mut()",
-            Some(Mutability::Not) => ".as_ref()",
-            None => "",
-        };
-
-        match can_move_expr_to_closure(cx, some_expr.expr) {
-            Some(captures) => {
-                // Check if captures the closure will need conflict with borrows made in the scrutinee.
-                // TODO: check all the references made in the scrutinee expression. This will require interacting
-                // with the borrow checker. Currently only `<local>[.<field>]*` is checked for.
-                if let Some(binding_ref_mutability) = binding_ref {
-                    let e = peel_hir_expr_while(scrutinee, |e| match e.kind {
-                        ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e),
-                        _ => None,
-                    });
-                    if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind {
-                        match captures.get(l) {
-                            Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return,
-                            Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => {
-                                return;
-                            },
-                            Some(CaptureKind::Ref(Mutability::Not)) | None => (),
-                        }
-                    }
-                }
-            },
-            None => return,
-        };
-
-        let mut app = Applicability::MachineApplicable;
-
-        // Remove address-of expressions from the scrutinee. Either `as_ref` will be called, or
-        // it's being passed by value.
-        let scrutinee = peel_hir_expr_refs(scrutinee).0;
-        let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
-        let scrutinee_str =
-            if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX {
-                format!("({})", scrutinee_str)
-            } else {
-                scrutinee_str.into()
-            };
-
-        let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
-            if_chain! {
-                if !some_expr.needs_unsafe_block;
-                if let Some(func) = can_pass_as_func(cx, id, some_expr.expr);
-                if func.span.ctxt() == some_expr.expr.span.ctxt();
-                then {
-                    snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
-                } else {
-                    if path_to_local_id(some_expr.expr, id)
-                        && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
-                        && binding_ref.is_some()
-                    {
-                        return;
-                    }
-
-                    // `ref` and `ref mut` annotations were handled earlier.
-                    let annotation = if matches!(annotation, BindingAnnotation::Mutable) {
-                        "mut "
-                    } else {
-                        ""
-                    };
-                    let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0;
-                    if some_expr.needs_unsafe_block {
-                        format!("|{}{}| unsafe {{ {} }}", annotation, some_binding, expr_snip)
-                    } else {
-                        format!("|{}{}| {}", annotation, some_binding, expr_snip)
-                    }
-                }
-            }
-        } else if !is_wild_none && explicit_ref.is_none() {
-            // TODO: handle explicit reference annotations.
-            let pat_snip = snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0;
-            let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0;
-            if some_expr.needs_unsafe_block {
-                format!("|{}| unsafe {{ {} }}", pat_snip, expr_snip)
-            } else {
-                format!("|{}| {}", pat_snip, expr_snip)
-            }
-        } else {
-            // Refutable bindings and mixed reference annotations can't be handled by `map`.
-            return;
-        };
-
-        span_lint_and_sugg(
-            cx,
-            MANUAL_MAP,
-            expr.span,
-            "manual implementation of `Option::map`",
-            "try this",
-            if else_pat.is_none() && is_else_clause(cx.tcx, expr) {
-                format!("{{ {}{}.map({}) }}", scrutinee_str, as_ref_str, body_str)
-            } else {
-                format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str)
-            },
-            app,
-        );
-    }
-}
-
-// Checks whether the expression could be passed as a function, or whether a closure is needed.
-// Returns the function to be passed to `map` if it exists.
-fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
-    match expr.kind {
-        ExprKind::Call(func, [arg])
-            if path_to_local_id(arg, binding)
-                && cx.typeck_results().expr_adjustments(arg).is_empty()
-                && !type_is_unsafe_function(cx, cx.typeck_results().expr_ty(func).peel_refs()) =>
-        {
-            Some(func)
-        },
-        _ => None,
-    }
-}
-
-enum OptionPat<'a> {
-    Wild,
-    None,
-    Some {
-        // The pattern contained in the `Some` tuple.
-        pattern: &'a Pat<'a>,
-        // The number of references before the `Some` tuple.
-        // e.g. `&&Some(_)` has a ref count of 2.
-        ref_count: usize,
-    },
-}
-
-struct SomeExpr<'tcx> {
-    expr: &'tcx Expr<'tcx>,
-    needs_unsafe_block: bool,
-}
-
-// Try to parse into a recognized `Option` pattern.
-// i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
-fn try_parse_pattern<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
-    fn f<'tcx>(
-        cx: &LateContext<'tcx>,
-        pat: &'tcx Pat<'_>,
-        ref_count: usize,
-        ctxt: SyntaxContext,
-    ) -> Option<OptionPat<'tcx>> {
-        match pat.kind {
-            PatKind::Wild => Some(OptionPat::Wild),
-            PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
-            PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone) => Some(OptionPat::None),
-            PatKind::TupleStruct(ref qpath, [pattern], _)
-                if is_lang_ctor(cx, qpath, OptionSome) && pat.span.ctxt() == ctxt =>
-            {
-                Some(OptionPat::Some { pattern, ref_count })
-            },
-            _ => None,
-        }
-    }
-    f(cx, pat, 0, ctxt)
-}
-
-// Checks for an expression wrapped by the `Some` constructor. Returns the contained expression.
-fn get_some_expr<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'_>,
-    needs_unsafe_block: bool,
-    ctxt: SyntaxContext,
-) -> Option<SomeExpr<'tcx>> {
-    // TODO: Allow more complex expressions.
-    match expr.kind {
-        ExprKind::Call(
-            Expr {
-                kind: ExprKind::Path(ref qpath),
-                ..
-            },
-            [arg],
-        ) if ctxt == expr.span.ctxt() && is_lang_ctor(cx, qpath, OptionSome) => Some(SomeExpr {
-            expr: arg,
-            needs_unsafe_block,
-        }),
-        ExprKind::Block(
-            Block {
-                stmts: [],
-                expr: Some(expr),
-                rules,
-                ..
-            },
-            _,
-        ) => get_some_expr(
-            cx,
-            expr,
-            needs_unsafe_block || *rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
-            ctxt,
-        ),
-        _ => None,
-    }
-}
-
-// Checks for the `None` value.
-fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    matches!(peel_blocks(expr).kind, ExprKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
-}
diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs
index 80845ace3f9..14f5faafd7c 100644
--- a/clippy_lints/src/manual_non_exhaustive.rs
+++ b/clippy_lints/src/manual_non_exhaustive.rs
@@ -113,7 +113,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
             let mut iter = fields.iter().filter_map(|f| match f.vis.kind {
                 VisibilityKind::Public => None,
                 VisibilityKind::Inherited => Some(Ok(f)),
-                _ => Some(Err(())),
+                VisibilityKind::Restricted { .. } => Some(Err(())),
             });
             if let Some(Ok(field)) = iter.next()
                 && iter.next().is_none()
diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs
deleted file mode 100644
index b3a91d9f18f..00000000000
--- a/clippy_lints/src/manual_unwrap_or.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-use clippy_utils::consts::constant_simple;
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::usage::contains_return_break_continue_macro;
-use clippy_utils::{in_constant, is_lang_ctor, path_to_local_id, sugg};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
-use rustc_hir::{Arm, Expr, ExprKind, PatKind};
-use rustc_lint::LintContext;
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Finds patterns that reimplement `Option::unwrap_or` or `Result::unwrap_or`.
-    ///
-    /// ### Why is this bad?
-    /// Concise code helps focusing on behavior instead of boilerplate.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let foo: Option<i32> = None;
-    /// match foo {
-    ///     Some(v) => v,
-    ///     None => 1,
-    /// };
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust
-    /// let foo: Option<i32> = None;
-    /// foo.unwrap_or(1);
-    /// ```
-    #[clippy::version = "1.49.0"]
-    pub MANUAL_UNWRAP_OR,
-    complexity,
-    "finds patterns that can be encoded more concisely with `Option::unwrap_or` or `Result::unwrap_or`"
-}
-
-declare_lint_pass!(ManualUnwrapOr => [MANUAL_UNWRAP_OR]);
-
-impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOr {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if in_external_macro(cx.sess(), expr.span) || in_constant(cx, expr.hir_id) {
-            return;
-        }
-        lint_manual_unwrap_or(cx, expr);
-    }
-}
-
-fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-    fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> {
-        if_chain! {
-            if arms.len() == 2;
-            if arms.iter().all(|arm| arm.guard.is_none());
-            if let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| {
-                match arm.pat.kind {
-                    PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
-                    PatKind::TupleStruct(ref qpath, [pat], _) =>
-                        matches!(pat.kind, PatKind::Wild) && is_lang_ctor(cx, qpath, ResultErr),
-                    _ => false,
-                }
-            });
-            let unwrap_arm = &arms[1 - idx];
-            if let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind;
-            if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk);
-            if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind;
-            if path_to_local_id(unwrap_arm.body, binding_hir_id);
-            if cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty();
-            if !contains_return_break_continue_macro(or_arm.body);
-            then {
-                Some(or_arm)
-            } else {
-                None
-            }
-        }
-    }
-
-    if_chain! {
-        if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind;
-        let ty = cx.typeck_results().expr_ty(scrutinee);
-        if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::Option) {
-            Some("Option")
-        } else if is_type_diagnostic_item(cx, ty, sym::Result) {
-            Some("Result")
-        } else {
-            None
-        };
-        if let Some(or_arm) = applicable_or_arm(cx, match_arms);
-        if let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span);
-        if let Some(indent) = indent_of(cx, expr.span);
-        if constant_simple(cx, cx.typeck_results(), or_arm.body).is_some();
-        then {
-            let reindented_or_body =
-                reindent_multiline(or_body_snippet.into(), true, Some(indent));
-
-            let suggestion = if scrutinee.span.from_expansion() {
-                    // we don't want parentheses around macro, e.g. `(some_macro!()).unwrap_or(0)`
-                    sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..")
-                }
-                else {
-                    sugg::Sugg::hir(cx, scrutinee, "..").maybe_par()
-                };
-
-            span_lint_and_sugg(
-                cx,
-                MANUAL_UNWRAP_OR, expr.span,
-                &format!("this pattern reimplements `{}::unwrap_or`", ty_name),
-                "replace with",
-                format!(
-                    "{}.unwrap_or({})",
-                    suggestion,
-                    reindented_or_body,
-                ),
-                Applicability::MachineApplicable,
-            );
-        }
-    }
-}
diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs
deleted file mode 100644
index 583b577ffe2..00000000000
--- a/clippy_lints/src/match_on_vec_items.rs
+++ /dev/null
@@ -1,104 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet;
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, LangItem, MatchSource};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for `match vec[idx]` or `match vec[n..m]`.
-    ///
-    /// ### Why is this bad?
-    /// This can panic at runtime.
-    ///
-    /// ### Example
-    /// ```rust, no_run
-    /// let arr = vec![0, 1, 2, 3];
-    /// let idx = 1;
-    ///
-    /// // Bad
-    /// match arr[idx] {
-    ///     0 => println!("{}", 0),
-    ///     1 => println!("{}", 3),
-    ///     _ => {},
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust, no_run
-    /// let arr = vec![0, 1, 2, 3];
-    /// let idx = 1;
-    ///
-    /// // Good
-    /// match arr.get(idx) {
-    ///     Some(0) => println!("{}", 0),
-    ///     Some(1) => println!("{}", 3),
-    ///     _ => {},
-    /// }
-    /// ```
-    #[clippy::version = "1.45.0"]
-    pub MATCH_ON_VEC_ITEMS,
-    pedantic,
-    "matching on vector elements can panic"
-}
-
-declare_lint_pass!(MatchOnVecItems => [MATCH_ON_VEC_ITEMS]);
-
-impl<'tcx> LateLintPass<'tcx> for MatchOnVecItems {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if_chain! {
-            if !in_external_macro(cx.sess(), expr.span);
-            if let ExprKind::Match(match_expr, _, MatchSource::Normal) = expr.kind;
-            if let Some(idx_expr) = is_vec_indexing(cx, match_expr);
-            if let ExprKind::Index(vec, idx) = idx_expr.kind;
-
-            then {
-                // FIXME: could be improved to suggest surrounding every pattern with Some(_),
-                // but only when `or_patterns` are stabilized.
-                span_lint_and_sugg(
-                    cx,
-                    MATCH_ON_VEC_ITEMS,
-                    match_expr.span,
-                    "indexing into a vector may panic",
-                    "try this",
-                    format!(
-                        "{}.get({})",
-                        snippet(cx, vec.span, ".."),
-                        snippet(cx, idx.span, "..")
-                    ),
-                    Applicability::MaybeIncorrect
-                );
-            }
-        }
-    }
-}
-
-fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
-    if_chain! {
-        if let ExprKind::Index(array, index) = expr.kind;
-        if is_vector(cx, array);
-        if !is_full_range(cx, index);
-
-        then {
-            return Some(expr);
-        }
-    }
-
-    None
-}
-
-fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let ty = cx.typeck_results().expr_ty(expr);
-    let ty = ty.peel_refs();
-    is_type_diagnostic_item(cx, ty, sym::Vec)
-}
-
-fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let ty = cx.typeck_results().expr_ty(expr);
-    let ty = ty.peel_refs();
-    is_type_lang_item(cx, ty, LangItem::RangeFull)
-}
diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/matches/collapsible_match.rs
index ec55009f347..07021f1bcad 100644
--- a/clippy_lints/src/collapsible_match.rs
+++ b/clippy_lints/src/matches/collapsible_match.rs
@@ -6,68 +6,28 @@ use if_chain::if_chain;
 use rustc_errors::MultiSpan;
 use rustc_hir::LangItem::OptionNone;
 use rustc_hir::{Arm, Expr, Guard, HirId, Let, Pat, PatKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_lint::LateContext;
 use rustc_span::Span;
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Finds nested `match` or `if let` expressions where the patterns may be "collapsed" together
-    /// without adding any branches.
-    ///
-    /// Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only
-    /// cases where merging would most likely make the code more readable.
-    ///
-    /// ### Why is this bad?
-    /// It is unnecessarily verbose and complex.
-    ///
-    /// ### Example
-    /// ```rust
-    /// fn func(opt: Option<Result<u64, String>>) {
-    ///     let n = match opt {
-    ///         Some(n) => match n {
-    ///             Ok(n) => n,
-    ///             _ => return,
-    ///         }
-    ///         None => return,
-    ///     };
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// fn func(opt: Option<Result<u64, String>>) {
-    ///     let n = match opt {
-    ///         Some(Ok(n)) => n,
-    ///         _ => return,
-    ///     };
-    /// }
-    /// ```
-    #[clippy::version = "1.50.0"]
-    pub COLLAPSIBLE_MATCH,
-    style,
-    "Nested `match` or `if let` expressions where the patterns may be \"collapsed\" together."
-}
-
-declare_lint_pass!(CollapsibleMatch => [COLLAPSIBLE_MATCH]);
+use super::COLLAPSIBLE_MATCH;
 
-impl<'tcx> LateLintPass<'tcx> for CollapsibleMatch {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
-        match IfLetOrMatch::parse(cx, expr) {
-            Some(IfLetOrMatch::Match(_, arms, _)) => {
-                if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) {
-                    for arm in arms {
-                        check_arm(cx, true, arm.pat, arm.body, arm.guard.as_ref(), Some(els_arm.body));
-                    }
-                }
-            },
-            Some(IfLetOrMatch::IfLet(_, pat, body, els)) => {
-                check_arm(cx, false, pat, body, None, els);
-            },
-            None => {},
+pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
+    if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) {
+        for arm in arms {
+            check_arm(cx, true, arm.pat, arm.body, arm.guard.as_ref(), Some(els_arm.body));
         }
     }
 }
 
+pub(super) fn check_if_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    pat: &'tcx Pat<'_>,
+    body: &'tcx Expr<'_>,
+    else_expr: Option<&'tcx Expr<'_>>,
+) {
+    check_arm(cx, false, pat, body, None, else_expr);
+}
+
 fn check_arm<'tcx>(
     cx: &LateContext<'tcx>,
     outer_is_match: bool,
diff --git a/clippy_lints/src/matches/manual_map.rs b/clippy_lints/src/matches/manual_map.rs
new file mode 100644
index 00000000000..542905a2d76
--- /dev/null
+++ b/clippy_lints/src/matches/manual_map.rs
@@ -0,0 +1,306 @@
+use crate::{map_unit_fn::OPTION_MAP_UNIT_FN, matches::MATCH_AS_REF};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function};
+use clippy_utils::{
+    can_move_expr_to_closure, is_else_clause, is_lang_ctor, is_lint_allowed, path_to_local_id, peel_blocks,
+    peel_hir_expr_refs, peel_hir_expr_while, CaptureKind,
+};
+use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::{OptionNone, OptionSome};
+use rustc_hir::{
+    def::Res, Arm, BindingAnnotation, Block, BlockCheckMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path,
+    QPath, UnsafeSource,
+};
+use rustc_lint::LateContext;
+use rustc_span::{sym, SyntaxContext};
+
+use super::MANUAL_MAP;
+
+pub(super) fn check_match<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    scrutinee: &'tcx Expr<'_>,
+    arms: &'tcx [Arm<'_>],
+) {
+    if let [arm1, arm2] = arms
+        && arm1.guard.is_none()
+        && arm2.guard.is_none()
+    {
+        check(cx, expr, scrutinee, arm1.pat, arm1.body, Some(arm2.pat), arm2.body);
+    }
+}
+
+pub(super) fn check_if_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    let_pat: &'tcx Pat<'_>,
+    let_expr: &'tcx Expr<'_>,
+    then_expr: &'tcx Expr<'_>,
+    else_expr: &'tcx Expr<'_>,
+) {
+    check(cx, expr, let_expr, let_pat, then_expr, None, else_expr);
+}
+
+#[expect(clippy::too_many_lines)]
+fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    scrutinee: &'tcx Expr<'_>,
+    then_pat: &'tcx Pat<'_>,
+    then_body: &'tcx Expr<'_>,
+    else_pat: Option<&'tcx Pat<'_>>,
+    else_body: &'tcx Expr<'_>,
+) {
+    let (scrutinee_ty, ty_ref_count, ty_mutability) =
+        peel_mid_ty_refs_is_mutable(cx.typeck_results().expr_ty(scrutinee));
+    if !(is_type_diagnostic_item(cx, scrutinee_ty, sym::Option)
+        && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Option))
+    {
+        return;
+    }
+
+    let expr_ctxt = expr.span.ctxt();
+    let (some_expr, some_pat, pat_ref_count, is_wild_none) = match (
+        try_parse_pattern(cx, then_pat, expr_ctxt),
+        else_pat.map_or(Some(OptionPat::Wild), |p| try_parse_pattern(cx, p, expr_ctxt)),
+    ) {
+        (Some(OptionPat::Wild), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => {
+            (else_body, pattern, ref_count, true)
+        },
+        (Some(OptionPat::None), Some(OptionPat::Some { pattern, ref_count })) if is_none_expr(cx, then_body) => {
+            (else_body, pattern, ref_count, false)
+        },
+        (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::Wild)) if is_none_expr(cx, else_body) => {
+            (then_body, pattern, ref_count, true)
+        },
+        (Some(OptionPat::Some { pattern, ref_count }), Some(OptionPat::None)) if is_none_expr(cx, else_body) => {
+            (then_body, pattern, ref_count, false)
+        },
+        _ => return,
+    };
+
+    // Top level or patterns aren't allowed in closures.
+    if matches!(some_pat.kind, PatKind::Or(_)) {
+        return;
+    }
+
+    let some_expr = match get_some_expr(cx, some_expr, false, expr_ctxt) {
+        Some(expr) => expr,
+        None => return,
+    };
+
+    // These two lints will go back and forth with each other.
+    if cx.typeck_results().expr_ty(some_expr.expr) == cx.tcx.types.unit
+        && !is_lint_allowed(cx, OPTION_MAP_UNIT_FN, expr.hir_id)
+    {
+        return;
+    }
+
+    // `map` won't perform any adjustments.
+    if !cx.typeck_results().expr_adjustments(some_expr.expr).is_empty() {
+        return;
+    }
+
+    // Determine which binding mode to use.
+    let explicit_ref = some_pat.contains_explicit_ref_binding();
+    let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then(|| ty_mutability));
+
+    let as_ref_str = match binding_ref {
+        Some(Mutability::Mut) => ".as_mut()",
+        Some(Mutability::Not) => ".as_ref()",
+        None => "",
+    };
+
+    match can_move_expr_to_closure(cx, some_expr.expr) {
+        Some(captures) => {
+            // Check if captures the closure will need conflict with borrows made in the scrutinee.
+            // TODO: check all the references made in the scrutinee expression. This will require interacting
+            // with the borrow checker. Currently only `<local>[.<field>]*` is checked for.
+            if let Some(binding_ref_mutability) = binding_ref {
+                let e = peel_hir_expr_while(scrutinee, |e| match e.kind {
+                    ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e),
+                    _ => None,
+                });
+                if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind {
+                    match captures.get(l) {
+                        Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return,
+                        Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => {
+                            return;
+                        },
+                        Some(CaptureKind::Ref(Mutability::Not)) | None => (),
+                    }
+                }
+            }
+        },
+        None => return,
+    };
+
+    let mut app = Applicability::MachineApplicable;
+
+    // Remove address-of expressions from the scrutinee. Either `as_ref` will be called, or
+    // it's being passed by value.
+    let scrutinee = peel_hir_expr_refs(scrutinee).0;
+    let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
+    let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX {
+        format!("({})", scrutinee_str)
+    } else {
+        scrutinee_str.into()
+    };
+
+    let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
+        if_chain! {
+            if !some_expr.needs_unsafe_block;
+            if let Some(func) = can_pass_as_func(cx, id, some_expr.expr);
+            if func.span.ctxt() == some_expr.expr.span.ctxt();
+            then {
+                snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
+            } else {
+                if path_to_local_id(some_expr.expr, id)
+                    && !is_lint_allowed(cx, MATCH_AS_REF, expr.hir_id)
+                    && binding_ref.is_some()
+                {
+                    return;
+                }
+
+                // `ref` and `ref mut` annotations were handled earlier.
+                let annotation = if matches!(annotation, BindingAnnotation::Mutable) {
+                    "mut "
+                } else {
+                    ""
+                };
+                let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0;
+                if some_expr.needs_unsafe_block {
+                    format!("|{}{}| unsafe {{ {} }}", annotation, some_binding, expr_snip)
+                } else {
+                    format!("|{}{}| {}", annotation, some_binding, expr_snip)
+                }
+            }
+        }
+    } else if !is_wild_none && explicit_ref.is_none() {
+        // TODO: handle explicit reference annotations.
+        let pat_snip = snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0;
+        let expr_snip = snippet_with_context(cx, some_expr.expr.span, expr_ctxt, "..", &mut app).0;
+        if some_expr.needs_unsafe_block {
+            format!("|{}| unsafe {{ {} }}", pat_snip, expr_snip)
+        } else {
+            format!("|{}| {}", pat_snip, expr_snip)
+        }
+    } else {
+        // Refutable bindings and mixed reference annotations can't be handled by `map`.
+        return;
+    };
+
+    span_lint_and_sugg(
+        cx,
+        MANUAL_MAP,
+        expr.span,
+        "manual implementation of `Option::map`",
+        "try this",
+        if else_pat.is_none() && is_else_clause(cx.tcx, expr) {
+            format!("{{ {}{}.map({}) }}", scrutinee_str, as_ref_str, body_str)
+        } else {
+            format!("{}{}.map({})", scrutinee_str, as_ref_str, body_str)
+        },
+        app,
+    );
+}
+
+// Checks whether the expression could be passed as a function, or whether a closure is needed.
+// Returns the function to be passed to `map` if it exists.
+fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+    match expr.kind {
+        ExprKind::Call(func, [arg])
+            if path_to_local_id(arg, binding)
+                && cx.typeck_results().expr_adjustments(arg).is_empty()
+                && !type_is_unsafe_function(cx, cx.typeck_results().expr_ty(func).peel_refs()) =>
+        {
+            Some(func)
+        },
+        _ => None,
+    }
+}
+
+enum OptionPat<'a> {
+    Wild,
+    None,
+    Some {
+        // The pattern contained in the `Some` tuple.
+        pattern: &'a Pat<'a>,
+        // The number of references before the `Some` tuple.
+        // e.g. `&&Some(_)` has a ref count of 2.
+        ref_count: usize,
+    },
+}
+
+struct SomeExpr<'tcx> {
+    expr: &'tcx Expr<'tcx>,
+    needs_unsafe_block: bool,
+}
+
+// Try to parse into a recognized `Option` pattern.
+// i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
+fn try_parse_pattern<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
+    fn f<'tcx>(
+        cx: &LateContext<'tcx>,
+        pat: &'tcx Pat<'_>,
+        ref_count: usize,
+        ctxt: SyntaxContext,
+    ) -> Option<OptionPat<'tcx>> {
+        match pat.kind {
+            PatKind::Wild => Some(OptionPat::Wild),
+            PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
+            PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone) => Some(OptionPat::None),
+            PatKind::TupleStruct(ref qpath, [pattern], _)
+                if is_lang_ctor(cx, qpath, OptionSome) && pat.span.ctxt() == ctxt =>
+            {
+                Some(OptionPat::Some { pattern, ref_count })
+            },
+            _ => None,
+        }
+    }
+    f(cx, pat, 0, ctxt)
+}
+
+// Checks for an expression wrapped by the `Some` constructor. Returns the contained expression.
+fn get_some_expr<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    needs_unsafe_block: bool,
+    ctxt: SyntaxContext,
+) -> Option<SomeExpr<'tcx>> {
+    // TODO: Allow more complex expressions.
+    match expr.kind {
+        ExprKind::Call(
+            Expr {
+                kind: ExprKind::Path(ref qpath),
+                ..
+            },
+            [arg],
+        ) if ctxt == expr.span.ctxt() && is_lang_ctor(cx, qpath, OptionSome) => Some(SomeExpr {
+            expr: arg,
+            needs_unsafe_block,
+        }),
+        ExprKind::Block(
+            Block {
+                stmts: [],
+                expr: Some(expr),
+                rules,
+                ..
+            },
+            _,
+        ) => get_some_expr(
+            cx,
+            expr,
+            needs_unsafe_block || *rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+            ctxt,
+        ),
+        _ => None,
+    }
+}
+
+// Checks for the `None` value.
+fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    matches!(peel_blocks(expr).kind, ExprKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
+}
diff --git a/clippy_lints/src/matches/manual_unwrap_or.rs b/clippy_lints/src/matches/manual_unwrap_or.rs
new file mode 100644
index 00000000000..e1111c80f2f
--- /dev/null
+++ b/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -0,0 +1,83 @@
+use clippy_utils::consts::constant_simple;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::usage::contains_return_break_continue_macro;
+use clippy_utils::{is_lang_ctor, path_to_local_id, sugg};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
+use rustc_hir::{Arm, Expr, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::MANUAL_UNWRAP_OR;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, scrutinee: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
+    let ty = cx.typeck_results().expr_ty(scrutinee);
+    if_chain! {
+        if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::Option) {
+            Some("Option")
+        } else if is_type_diagnostic_item(cx, ty, sym::Result) {
+            Some("Result")
+        } else {
+            None
+        };
+        if let Some(or_arm) = applicable_or_arm(cx, arms);
+        if let Some(or_body_snippet) = snippet_opt(cx, or_arm.body.span);
+        if let Some(indent) = indent_of(cx, expr.span);
+        if constant_simple(cx, cx.typeck_results(), or_arm.body).is_some();
+        then {
+            let reindented_or_body =
+                reindent_multiline(or_body_snippet.into(), true, Some(indent));
+
+            let suggestion = if scrutinee.span.from_expansion() {
+                    // we don't want parentheses around macro, e.g. `(some_macro!()).unwrap_or(0)`
+                    sugg::Sugg::hir_with_macro_callsite(cx, scrutinee, "..")
+                }
+                else {
+                    sugg::Sugg::hir(cx, scrutinee, "..").maybe_par()
+                };
+
+            span_lint_and_sugg(
+                cx,
+                MANUAL_UNWRAP_OR, expr.span,
+                &format!("this pattern reimplements `{}::unwrap_or`", ty_name),
+                "replace with",
+                format!(
+                    "{}.unwrap_or({})",
+                    suggestion,
+                    reindented_or_body,
+                ),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
+
+fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> {
+    if_chain! {
+        if arms.len() == 2;
+        if arms.iter().all(|arm| arm.guard.is_none());
+        if let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| {
+            match arm.pat.kind {
+                PatKind::Path(ref qpath) => is_lang_ctor(cx, qpath, OptionNone),
+                PatKind::TupleStruct(ref qpath, [pat], _) =>
+                    matches!(pat.kind, PatKind::Wild) && is_lang_ctor(cx, qpath, ResultErr),
+                _ => false,
+            }
+        });
+        let unwrap_arm = &arms[1 - idx];
+        if let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = unwrap_arm.pat.kind;
+        if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk);
+        if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind;
+        if path_to_local_id(unwrap_arm.body, binding_hir_id);
+        if cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty();
+        if !contains_return_break_continue_macro(or_arm.body);
+        then {
+            Some(or_arm)
+        } else {
+            None
+        }
+    }
+}
diff --git a/clippy_lints/src/matches/match_bool.rs b/clippy_lints/src/matches/match_bool.rs
index 90c50b994d2..1c216e13570 100644
--- a/clippy_lints/src/matches/match_bool.rs
+++ b/clippy_lints/src/matches/match_bool.rs
@@ -24,8 +24,8 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
                     let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
                         if let ExprKind::Lit(ref lit) = arm_bool.kind {
                             match lit.node {
-                                LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)),
-                                LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)),
+                                LitKind::Bool(true) => Some((arms[0].body, arms[1].body)),
+                                LitKind::Bool(false) => Some((arms[1].body, arms[0].body)),
                                 _ => None,
                             }
                         } else {
diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs
index 2e1f7646eb4..a68eec842ab 100644
--- a/clippy_lints/src/matches/match_like_matches.rs
+++ b/clippy_lints/src/matches/match_like_matches.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_wild;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{higher, is_wild};
 use rustc_ast::{Attribute, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat};
@@ -11,22 +11,24 @@ use rustc_span::source_map::Spanned;
 use super::MATCH_LIKE_MATCHES_MACRO;
 
 /// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
-pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let Some(higher::IfLet {
-        let_pat,
+pub(crate) fn check_if_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    let_pat: &'tcx Pat<'_>,
+    let_expr: &'tcx Expr<'_>,
+    then_expr: &'tcx Expr<'_>,
+    else_expr: &'tcx Expr<'_>,
+) {
+    find_matches_sugg(
+        cx,
         let_expr,
-        if_then,
-        if_else: Some(if_else),
-    }) = higher::IfLet::hir(cx, expr)
-    {
-        find_matches_sugg(
-            cx,
-            let_expr,
-            IntoIterator::into_iter([(&[][..], Some(let_pat), if_then, None), (&[][..], None, if_else, None)]),
-            expr,
-            true,
-        );
-    }
+        IntoIterator::into_iter([
+            (&[][..], Some(let_pat), then_expr, None),
+            (&[][..], None, else_expr, None),
+        ]),
+        expr,
+        true,
+    );
 }
 
 pub(super) fn check_match<'tcx>(
diff --git a/clippy_lints/src/matches/match_on_vec_items.rs b/clippy_lints/src/matches/match_on_vec_items.rs
new file mode 100644
index 00000000000..2917f85c45f
--- /dev/null
+++ b/clippy_lints/src/matches/match_on_vec_items.rs
@@ -0,0 +1,61 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::MATCH_ON_VEC_ITEMS;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) {
+    if_chain! {
+        if let Some(idx_expr) = is_vec_indexing(cx, scrutinee);
+        if let ExprKind::Index(vec, idx) = idx_expr.kind;
+
+        then {
+            // FIXME: could be improved to suggest surrounding every pattern with Some(_),
+            // but only when `or_patterns` are stabilized.
+            span_lint_and_sugg(
+                cx,
+                MATCH_ON_VEC_ITEMS,
+                scrutinee.span,
+                "indexing into a vector may panic",
+                "try this",
+                format!(
+                    "{}.get({})",
+                    snippet(cx, vec.span, ".."),
+                    snippet(cx, idx.span, "..")
+                ),
+                Applicability::MaybeIncorrect
+            );
+        }
+    }
+}
+
+fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+    if_chain! {
+        if let ExprKind::Index(array, index) = expr.kind;
+        if is_vector(cx, array);
+        if !is_full_range(cx, index);
+
+        then {
+            return Some(expr);
+        }
+    }
+
+    None
+}
+
+fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.typeck_results().expr_ty(expr);
+    let ty = ty.peel_refs();
+    is_type_diagnostic_item(cx, ty, sym::Vec)
+}
+
+fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.typeck_results().expr_ty(expr);
+    let ty = ty.peel_refs();
+    is_type_lang_item(cx, ty, LangItem::RangeFull)
+}
diff --git a/clippy_lints/src/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs
index 85aec93670b..8302ce426e5 100644
--- a/clippy_lints/src/match_str_case_mismatch.rs
+++ b/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -3,48 +3,13 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
+use rustc_hir::{Arm, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
 use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::Symbol;
 use rustc_span::{sym, Span};
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for `match` expressions modifying the case of a string with non-compliant arms
-    ///
-    /// ### Why is this bad?
-    /// The arm is unreachable, which is likely a mistake
-    ///
-    /// ### Example
-    /// ```rust
-    /// # let text = "Foo";
-    ///
-    /// match &*text.to_ascii_lowercase() {
-    ///     "foo" => {},
-    ///     "Bar" => {},
-    ///     _ => {},
-    /// }
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// # let text = "Foo";
-    ///
-    /// match &*text.to_ascii_lowercase() {
-    ///     "foo" => {},
-    ///     "bar" => {},
-    ///     _ => {},
-    /// }
-    /// ```
-    #[clippy::version = "1.58.0"]
-    pub MATCH_STR_CASE_MISMATCH,
-    correctness,
-    "creation of a case altering match expression with non-compliant arms"
-}
-
-declare_lint_pass!(MatchStrCaseMismatch => [MATCH_STR_CASE_MISMATCH]);
+use super::MATCH_STR_CASE_MISMATCH;
 
 #[derive(Debug)]
 enum CaseMethod {
@@ -54,25 +19,21 @@ enum CaseMethod {
     AsciiUppercase,
 }
 
-impl<'tcx> LateLintPass<'tcx> for MatchStrCaseMismatch {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if !in_external_macro(cx.tcx.sess, expr.span);
-            if let ExprKind::Match(match_expr, arms, MatchSource::Normal) = expr.kind;
-            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(match_expr).kind();
-            if let ty::Str = ty.kind();
-            then {
-                let mut visitor = MatchExprVisitor {
-                    cx,
-                    case_method: None,
-                };
-
-                visitor.visit_expr(match_expr);
-
-                if let Some(case_method) = visitor.case_method {
-                    if let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms) {
-                        lint(cx, &case_method, bad_case_span, bad_case_sym.as_str());
-                    }
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
+    if_chain! {
+        if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(scrutinee).kind();
+        if let ty::Str = ty.kind();
+        then {
+            let mut visitor = MatchExprVisitor {
+                cx,
+                case_method: None,
+            };
+
+            visitor.visit_expr(scrutinee);
+
+            if let Some(case_method) = visitor.case_method {
+                if let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms) {
+                    lint(cx, &case_method, bad_case_span, bad_case_sym.as_str());
                 }
             }
         }
diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs
index 3d8391bce2b..d1e42f39e47 100644
--- a/clippy_lints/src/matches/mod.rs
+++ b/clippy_lints/src/matches/mod.rs
@@ -1,26 +1,34 @@
 use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context};
-use clippy_utils::{meets_msrv, msrvs};
+use clippy_utils::{higher, in_constant, meets_msrv, msrvs};
 use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
 use rustc_lexer::{tokenize, TokenKind};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{Span, SpanData, SyntaxContext};
 
+mod collapsible_match;
 mod infallible_destructuring_match;
+mod manual_map;
+mod manual_unwrap_or;
 mod match_as_ref;
 mod match_bool;
 mod match_like_matches;
+mod match_on_vec_items;
 mod match_ref_pats;
 mod match_same_arms;
 mod match_single_binding;
+mod match_str_case_mismatch;
 mod match_wild_enum;
 mod match_wild_err_arm;
 mod needless_match;
 mod overlapping_arms;
 mod redundant_pattern_match;
 mod rest_pat_in_fully_bound_struct;
+mod significant_drop_in_scrutinee;
 mod single_match;
+mod try_err;
 mod wild_in_or_pats;
 
 declare_clippy_lint! {
@@ -610,6 +618,274 @@ declare_clippy_lint! {
     "`match` or match-like `if let` that are unnecessary"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Finds nested `match` or `if let` expressions where the patterns may be "collapsed" together
+    /// without adding any branches.
+    ///
+    /// Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only
+    /// cases where merging would most likely make the code more readable.
+    ///
+    /// ### Why is this bad?
+    /// It is unnecessarily verbose and complex.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn func(opt: Option<Result<u64, String>>) {
+    ///     let n = match opt {
+    ///         Some(n) => match n {
+    ///             Ok(n) => n,
+    ///             _ => return,
+    ///         }
+    ///         None => return,
+    ///     };
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn func(opt: Option<Result<u64, String>>) {
+    ///     let n = match opt {
+    ///         Some(Ok(n)) => n,
+    ///         _ => return,
+    ///     };
+    /// }
+    /// ```
+    #[clippy::version = "1.50.0"]
+    pub COLLAPSIBLE_MATCH,
+    style,
+    "Nested `match` or `if let` expressions where the patterns may be \"collapsed\" together."
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Finds patterns that reimplement `Option::unwrap_or` or `Result::unwrap_or`.
+    ///
+    /// ### Why is this bad?
+    /// Concise code helps focusing on behavior instead of boilerplate.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let foo: Option<i32> = None;
+    /// match foo {
+    ///     Some(v) => v,
+    ///     None => 1,
+    /// };
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// let foo: Option<i32> = None;
+    /// foo.unwrap_or(1);
+    /// ```
+    #[clippy::version = "1.49.0"]
+    pub MANUAL_UNWRAP_OR,
+    complexity,
+    "finds patterns that can be encoded more concisely with `Option::unwrap_or` or `Result::unwrap_or`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `match vec[idx]` or `match vec[n..m]`.
+    ///
+    /// ### Why is this bad?
+    /// This can panic at runtime.
+    ///
+    /// ### Example
+    /// ```rust, no_run
+    /// let arr = vec![0, 1, 2, 3];
+    /// let idx = 1;
+    ///
+    /// // Bad
+    /// match arr[idx] {
+    ///     0 => println!("{}", 0),
+    ///     1 => println!("{}", 3),
+    ///     _ => {},
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust, no_run
+    /// let arr = vec![0, 1, 2, 3];
+    /// let idx = 1;
+    ///
+    /// // Good
+    /// match arr.get(idx) {
+    ///     Some(0) => println!("{}", 0),
+    ///     Some(1) => println!("{}", 3),
+    ///     _ => {},
+    /// }
+    /// ```
+    #[clippy::version = "1.45.0"]
+    pub MATCH_ON_VEC_ITEMS,
+    pedantic,
+    "matching on vector elements can panic"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `match` expressions modifying the case of a string with non-compliant arms
+    ///
+    /// ### Why is this bad?
+    /// The arm is unreachable, which is likely a mistake
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let text = "Foo";
+    /// match &*text.to_ascii_lowercase() {
+    ///     "foo" => {},
+    ///     "Bar" => {},
+    ///     _ => {},
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # let text = "Foo";
+    /// match &*text.to_ascii_lowercase() {
+    ///     "foo" => {},
+    ///     "bar" => {},
+    ///     _ => {},
+    /// }
+    /// ```
+    #[clippy::version = "1.58.0"]
+    pub MATCH_STR_CASE_MISMATCH,
+    correctness,
+    "creation of a case altering match expression with non-compliant arms"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Check for temporaries returned from function calls in a match scrutinee that have the
+    /// `clippy::has_significant_drop` attribute.
+    ///
+    /// ### Why is this bad?
+    /// The `clippy::has_significant_drop` attribute can be added to types whose Drop impls have
+    /// an important side-effect, such as unlocking a mutex, making it important for users to be
+    /// able to accurately understand their lifetimes. When a temporary is returned in a function
+    /// call in a match scrutinee, its lifetime lasts until the end of the match block, which may
+    /// be surprising.
+    ///
+    /// For `Mutex`es this can lead to a deadlock. This happens when the match scrutinee uses a
+    /// function call that returns a `MutexGuard` and then tries to lock again in one of the match
+    /// arms. In that case the `MutexGuard` in the scrutinee will not be dropped until the end of
+    /// the match block and thus will not unlock.
+    ///
+    /// ### Example
+    /// ```rust.ignore
+    /// # use std::sync::Mutex;
+    ///
+    /// # struct State {}
+    ///
+    /// # impl State {
+    /// #     fn foo(&self) -> bool {
+    /// #         true
+    /// #     }
+    ///
+    /// #     fn bar(&self) {}
+    /// # }
+    ///
+    ///
+    /// let mutex = Mutex::new(State {});
+    ///
+    /// match mutex.lock().unwrap().foo() {
+    ///     true => {
+    ///         mutex.lock().unwrap().bar(); // Deadlock!
+    ///     }
+    ///     false => {}
+    /// };
+    ///
+    /// println!("All done!");
+    ///
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # use std::sync::Mutex;
+    ///
+    /// # struct State {}
+    ///
+    /// # impl State {
+    /// #     fn foo(&self) -> bool {
+    /// #         true
+    /// #     }
+    ///
+    /// #     fn bar(&self) {}
+    /// # }
+    ///
+    /// let mutex = Mutex::new(State {});
+    ///
+    /// let is_foo = mutex.lock().unwrap().foo();
+    /// match is_foo {
+    ///     true => {
+    ///         mutex.lock().unwrap().bar();
+    ///     }
+    ///     false => {}
+    /// };
+    ///
+    /// println!("All done!");
+    /// ```
+    #[clippy::version = "1.60.0"]
+    pub SIGNIFICANT_DROP_IN_SCRUTINEE,
+    suspicious,
+    "warns when a temporary of a type with a drop with a significant side-effect might have a surprising lifetime"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usages of `Err(x)?`.
+    ///
+    /// ### Why is this bad?
+    /// The `?` operator is designed to allow calls that
+    /// can fail to be easily chained. For example, `foo()?.bar()` or
+    /// `foo(bar()?)`. Because `Err(x)?` can't be used that way (it will
+    /// always return), it is more clear to write `return Err(x)`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn foo(fail: bool) -> Result<i32, String> {
+    ///     if fail {
+    ///       Err("failed")?;
+    ///     }
+    ///     Ok(0)
+    /// }
+    /// ```
+    /// Could be written:
+    ///
+    /// ```rust
+    /// fn foo(fail: bool) -> Result<i32, String> {
+    ///     if fail {
+    ///       return Err("failed".into());
+    ///     }
+    ///     Ok(0)
+    /// }
+    /// ```
+    #[clippy::version = "1.38.0"]
+    pub TRY_ERR,
+    restriction,
+    "return errors explicitly rather than hiding them behind a `?`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usages of `match` which could be implemented using `map`
+    ///
+    /// ### Why is this bad?
+    /// Using the `map` method is clearer and more concise.
+    ///
+    /// ### Example
+    /// ```rust
+    /// match Some(0) {
+    ///     Some(x) => Some(x + 1),
+    ///     None => None,
+    /// };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// Some(0).map(|x| x + 1);
+    /// ```
+    #[clippy::version = "1.52.0"]
+    pub MANUAL_MAP,
+    style,
+    "reimplementation of `map`"
+}
+
 #[derive(Default)]
 pub struct Matches {
     msrv: Option<RustcVersion>,
@@ -644,19 +920,42 @@ impl_lint_pass!(Matches => [
     MATCH_LIKE_MATCHES_MACRO,
     MATCH_SAME_ARMS,
     NEEDLESS_MATCH,
+    COLLAPSIBLE_MATCH,
+    MANUAL_UNWRAP_OR,
+    MATCH_ON_VEC_ITEMS,
+    MATCH_STR_CASE_MISMATCH,
+    SIGNIFICANT_DROP_IN_SCRUTINEE,
+    TRY_ERR,
+    MANUAL_MAP,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Matches {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if expr.span.from_expansion() {
+        if in_external_macro(cx.sess(), expr.span) {
             return;
         }
+        let from_expansion = expr.span.from_expansion();
 
         if let ExprKind::Match(ex, arms, source) = expr.kind {
-            if !span_starts_with(cx, expr.span, "match") {
+            if source == MatchSource::Normal && !span_starts_with(cx, expr.span, "match") {
                 return;
             }
-            if !contains_cfg_arm(cx, expr, ex, arms) {
+            if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) {
+                significant_drop_in_scrutinee::check(cx, expr, ex, source);
+            }
+
+            collapsible_match::check_match(cx, arms);
+            if !from_expansion {
+                // These don't depend on a relationship between multiple arms
+                match_wild_err_arm::check(cx, ex, arms);
+                wild_in_or_pats::check(cx, arms);
+            }
+
+            if source == MatchSource::TryDesugar {
+                try_err::check(cx, expr, ex);
+            }
+
+            if !from_expansion && !contains_cfg_arm(cx, expr, ex, arms) {
                 if source == MatchSource::Normal {
                     if !(meets_msrv(self.msrv, msrvs::MATCHES_MACRO)
                         && match_like_matches::check_match(cx, expr, ex, arms))
@@ -671,6 +970,13 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                     match_wild_enum::check(cx, ex, arms);
                     match_as_ref::check(cx, ex, arms, expr);
                     needless_match::check_match(cx, ex, arms, expr);
+                    match_on_vec_items::check(cx, ex);
+                    match_str_case_mismatch::check(cx, ex, arms);
+
+                    if !in_constant(cx, expr.hir_id) {
+                        manual_unwrap_or::check(cx, expr, ex, arms);
+                        manual_map::check_match(cx, expr, ex, arms);
+                    }
 
                     if self.infallible_destructuring_match_linted {
                         self.infallible_destructuring_match_linted = false;
@@ -680,16 +986,35 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                 }
                 match_ref_pats::check(cx, ex, arms.iter().map(|el| el.pat), expr);
             }
-
-            // These don't depend on a relationship between multiple arms
-            match_wild_err_arm::check(cx, ex, arms);
-            wild_in_or_pats::check(cx, arms);
-        } else {
-            if meets_msrv(self.msrv, msrvs::MATCHES_MACRO) {
-                match_like_matches::check(cx, expr);
+        } else if let Some(if_let) = higher::IfLet::hir(cx, expr) {
+            collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else);
+            if !from_expansion {
+                if let Some(else_expr) = if_let.if_else {
+                    if meets_msrv(self.msrv, msrvs::MATCHES_MACRO) {
+                        match_like_matches::check_if_let(
+                            cx,
+                            expr,
+                            if_let.let_pat,
+                            if_let.let_expr,
+                            if_let.if_then,
+                            else_expr,
+                        );
+                    }
+                    if !in_constant(cx, expr.hir_id) {
+                        manual_map::check_if_let(cx, expr, if_let.let_pat, if_let.let_expr, if_let.if_then, else_expr);
+                    }
+                }
+                redundant_pattern_match::check_if_let(
+                    cx,
+                    expr,
+                    if_let.let_pat,
+                    if_let.let_expr,
+                    if_let.if_else.is_some(),
+                );
+                needless_match::check_if_let(cx, expr, &if_let);
             }
+        } else if !from_expansion {
             redundant_pattern_match::check(cx, expr);
-            needless_match::check(cx, expr);
         }
     }
 
diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs
index f920ad4651f..fa19cddd35e 100644
--- a/clippy_lints/src/matches/needless_match.rs
+++ b/clippy_lints/src/matches/needless_match.rs
@@ -47,20 +47,18 @@ pub(crate) fn check_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>],
 ///     some_enum
 /// }
 /// ```
-pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>) {
-    if let Some(ref if_let) = higher::IfLet::hir(cx, ex) {
-        if !is_else_clause(cx.tcx, ex) && expr_ty_matches_p_ty(cx, if_let.let_expr, ex) && check_if_let(cx, if_let) {
-            let mut applicability = Applicability::MachineApplicable;
-            span_lint_and_sugg(
-                cx,
-                NEEDLESS_MATCH,
-                ex.span,
-                "this if-let expression is unnecessary",
-                "replace it with",
-                snippet_with_applicability(cx, if_let.let_expr.span, "..", &mut applicability).to_string(),
-                applicability,
-            );
-        }
+pub(crate) fn check_if_let<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'_>, if_let: &higher::IfLet<'tcx>) {
+    if !is_else_clause(cx.tcx, ex) && expr_ty_matches_p_ty(cx, if_let.let_expr, ex) && check_if_let_inner(cx, if_let) {
+        let mut applicability = Applicability::MachineApplicable;
+        span_lint_and_sugg(
+            cx,
+            NEEDLESS_MATCH,
+            ex.span,
+            "this if-let expression is unnecessary",
+            "replace it with",
+            snippet_with_applicability(cx, if_let.let_expr.span, "..", &mut applicability).to_string(),
+            applicability,
+        );
     }
 }
 
@@ -77,7 +75,7 @@ fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>])
     true
 }
 
-fn check_if_let(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool {
+fn check_if_let_inner(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool {
     if let Some(if_else) = if_let.if_else {
         if !pat_same_as_expr(if_let.let_pat, peel_blocks_with_stmt(if_let.if_then)) {
             return false;
@@ -85,7 +83,7 @@ fn check_if_let(cx: &LateContext<'_>, if_let: &higher::IfLet<'_>) -> bool {
 
         // Recursively check for each `else if let` phrase,
         if let Some(ref nested_if_let) = higher::IfLet::hir(cx, if_else) {
-            return check_if_let(cx, nested_if_let);
+            return check_if_let_inner(cx, nested_if_let);
         }
 
         if matches!(if_else.kind, ExprKind::Block(..)) {
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 1a8b9d15f37..095cd43ea13 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -18,19 +18,21 @@ use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty};
 use rustc_span::sym;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let Some(higher::IfLet {
-        if_else,
-        let_pat,
-        let_expr,
-        ..
-    }) = higher::IfLet::hir(cx, expr)
-    {
-        find_sugg_for_if_let(cx, expr, let_pat, let_expr, "if", if_else.is_some());
-    } else if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
+    if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
         find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
     }
 }
 
+pub(super) fn check_if_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    pat: &'tcx Pat<'_>,
+    scrutinee: &'tcx Expr<'_>,
+    has_else: bool,
+) {
+    find_sugg_for_if_let(cx, expr, pat, scrutinee, "if", has_else);
+}
+
 // Extract the generic arguments out of a type
 fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
     if_chain! {
diff --git a/clippy_lints/src/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 424b361a905..a211dc18f9e 100644
--- a/clippy_lints/src/significant_drop_in_scrutinee.rs
+++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -4,103 +4,25 @@ use clippy_utils::get_attr;
 use clippy_utils::source::{indent_of, snippet};
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_hir::{Expr, ExprKind, MatchSource};
+use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{Ty, TypeAndMut};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 
-declare_clippy_lint! {
-    /// ### What it does
-    /// Check for temporaries returned from function calls in a match scrutinee that have the
-    /// `clippy::has_significant_drop` attribute.
-    ///
-    /// ### Why is this bad?
-    /// The `clippy::has_significant_drop` attribute can be added to types whose Drop impls have
-    /// an important side-effect, such as unlocking a mutex, making it important for users to be
-    /// able to accurately understand their lifetimes. When a temporary is returned in a function
-    /// call in a match scrutinee, its lifetime lasts until the end of the match block, which may
-    /// be surprising.
-    ///
-    /// For `Mutex`es this can lead to a deadlock. This happens when the match scrutinee uses a
-    /// function call that returns a `MutexGuard` and then tries to lock again in one of the match
-    /// arms. In that case the `MutexGuard` in the scrutinee will not be dropped until the end of
-    /// the match block and thus will not unlock.
-    ///
-    /// ### Example
-    /// ```rust.ignore
-    /// # use std::sync::Mutex;
-    ///
-    /// # struct State {}
-    ///
-    /// # impl State {
-    /// #     fn foo(&self) -> bool {
-    /// #         true
-    /// #     }
-    ///
-    /// #     fn bar(&self) {}
-    /// # }
-    ///
-    ///
-    /// let mutex = Mutex::new(State {});
-    ///
-    /// match mutex.lock().unwrap().foo() {
-    ///     true => {
-    ///         mutex.lock().unwrap().bar(); // Deadlock!
-    ///     }
-    ///     false => {}
-    /// };
-    ///
-    /// println!("All done!");
-    ///
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// # use std::sync::Mutex;
-    ///
-    /// # struct State {}
-    ///
-    /// # impl State {
-    /// #     fn foo(&self) -> bool {
-    /// #         true
-    /// #     }
-    ///
-    /// #     fn bar(&self) {}
-    /// # }
-    ///
-    /// let mutex = Mutex::new(State {});
-    ///
-    /// let is_foo = mutex.lock().unwrap().foo();
-    /// match is_foo {
-    ///     true => {
-    ///         mutex.lock().unwrap().bar();
-    ///     }
-    ///     false => {}
-    /// };
-    ///
-    /// println!("All done!");
-    /// ```
-    #[clippy::version = "1.60.0"]
-    pub SIGNIFICANT_DROP_IN_SCRUTINEE,
-    suspicious,
-    "warns when a temporary of a type with a drop with a significant side-effect might have a surprising lifetime"
-}
-
-declare_lint_pass!(SignificantDropInScrutinee => [SIGNIFICANT_DROP_IN_SCRUTINEE]);
+use super::SIGNIFICANT_DROP_IN_SCRUTINEE;
 
-impl<'tcx> LateLintPass<'tcx> for SignificantDropInScrutinee {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if let Some(suggestions) = has_significant_drop_in_scrutinee(cx, expr) {
-            for found in suggestions {
-                span_lint_and_then(
-                    cx,
-                    SIGNIFICANT_DROP_IN_SCRUTINEE,
-                    found.found_span,
-                    "temporary with significant drop in match scrutinee",
-                    |diag| set_diagnostic(diag, cx, expr, found),
-                );
-            }
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    source: MatchSource,
+) {
+    if let Some((suggestions, message)) = has_significant_drop_in_scrutinee(cx, scrutinee, source) {
+        for found in suggestions {
+            span_lint_and_then(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, found.found_span, message, |diag| {
+                set_diagnostic(diag, cx, expr, found);
+            });
         }
     }
 }
@@ -152,13 +74,18 @@ fn set_diagnostic<'tcx>(diag: &mut Diagnostic, cx: &LateContext<'tcx>, expr: &'t
 /// may have a surprising lifetime.
 fn has_significant_drop_in_scrutinee<'tcx, 'a>(
     cx: &'a LateContext<'tcx>,
-    expr: &'tcx Expr<'tcx>,
-) -> Option<Vec<FoundSigDrop>> {
+    scrutinee: &'tcx Expr<'tcx>,
+    source: MatchSource,
+) -> Option<(Vec<FoundSigDrop>, &'static str)> {
     let mut helper = SigDropHelper::new(cx);
-    match expr.kind {
-        ExprKind::Match(match_expr, _, _) => helper.find_sig_drop(match_expr),
-        _ => None,
-    }
+    helper.find_sig_drop(scrutinee).map(|drops| {
+        let message = if source == MatchSource::Normal {
+            "temporary with significant drop in match scrutinee"
+        } else {
+            "temporary with significant drop in for loop"
+        };
+        (drops, message)
+    })
 }
 
 struct SigDropHelper<'a, 'tcx> {
@@ -213,6 +140,19 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
         self.sig_drop_spans.take()
     }
 
+    fn replace_current_sig_drop(
+        &mut self,
+        found_span: Span,
+        is_unit_return_val: bool,
+        lint_suggestion: LintSuggestion,
+    ) {
+        self.current_sig_drop.replace(FoundSigDrop {
+            found_span,
+            is_unit_return_val,
+            lint_suggestion,
+        });
+    }
+
     /// This will try to set the current suggestion (so it can be moved into the suggestions vec
     /// later). If `allow_move_and_clone` is false, the suggestion *won't* be set -- this gives us
     /// an opportunity to look for another type in the chain that will be trivially copyable.
@@ -229,25 +169,15 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
             // but let's avoid any chance of an ICE
             if let Some(TypeAndMut { ty, .. }) = ty.builtin_deref(true) {
                 if ty.is_trivially_pure_clone_copy() {
-                    self.current_sig_drop.replace(FoundSigDrop {
-                        found_span: expr.span,
-                        is_unit_return_val: false,
-                        lint_suggestion: LintSuggestion::MoveAndDerefToCopy,
-                    });
+                    self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndDerefToCopy);
                 } else if allow_move_and_clone {
-                    self.current_sig_drop.replace(FoundSigDrop {
-                        found_span: expr.span,
-                        is_unit_return_val: false,
-                        lint_suggestion: LintSuggestion::MoveAndClone,
-                    });
+                    self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndClone);
                 }
             }
         } else if ty.is_trivially_pure_clone_copy() {
-            self.current_sig_drop.replace(FoundSigDrop {
-                found_span: expr.span,
-                is_unit_return_val: false,
-                lint_suggestion: LintSuggestion::MoveOnly,
-            });
+            self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveOnly);
+        } else if allow_move_and_clone {
+            self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndClone);
         }
     }
 
@@ -279,11 +209,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
         // If either side had a significant drop, suggest moving the entire scrutinee to avoid
         // unnecessary copies and to simplify cases where both sides have significant drops.
         if self.has_significant_drop {
-            self.current_sig_drop.replace(FoundSigDrop {
-                found_span: span,
-                is_unit_return_val,
-                lint_suggestion: LintSuggestion::MoveOnly,
-            });
+            self.replace_current_sig_drop(span, is_unit_return_val, LintSuggestion::MoveOnly);
         }
 
         self.special_handling_for_binary_op = false;
@@ -363,34 +289,34 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
                 }
             }
             ExprKind::Box(..) |
-                ExprKind::Array(..) |
-                ExprKind::Call(..) |
-                ExprKind::Unary(..) |
-                ExprKind::If(..) |
-                ExprKind::Match(..) |
-                ExprKind::Field(..) |
-                ExprKind::Index(..) |
-                ExprKind::Ret(..) |
-                ExprKind::Repeat(..) |
-                ExprKind::Yield(..) |
-                ExprKind::MethodCall(..) => walk_expr(self, ex),
+            ExprKind::Array(..) |
+            ExprKind::Call(..) |
+            ExprKind::Unary(..) |
+            ExprKind::If(..) |
+            ExprKind::Match(..) |
+            ExprKind::Field(..) |
+            ExprKind::Index(..) |
+            ExprKind::Ret(..) |
+            ExprKind::Repeat(..) |
+            ExprKind::Yield(..) |
+            ExprKind::MethodCall(..) => walk_expr(self, ex),
             ExprKind::AddrOf(_, _, _) |
-                ExprKind::Block(_, _) |
-                ExprKind::Break(_, _) |
-                ExprKind::Cast(_, _) |
-                // Don't want to check the closure itself, only invocation, which is covered by MethodCall
-                ExprKind::Closure(_, _, _, _, _) |
-                ExprKind::ConstBlock(_) |
-                ExprKind::Continue(_) |
-                ExprKind::DropTemps(_) |
-                ExprKind::Err |
-                ExprKind::InlineAsm(_) |
-                ExprKind::Let(_) |
-                ExprKind::Lit(_) |
-                ExprKind::Loop(_, _, _, _) |
-                ExprKind::Path(_) |
-                ExprKind::Struct(_, _, _) |
-                ExprKind::Type(_, _) => {
+            ExprKind::Block(_, _) |
+            ExprKind::Break(_, _) |
+            ExprKind::Cast(_, _) |
+            // Don't want to check the closure itself, only invocation, which is covered by MethodCall
+            ExprKind::Closure(_, _, _, _, _) |
+            ExprKind::ConstBlock(_) |
+            ExprKind::Continue(_) |
+            ExprKind::DropTemps(_) |
+            ExprKind::Err |
+            ExprKind::InlineAsm(_) |
+            ExprKind::Let(_) |
+            ExprKind::Lit(_) |
+            ExprKind::Loop(_, _, _, _) |
+            ExprKind::Path(_) |
+            ExprKind::Struct(_, _, _) |
+            ExprKind::Type(_, _) => {
                 return;
             }
         }
diff --git a/clippy_lints/src/matches/try_err.rs b/clippy_lints/src/matches/try_err.rs
new file mode 100644
index 00000000000..0491a0679f3
--- /dev/null
+++ b/clippy_lints/src/matches/try_err.rs
@@ -0,0 +1,145 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{get_parent_expr, is_lang_ctor, match_def_path, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::ResultErr;
+use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{hygiene, sym};
+
+use super::TRY_ERR;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutinee: &'tcx Expr<'_>) {
+    // Looks for a structure like this:
+    // match ::std::ops::Try::into_result(Err(5)) {
+    //     ::std::result::Result::Err(err) =>
+    //         #[allow(unreachable_code)]
+    //         return ::std::ops::Try::from_error(::std::convert::From::from(err)),
+    //     ::std::result::Result::Ok(val) =>
+    //         #[allow(unreachable_code)]
+    //         val,
+    // };
+    if_chain! {
+        if let ExprKind::Call(match_fun, try_args) = scrutinee.kind;
+        if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
+        if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..));
+        if let Some(try_arg) = try_args.get(0);
+        if let ExprKind::Call(err_fun, err_args) = try_arg.kind;
+        if let Some(err_arg) = err_args.get(0);
+        if let ExprKind::Path(ref err_fun_path) = err_fun.kind;
+        if is_lang_ctor(cx, err_fun_path, ResultErr);
+        if let Some(return_ty) = find_return_type(cx, &expr.kind);
+        then {
+            let prefix;
+            let suffix;
+            let err_ty;
+
+            if let Some(ty) = result_error_type(cx, return_ty) {
+                prefix = "Err(";
+                suffix = ")";
+                err_ty = ty;
+            } else if let Some(ty) = poll_result_error_type(cx, return_ty) {
+                prefix = "Poll::Ready(Err(";
+                suffix = "))";
+                err_ty = ty;
+            } else if let Some(ty) = poll_option_result_error_type(cx, return_ty) {
+                prefix = "Poll::Ready(Some(Err(";
+                suffix = ")))";
+                err_ty = ty;
+            } else {
+                return;
+            };
+
+            let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
+            let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt());
+            let mut applicability = Applicability::MachineApplicable;
+            let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability);
+            let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) {
+                "" // already returns
+            } else {
+                "return "
+            };
+            let suggestion = if err_ty == expr_err_ty {
+                format!("{}{}{}{}", ret_prefix, prefix, origin_snippet, suffix)
+            } else {
+                format!("{}{}{}.into(){}", ret_prefix, prefix, origin_snippet, suffix)
+            };
+
+            span_lint_and_sugg(
+                cx,
+                TRY_ERR,
+                expr.span,
+                "returning an `Err(_)` with the `?` operator",
+                "try this",
+                suggestion,
+                applicability,
+            );
+        }
+    }
+}
+
+/// Finds function return type by examining return expressions in match arms.
+fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> Option<Ty<'tcx>> {
+    if let ExprKind::Match(_, arms, MatchSource::TryDesugar) = expr {
+        for arm in arms.iter() {
+            if let ExprKind::Ret(Some(ret)) = arm.body.kind {
+                return Some(cx.typeck_results().expr_ty(ret));
+            }
+        }
+    }
+    None
+}
+
+/// Extracts the error type from Result<T, E>.
+fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+    if_chain! {
+        if let ty::Adt(_, subst) = ty.kind();
+        if is_type_diagnostic_item(cx, ty, sym::Result);
+        then {
+            Some(subst.type_at(1))
+        } else {
+            None
+        }
+    }
+}
+
+/// Extracts the error type from Poll<Result<T, E>>.
+fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+    if_chain! {
+        if let ty::Adt(def, subst) = ty.kind();
+        if match_def_path(cx, def.did(), &paths::POLL);
+        let ready_ty = subst.type_at(0);
+
+        if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
+        if cx.tcx.is_diagnostic_item(sym::Result, ready_def.did());
+        then {
+            Some(ready_subst.type_at(1))
+        } else {
+            None
+        }
+    }
+}
+
+/// Extracts the error type from Poll<Option<Result<T, E>>>.
+fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+    if_chain! {
+        if let ty::Adt(def, subst) = ty.kind();
+        if match_def_path(cx, def.did(), &paths::POLL);
+        let ready_ty = subst.type_at(0);
+
+        if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
+        if cx.tcx.is_diagnostic_item(sym::Option, ready_def.did());
+        let some_ty = ready_subst.type_at(0);
+
+        if let ty::Adt(some_def, some_subst) = some_ty.kind();
+        if cx.tcx.is_diagnostic_item(sym::Result, some_def.did());
+        then {
+            Some(some_subst.type_at(1))
+        } else {
+            None
+        }
+    }
+}
diff --git a/clippy_lints/src/methods/get_last_with_len.rs b/clippy_lints/src/methods/get_last_with_len.rs
new file mode 100644
index 00000000000..23368238ef5
--- /dev/null
+++ b/clippy_lints/src/methods/get_last_with_len.rs
@@ -0,0 +1,55 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::SpanlessEq;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::source_map::Spanned;
+use rustc_span::sym;
+
+use super::GET_LAST_WITH_LEN;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
+    // Argument to "get" is a subtraction
+    if let ExprKind::Binary(
+        Spanned {
+            node: BinOpKind::Sub, ..
+        },
+        lhs,
+        rhs,
+    ) = arg.kind
+
+        // LHS of subtraction is "x.len()"
+        && let ExprKind::MethodCall(lhs_path, [lhs_recv], _) = &lhs.kind
+        && lhs_path.ident.name == sym::len
+
+        // RHS of subtraction is 1
+        && let ExprKind::Lit(rhs_lit) = &rhs.kind
+        && let LitKind::Int(1, ..) = rhs_lit.node
+
+        // check that recv == lhs_recv `recv.get(lhs_recv.len() - 1)`
+        && SpanlessEq::new(cx).eq_expr(recv, lhs_recv)
+        && !recv.can_have_side_effects()
+    {
+        let method = match cx.typeck_results().expr_ty_adjusted(recv).peel_refs().kind() {
+            ty::Adt(def, _) if cx.tcx.is_diagnostic_item(sym::VecDeque, def.did()) => "back",
+            ty::Slice(_) => "last",
+            _ => return,
+        };
+
+        let mut applicability = Applicability::MachineApplicable;
+        let recv_snippet = snippet_with_applicability(cx, recv.span, "_", &mut applicability);
+
+        span_lint_and_sugg(
+            cx,
+            GET_LAST_WITH_LEN,
+            expr.span,
+            &format!("accessing last element with `{recv_snippet}.get({recv_snippet}.len() - 1)`"),
+            "try",
+            format!("{recv_snippet}.{method}()"),
+            applicability,
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/iter_next_slice.rs b/clippy_lints/src/methods/iter_next_slice.rs
index d053ff56756..b8d1dabe007 100644
--- a/clippy_lints/src/methods/iter_next_slice.rs
+++ b/clippy_lints/src/methods/iter_next_slice.rs
@@ -34,13 +34,18 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
             if let ast::LitKind::Int(start_idx, _) = start_lit.node;
             then {
                 let mut applicability = Applicability::MachineApplicable;
+                let suggest = if start_idx == 0 {
+                    format!("{}.first()", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability))
+                } else {
+                    format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx)
+                };
                 span_lint_and_sugg(
                     cx,
                     ITER_NEXT_SLICE,
                     expr.span,
                     "using `.iter().next()` on a Slice without end index",
                     "try calling",
-                    format!("{}.get({})", snippet_with_applicability(cx, caller_var.span, "..", &mut applicability), start_idx),
+                    suggest,
                     applicability,
                 );
             }
@@ -55,7 +60,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal
             "using `.iter().next()` on an array",
             "try calling",
             format!(
-                "{}.get(0)",
+                "{}.first()",
                 snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability)
             ),
             applicability,
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 3bf48e18019..7308e74c323 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -21,6 +21,7 @@ mod filter_next;
 mod flat_map_identity;
 mod flat_map_option;
 mod from_iter_instead_of_collect;
+mod get_last_with_len;
 mod get_unwrap;
 mod implicit_clone;
 mod inefficient_to_string;
@@ -44,6 +45,7 @@ mod map_identity;
 mod map_unwrap_or;
 mod needless_option_as_deref;
 mod needless_option_take;
+mod no_effect_replace;
 mod ok_expect;
 mod option_as_ref_deref;
 mod option_map_or_none;
@@ -192,25 +194,18 @@ declare_clippy_lint! {
     ///
     /// ### Examples
     /// ```rust
-    /// # let opt = Some(1);
-    ///
-    /// // Bad
-    /// opt.unwrap();
-    ///
-    /// // Good
-    /// opt.expect("more helpful message");
+    /// # let option = Some(1);
+    /// # let result: Result<usize, ()> = Ok(1);
+    /// option.unwrap();
+    /// result.unwrap();
     /// ```
     ///
-    /// // or
-    ///
+    /// Use instead:
     /// ```rust
-    /// # let res: Result<usize, ()> = Ok(1);
-    ///
-    /// // Bad
-    /// res.unwrap();
-    ///
-    /// // Good
-    /// res.expect("more helpful message");
+    /// # let option = Some(1);
+    /// # let result: Result<usize, ()> = Ok(1);
+    /// option.expect("more helpful message");
+    /// result.expect("more helpful message");
     /// ```
     #[clippy::version = "1.45.0"]
     pub UNWRAP_USED,
@@ -233,27 +228,21 @@ declare_clippy_lint! {
     ///
     /// ### Examples
     /// ```rust,ignore
-    /// # let opt = Some(1);
-    ///
-    /// // Bad
-    /// opt.expect("one");
-    ///
-    /// // Good
-    /// let opt = Some(1);
-    /// opt?;
+    /// # let option = Some(1);
+    /// # let result: Result<usize, ()> = Ok(1);
+    /// option.expect("one");
+    /// result.expect("one");
     /// ```
     ///
-    /// // or
-    ///
-    /// ```rust
-    /// # let res: Result<usize, ()> = Ok(1);
+    /// Use instead:
+    /// ```rust,ignore
+    /// # let option = Some(1);
+    /// # let result: Result<usize, ()> = Ok(1);
+    /// option?;
     ///
-    /// // Bad
-    /// res.expect("one");
+    /// // or
     ///
-    /// // Good
-    /// res?;
-    /// # Ok::<(), ()>(())
+    /// result?;
     /// ```
     #[clippy::version = "1.45.0"]
     pub EXPECT_USED,
@@ -429,26 +418,20 @@ declare_clippy_lint! {
     ///
     /// ### Examples
     /// ```rust
-    /// # let x = Some(1);
-    ///
-    /// // Bad
-    /// x.map(|a| a + 1).unwrap_or(0);
-    ///
-    /// // Good
-    /// x.map_or(0, |a| a + 1);
+    /// # let option = Some(1);
+    /// # let result: Result<usize, ()> = Ok(1);
+    /// # fn some_function(foo: ()) -> usize { 1 }
+    /// option.map(|a| a + 1).unwrap_or(0);
+    /// result.map(|a| a + 1).unwrap_or_else(some_function);
     /// ```
     ///
-    /// // or
-    ///
+    /// Use instead:
     /// ```rust
-    /// # let x: Result<usize, ()> = Ok(1);
+    /// # let option = Some(1);
+    /// # let result: Result<usize, ()> = Ok(1);
     /// # fn some_function(foo: ()) -> usize { 1 }
-    ///
-    /// // Bad
-    /// x.map(|a| a + 1).unwrap_or_else(some_function);
-    ///
-    /// // Good
-    /// x.map_or_else(some_function, |a| a + 1);
+    /// option.map_or(0, |a| a + 1);
+    /// result.map_or_else(some_function, |a| a + 1);
     /// ```
     #[clippy::version = "1.45.0"]
     pub MAP_UNWRAP_OR,
@@ -791,13 +774,14 @@ declare_clippy_lint! {
     /// # let foo = Some(String::new());
     /// foo.unwrap_or(String::new());
     /// ```
-    /// this can instead be written:
+    ///
+    /// Use instead:
     /// ```rust
     /// # let foo = Some(String::new());
     /// foo.unwrap_or_else(String::new);
-    /// ```
-    /// or
-    /// ```rust
+    ///
+    /// // or
+    ///
     /// # let foo = Some(String::new());
     /// foo.unwrap_or_default();
     /// ```
@@ -861,15 +845,14 @@ declare_clippy_lint! {
     /// # let err_code = "418";
     /// # let err_msg = "I'm a teapot";
     /// foo.expect(&format!("Err {}: {}", err_code, err_msg));
-    /// ```
-    /// or
-    /// ```rust
+    ///
+    /// // or
+    ///
     /// # let foo = Some(String::new());
-    /// # let err_code = "418";
-    /// # let err_msg = "I'm a teapot";
     /// foo.expect(format!("Err {}: {}", err_code, err_msg).as_str());
     /// ```
-    /// this can instead be written:
+    ///
+    /// Use instead:
     /// ```rust
     /// # let foo = Some(String::new());
     /// # let err_code = "418";
@@ -1211,6 +1194,38 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for using `x.get(x.len() - 1)` instead of
+    /// `x.last()`.
+    ///
+    /// ### Why is this bad?
+    /// Using `x.last()` is easier to read and has the same
+    /// result.
+    ///
+    /// Note that using `x[x.len() - 1]` is semantically different from
+    /// `x.last()`.  Indexing into the array will panic on out-of-bounds
+    /// accesses, while `x.get()` and `x.last()` will return `None`.
+    ///
+    /// There is another lint (get_unwrap) that covers the case of using
+    /// `x.get(index).unwrap()` instead of `x[index]`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// // Bad
+    /// let x = vec![2, 3, 5];
+    /// let last_element = x.get(x.len() - 1);
+    ///
+    /// // Good
+    /// let x = vec![2, 3, 5];
+    /// let last_element = x.last();
+    /// ```
+    #[clippy::version = "1.37.0"]
+    pub GET_LAST_WITH_LEN,
+    complexity,
+    "Using `x.get(x.len() - 1)` when `x.last()` is correct and simpler"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for use of `.get().unwrap()` (or
     /// `.get_mut().unwrap`) on a standard library type which implements `Index`
     ///
@@ -2195,6 +2210,24 @@ declare_clippy_lint! {
     "using `.as_ref().take()` on a temporary value"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `replace` statements which have no effect.
+    ///
+    /// ### Why is this bad?
+    /// It's either a mistake or confusing.
+    ///
+    /// ### Example
+    /// ```rust
+    /// "1234".replace("12", "12");
+    /// "1234".replacen("12", "12", 1);
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub NO_EFFECT_REPLACE,
+    suspicious,
+    "replace with no effect"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Option<RustcVersion>,
@@ -2264,6 +2297,7 @@ impl_lint_pass!(Methods => [
     BYTES_NTH,
     ITER_SKIP_NEXT,
     GET_UNWRAP,
+    GET_LAST_WITH_LEN,
     STRING_EXTEND_CHARS,
     ITER_CLONED_COLLECT,
     ITER_WITH_DRAIN,
@@ -2294,6 +2328,7 @@ impl_lint_pass!(Methods => [
     NEEDLESS_OPTION_AS_DEREF,
     IS_DIGIT_ASCII_RADIX,
     NEEDLESS_OPTION_TAKE,
+    NO_EFFECT_REPLACE,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -2590,6 +2625,7 @@ impl Methods {
                         inspect_for_each::check(cx, expr, span2);
                     }
                 },
+                ("get", [arg]) => get_last_with_len::check(cx, expr, recv, arg),
                 ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
                 ("is_file", []) => filetype_is_file::check(cx, expr, recv),
                 ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
@@ -2705,6 +2741,9 @@ impl Methods {
                         unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
                     },
                 },
+                ("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => {
+                    no_effect_replace::check(cx, expr, arg1, arg2);
+                },
                 _ => {},
             }
         }
diff --git a/clippy_lints/src/methods/no_effect_replace.rs b/clippy_lints/src/methods/no_effect_replace.rs
new file mode 100644
index 00000000000..a76341855b6
--- /dev/null
+++ b/clippy_lints/src/methods/no_effect_replace.rs
@@ -0,0 +1,47 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::SpanlessEq;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_hir::ExprKind;
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::NO_EFFECT_REPLACE;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx rustc_hir::Expr<'_>,
+    arg1: &'tcx rustc_hir::Expr<'_>,
+    arg2: &'tcx rustc_hir::Expr<'_>,
+) {
+    let ty = cx.typeck_results().expr_ty(expr).peel_refs();
+    if !(ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String)) {
+        return;
+    }
+
+    if_chain! {
+        if let ExprKind::Lit(spanned) = &arg1.kind;
+        if let Some(param1) = lit_string_value(&spanned.node);
+
+        if let ExprKind::Lit(spanned) = &arg2.kind;
+        if let LitKind::Str(param2, _) = &spanned.node;
+        if param1 == param2.as_str();
+
+        then {
+            span_lint(cx, NO_EFFECT_REPLACE, expr.span, "replacing text with itself");
+        }
+    }
+
+    if SpanlessEq::new(cx).eq_expr(arg1, arg2) {
+        span_lint(cx, NO_EFFECT_REPLACE, expr.span, "replacing text with itself");
+    }
+}
+
+fn lit_string_value(node: &LitKind) -> Option<String> {
+    match node {
+        LitKind::Char(value) => Some(value.to_string()),
+        LitKind::Str(value, _) => Some(value.as_str().to_owned()),
+        _ => None,
+    }
+}
diff --git a/clippy_lints/src/methods/option_map_or_none.rs b/clippy_lints/src/methods/option_map_or_none.rs
index 76bc9466ed8..8989db54f6c 100644
--- a/clippy_lints/src/methods/option_map_or_none.rs
+++ b/clippy_lints/src/methods/option_map_or_none.rs
@@ -97,7 +97,7 @@ pub(super) fn check<'tcx>(
         let func_snippet = snippet(cx, map_arg.span, "..");
         let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
                        `and_then(..)` instead";
-        return span_lint_and_sugg(
+        span_lint_and_sugg(
             cx,
             OPTION_MAP_OR_NONE,
             expr.span,
@@ -110,7 +110,7 @@ pub(super) fn check<'tcx>(
         let msg = "called `map_or(None, Some)` on a `Result` value. This can be done more directly by calling \
                        `ok()` instead";
         let self_snippet = snippet(cx, recv.span, "..");
-        return span_lint_and_sugg(
+        span_lint_and_sugg(
             cx,
             RESULT_MAP_OR_INTO_OPTION,
             expr.span,
diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index 97c4feb3122..b4c6bfb31ed 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -415,7 +415,7 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id:
 /// Returns true if the named method can be used to convert the receiver to its "owned"
 /// representation.
 fn is_to_owned_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool {
-    is_clone_like(cx, &*method_name.as_str(), method_def_id)
+    is_clone_like(cx, method_name.as_str(), method_def_id)
         || is_cow_into_owned(cx, method_name, method_def_id)
         || is_to_string(cx, method_name, method_def_id)
 }
diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs
index 65d1f440b76..a081cde8572 100644
--- a/clippy_lints/src/minmax.rs
+++ b/clippy_lints/src/minmax.rs
@@ -18,11 +18,11 @@ declare_clippy_lint! {
     /// the least it hurts readability of the code.
     ///
     /// ### Example
-    /// ```ignore
+    /// ```rust,ignore
     /// min(0, max(100, x))
-    /// ```
-    /// or
-    /// ```ignore
+    ///
+    /// // or
+    ///
     /// x.max(100).min(0)
     /// ```
     /// It will always be equal to `0`. Probably the author meant to clamp the value
diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs
index 7fdc28c5a06..55665699453 100644
--- a/clippy_lints/src/misc.rs
+++ b/clippy_lints/src/misc.rs
@@ -103,11 +103,14 @@ declare_clippy_lint! {
     /// let x = 1.2331f64;
     /// let y = 1.2332f64;
     ///
-    /// // Bad
     /// if y == 1.23f64 { }
     /// if y != x {} // where both are floats
+    /// ```
     ///
-    /// // Good
+    /// Use instead:
+    /// ```rust
+    /// # let x = 1.2331f64;
+    /// # let y = 1.2332f64;
     /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
     /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
     /// // let error_margin = std::f64::EPSILON;
@@ -258,10 +261,13 @@ declare_clippy_lint! {
     /// let x: f64 = 1.0;
     /// const ONE: f64 = 1.00;
     ///
-    /// // Bad
     /// if x == ONE { } // where both are floats
+    /// ```
     ///
-    /// // Good
+    /// Use instead:
+    /// ```rust
+    /// # let x: f64 = 1.0;
+    /// # const ONE: f64 = 1.00;
     /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
     /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
     /// // let error_margin = std::f64::EPSILON;
diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs
new file mode 100644
index 00000000000..d466d54a6ba
--- /dev/null
+++ b/clippy_lints/src/mismatching_type_param_order.rs
@@ -0,0 +1,116 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{GenericArg, Item, ItemKind, QPath, Ty, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::GenericParamDefKind;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for type parameters which are positioned inconsistently between
+    /// a type definition and impl block. Specifically, a paramater in an impl
+    /// block which has the same name as a parameter in the type def, but is in
+    /// a different place.
+    ///
+    /// ### Why is this bad?
+    /// Type parameters are determined by their position rather than name.
+    /// Naming type parameters inconsistently may cause you to refer to the
+    /// wrong type parameter.
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct Foo<A, B> {
+    ///     x: A,
+    ///     y: B,
+    /// }
+    /// // inside the impl, B refers to Foo::A
+    /// impl<B, A> Foo<B, A> {}
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct Foo<A, B> {
+    ///     x: A,
+    ///     y: B,
+    /// }
+    /// impl<A, B> Foo<A, B> {}
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub MISMATCHING_TYPE_PARAM_ORDER,
+    pedantic,
+    "type parameter positioned inconsistently between type def and impl block"
+}
+declare_lint_pass!(TypeParamMismatch => [MISMATCHING_TYPE_PARAM_ORDER]);
+
+impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if_chain! {
+            if !item.span.from_expansion();
+            if let ItemKind::Impl(imp) = &item.kind;
+            if let TyKind::Path(QPath::Resolved(_, path)) = &imp.self_ty.kind;
+            if let Some(segment) = path.segments.iter().next();
+            if let Some(generic_args) = segment.args;
+            if !generic_args.args.is_empty();
+            then {
+                // get the name and span of the generic parameters in the Impl
+                let impl_params = generic_args.args.iter()
+                .filter_map(|p|
+                    match p {
+                        GenericArg::Type(Ty {kind: TyKind::Path(QPath::Resolved(_, path)), ..}) =>
+                            Some((path.segments[0].ident.to_string(), path.span)),
+                        _ => None,
+                    }
+                );
+
+                // find the type that the Impl is for
+                // only lint on struct/enum/union for now
+                let defid = match path.res {
+                    Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, defid) => defid,
+                    _ => return,
+                };
+
+                // get the names of the generic parameters in the type
+                let type_params = &cx.tcx.generics_of(defid).params;
+                let type_param_names: Vec<_> = type_params.iter()
+                .filter_map(|p|
+                    match p.kind {
+                        GenericParamDefKind::Type {..} => Some(p.name.to_string()),
+                        _ => None,
+                    }
+                ).collect();
+                // hashmap of name -> index for mismatch_param_name
+                let type_param_names_hashmap: FxHashMap<&String, usize> =
+                    type_param_names.iter().enumerate().map(|(i, param)| (param, i)).collect();
+
+                let type_name = segment.ident;
+                for (i, (impl_param_name, impl_param_span)) in impl_params.enumerate() {
+                    if mismatch_param_name(i, &impl_param_name, &type_param_names_hashmap) {
+                        let msg = format!("`{}` has a similarly named generic type parameter `{}` in its declaration, but in a different order",
+                                          type_name, impl_param_name);
+                        let help = format!("try `{}`, or a name that does not conflict with `{}`'s generic params",
+                                           type_param_names[i], type_name);
+                        span_lint_and_help(
+                            cx,
+                            MISMATCHING_TYPE_PARAM_ORDER,
+                            impl_param_span,
+                            &msg,
+                            None,
+                            &help
+                        );
+                    }
+                }
+            }
+        }
+    }
+}
+
+// Checks if impl_param_name is the same as one of type_param_names,
+// and is in a different position
+fn mismatch_param_name(i: usize, impl_param_name: &String, type_param_names: &FxHashMap<&String, usize>) -> bool {
+    if let Some(j) = type_param_names.get(impl_param_name) {
+        if i != *j {
+            return true;
+        }
+    }
+    false
+}
diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs
index a20377f320b..b99052e66ba 100644
--- a/clippy_lints/src/missing_doc.rs
+++ b/clippy_lints/src/missing_doc.rs
@@ -7,7 +7,8 @@
 
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint;
-use rustc_ast::ast;
+use if_chain::if_chain;
+use rustc_ast::ast::{self, MetaItem, MetaItemKind};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::{self, DefIdTree};
@@ -57,6 +58,20 @@ impl MissingDoc {
         *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
     }
 
+    fn has_include(meta: Option<MetaItem>) -> bool {
+        if_chain! {
+            if let Some(meta) = meta;
+            if let MetaItemKind::List(list) = meta.kind;
+            if let Some(meta) = list.get(0);
+            if let Some(name) = meta.ident();
+            then {
+                name.name == sym::include
+            } else {
+                false
+            }
+        }
+    }
+
     fn check_missing_docs_attrs(
         &self,
         cx: &LateContext<'_>,
@@ -80,7 +95,9 @@ impl MissingDoc {
             return;
         }
 
-        let has_doc = attrs.iter().any(|a| a.doc_str().is_some());
+        let has_doc = attrs
+            .iter()
+            .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
         if !has_doc {
             span_lint(
                 cx,
diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs
index 405fc23e8de..024bd076071 100644
--- a/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -120,7 +120,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
                         self.visit_expr(if_expr);
                     }
                     // make sure top level arm expressions aren't linted
-                    self.maybe_walk_expr(&*arm.body);
+                    self.maybe_walk_expr(arm.body);
                 }
             },
             _ => walk_expr(self, e),
diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs
index cba54e14212..7e2531c7ca5 100644
--- a/clippy_lints/src/mut_key.rs
+++ b/clippy_lints/src/mut_key.rs
@@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
         if let hir::PatKind::Wild = local.pat.kind {
             return;
         }
-        check_ty(cx, local.span, cx.typeck_results().pat_ty(&*local.pat));
+        check_ty(cx, local.span, cx.typeck_results().pat_ty(local.pat));
     }
 }
 
diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs
index bb6d820b08c..321db08dfe8 100644
--- a/clippy_lints/src/mutable_debug_assertion.rs
+++ b/clippy_lints/src/mutable_debug_assertion.rs
@@ -22,9 +22,12 @@ declare_clippy_lint! {
     /// ### Example
     /// ```rust,ignore
     /// debug_assert_eq!(vec![3].pop(), Some(3));
+    ///
     /// // or
-    /// fn take_a_mut_parameter(_: &mut u32) -> bool { unimplemented!() }
-    /// debug_assert!(take_a_mut_parameter(&mut 5));
+    ///
+    /// # let mut x = 5;
+    /// # fn takes_a_mut_parameter(_: &mut u32) -> bool { unimplemented!() }
+    /// debug_assert!(takes_a_mut_parameter(&mut x));
     /// ```
     #[clippy::version = "1.40.0"]
     pub DEBUG_ASSERT_WITH_MUT_CALL,
@@ -92,10 +95,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
                 self.found = true;
                 return;
             },
-            ExprKind::If(..) => {
-                self.found = true;
-                return;
-            },
             ExprKind::Path(_) => {
                 if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
                     if adj
diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs
index b70871b38be..26c694a71fe 100644
--- a/clippy_lints/src/needless_late_init.rs
+++ b/clippy_lints/src/needless_late_init.rs
@@ -194,14 +194,15 @@ fn assignment_suggestions<'tcx>(
         }))
         .collect::<Option<Vec<(Span, String)>>>()?;
 
-    let applicability = if suggestions.len() > 1 {
+    match suggestions.len() {
+        // All of `exprs` are never types
+        // https://github.com/rust-lang/rust-clippy/issues/8911
+        0 => None,
+        1 => Some((Applicability::MachineApplicable, suggestions)),
         // multiple suggestions don't work with rustfix in multipart_suggest
         // https://github.com/rust-lang/rustfix/issues/141
-        Applicability::Unspecified
-    } else {
-        Applicability::MachineApplicable
-    };
-    Some((applicability, suggestions))
+        _ => Some((Applicability::Unspecified, suggestions)),
+    }
 }
 
 struct Usage<'tcx> {
diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/numeric_arithmetic.rs
index c5948707c81..5c4de338149 100644
--- a/clippy_lints/src/arithmetic.rs
+++ b/clippy_lints/src/numeric_arithmetic.rs
@@ -51,16 +51,16 @@ declare_clippy_lint! {
 }
 
 #[derive(Copy, Clone, Default)]
-pub struct Arithmetic {
+pub struct NumericArithmetic {
     expr_span: Option<Span>,
     /// This field is used to check whether expressions are constants, such as in enum discriminants
     /// and consts
     const_span: Option<Span>,
 }
 
-impl_lint_pass!(Arithmetic => [INTEGER_ARITHMETIC, FLOAT_ARITHMETIC]);
+impl_lint_pass!(NumericArithmetic => [INTEGER_ARITHMETIC, FLOAT_ARITHMETIC]);
 
-impl<'tcx> LateLintPass<'tcx> for Arithmetic {
+impl<'tcx> LateLintPass<'tcx> for NumericArithmetic {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if self.expr_span.is_some() {
             return;
diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs
index b7a56970b33..21acf003d92 100644
--- a/clippy_lints/src/panic_in_result_fn.rs
+++ b/clippy_lints/src/panic_in_result_fn.rs
@@ -61,7 +61,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir
     expr_visitor_no_bodies(|expr| {
         let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return true };
         if matches!(
-            &*cx.tcx.item_name(macro_call.def_id).as_str(),
+            cx.tcx.item_name(macro_call.def_id).as_str(),
             "unimplemented" | "unreachable" | "panic" | "todo" | "assert" | "assert_eq" | "assert_ne"
         ) {
             panics.push(macro_call.span);
diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs
index e3ded716341..5a93431f25a 100644
--- a/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/clippy_lints/src/pass_by_ref_or_value.rs
@@ -233,7 +233,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
         }
 
         if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
-            self.check_poly_fn(cx, item.def_id, &*method_sig.decl, None);
+            self.check_poly_fn(cx, item.def_id, method_sig.decl, None);
         }
     }
 
diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs
index 26dc88a406e..584b561dcf0 100644
--- a/clippy_lints/src/ranges.rs
+++ b/clippy_lints/src/ranges.rs
@@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges {
             },
             ExprKind::Binary(ref op, l, r) => {
                 if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
-                    check_possible_range_contains(cx, op.node, l, r, expr);
+                    check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
                 }
             },
             _ => {},
@@ -213,12 +213,12 @@ fn check_possible_range_contains(
     left: &Expr<'_>,
     right: &Expr<'_>,
     expr: &Expr<'_>,
+    span: Span,
 ) {
     if in_constant(cx, expr.hir_id) {
         return;
     }
 
-    let span = expr.span;
     let combine_and = match op {
         BinOpKind::And | BinOpKind::BitAnd => true,
         BinOpKind::Or | BinOpKind::BitOr => false,
@@ -294,6 +294,20 @@ fn check_possible_range_contains(
             );
         }
     }
+
+    // If the LHS is the same operator, we have to recurse to get the "real" RHS, since they have
+    // the same operator precedence
+    if_chain! {
+        if let ExprKind::Binary(ref lhs_op, _left, new_lhs) = left.kind;
+        if op == lhs_op.node;
+        let new_span = Span::new(new_lhs.span.lo(), right.span.hi(), expr.span.ctxt(), expr.span.parent());
+        if let Some(snip) = &snippet_opt(cx, new_span);
+        // Do not continue if we have mismatched number of parens, otherwise the suggestion is wrong
+        if snip.matches('(').count() == snip.matches(')').count();
+        then {
+            check_possible_range_contains(cx, op, new_lhs, right, expr, new_span);
+        }
+    }
 }
 
 struct RangeBounds<'a> {
@@ -363,7 +377,7 @@ fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args:
         // `.iter()` and `.len()` called on same `Path`
         if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_args[0].kind;
         if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind;
-        if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments);
+        if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
         then {
             span_lint(cx,
                 RANGE_ZIP_WITH_LEN,
diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs
index 110f58f3734..8db8c4e9b78 100644
--- a/clippy_lints/src/rc_clone_in_vec_init.rs
+++ b/clippy_lints/src/rc_clone_in_vec_init.rs
@@ -2,7 +2,9 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::VecArgs;
 use clippy_utils::last_path_segment;
 use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::paths;
 use clippy_utils::source::{indent_of, snippet};
+use clippy_utils::ty::match_type;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -11,10 +13,11 @@ use rustc_span::{sym, Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `Arc::new` or `Rc::new` in `vec![elem; len]`
+    /// Checks for reference-counted pointers (`Arc`, `Rc`, `rc::Weak`, and `sync::Weak`)
+    /// in `vec![elem; len]`
     ///
     /// ### Why is this bad?
-    /// This will create `elem` once and clone it `len` times - doing so with `Arc` or `Rc`
+    /// This will create `elem` once and clone it `len` times - doing so with `Arc`/`Rc`/`Weak`
     /// is a bit misleading, as it will create references to the same pointer, rather
     /// than different instances.
     ///
@@ -26,7 +29,6 @@ declare_clippy_lint! {
     /// ```
     /// Use instead:
     /// ```rust
-    ///
     /// // Initialize each value separately:
     /// let mut data = Vec::with_capacity(100);
     /// for _ in 0..100 {
@@ -42,7 +44,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.62.0"]
     pub RC_CLONE_IN_VEC_INIT,
     suspicious,
-    "initializing `Arc` or `Rc` in `vec![elem; len]`"
+    "initializing reference-counted pointer in `vec![elem; len]`"
 }
 declare_lint_pass!(RcCloneInVecInit => [RC_CLONE_IN_VEC_INIT]);
 
@@ -50,26 +52,12 @@ impl LateLintPass<'_> for RcCloneInVecInit {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return; };
         let Some(VecArgs::Repeat(elem, len)) = VecArgs::hir(cx, expr) else { return; };
-        let Some(symbol) = new_reference_call(cx, elem) else { return; };
+        let Some((symbol, func_span)) = ref_init(cx, elem) else { return; };
 
-        emit_lint(cx, symbol, macro_call.span, elem, len);
+        emit_lint(cx, symbol, macro_call.span, elem, len, func_span);
     }
 }
 
-fn elem_snippet(cx: &LateContext<'_>, elem: &Expr<'_>, symbol_name: &str) -> String {
-    let elem_snippet = snippet(cx, elem.span, "..").to_string();
-    if elem_snippet.contains('\n') {
-        // This string must be found in `elem_snippet`, otherwise we won't be constructing
-        // the snippet in the first place.
-        let reference_creation = format!("{symbol_name}::new");
-        let (code_until_reference_creation, _right) = elem_snippet.split_once(&reference_creation).unwrap();
-
-        return format!("{code_until_reference_creation}{reference_creation}(..)");
-    }
-
-    elem_snippet
-}
-
 fn loop_init_suggestion(elem: &str, len: &str, indent: &str) -> String {
     format!(
         r#"{{
@@ -89,17 +77,17 @@ fn extract_suggestion(elem: &str, len: &str, indent: &str) -> String {
     )
 }
 
-fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, elem: &Expr<'_>, len: &Expr<'_>) {
+fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, elem: &Expr<'_>, len: &Expr<'_>, func_span: Span) {
     let symbol_name = symbol.as_str();
 
     span_lint_and_then(
         cx,
         RC_CLONE_IN_VEC_INIT,
         lint_span,
-        &format!("calling `{symbol_name}::new` in `vec![elem; len]`"),
+        "initializing a reference-counted pointer in `vec![elem; len]`",
         |diag| {
             let len_snippet = snippet(cx, len.span, "..");
-            let elem_snippet = elem_snippet(cx, elem, symbol_name);
+            let elem_snippet = format!("{}(..)", snippet(cx, elem.span.with_hi(func_span.hi()), ".."));
             let indentation = " ".repeat(indent_of(cx, lint_span).unwrap_or(0));
             let loop_init_suggestion = loop_init_suggestion(&elem_snippet, len_snippet.as_ref(), &indentation);
             let extract_suggestion = extract_suggestion(&elem_snippet, len_snippet.as_ref(), &indentation);
@@ -109,7 +97,7 @@ fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, elem: &Expr<
                 lint_span,
                 format!("consider initializing each `{symbol_name}` element individually"),
                 loop_init_suggestion,
-                Applicability::Unspecified,
+                Applicability::HasPlaceholders,
             );
             diag.span_suggestion(
                 lint_span,
@@ -117,23 +105,33 @@ fn emit_lint(cx: &LateContext<'_>, symbol: Symbol, lint_span: Span, elem: &Expr<
                     "or if this is intentional, consider extracting the `{symbol_name}` initialization to a variable"
                 ),
                 extract_suggestion,
-                Applicability::Unspecified,
+                Applicability::HasPlaceholders,
             );
         },
     );
 }
 
-/// Checks whether the given `expr` is a call to `Arc::new` or `Rc::new`
-fn new_reference_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
+/// Checks whether the given `expr` is a call to `Arc::new`, `Rc::new`, or evaluates to a `Weak`
+fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> {
     if_chain! {
         if let ExprKind::Call(func, _args) = expr.kind;
         if let ExprKind::Path(ref func_path @ QPath::TypeRelative(ty, _)) = func.kind;
         if let TyKind::Path(ref ty_path) = ty.kind;
         if let Some(def_id) = cx.qpath_res(ty_path, ty.hir_id).opt_def_id();
-        if last_path_segment(func_path).ident.name == sym::new;
 
         then {
-            return cx.tcx.get_diagnostic_name(def_id).filter(|symbol| symbol == &sym::Arc || symbol == &sym::Rc);
+            if last_path_segment(func_path).ident.name == sym::new
+                && let Some(symbol) = cx
+                    .tcx
+                    .get_diagnostic_name(def_id)
+                    .filter(|symbol| symbol == &sym::Arc || symbol == &sym::Rc) {
+                return Some((symbol, func.span));
+            }
+
+            let ty_path = cx.typeck_results().expr_ty(expr);
+            if match_type(cx, ty_path, &paths::WEAK_RC) || match_type(cx, ty_path, &paths::WEAK_ARC) {
+                return Some((Symbol::intern("Weak"), func.span));
+            }
         }
     }
 
diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs
index ab16fe47d4d..249f11f9850 100644
--- a/clippy_lints/src/redundant_clone.rs
+++ b/clippy_lints/src/redundant_clone.rs
@@ -288,8 +288,8 @@ fn is_call_with_ref_arg<'tcx>(
         if let mir::TerminatorKind::Call { func, args, destination, .. } = kind;
         if args.len() == 1;
         if let mir::Operand::Move(mir::Place { local, .. }) = &args[0];
-        if let ty::FnDef(def_id, _) = *func.ty(&*mir, cx.tcx).kind();
-        if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(&*mir, cx.tcx));
+        if let ty::FnDef(def_id, _) = *func.ty(mir, cx.tcx).kind();
+        if let (inner_ty, 1) = walk_ptrs_ty_depth(args[0].ty(mir, cx.tcx));
         if !is_copy(cx, inner_ty);
         then {
             Some((def_id, *local, inner_ty, destination.as_local()?))
@@ -318,7 +318,7 @@ fn find_stmt_assigns_to<'tcx>(
         None
     })?;
 
-    match (by_ref, &*rvalue) {
+    match (by_ref, rvalue) {
         (true, mir::Rvalue::Ref(_, _, place)) | (false, mir::Rvalue::Use(mir::Operand::Copy(place))) => {
             Some(base_local_and_movability(cx, mir, *place))
         },
diff --git a/clippy_lints/src/redundant_static_lifetimes.rs b/clippy_lints/src/redundant_static_lifetimes.rs
index 2d26c49252f..0825f00f421 100644
--- a/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/clippy_lints/src/redundant_static_lifetimes.rs
@@ -51,12 +51,12 @@ impl RedundantStaticLifetimes {
     fn visit_type(&mut self, ty: &Ty, cx: &EarlyContext<'_>, reason: &str) {
         match ty.kind {
             // Be careful of nested structures (arrays and tuples)
-            TyKind::Array(ref ty, _) => {
-                self.visit_type(&*ty, cx, reason);
+            TyKind::Array(ref ty, _) | TyKind::Slice(ref ty) => {
+                self.visit_type(ty, cx, reason);
             },
             TyKind::Tup(ref tup) => {
                 for tup_ty in tup {
-                    self.visit_type(&*tup_ty, cx, reason);
+                    self.visit_type(tup_ty, cx, reason);
                 }
             },
             // This is what we are looking for !
@@ -89,9 +89,6 @@ impl RedundantStaticLifetimes {
                 }
                 self.visit_type(&*borrow_type.ty, cx, reason);
             },
-            TyKind::Slice(ref ty) => {
-                self.visit_type(ty, cx, reason);
-            },
             _ => {},
         }
     }
diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs
index 8068fa22d9c..e525eba53e2 100644
--- a/clippy_lints/src/returns.rs
+++ b/clippy_lints/src/returns.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::snippet_opt;
+use clippy_utils::source::{snippet_opt, snippet_with_context};
 use clippy_utils::{fn_def_id, path_to_local_id};
 use if_chain::if_chain;
 use rustc_ast::ast::Attribute;
@@ -226,14 +226,10 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Spa
     }
     match inner_span {
         Some(inner_span) => {
-            if in_external_macro(cx.tcx.sess, inner_span) || inner_span.from_expansion() {
-                return;
-            }
-
+            let mut applicability = Applicability::MachineApplicable;
             span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
-                if let Some(snippet) = snippet_opt(cx, inner_span) {
-                    diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
-                }
+                let (snippet, _) = snippet_with_context(cx, inner_span, ret_span.ctxt(), "..", &mut applicability);
+                diag.span_suggestion(ret_span, "remove `return`", snippet, applicability);
             });
         },
         None => match replacement {
@@ -287,7 +283,7 @@ struct BorrowVisitor<'a, 'tcx> {
 
 impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if self.borrows {
+        if self.borrows || expr.span.from_expansion() {
             return;
         }
 
diff --git a/clippy_lints/src/same_name_method.rs b/clippy_lints/src/same_name_method.rs
index c5c174cc8f6..9158cbcc04e 100644
--- a/clippy_lints/src/same_name_method.rs
+++ b/clippy_lints/src/same_name_method.rs
@@ -54,11 +54,11 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
             if matches!(cx.tcx.def_kind(id.def_id), DefKind::Impl)
                 && let item = cx.tcx.hir().item(id)
                 && let ItemKind::Impl(Impl {
-                  items,
-                  of_trait,
-                  self_ty,
-                  ..
-                                      }) = &item.kind
+                    items,
+                    of_trait,
+                    self_ty,
+                    ..
+                }) = &item.kind
                 && let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
             {
                 if !map.contains_key(res) {
diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs
index 2a80e6f918d..4f74c1e44c2 100644
--- a/clippy_lints/src/shadow.rs
+++ b/clippy_lints/src/shadow.rs
@@ -5,9 +5,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::hir_id::ItemLocalId;
-use rustc_hir::{
-    Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp,
-};
+use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, Let, Node, Pat, PatKind, QPath, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{Span, Symbol};
@@ -141,31 +139,34 @@ impl<'tcx> LateLintPass<'tcx> for Shadow {
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
         let hir = cx.tcx.hir();
-        if !matches!(hir.body_owner_kind(hir.body_owner_def_id(body.id())), BodyOwnerKind::Closure)
-        {
+        if !matches!(
+            hir.body_owner_kind(hir.body_owner_def_id(body.id())),
+            BodyOwnerKind::Closure
+        ) {
             self.bindings.push(FxHashMap::default());
         }
     }
 
     fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
         let hir = cx.tcx.hir();
-        if !matches!(hir.body_owner_kind(hir.body_owner_def_id(body.id())), BodyOwnerKind::Closure)
-        {
+        if !matches!(
+            hir.body_owner_kind(hir.body_owner_def_id(body.id())),
+            BodyOwnerKind::Closure
+        ) {
             self.bindings.pop();
         }
     }
 }
 
-fn is_shadow(
-    cx: &LateContext<'_>,
-    owner: LocalDefId,
-    first: ItemLocalId,
-    second: ItemLocalId,
-) -> bool {
-    let scope_tree = cx.tcx.region_scope_tree(owner);
-    let first_scope = scope_tree.var_scope(first).unwrap();
-    let second_scope = scope_tree.var_scope(second).unwrap();
-    scope_tree.is_subscope_of(second_scope, first_scope)
+fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second: ItemLocalId) -> bool {
+    let scope_tree = cx.tcx.region_scope_tree(owner.to_def_id());
+    if let Some(first_scope) = scope_tree.var_scope(first) {
+        if let Some(second_scope) = scope_tree.var_scope(second) {
+            return scope_tree.is_subscope_of(second_scope, first_scope);
+        }
+    }
+
+    false
 }
 
 fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span) {
@@ -177,16 +178,15 @@ fn lint_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, shadowed: HirId, span: Span)
                 snippet(cx, expr.span, "..")
             );
             (SHADOW_SAME, msg)
-        }
+        },
         Some(expr) if is_local_used(cx, expr, shadowed) => {
             let msg = format!("`{}` is shadowed", snippet(cx, pat.span, "_"));
             (SHADOW_REUSE, msg)
-        }
+        },
         _ => {
-            let msg =
-                format!("`{}` shadows a previous, unrelated binding", snippet(cx, pat.span, "_"));
+            let msg = format!("`{}` shadows a previous, unrelated binding", snippet(cx, pat.span, "_"));
             (SHADOW_UNRELATED, msg)
-        }
+        },
     };
     span_lint_and_note(
         cx,
@@ -215,7 +215,14 @@ fn is_self_shadow(cx: &LateContext<'_>, pat: &Pat<'_>, mut expr: &Expr<'_>, hir_
         expr = match expr.kind {
             ExprKind::Box(e)
             | ExprKind::AddrOf(_, _, e)
-            | ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _)
+            | ExprKind::Block(
+                &Block {
+                    stmts: [],
+                    expr: Some(e),
+                    ..
+                },
+                _,
+            )
             | ExprKind::Unary(UnOp::Deref, e) => e,
             ExprKind::Path(QPath::Resolved(None, path)) => break path.res == Res::Local(hir_id),
             _ => break false,
diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs
index 3d7dc49b406..bfb9f0d01e1 100644
--- a/clippy_lints/src/size_of_in_element_count.rs
+++ b/clippy_lints/src/size_of_in_element_count.rs
@@ -110,7 +110,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
         // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods
         if let ExprKind::MethodCall(method_path, [ptr_self, .., count], _) = expr.kind;
         let method_ident = method_path.ident.as_str();
-        if METHODS.iter().any(|m| *m == &*method_ident);
+        if METHODS.iter().any(|m| *m == method_ident);
 
         // Get the pointee type
         if let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) =
diff --git a/clippy_lints/src/swap_ptr_to_ref.rs b/clippy_lints/src/swap_ptr_to_ref.rs
new file mode 100644
index 00000000000..75d3b040c96
--- /dev/null
+++ b/clippy_lints/src/swap_ptr_to_ref.rs
@@ -0,0 +1,80 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::{match_def_path, path_def_id, paths};
+use rustc_errors::Applicability;
+use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{Span, SyntaxContext};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `core::mem::swap` where either parameter is derived from a pointer
+    ///
+    /// ### Why is this bad?
+    /// When at least one parameter to `swap` is derived from a pointer it may overlap with the
+    /// other. This would then lead to undefined behavior.
+    ///
+    /// ### Example
+    /// ```rust
+    /// unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) {
+    ///     for (&x, &y) in x.iter().zip(y) {
+    ///         core::mem::swap(&mut *x, &mut *y);
+    ///     }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) {
+    ///     for (&x, &y) in x.iter().zip(y) {
+    ///         core::ptr::swap(x, y);
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub SWAP_PTR_TO_REF,
+    suspicious,
+    "call to `mem::swap` using pointer derived references"
+}
+declare_lint_pass!(SwapPtrToRef => [SWAP_PTR_TO_REF]);
+
+impl LateLintPass<'_> for SwapPtrToRef {
+    fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
+        if let ExprKind::Call(fn_expr, [arg1, arg2]) = e.kind
+            && let Some(fn_id) = path_def_id(cx, fn_expr)
+            && match_def_path(cx, fn_id, &paths::MEM_SWAP)
+            && let ctxt = e.span.ctxt()
+            && let (from_ptr1, arg1_span) = is_ptr_to_ref(cx, arg1, ctxt)
+            && let (from_ptr2, arg2_span) = is_ptr_to_ref(cx, arg2, ctxt)
+            && (from_ptr1 || from_ptr2)
+        {
+            span_lint_and_then(
+                cx,
+                SWAP_PTR_TO_REF,
+                e.span,
+                "call to `core::mem::swap` with a parameter derived from a raw pointer",
+                |diag| {
+                    if !((from_ptr1 && arg1_span.is_none()) || (from_ptr2 && arg2_span.is_none())) {
+                        let mut app = Applicability::MachineApplicable;
+                        let snip1 = snippet_with_context(cx, arg1_span.unwrap_or(arg1.span), ctxt, "..", &mut app).0;
+                        let snip2 = snippet_with_context(cx, arg2_span.unwrap_or(arg2.span), ctxt, "..", &mut app).0;
+                        diag.span_suggestion(e.span, "use ptr::swap", format!("core::ptr::swap({}, {})", snip1, snip2), app);
+                    }
+                }
+            );
+        }
+    }
+}
+
+/// Checks if the expression converts a mutable pointer to a mutable reference. If it is, also
+/// returns the span of the pointer expression if it's suitable for making a suggestion.
+fn is_ptr_to_ref(cx: &LateContext<'_>, e: &Expr<'_>, ctxt: SyntaxContext) -> (bool, Option<Span>) {
+    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, borrowed_expr) = e.kind
+        && let ExprKind::Unary(UnOp::Deref, derefed_expr) = borrowed_expr.kind
+        && cx.typeck_results().expr_ty(derefed_expr).is_unsafe_ptr()
+    {
+        (true, (borrowed_expr.span.ctxt() == ctxt || derefed_expr.span.ctxt() == ctxt).then(|| derefed_expr.span))
+    } else {
+        (false, None)
+    }
+}
diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 911da3997ae..b91be0eb4be 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -36,7 +36,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.38.0"]
     pub TYPE_REPETITION_IN_BOUNDS,
-    pedantic,
+    nursery,
     "Types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`"
 }
 
@@ -54,19 +54,19 @@ declare_clippy_lint! {
     /// fn func<T: Clone + Default>(arg: T) where T: Clone + Default {}
     /// ```
     ///
-    /// Could be written as:
-    ///
+    /// Use instead:
     /// ```rust
+    /// # mod hidden {
     /// fn func<T: Clone + Default>(arg: T) {}
-    /// ```
-    /// or
+    /// # }
+    ///
+    /// // or
     ///
-    /// ```rust
     /// fn func<T>(arg: T) where T: Clone + Default {}
     /// ```
     #[clippy::version = "1.47.0"]
     pub TRAIT_DUPLICATION_IN_BOUNDS,
-    pedantic,
+    nursery,
     "Check if the same trait bounds are specified twice during a function declaration"
 }
 
diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs
index d2a040beb0c..cbe1406728b 100644
--- a/clippy_lints/src/transmute/mod.rs
+++ b/clippy_lints/src/transmute/mod.rs
@@ -59,7 +59,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub USELESS_TRANSMUTE,
-    nursery,
+    complexity,
     "transmutes that have the same to and from types or could be a cast/coercion"
 }
 
diff --git a/clippy_lints/src/transmute/useless_transmute.rs b/clippy_lints/src/transmute/useless_transmute.rs
index 3cc3d40a143..a0d104e2390 100644
--- a/clippy_lints/src/transmute/useless_transmute.rs
+++ b/clippy_lints/src/transmute/useless_transmute.rs
@@ -4,7 +4,7 @@ use clippy_utils::sugg;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TypeFoldable};
 
 /// Checks for `useless_transmute` lint.
 /// Returns `true` if it's triggered, otherwise returns `false`.
@@ -16,7 +16,7 @@ pub(super) fn check<'tcx>(
     arg: &'tcx Expr<'_>,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
-        _ if from_ty == to_ty => {
+        _ if from_ty == to_ty && !from_ty.has_erased_regions() => {
             span_lint(
                 cx,
                 USELESS_TRANSMUTE,
@@ -26,28 +26,31 @@ pub(super) fn check<'tcx>(
             true
         },
         (ty::Ref(_, rty, rty_mutbl), ty::RawPtr(ptr_ty)) => {
-            span_lint_and_then(
-                cx,
-                USELESS_TRANSMUTE,
-                e.span,
-                "transmute from a reference to a pointer",
-                |diag| {
-                    if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
-                        let rty_and_mut = ty::TypeAndMut {
-                            ty: *rty,
-                            mutbl: *rty_mutbl,
-                        };
+            // No way to give the correct suggestion here. Avoid linting for now.
+            if !rty.has_erased_regions() {
+                span_lint_and_then(
+                    cx,
+                    USELESS_TRANSMUTE,
+                    e.span,
+                    "transmute from a reference to a pointer",
+                    |diag| {
+                        if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
+                            let rty_and_mut = ty::TypeAndMut {
+                                ty: *rty,
+                                mutbl: *rty_mutbl,
+                            };
 
-                        let sugg = if *ptr_ty == rty_and_mut {
-                            arg.as_ty(to_ty)
-                        } else {
-                            arg.as_ty(cx.tcx.mk_ptr(rty_and_mut)).as_ty(to_ty)
-                        };
+                            let sugg = if *ptr_ty == rty_and_mut {
+                                arg.as_ty(to_ty)
+                            } else {
+                                arg.as_ty(cx.tcx.mk_ptr(rty_and_mut)).as_ty(to_ty)
+                            };
 
-                        diag.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified);
-                    }
-                },
-            );
+                            diag.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified);
+                        }
+                    },
+                );
+            }
             true
         },
         (ty::Int(_) | ty::Uint(_), ty::RawPtr(_)) => {
diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs
deleted file mode 100644
index e108f7be12e..00000000000
--- a/clippy_lints/src/try_err.rs
+++ /dev/null
@@ -1,186 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{get_parent_expr, is_lang_ctor, match_def_path, paths};
-use if_chain::if_chain;
-use rustc_errors::Applicability;
-use rustc_hir::LangItem::ResultErr;
-use rustc_hir::{Expr, ExprKind, LangItem, MatchSource, QPath};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Ty};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{hygiene, sym};
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for usages of `Err(x)?`.
-    ///
-    /// ### Why is this bad?
-    /// The `?` operator is designed to allow calls that
-    /// can fail to be easily chained. For example, `foo()?.bar()` or
-    /// `foo(bar()?)`. Because `Err(x)?` can't be used that way (it will
-    /// always return), it is more clear to write `return Err(x)`.
-    ///
-    /// ### Example
-    /// ```rust
-    /// fn foo(fail: bool) -> Result<i32, String> {
-    ///     if fail {
-    ///       Err("failed")?;
-    ///     }
-    ///     Ok(0)
-    /// }
-    /// ```
-    /// Could be written:
-    ///
-    /// ```rust
-    /// fn foo(fail: bool) -> Result<i32, String> {
-    ///     if fail {
-    ///       return Err("failed".into());
-    ///     }
-    ///     Ok(0)
-    /// }
-    /// ```
-    #[clippy::version = "1.38.0"]
-    pub TRY_ERR,
-    restriction,
-    "return errors explicitly rather than hiding them behind a `?`"
-}
-
-declare_lint_pass!(TryErr => [TRY_ERR]);
-
-impl<'tcx> LateLintPass<'tcx> for TryErr {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        // Looks for a structure like this:
-        // match ::std::ops::Try::into_result(Err(5)) {
-        //     ::std::result::Result::Err(err) =>
-        //         #[allow(unreachable_code)]
-        //         return ::std::ops::Try::from_error(::std::convert::From::from(err)),
-        //     ::std::result::Result::Ok(val) =>
-        //         #[allow(unreachable_code)]
-        //         val,
-        // };
-        if_chain! {
-            if !in_external_macro(cx.tcx.sess, expr.span);
-            if let ExprKind::Match(match_arg, _, MatchSource::TryDesugar) = expr.kind;
-            if let ExprKind::Call(match_fun, try_args) = match_arg.kind;
-            if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
-            if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..));
-            if let Some(try_arg) = try_args.get(0);
-            if let ExprKind::Call(err_fun, err_args) = try_arg.kind;
-            if let Some(err_arg) = err_args.get(0);
-            if let ExprKind::Path(ref err_fun_path) = err_fun.kind;
-            if is_lang_ctor(cx, err_fun_path, ResultErr);
-            if let Some(return_ty) = find_return_type(cx, &expr.kind);
-            then {
-                let prefix;
-                let suffix;
-                let err_ty;
-
-                if let Some(ty) = result_error_type(cx, return_ty) {
-                    prefix = "Err(";
-                    suffix = ")";
-                    err_ty = ty;
-                } else if let Some(ty) = poll_result_error_type(cx, return_ty) {
-                    prefix = "Poll::Ready(Err(";
-                    suffix = "))";
-                    err_ty = ty;
-                } else if let Some(ty) = poll_option_result_error_type(cx, return_ty) {
-                    prefix = "Poll::Ready(Some(Err(";
-                    suffix = ")))";
-                    err_ty = ty;
-                } else {
-                    return;
-                };
-
-                let expr_err_ty = cx.typeck_results().expr_ty(err_arg);
-                let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt());
-                let mut applicability = Applicability::MachineApplicable;
-                let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability);
-                let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) {
-                    "" // already returns
-                } else {
-                    "return "
-                };
-                let suggestion = if err_ty == expr_err_ty {
-                    format!("{}{}{}{}", ret_prefix, prefix, origin_snippet, suffix)
-                } else {
-                    format!("{}{}{}.into(){}", ret_prefix, prefix, origin_snippet, suffix)
-                };
-
-                span_lint_and_sugg(
-                    cx,
-                    TRY_ERR,
-                    expr.span,
-                    "returning an `Err(_)` with the `?` operator",
-                    "try this",
-                    suggestion,
-                    applicability,
-                );
-            }
-        }
-    }
-}
-
-/// Finds function return type by examining return expressions in match arms.
-fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> Option<Ty<'tcx>> {
-    if let ExprKind::Match(_, arms, MatchSource::TryDesugar) = expr {
-        for arm in arms.iter() {
-            if let ExprKind::Ret(Some(ret)) = arm.body.kind {
-                return Some(cx.typeck_results().expr_ty(ret));
-            }
-        }
-    }
-    None
-}
-
-/// Extracts the error type from Result<T, E>.
-fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
-    if_chain! {
-        if let ty::Adt(_, subst) = ty.kind();
-        if is_type_diagnostic_item(cx, ty, sym::Result);
-        then {
-            Some(subst.type_at(1))
-        } else {
-            None
-        }
-    }
-}
-
-/// Extracts the error type from Poll<Result<T, E>>.
-fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
-    if_chain! {
-        if let ty::Adt(def, subst) = ty.kind();
-        if match_def_path(cx, def.did(), &paths::POLL);
-        let ready_ty = subst.type_at(0);
-
-        if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
-        if cx.tcx.is_diagnostic_item(sym::Result, ready_def.did());
-        then {
-            Some(ready_subst.type_at(1))
-        } else {
-            None
-        }
-    }
-}
-
-/// Extracts the error type from Poll<Option<Result<T, E>>>.
-fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
-    if_chain! {
-        if let ty::Adt(def, subst) = ty.kind();
-        if match_def_path(cx, def.did(), &paths::POLL);
-        let ready_ty = subst.type_at(0);
-
-        if let ty::Adt(ready_def, ready_subst) = ready_ty.kind();
-        if cx.tcx.is_diagnostic_item(sym::Option, ready_def.did());
-        let some_ty = ready_subst.type_at(0);
-
-        if let ty::Adt(some_def, some_subst) = some_ty.kind();
-        if cx.tcx.is_diagnostic_item(sym::Result, some_def.did());
-        then {
-            Some(some_subst.type_at(1))
-        } else {
-            None
-        }
-    }
-}
diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs
new file mode 100644
index 00000000000..306afe44148
--- /dev/null
+++ b/clippy_lints/src/unused_rounding.rs
@@ -0,0 +1,69 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::ast::{Expr, ExprKind, LitFloatType, LitKind};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Detects cases where a whole-number literal float is being rounded, using
+    /// the `floor`, `ceil`, or `round` methods.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// This is unnecessary and confusing to the reader. Doing this is probably a mistake.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x = 1f32.ceil();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let x = 1f32;
+    /// ```
+    #[clippy::version = "1.62.0"]
+    pub UNUSED_ROUNDING,
+    nursery,
+    "Uselessly rounding a whole number floating-point literal"
+}
+declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
+
+fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> {
+    if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind
+        && let method_name = name_ident.ident.name.as_str()
+        && (method_name == "ceil" || method_name == "round" || method_name == "floor")
+        && !args.is_empty()
+        && let ExprKind::Lit(spanned) = &args[0].kind
+        && let LitKind::Float(symbol, ty) = spanned.kind {
+            let f = symbol.as_str().parse::<f64>().unwrap();
+            let f_str = symbol.to_string() + if let LitFloatType::Suffixed(ty) = ty {
+                ty.name_str()
+            } else {
+                ""
+            };
+            if f.fract() == 0.0 {
+                Some((method_name, f_str))
+            } else {
+                None
+            }
+        } else {
+            None
+        }
+}
+
+impl EarlyLintPass for UnusedRounding {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        if let Some((method_name, float)) = is_useless_rounding(expr) {
+            span_lint_and_sugg(
+                cx,
+                UNUSED_ROUNDING,
+                expr.span,
+                &format!("used the `{}` method with a whole number float", method_name),
+                &format!("remove the `{}` method call", method_name),
+                float,
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs
index 66f7748e9e0..486ea5e5ccf 100644
--- a/clippy_lints/src/use_self.rs
+++ b/clippy_lints/src/use_self.rs
@@ -258,13 +258,21 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             if !pat.span.from_expansion();
             if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
             if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
-            if let PatKind::Path(QPath::Resolved(_, path)) = pat.kind;
-            if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _));
+            // get the path from the pattern
+            if let PatKind::Path(QPath::Resolved(_, path))
+                 | PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
+                 | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind;
             if cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id);
-            if let [first, ..] = path.segments;
-            if let Some(hir_id) = first.hir_id;
             then {
-                span_lint(cx, cx.tcx.hir().span(hir_id));
+                match path.res {
+                    Res::Def(DefKind::Ctor(ctor_of, _), ..) => match ctor_of {
+                            CtorOf::Variant => lint_path_to_variant(cx, path),
+                            CtorOf::Struct => span_lint(cx, path.span),
+                    },
+                    Res::Def(DefKind::Variant, ..) => lint_path_to_variant(cx, path),
+                    Res::Def(DefKind::Struct, ..) => span_lint(cx, path.span),
+                    _ => ()
+                }
             }
         }
     }
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index cd4d16fe95f..b5c5d35135f 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -340,6 +340,10 @@ define_Conf! {
     ///
     /// Whether `unwrap` should be allowed in test functions
     (allow_unwrap_in_tests: bool = false),
+    /// Lint: DBG_MACRO.
+    ///
+    /// Whether `dbg!` should be allowed in test functions
+    (allow_dbg_in_tests: bool = false),
 }
 
 /// Search for the configuration file.
diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs
index 0e8f40e9210..60f98876994 100644
--- a/clippy_lints/src/utils/internal_lints.rs
+++ b/clippy_lints/src/utils/internal_lints.rs
@@ -422,7 +422,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
             }
         } else if let Some(macro_call) = root_macro_call_first_node(cx, item) {
             if !matches!(
-                &*cx.tcx.item_name(macro_call.def_id).as_str(),
+                cx.tcx.item_name(macro_call.def_id).as_str(),
                 "impl_lint_pass" | "declare_lint_pass"
             ) {
                 return;
@@ -504,7 +504,7 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'
             return;
         }
 
-        if RustcVersion::parse(&*value.as_str()).is_err() {
+        if RustcVersion::parse(value.as_str()).is_err() {
             span_lint_and_help(
                 cx,
                 INVALID_CLIPPY_VERSION_ATTRIBUTE,
@@ -595,7 +595,7 @@ impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
         if_chain! {
             if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind;
             let fn_name = path.ident;
-            if let Some(sugg) = self.map.get(&*fn_name.as_str());
+            if let Some(sugg) = self.map.get(fn_name.as_str());
             let ty = cx.typeck_results().expr_ty(self_arg).peel_refs();
             if match_type(cx, ty, &paths::EARLY_CONTEXT)
                 || match_type(cx, ty, &paths::LATE_CONTEXT);
@@ -679,7 +679,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleCalls {
             then {
                 let and_then_snippets = get_and_then_snippets(cx, and_then_args);
                 let mut sle = SpanlessEq::new(cx).deny_side_effects();
-                match &*ps.ident.as_str() {
+                match ps.ident.as_str() {
                     "span_suggestion" if sle.eq_expr(&and_then_args[2], &span_call_args[1]) => {
                         suggest_suggestion(cx, expr, &and_then_snippets, &span_suggestion_snippets(cx, span_call_args));
                     },
diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 8c1910b3b2a..cf2de6a42af 100644
--- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -7,6 +7,7 @@
 //! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
 //! a simple mistake)
 
+use crate::renamed_lints::RENAMED_LINTS;
 use crate::utils::internal_lints::{extract_clippy_version_value, is_lint_ref_type};
 
 use clippy_utils::diagnostics::span_lint;
@@ -26,6 +27,7 @@ use rustc_span::{sym, Loc, Span, Symbol};
 use serde::{ser::SerializeStruct, Serialize, Serializer};
 use std::collections::BinaryHeap;
 use std::fmt;
+use std::fmt::Write as _;
 use std::fs::{self, OpenOptions};
 use std::io::prelude::*;
 use std::path::Path;
@@ -85,6 +87,21 @@ macro_rules! CONFIGURATION_VALUE_TEMPLATE {
     };
 }
 
+macro_rules! RENAMES_SECTION_TEMPLATE {
+    () => {
+        r#"
+### Past names
+
+{names}
+"#
+    };
+}
+macro_rules! RENAME_VALUE_TEMPLATE {
+    () => {
+        "* `{name}`\n"
+    };
+}
+
 const LINT_EMISSION_FUNCTIONS: [&[&str]; 8] = [
     &["clippy_utils", "diagnostics", "span_lint"],
     &["clippy_utils", "diagnostics", "span_lint_and_help"],
@@ -198,9 +215,10 @@ impl Drop for MetadataCollector {
 
         // Mapping the final data
         let mut lints = std::mem::take(&mut self.lints).into_sorted_vec();
-        lints
-            .iter_mut()
-            .for_each(|x| x.applicability = Some(applicability_info.remove(&x.id).unwrap_or_default()));
+        collect_renames(&mut lints);
+        for x in &mut lints {
+            x.applicability = Some(applicability_info.remove(&x.id).unwrap_or_default());
+        }
 
         // Outputting
         if Path::new(OUTPUT_FILE).exists() {
@@ -527,12 +545,11 @@ fn extract_attr_docs_or_lint(cx: &LateContext<'_>, item: &Item<'_>) -> Option<St
 fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
     let attrs = cx.tcx.hir().attrs(item.hir_id());
     let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str);
-    let mut docs = String::from(&*lines.next()?.as_str());
+    let mut docs = String::from(lines.next()?.as_str());
     let mut in_code_block = false;
     let mut is_code_block_rust = false;
     for line in lines {
         let line = line.as_str();
-        let line = &*line;
 
         // Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :)
         if is_code_block_rust && line.trim_start().starts_with("# ") {
@@ -643,6 +660,37 @@ fn is_deprecated_lint(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
     false
 }
 
+fn collect_renames(lints: &mut Vec<LintMetadata>) {
+    for lint in lints {
+        let mut collected = String::new();
+        let mut names = vec![lint.id.clone()];
+
+        loop {
+            if let Some(lint_name) = names.pop() {
+                for (k, v) in RENAMED_LINTS {
+                    if_chain! {
+                        if let Some(name) = v.strip_prefix(CLIPPY_LINT_GROUP_PREFIX);
+                        if name == lint_name;
+                        if let Some(past_name) = k.strip_prefix(CLIPPY_LINT_GROUP_PREFIX);
+                        then {
+                            write!(collected, RENAME_VALUE_TEMPLATE!(), name = past_name).unwrap();
+                            names.push(past_name.to_string());
+                        }
+                    }
+                }
+
+                continue;
+            }
+
+            break;
+        }
+
+        if !collected.is_empty() {
+            write!(&mut lint.docs, RENAMES_SECTION_TEMPLATE!(), names = collected).unwrap();
+        }
+    }
+}
+
 // ==================================================================
 // Lint emission
 // ==================================================================
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index 9f162a117b2..d487868cafe 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -478,7 +478,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
     fn ifthenelse(&mut self, cond: &Expr<'_>, then: &Expr<'_>, otherwise: Option<&Expr<'_>>) -> Option<Constant> {
         if let Some(Constant::Bool(b)) = self.expr(cond) {
             if b {
-                self.expr(&*then)
+                self.expr(then)
             } else {
                 otherwise.as_ref().and_then(|expr| self.expr(expr))
             }
diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs
index 39595f589c7..0f8e9ab0cd9 100644
--- a/clippy_utils/src/diagnostics.rs
+++ b/clippy_utils/src/diagnostics.rs
@@ -155,13 +155,7 @@ where
     });
 }
 
-pub fn span_lint_hir(
-    cx: &LateContext<'_>,
-    lint: &'static Lint,
-    hir_id: HirId,
-    sp: Span,
-    msg: &str,
-) {
+pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
     cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
         let mut diag = diag.build(msg);
         docs_link(&mut diag, lint);
@@ -278,9 +272,7 @@ pub fn span_lint_and_sugg_for_edges(
         let sugg_lines_count = sugg.lines().count();
         if sugg_lines_count > MAX_SUGGESTION_HIGHLIGHT_LINES {
             let sm = cx.sess().source_map();
-            if let (Ok(line_upper), Ok(line_bottom)) =
-                (sm.lookup_line(sp.lo()), sm.lookup_line(sp.hi()))
-            {
+            if let (Ok(line_upper), Ok(line_bottom)) = (sm.lookup_line(sp.lo()), sm.lookup_line(sp.hi())) {
                 let split_idx = MAX_SUGGESTION_HIGHLIGHT_LINES / 2;
                 let span_upper = sm.span_until_char(
                     sp.with_hi(line_upper.sf.lines(|lines| lines[line_upper.line + split_idx])),
diff --git a/clippy_utils/src/higher.rs b/clippy_utils/src/higher.rs
index 1e0fc789af2..4604ae5c2c7 100644
--- a/clippy_utils/src/higher.rs
+++ b/clippy_utils/src/higher.rs
@@ -35,7 +35,7 @@ impl<'tcx> ForLoop<'tcx> {
             if let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind;
             if let hir::ExprKind::Call(_, [arg]) = iterexpr.kind;
             if let hir::ExprKind::Loop(block, ..) = arm.body.kind;
-            if let [stmt] = &*block.stmts;
+            if let [stmt] = block.stmts;
             if let hir::StmtKind::Expr(e) = stmt.kind;
             if let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind;
             if let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind;
diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs
index fc1a4e1f602..0603471c343 100644
--- a/clippy_utils/src/hir_utils.rs
+++ b/clippy_utils/src/hir_utils.rs
@@ -411,10 +411,10 @@ impl HirEqInterExpr<'_, '_, '_> {
             (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
             (&TyKind::Array(lt, ll), &TyKind::Array(rt, rl)) => self.eq_ty(lt, rt) && self.eq_array_length(ll, rl),
             (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
-                l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
+                l_mut.mutbl == r_mut.mutbl && self.eq_ty(l_mut.ty, r_mut.ty)
             },
             (&TyKind::Rptr(_, ref l_rmut), &TyKind::Rptr(_, ref r_rmut)) => {
-                l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
+                l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(l_rmut.ty, r_rmut.ty)
             },
             (&TyKind::Path(ref l), &TyKind::Path(ref r)) => self.eq_qpath(l, r),
             (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
@@ -608,7 +608,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_name(i.ident.name);
                 }
                 if let Some(j) = *j {
-                    self.hash_expr(&*j);
+                    self.hash_expr(j);
                 }
             },
             ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => {
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 833f8cde63a..5f051e3f444 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -1443,7 +1443,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
         },
         PatKind::Tuple(pats, _) => are_refutable(cx, pats),
         PatKind::Struct(ref qpath, fields, _) => {
-            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
+            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| field.pat))
         },
         PatKind::TupleStruct(ref qpath, pats, _) => is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats),
         PatKind::Slice(head, middle, tail) => {
@@ -1658,7 +1658,7 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
     let mut blocks: Vec<&Block<'_>> = Vec::new();
 
     while let Some(higher::IfOrIfLet { cond, then, r#else }) = higher::IfOrIfLet::hir(expr) {
-        conds.push(&*cond);
+        conds.push(cond);
         if let ExprKind::Block(block, _) = then.kind {
             blocks.push(block);
         } else {
@@ -1916,7 +1916,17 @@ pub fn fn_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<DefId> {
                 ..
             },
             ..,
-        ) => cx.typeck_results().qpath_res(qpath, *path_hir_id).opt_def_id(),
+        ) => {
+            // Only return Fn-like DefIds, not the DefIds of statics/consts/etc that contain or
+            // deref to fn pointers, dyn Fn, impl Fn - #8850
+            if let Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) =
+                cx.typeck_results().qpath_res(qpath, *path_hir_id)
+            {
+                Some(id)
+            } else {
+                None
+            }
+        },
         _ => None,
     }
 }
@@ -2073,7 +2083,8 @@ static TEST_ITEM_NAMES_CACHE: SyncOnceCell<Mutex<FxHashMap<LocalDefId, Vec<Symbo
 fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
     let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
     let mut map: MutexGuard<'_, FxHashMap<LocalDefId, Vec<Symbol>>> = cache.lock().unwrap();
-    match map.entry(module) {
+    let value = map.entry(module);
+    match value {
         Entry::Occupied(entry) => f(entry.get()),
         Entry::Vacant(entry) => {
             let mut names = Vec::new();
diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs
index 134fd1ce505..b9ec2c19fdd 100644
--- a/clippy_utils/src/msrvs.rs
+++ b/clippy_utils/src/msrvs.rs
@@ -30,6 +30,7 @@ msrv_aliases! {
     1,34,0 { TRY_FROM }
     1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
     1,28,0 { FROM_BOOL }
+    1,26,0 { RANGE_INCLUSIVE }
     1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR }
     1,16,0 { STR_REPEAT }
     1,24,0 { IS_ASCII_DIGIT }
diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs
index 9b9cbff2d14..89789c3d851 100644
--- a/clippy_utils/src/paths.rs
+++ b/clippy_utils/src/paths.rs
@@ -73,6 +73,7 @@ pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
 pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"];
 #[cfg(feature = "internal")]
 pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
+pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"];
 pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"];
 pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
 /// Preferably use the diagnostic item `sym::Option` where possible
@@ -141,6 +142,7 @@ pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
 pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
 pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
 pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"];
+pub const SLICE_GET: [&str; 4] = ["core", "slice", "<impl [T]>", "get"];
 pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
 pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
 pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs
index 58abef38ea8..498dcbb8900 100644
--- a/clippy_utils/src/qualify_min_const_fn.rs
+++ b/clippy_utils/src/qualify_min_const_fn.rs
@@ -121,24 +121,18 @@ fn check_rvalue<'tcx>(
 ) -> McfResult {
     match rvalue {
         Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
-        Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => check_operand(tcx, operand, span, body),
         Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
             check_place(tcx, *place, span, body)
         },
-        Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
-            Err((span, "casting pointers to ints is unstable in const fn".into()))
-        },
-        Rvalue::Cast(CastKind::Misc, operand, _) => {
-            check_operand(tcx, operand, span, body)
-        },
-        Rvalue::Cast(
+        Rvalue::Repeat(operand, _)
+        | Rvalue::Use(operand)
+        | Rvalue::Cast(
             CastKind::PointerFromExposedAddress
+            | CastKind::Misc
             | CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
             operand,
-            _
-        ) => {
-            check_operand(tcx, operand, span, body)
-        },
+            _,
+        ) => check_operand(tcx, operand, span, body),
         Rvalue::Cast(
             CastKind::Pointer(
                 PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer,
@@ -163,6 +157,9 @@ fn check_rvalue<'tcx>(
                 Err((span, "unsizing casts are not allowed in const fn".into()))
             }
         },
+        Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => {
+            Err((span, "casting pointers to ints is unstable in const fn".into()))
+        },
         // binops are fine on integers
         Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
             check_operand(tcx, lhs, span, body)?;
diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs
index 04ef2f57447..f88a92fb11c 100644
--- a/clippy_utils/src/source.rs
+++ b/clippy_utils/src/source.rs
@@ -8,7 +8,7 @@ use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_span::hygiene;
 use rustc_span::source_map::SourceMap;
-use rustc_span::{BytePos, Pos, Span, SyntaxContext};
+use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext};
 use std::borrow::Cow;
 
 /// Checks if the span starts with the given text. This will return false if the span crosses
@@ -389,6 +389,27 @@ pub fn without_block_comments(lines: Vec<&str>) -> Vec<&str> {
     without
 }
 
+/// Trims the whitespace from the start and the end of the span.
+pub fn trim_span(sm: &SourceMap, span: Span) -> Span {
+    let data = span.data();
+    let sf: &_ = &sm.lookup_source_file(data.lo);
+    let Some(src) = sf.src.as_deref() else {
+        return span;
+    };
+    let Some(snip) = &src.get((data.lo - sf.start_pos).to_usize()..(data.hi - sf.start_pos).to_usize()) else {
+        return span;
+    };
+    let trim_start = snip.len() - snip.trim_start().len();
+    let trim_end = snip.len() - snip.trim_end().len();
+    SpanData {
+        lo: data.lo + BytePos::from_usize(trim_start),
+        hi: data.hi - BytePos::from_usize(trim_end),
+        ctxt: data.ctxt,
+        parent: data.parent,
+    }
+    .span()
+}
+
 #[cfg(test)]
 mod test {
     use super::{reindent_multiline, without_block_comments};
diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs
index 75d27d3b594..a10515d2fec 100644
--- a/clippy_utils/src/ty.rs
+++ b/clippy_utils/src/ty.rs
@@ -13,7 +13,8 @@ use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
 use rustc_middle::ty::{
-    self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy, VariantDiscr,
+    self, AdtDef, Binder, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy,
+    VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
@@ -152,17 +153,28 @@ pub fn implements_trait<'tcx>(
     trait_id: DefId,
     ty_params: &[GenericArg<'tcx>],
 ) -> bool {
+    implements_trait_with_env(cx.tcx, cx.param_env, ty, trait_id, ty_params)
+}
+
+/// Same as `implements_trait` but allows using a `ParamEnv` different from the lint context.
+pub fn implements_trait_with_env<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+    trait_id: DefId,
+    ty_params: &[GenericArg<'tcx>],
+) -> bool {
     // Clippy shouldn't have infer types
     assert!(!ty.needs_infer());
 
-    let ty = cx.tcx.erase_regions(ty);
+    let ty = tcx.erase_regions(ty);
     if ty.has_escaping_bound_vars() {
         return false;
     }
-    let ty_params = cx.tcx.mk_substs(ty_params.iter());
-    cx.tcx.infer_ctxt().enter(|infcx| {
+    let ty_params = tcx.mk_substs(ty_params.iter());
+    tcx.infer_ctxt().enter(|infcx| {
         infcx
-            .type_implements_trait(trait_id, ty, ty_params, cx.param_env)
+            .type_implements_trait(trait_id, ty, ty_params, param_env)
             .must_apply_modulo_regions()
     })
 }
diff --git a/doc/adding_lints.md b/doc/adding_lints.md
index e8f0c338fd5..3e0b1c5c4f7 100644
--- a/doc/adding_lints.md
+++ b/doc/adding_lints.md
@@ -516,11 +516,12 @@ declare_clippy_lint! {
     /// ### Example
     ///
     /// ```rust,ignore
-    /// // Bad
-    /// Insert a short example of code that triggers the lint
-    ///
-    /// // Good
-    /// Insert a short example of improved code that doesn't trigger the lint
+    /// // A short example of code that triggers the lint
+    /// ```
+    /// 
+    /// Use instead:
+    /// ```rust,ignore
+    /// // A short example of improved code that doesn't trigger the lint
     /// ```
     #[clippy::version = "1.29.0"]
     pub FOO_FUNCTIONS,
diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md
index 131ac3c3611..1d1aee0da2c 100644
--- a/doc/common_tools_writing_lints.md
+++ b/doc/common_tools_writing_lints.md
@@ -159,7 +159,8 @@ A list of defined paths for Clippy can be found in [paths.rs][paths]
 To check if our type defines a method called `some_method`:
 
 ```rust
-use clippy_utils::{is_type_diagnostic_item, return_ty};
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::return_ty;
 
 impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
diff --git a/lintcheck/Cargo.toml b/lintcheck/Cargo.toml
index e63f65ce2f7..504d58b5197 100644
--- a/lintcheck/Cargo.toml
+++ b/lintcheck/Cargo.toml
@@ -11,7 +11,7 @@ publish = false
 
 [dependencies]
 cargo_metadata = "0.14"
-clap = "2.33"
+clap = "3.1"
 flate2 = "1.0"
 rayon = "1.5.1"
 serde = { version = "1.0", features = ["derive"] }
diff --git a/lintcheck/src/config.rs b/lintcheck/src/config.rs
index de32b484360..a6f93d2a1c0 100644
--- a/lintcheck/src/config.rs
+++ b/lintcheck/src/config.rs
@@ -1,47 +1,47 @@
-use clap::{App, Arg, ArgMatches};
+use clap::{Arg, ArgMatches, Command};
 use std::env;
 use std::path::PathBuf;
 
-fn get_clap_config<'a>() -> ArgMatches<'a> {
-    App::new("lintcheck")
+fn get_clap_config() -> ArgMatches {
+    Command::new("lintcheck")
         .about("run clippy on a set of crates and check output")
         .arg(
-            Arg::with_name("only")
+            Arg::new("only")
                 .takes_value(true)
                 .value_name("CRATE")
                 .long("only")
                 .help("Only process a single crate of the list"),
         )
         .arg(
-            Arg::with_name("crates-toml")
+            Arg::new("crates-toml")
                 .takes_value(true)
                 .value_name("CRATES-SOURCES-TOML-PATH")
                 .long("crates-toml")
                 .help("Set the path for a crates.toml where lintcheck should read the sources from"),
         )
         .arg(
-            Arg::with_name("threads")
+            Arg::new("threads")
                 .takes_value(true)
                 .value_name("N")
-                .short("j")
+                .short('j')
                 .long("jobs")
                 .help("Number of threads to use, 0 automatic choice"),
         )
         .arg(
-            Arg::with_name("fix")
+            Arg::new("fix")
                 .long("--fix")
                 .help("Runs cargo clippy --fix and checks if all suggestions apply"),
         )
         .arg(
-            Arg::with_name("filter")
+            Arg::new("filter")
                 .long("--filter")
                 .takes_value(true)
-                .multiple(true)
+                .multiple_occurrences(true)
                 .value_name("clippy_lint_name")
                 .help("Apply a filter to only collect specified lints, this also overrides `allow` attributes"),
         )
         .arg(
-            Arg::with_name("markdown")
+            Arg::new("markdown")
                 .long("--markdown")
                 .help("Change the reports table to use markdown links"),
         )
diff --git a/tests/compile-test.rs b/tests/compile-test.rs
index c9710e3db8e..7d219835723 100644
--- a/tests/compile-test.rs
+++ b/tests/compile-test.rs
@@ -1,5 +1,6 @@
 #![feature(test)] // compiletest_rs requires this attribute
 #![feature(once_cell)]
+#![feature(is_sorted)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
@@ -22,6 +23,7 @@ const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal");
 
 /// All crates used in UI tests are listed here
 static TEST_DEPENDENCIES: &[&str] = &[
+    "clap",
     "clippy_utils",
     "derive_new",
     "futures",
@@ -40,6 +42,8 @@ static TEST_DEPENDENCIES: &[&str] = &[
 // Test dependencies may need an `extern crate` here to ensure that they show up
 // in the depinfo file (otherwise cargo thinks they are unused)
 #[allow(unused_extern_crates)]
+extern crate clap;
+#[allow(unused_extern_crates)]
 extern crate clippy_utils;
 #[allow(unused_extern_crates)]
 extern crate derive_new;
@@ -109,8 +113,9 @@ static EXTERN_FLAGS: SyncLazy<String> = SyncLazy::new(|| {
         not_found.is_empty(),
         "dependencies not found in depinfo: {:?}\n\
         help: Make sure the `-Z binary-dep-depinfo` rust flag is enabled\n\
-        help: Try adding to dev-dependencies in Cargo.toml",
-        not_found
+        help: Try adding to dev-dependencies in Cargo.toml\n\
+        help: Be sure to also add `extern crate ...;` to tests/compile-test.rs",
+        not_found,
     );
     crates
         .into_iter()
@@ -162,7 +167,8 @@ fn base_config(test_dir: &str) -> compiletest::Config {
 }
 
 fn run_ui() {
-    let config = base_config("ui");
+    let mut config = base_config("ui");
+    config.rustfix_coverage = true;
     // use tests/clippy.toml
     let _g = VarGuard::set("CARGO_MANIFEST_DIR", fs::canonicalize("tests").unwrap());
     let _threads = VarGuard::set(
@@ -175,6 +181,7 @@ fn run_ui() {
         }),
     );
     compiletest::run_tests(&config);
+    check_rustfix_coverage();
 }
 
 fn run_internal_tests() {
@@ -337,6 +344,88 @@ fn compile_test() {
     run_internal_tests();
 }
 
+const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[
+    "assign_ops2.rs",
+    "borrow_deref_ref_unfixable.rs",
+    "cast_size_32bit.rs",
+    "char_lit_as_u8.rs",
+    "cmp_owned/without_suggestion.rs",
+    "dbg_macro.rs",
+    "deref_addrof_double_trigger.rs",
+    "doc/unbalanced_ticks.rs",
+    "eprint_with_newline.rs",
+    "explicit_counter_loop.rs",
+    "iter_skip_next_unfixable.rs",
+    "let_and_return.rs",
+    "literals.rs",
+    "map_flatten.rs",
+    "map_unwrap_or.rs",
+    "match_bool.rs",
+    "mem_replace_macro.rs",
+    "needless_arbitrary_self_type_unfixable.rs",
+    "needless_borrow_pat.rs",
+    "needless_for_each_unfixable.rs",
+    "nonminimal_bool.rs",
+    "print_literal.rs",
+    "print_with_newline.rs",
+    "redundant_static_lifetimes_multiple.rs",
+    "ref_binding_to_reference.rs",
+    "repl_uninit.rs",
+    "result_map_unit_fn_unfixable.rs",
+    "search_is_some.rs",
+    "single_component_path_imports_nested_first.rs",
+    "string_add.rs",
+    "toplevel_ref_arg_non_rustfix.rs",
+    "unit_arg.rs",
+    "unnecessary_clone.rs",
+    "unnecessary_lazy_eval_unfixable.rs",
+    "write_literal.rs",
+    "write_literal_2.rs",
+    "write_with_newline.rs",
+];
+
+fn check_rustfix_coverage() {
+    let missing_coverage_path = Path::new("target/debug/test/ui/rustfix_missing_coverage.txt");
+
+    if let Ok(missing_coverage_contents) = std::fs::read_to_string(missing_coverage_path) {
+        assert!(RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS.iter().is_sorted_by_key(Path::new));
+
+        for rs_path in missing_coverage_contents.lines() {
+            if Path::new(rs_path).starts_with("tests/ui/crashes") {
+                continue;
+            }
+            let filename = Path::new(rs_path).strip_prefix("tests/ui/").unwrap();
+            assert!(
+                RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS
+                    .binary_search_by_key(&filename, Path::new)
+                    .is_ok(),
+                "`{}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \
+                Please either add `// run-rustfix` at the top of the file or add the file to \
+                `RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS` in `tests/compile-test.rs`.",
+                rs_path,
+            );
+        }
+    }
+}
+
+#[test]
+fn rustfix_coverage_known_exceptions_accuracy() {
+    for filename in RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS {
+        let rs_path = Path::new("tests/ui").join(filename);
+        assert!(
+            rs_path.exists(),
+            "`{}` does not exists",
+            rs_path.strip_prefix(env!("CARGO_MANIFEST_DIR")).unwrap().display()
+        );
+        let fixed_path = rs_path.with_extension("fixed");
+        assert!(
+            !fixed_path.exists(),
+            "`{}` exists",
+            fixed_path.strip_prefix(env!("CARGO_MANIFEST_DIR")).unwrap().display()
+        );
+    }
+}
+
 /// Restores an env var on drop
 #[must_use]
 struct VarGuard {
diff --git a/tests/ui-internal/unnecessary_symbol_str.fixed b/tests/ui-internal/unnecessary_symbol_str.fixed
index 4f5336663a8..6033d06e4f6 100644
--- a/tests/ui-internal/unnecessary_symbol_str.fixed
+++ b/tests/ui-internal/unnecessary_symbol_str.fixed
@@ -2,6 +2,7 @@
 #![feature(rustc_private)]
 #![deny(clippy::internal)]
 #![allow(
+    clippy::borrow_deref_ref,
     clippy::unnecessary_operation,
     unused_must_use,
     clippy::missing_clippy_version_attribute
diff --git a/tests/ui-internal/unnecessary_symbol_str.rs b/tests/ui-internal/unnecessary_symbol_str.rs
index 894aa1d3bc6..1bb5d55f0b6 100644
--- a/tests/ui-internal/unnecessary_symbol_str.rs
+++ b/tests/ui-internal/unnecessary_symbol_str.rs
@@ -2,6 +2,7 @@
 #![feature(rustc_private)]
 #![deny(clippy::internal)]
 #![allow(
+    clippy::borrow_deref_ref,
     clippy::unnecessary_operation,
     unused_must_use,
     clippy::missing_clippy_version_attribute
diff --git a/tests/ui-internal/unnecessary_symbol_str.stderr b/tests/ui-internal/unnecessary_symbol_str.stderr
index 75367bf4bc5..a1f507f331d 100644
--- a/tests/ui-internal/unnecessary_symbol_str.stderr
+++ b/tests/ui-internal/unnecessary_symbol_str.stderr
@@ -1,5 +1,5 @@
 error: unnecessary `Symbol` to string conversion
-  --> $DIR/unnecessary_symbol_str.rs:15:5
+  --> $DIR/unnecessary_symbol_str.rs:16:5
    |
 LL |     Symbol::intern("foo").as_str() == "clippy";
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::sym::clippy`
@@ -12,25 +12,25 @@ LL | #![deny(clippy::internal)]
    = note: `#[deny(clippy::unnecessary_symbol_str)]` implied by `#[deny(clippy::internal)]`
 
 error: unnecessary `Symbol` to string conversion
-  --> $DIR/unnecessary_symbol_str.rs:16:5
+  --> $DIR/unnecessary_symbol_str.rs:17:5
    |
 LL |     Symbol::intern("foo").to_string() == "self";
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::symbol::kw::SelfLower`
 
 error: unnecessary `Symbol` to string conversion
-  --> $DIR/unnecessary_symbol_str.rs:17:5
+  --> $DIR/unnecessary_symbol_str.rs:18:5
    |
 LL |     Symbol::intern("foo").to_ident_string() != "Self";
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") != rustc_span::symbol::kw::SelfUpper`
 
 error: unnecessary `Symbol` to string conversion
-  --> $DIR/unnecessary_symbol_str.rs:18:5
+  --> $DIR/unnecessary_symbol_str.rs:19:5
    |
 LL |     &*Ident::empty().as_str() == "clippy";
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy`
 
 error: unnecessary `Symbol` to string conversion
-  --> $DIR/unnecessary_symbol_str.rs:19:5
+  --> $DIR/unnecessary_symbol_str.rs:20:5
    |
 LL |     "clippy" == Ident::empty().to_string();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name`
diff --git a/tests/ui-toml/dbg_macro/clippy.toml b/tests/ui-toml/dbg_macro/clippy.toml
new file mode 100644
index 00000000000..4296655a040
--- /dev/null
+++ b/tests/ui-toml/dbg_macro/clippy.toml
@@ -0,0 +1 @@
+allow-dbg-in-tests = true
diff --git a/tests/ui-toml/dbg_macro/dbg_macro.rs b/tests/ui-toml/dbg_macro/dbg_macro.rs
new file mode 100644
index 00000000000..5d9ce18f631
--- /dev/null
+++ b/tests/ui-toml/dbg_macro/dbg_macro.rs
@@ -0,0 +1,39 @@
+// compile-flags: --test
+#![warn(clippy::dbg_macro)]
+
+fn foo(n: u32) -> u32 {
+    if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
+}
+
+fn factorial(n: u32) -> u32 {
+    if dbg!(n <= 1) {
+        dbg!(1)
+    } else {
+        dbg!(n * factorial(n - 1))
+    }
+}
+
+fn main() {
+    dbg!(42);
+    dbg!(dbg!(dbg!(42)));
+    foo(3) + dbg!(factorial(4));
+    dbg!(1, 2, dbg!(3, 4));
+    dbg!(1, 2, 3, 4, 5);
+}
+
+#[test]
+pub fn issue8481() {
+    dbg!(1);
+}
+
+#[cfg(test)]
+fn foo2() {
+    dbg!(1);
+}
+
+#[cfg(test)]
+mod mod1 {
+    fn func() {
+        dbg!(1);
+    }
+}
diff --git a/tests/ui-toml/dbg_macro/dbg_macro.stderr b/tests/ui-toml/dbg_macro/dbg_macro.stderr
new file mode 100644
index 00000000000..46efb86dcfc
--- /dev/null
+++ b/tests/ui-toml/dbg_macro/dbg_macro.stderr
@@ -0,0 +1,102 @@
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:5:22
+   |
+LL |     if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
+   |                      ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::dbg-macro` implied by `-D warnings`
+help: ensure to avoid having uses of it in version control
+   |
+LL |     if let Some(n) = n.checked_sub(4) { n } else { n }
+   |                      ~~~~~~~~~~~~~~~~
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:9:8
+   |
+LL |     if dbg!(n <= 1) {
+   |        ^^^^^^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |     if n <= 1 {
+   |        ~~~~~~
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:10:9
+   |
+LL |         dbg!(1)
+   |         ^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |         1
+   |
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:12:9
+   |
+LL |         dbg!(n * factorial(n - 1))
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |         n * factorial(n - 1)
+   |
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:17:5
+   |
+LL |     dbg!(42);
+   |     ^^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |     42;
+   |     ~~
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:18:5
+   |
+LL |     dbg!(dbg!(dbg!(42)));
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |     dbg!(dbg!(42));
+   |     ~~~~~~~~~~~~~~
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:19:14
+   |
+LL |     foo(3) + dbg!(factorial(4));
+   |              ^^^^^^^^^^^^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |     foo(3) + factorial(4);
+   |              ~~~~~~~~~~~~
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:20:5
+   |
+LL |     dbg!(1, 2, dbg!(3, 4));
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |     (1, 2, dbg!(3, 4));
+   |     ~~~~~~~~~~~~~~~~~~
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:21:5
+   |
+LL |     dbg!(1, 2, 3, 4, 5);
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |     (1, 2, 3, 4, 5);
+   |     ~~~~~~~~~~~~~~~
+
+error: aborting due to 9 previous errors
+
diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 92838aa57df..1d87fd91a25 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,5 @@
 error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of
+           allow-dbg-in-tests
            allow-expect-in-tests
            allow-unwrap-in-tests
            allowed-scripts
diff --git a/tests/ui-toml/unwrap_used/unwrap_used.rs b/tests/ui-toml/unwrap_used/unwrap_used.rs
index 74d0d7c2650..0e82fb20e45 100644
--- a/tests/ui-toml/unwrap_used/unwrap_used.rs
+++ b/tests/ui-toml/unwrap_used/unwrap_used.rs
@@ -1,6 +1,6 @@
 // compile-flags: --test
 
-#![allow(unused_mut, clippy::from_iter_instead_of_collect)]
+#![allow(unused_mut, clippy::get_first, clippy::from_iter_instead_of_collect)]
 #![warn(clippy::unwrap_used)]
 #![deny(clippy::get_unwrap)]
 
diff --git a/tests/ui/almost_complete_letter_range.fixed b/tests/ui/almost_complete_letter_range.fixed
new file mode 100644
index 00000000000..39f8f0c2949
--- /dev/null
+++ b/tests/ui/almost_complete_letter_range.fixed
@@ -0,0 +1,66 @@
+// run-rustfix
+// edition:2018
+
+#![feature(custom_inner_attributes)]
+#![feature(exclusive_range_pattern)]
+#![feature(stmt_expr_attributes)]
+#![warn(clippy::almost_complete_letter_range)]
+#![allow(ellipsis_inclusive_range_patterns)]
+
+macro_rules! a {
+    () => {
+        'a'
+    };
+}
+
+fn main() {
+    #[rustfmt::skip]
+    {
+        let _ = ('a') ..='z';
+        let _ = 'A' ..= ('Z');
+    }
+
+    let _ = 'b'..'z';
+    let _ = 'B'..'Z';
+
+    let _ = (b'a')..=(b'z');
+    let _ = b'A'..=b'Z';
+
+    let _ = b'b'..b'z';
+    let _ = b'B'..b'Z';
+
+    let _ = a!()..='z';
+
+    let _ = match 0u8 {
+        b'a'..=b'z' if true => 1,
+        b'A'..=b'Z' if true => 2,
+        b'b'..b'z' => 3,
+        b'B'..b'Z' => 4,
+        _ => 5,
+    };
+
+    let _ = match 'x' {
+        'a'..='z' if true => 1,
+        'A'..='Z' if true => 2,
+        'b'..'z' => 3,
+        'B'..'Z' => 4,
+        _ => 5,
+    };
+}
+
+fn _under_msrv() {
+    #![clippy::msrv = "1.25"]
+    let _ = match 'a' {
+        'a'...'z' => 1,
+        _ => 2,
+    };
+}
+
+fn _meets_msrv() {
+    #![clippy::msrv = "1.26"]
+    let _ = 'a'..='z';
+    let _ = match 'a' {
+        'a'..='z' => 1,
+        _ => 2,
+    };
+}
diff --git a/tests/ui/almost_complete_letter_range.rs b/tests/ui/almost_complete_letter_range.rs
new file mode 100644
index 00000000000..3dc02199257
--- /dev/null
+++ b/tests/ui/almost_complete_letter_range.rs
@@ -0,0 +1,66 @@
+// run-rustfix
+// edition:2018
+
+#![feature(custom_inner_attributes)]
+#![feature(exclusive_range_pattern)]
+#![feature(stmt_expr_attributes)]
+#![warn(clippy::almost_complete_letter_range)]
+#![allow(ellipsis_inclusive_range_patterns)]
+
+macro_rules! a {
+    () => {
+        'a'
+    };
+}
+
+fn main() {
+    #[rustfmt::skip]
+    {
+        let _ = ('a') ..'z';
+        let _ = 'A' .. ('Z');
+    }
+
+    let _ = 'b'..'z';
+    let _ = 'B'..'Z';
+
+    let _ = (b'a')..(b'z');
+    let _ = b'A'..b'Z';
+
+    let _ = b'b'..b'z';
+    let _ = b'B'..b'Z';
+
+    let _ = a!()..'z';
+
+    let _ = match 0u8 {
+        b'a'..b'z' if true => 1,
+        b'A'..b'Z' if true => 2,
+        b'b'..b'z' => 3,
+        b'B'..b'Z' => 4,
+        _ => 5,
+    };
+
+    let _ = match 'x' {
+        'a'..'z' if true => 1,
+        'A'..'Z' if true => 2,
+        'b'..'z' => 3,
+        'B'..'Z' => 4,
+        _ => 5,
+    };
+}
+
+fn _under_msrv() {
+    #![clippy::msrv = "1.25"]
+    let _ = match 'a' {
+        'a'..'z' => 1,
+        _ => 2,
+    };
+}
+
+fn _meets_msrv() {
+    #![clippy::msrv = "1.26"]
+    let _ = 'a'..'z';
+    let _ = match 'a' {
+        'a'..'z' => 1,
+        _ => 2,
+    };
+}
diff --git a/tests/ui/almost_complete_letter_range.stderr b/tests/ui/almost_complete_letter_range.stderr
new file mode 100644
index 00000000000..74980ec1a92
--- /dev/null
+++ b/tests/ui/almost_complete_letter_range.stderr
@@ -0,0 +1,100 @@
+error: almost complete ascii letter range
+  --> $DIR/almost_complete_letter_range.rs:19:17
+   |
+LL |         let _ = ('a') ..'z';
+   |                 ^^^^^^--^^^
+   |                       |
+   |                       help: use an inclusive range: `..=`
+   |
+   = note: `-D clippy::almost-complete-letter-range` implied by `-D warnings`
+
+error: almost complete ascii letter range
+  --> $DIR/almost_complete_letter_range.rs:20:17
+   |
+LL |         let _ = 'A' .. ('Z');
+   |                 ^^^^--^^^^^^
+   |                     |
+   |                     help: use an inclusive range: `..=`
+
+error: almost complete ascii letter range
+  --> $DIR/almost_complete_letter_range.rs:26:13
+   |
+LL |     let _ = (b'a')..(b'z');
+   |             ^^^^^^--^^^^^^
+   |                   |
+   |                   help: use an inclusive range: `..=`
+
+error: almost complete ascii letter range
+  --> $DIR/almost_complete_letter_range.rs:27:13
+   |
+LL |     let _ = b'A'..b'Z';
+   |             ^^^^--^^^^
+   |                 |
+   |                 help: use an inclusive range: `..=`
+
+error: almost complete ascii letter range
+  --> $DIR/almost_complete_letter_range.rs:32:13
+   |
+LL |     let _ = a!()..'z';
+   |             ^^^^--^^^
+   |                 |
+   |                 help: use an inclusive range: `..=`
+
+error: almost complete ascii letter range
+  --> $DIR/almost_complete_letter_range.rs:35:9
+   |
+LL |         b'a'..b'z' if true => 1,
+   |         ^^^^--^^^^
+   |             |
+   |             help: use an inclusive range: `..=`
+
+error: almost complete ascii letter range
+  --> $DIR/almost_complete_letter_range.rs:36:9
+   |
+LL |         b'A'..b'Z' if true => 2,
+   |         ^^^^--^^^^
+   |             |
+   |             help: use an inclusive range: `..=`
+
+error: almost complete ascii letter range
+  --> $DIR/almost_complete_letter_range.rs:43:9
+   |
+LL |         'a'..'z' if true => 1,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: almost complete ascii letter range
+  --> $DIR/almost_complete_letter_range.rs:44:9
+   |
+LL |         'A'..'Z' if true => 2,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: almost complete ascii letter range
+  --> $DIR/almost_complete_letter_range.rs:54:9
+   |
+LL |         'a'..'z' => 1,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `...`
+
+error: almost complete ascii letter range
+  --> $DIR/almost_complete_letter_range.rs:61:13
+   |
+LL |     let _ = 'a'..'z';
+   |             ^^^--^^^
+   |                |
+   |                help: use an inclusive range: `..=`
+
+error: almost complete ascii letter range
+  --> $DIR/almost_complete_letter_range.rs:63:9
+   |
+LL |         'a'..'z' => 1,
+   |         ^^^--^^^
+   |            |
+   |            help: use an inclusive range: `..=`
+
+error: aborting due to 12 previous errors
+
diff --git a/tests/ui/as_underscore.fixed b/tests/ui/as_underscore.fixed
new file mode 100644
index 00000000000..948f6d8e6b1
--- /dev/null
+++ b/tests/ui/as_underscore.fixed
@@ -0,0 +1,13 @@
+// run-rustfix
+
+#![warn(clippy::as_underscore)]
+
+fn foo(_n: usize) {}
+
+fn main() {
+    let n: u16 = 256;
+    foo(n as usize);
+
+    let n = 0_u128;
+    let _n: u8 = n as u8;
+}
diff --git a/tests/ui/as_underscore.rs b/tests/ui/as_underscore.rs
new file mode 100644
index 00000000000..97785ed08a8
--- /dev/null
+++ b/tests/ui/as_underscore.rs
@@ -0,0 +1,13 @@
+// run-rustfix
+
+#![warn(clippy::as_underscore)]
+
+fn foo(_n: usize) {}
+
+fn main() {
+    let n: u16 = 256;
+    foo(n as _);
+
+    let n = 0_u128;
+    let _n: u8 = n as _;
+}
diff --git a/tests/ui/as_underscore.stderr b/tests/ui/as_underscore.stderr
new file mode 100644
index 00000000000..d7cd58d965a
--- /dev/null
+++ b/tests/ui/as_underscore.stderr
@@ -0,0 +1,20 @@
+error: using `as _` conversion
+  --> $DIR/as_underscore.rs:9:9
+   |
+LL |     foo(n as _);
+   |         ^^^^^-
+   |              |
+   |              help: consider giving the type explicitly: `usize`
+   |
+   = note: `-D clippy::as-underscore` implied by `-D warnings`
+
+error: using `as _` conversion
+  --> $DIR/as_underscore.rs:12:18
+   |
+LL |     let _n: u8 = n as _;
+   |                  ^^^^^-
+   |                       |
+   |                       help: consider giving the type explicitly: `u8`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/bind_instead_of_map_multipart.fixed b/tests/ui/bind_instead_of_map_multipart.fixed
new file mode 100644
index 00000000000..e1589843226
--- /dev/null
+++ b/tests/ui/bind_instead_of_map_multipart.fixed
@@ -0,0 +1,62 @@
+// run-rustfix
+#![deny(clippy::bind_instead_of_map)]
+#![allow(clippy::blocks_in_if_conditions)]
+
+pub fn main() {
+    let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() });
+    let _ = Some("42").and_then(|s| if s.len() < 42 { None } else { Some(s.len()) });
+
+    let _ = Ok::<_, ()>("42").map(|s| if s.len() < 42 { 0 } else { s.len() });
+    let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Err(()) } else { Ok(s.len()) });
+
+    let _ = Err::<(), _>("42").map_err(|s| if s.len() < 42 { s.len() + 20 } else { s.len() });
+    let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Ok(()) } else { Err(s.len()) });
+
+    hard_example();
+    macro_example();
+}
+
+fn hard_example() {
+    Some("42").map(|s| {
+        if {
+            if s == "43" {
+                return 43;
+            }
+            s == "42"
+        } {
+            return 45;
+        }
+        match s.len() {
+            10 => 2,
+            20 => {
+                if foo() {
+                    return {
+                        if foo() {
+                            return 20;
+                        }
+                        println!("foo");
+                        3
+                    };
+                }
+                20
+            },
+            40 => 30,
+            _ => 1,
+        }
+    });
+}
+
+fn foo() -> bool {
+    true
+}
+
+macro_rules! m {
+    () => {
+        Some(10)
+    };
+}
+
+fn macro_example() {
+    let _ = Some("").and_then(|s| if s.len() == 20 { m!() } else { Some(20) });
+    let _ = Some("").map(|s| if s.len() == 20 { m!() } else { Some(20) });
+}
diff --git a/tests/ui/bind_instead_of_map_multipart.rs b/tests/ui/bind_instead_of_map_multipart.rs
index 91d9d11e3c1..49944403f6d 100644
--- a/tests/ui/bind_instead_of_map_multipart.rs
+++ b/tests/ui/bind_instead_of_map_multipart.rs
@@ -1,3 +1,4 @@
+// run-rustfix
 #![deny(clippy::bind_instead_of_map)]
 #![allow(clippy::blocks_in_if_conditions)]
 
diff --git a/tests/ui/bind_instead_of_map_multipart.stderr b/tests/ui/bind_instead_of_map_multipart.stderr
index e4f605a4de3..f822b6f49fa 100644
--- a/tests/ui/bind_instead_of_map_multipart.stderr
+++ b/tests/ui/bind_instead_of_map_multipart.stderr
@@ -1,11 +1,11 @@
 error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`
-  --> $DIR/bind_instead_of_map_multipart.rs:5:13
+  --> $DIR/bind_instead_of_map_multipart.rs:6:13
    |
 LL |     let _ = Some("42").and_then(|s| if s.len() < 42 { Some(0) } else { Some(s.len()) });
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/bind_instead_of_map_multipart.rs:1:9
+  --> $DIR/bind_instead_of_map_multipart.rs:2:9
    |
 LL | #![deny(clippy::bind_instead_of_map)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL |     let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() });
    |                        ~~~                       ~          ~~~~~~~
 
 error: using `Result.and_then(|x| Ok(y))`, which is more succinctly expressed as `map(|x| y)`
-  --> $DIR/bind_instead_of_map_multipart.rs:8:13
+  --> $DIR/bind_instead_of_map_multipart.rs:9:13
    |
 LL |     let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Ok(0) } else { Ok(s.len()) });
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL |     let _ = Ok::<_, ()>("42").map(|s| if s.len() < 42 { 0 } else { s.len()
    |                               ~~~                       ~          ~~~~~~~
 
 error: using `Result.or_else(|x| Err(y))`, which is more succinctly expressed as `map_err(|x| y)`
-  --> $DIR/bind_instead_of_map_multipart.rs:11:13
+  --> $DIR/bind_instead_of_map_multipart.rs:12:13
    |
 LL |     let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Err(s.len() + 20) } else { Err(s.len()) });
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL |     let _ = Err::<(), _>("42").map_err(|s| if s.len() < 42 { s.len() + 20 }
    |                                ~~~~~~~                       ~~~~~~~~~~~~          ~~~~~~~
 
 error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`
-  --> $DIR/bind_instead_of_map_multipart.rs:19:5
+  --> $DIR/bind_instead_of_map_multipart.rs:20:5
    |
 LL | /     Some("42").and_then(|s| {
 LL | |         if {
@@ -59,7 +59,7 @@ LL |             s == "42"
  ...
 
 error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)`
-  --> $DIR/bind_instead_of_map_multipart.rs:60:13
+  --> $DIR/bind_instead_of_map_multipart.rs:61:13
    |
 LL |     let _ = Some("").and_then(|s| if s.len() == 20 { Some(m!()) } else { Some(Some(20)) });
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/borrow_deref_ref.fixed b/tests/ui/borrow_deref_ref.fixed
new file mode 100644
index 00000000000..bf4691c5bc9
--- /dev/null
+++ b/tests/ui/borrow_deref_ref.fixed
@@ -0,0 +1,59 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+
+fn main() {}
+
+mod should_lint {
+    fn one_help() {
+        let a = &12;
+        let b = a;
+
+        let b = &mut bar(&12);
+    }
+
+    fn bar(x: &u32) -> &u32 {
+        x
+    }
+}
+
+// this mod explains why we should not lint `&mut &* (&T)`
+mod should_not_lint1 {
+    fn foo(x: &mut &u32) {
+        *x = &1;
+    }
+
+    fn main() {
+        let mut x = &0;
+        foo(&mut &*x); // should not lint
+        assert_eq!(*x, 0);
+
+        foo(&mut x);
+        assert_eq!(*x, 1);
+    }
+}
+
+// similar to should_not_lint1
+mod should_not_lint2 {
+    struct S<'a> {
+        a: &'a u32,
+        b: u32,
+    }
+
+    fn main() {
+        let s = S { a: &1, b: 1 };
+        let x = &mut &*s.a;
+        *x = &2;
+    }
+}
+
+// this mod explains why we should not lint `& &* (&T)`
+mod false_negative {
+    fn foo() {
+        let x = &12;
+        let addr_x = &x as *const _ as usize;
+        let addr_y = &x as *const _ as usize; // assert ok
+        // let addr_y = &x as *const _ as usize; // assert fail
+        assert_ne!(addr_x, addr_y);
+    }
+}
diff --git a/tests/ui/borrow_deref_ref.rs b/tests/ui/borrow_deref_ref.rs
new file mode 100644
index 00000000000..28c005fdbef
--- /dev/null
+++ b/tests/ui/borrow_deref_ref.rs
@@ -0,0 +1,59 @@
+// run-rustfix
+
+#![allow(dead_code, unused_variables)]
+
+fn main() {}
+
+mod should_lint {
+    fn one_help() {
+        let a = &12;
+        let b = &*a;
+
+        let b = &mut &*bar(&12);
+    }
+
+    fn bar(x: &u32) -> &u32 {
+        x
+    }
+}
+
+// this mod explains why we should not lint `&mut &* (&T)`
+mod should_not_lint1 {
+    fn foo(x: &mut &u32) {
+        *x = &1;
+    }
+
+    fn main() {
+        let mut x = &0;
+        foo(&mut &*x); // should not lint
+        assert_eq!(*x, 0);
+
+        foo(&mut x);
+        assert_eq!(*x, 1);
+    }
+}
+
+// similar to should_not_lint1
+mod should_not_lint2 {
+    struct S<'a> {
+        a: &'a u32,
+        b: u32,
+    }
+
+    fn main() {
+        let s = S { a: &1, b: 1 };
+        let x = &mut &*s.a;
+        *x = &2;
+    }
+}
+
+// this mod explains why we should not lint `& &* (&T)`
+mod false_negative {
+    fn foo() {
+        let x = &12;
+        let addr_x = &x as *const _ as usize;
+        let addr_y = &&*x as *const _ as usize; // assert ok
+        // let addr_y = &x as *const _ as usize; // assert fail
+        assert_ne!(addr_x, addr_y);
+    }
+}
diff --git a/tests/ui/borrow_deref_ref.stderr b/tests/ui/borrow_deref_ref.stderr
new file mode 100644
index 00000000000..d72de37c69f
--- /dev/null
+++ b/tests/ui/borrow_deref_ref.stderr
@@ -0,0 +1,22 @@
+error: deref on an immutable reference
+  --> $DIR/borrow_deref_ref.rs:10:17
+   |
+LL |         let b = &*a;
+   |                 ^^^ help: if you would like to reborrow, try removing `&*`: `a`
+   |
+   = note: `-D clippy::borrow-deref-ref` implied by `-D warnings`
+
+error: deref on an immutable reference
+  --> $DIR/borrow_deref_ref.rs:12:22
+   |
+LL |         let b = &mut &*bar(&12);
+   |                      ^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `bar(&12)`
+
+error: deref on an immutable reference
+  --> $DIR/borrow_deref_ref.rs:55:23
+   |
+LL |         let addr_y = &&*x as *const _ as usize; // assert ok
+   |                       ^^^ help: if you would like to reborrow, try removing `&*`: `x`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/borrow_deref_ref_unfixable.rs b/tests/ui/borrow_deref_ref_unfixable.rs
new file mode 100644
index 00000000000..a8e2bbfef0f
--- /dev/null
+++ b/tests/ui/borrow_deref_ref_unfixable.rs
@@ -0,0 +1,10 @@
+#![allow(dead_code, unused_variables)]
+
+fn main() {}
+
+mod should_lint {
+    fn two_helps() {
+        let s = &String::new();
+        let x: &str = &*s;
+    }
+}
diff --git a/tests/ui/borrow_deref_ref_unfixable.stderr b/tests/ui/borrow_deref_ref_unfixable.stderr
new file mode 100644
index 00000000000..738b01e7ec1
--- /dev/null
+++ b/tests/ui/borrow_deref_ref_unfixable.stderr
@@ -0,0 +1,18 @@
+error: deref on an immutable reference
+  --> $DIR/borrow_deref_ref_unfixable.rs:8:23
+   |
+LL |         let x: &str = &*s;
+   |                       ^^^
+   |
+   = note: `-D clippy::borrow-deref-ref` implied by `-D warnings`
+help: if you would like to reborrow, try removing `&*`
+   |
+LL |         let x: &str = s;
+   |                       ~
+help: if you would like to deref, try using `&**`
+   |
+LL |         let x: &str = &**s;
+   |                       ~~~~
+
+error: aborting due to previous error
+
diff --git a/tests/ui/cast_abs_to_unsigned.fixed b/tests/ui/cast_abs_to_unsigned.fixed
index 4ec2465be06..a68b32b097e 100644
--- a/tests/ui/cast_abs_to_unsigned.fixed
+++ b/tests/ui/cast_abs_to_unsigned.fixed
@@ -5,4 +5,25 @@ fn main() {
     let x: i32 = -42;
     let y: u32 = x.unsigned_abs();
     println!("The absolute value of {} is {}", x, y);
+
+    let a: i32 = -3;
+    let _: usize = a.unsigned_abs() as usize;
+    let _: usize = a.unsigned_abs() as _;
+    let _ = a.unsigned_abs() as usize;
+
+    let a: i64 = -3;
+    let _ = a.unsigned_abs() as usize;
+    let _ = a.unsigned_abs() as u8;
+    let _ = a.unsigned_abs() as u16;
+    let _ = a.unsigned_abs() as u32;
+    let _ = a.unsigned_abs();
+    let _ = a.unsigned_abs() as u128;
+
+    let a: isize = -3;
+    let _ = a.unsigned_abs();
+    let _ = a.unsigned_abs() as u8;
+    let _ = a.unsigned_abs() as u16;
+    let _ = a.unsigned_abs() as u32;
+    let _ = a.unsigned_abs() as u64;
+    let _ = a.unsigned_abs() as u128;
 }
diff --git a/tests/ui/cast_abs_to_unsigned.rs b/tests/ui/cast_abs_to_unsigned.rs
index 59b9c8c3678..110fbc6c2df 100644
--- a/tests/ui/cast_abs_to_unsigned.rs
+++ b/tests/ui/cast_abs_to_unsigned.rs
@@ -5,4 +5,25 @@ fn main() {
     let x: i32 = -42;
     let y: u32 = x.abs() as u32;
     println!("The absolute value of {} is {}", x, y);
+
+    let a: i32 = -3;
+    let _: usize = a.abs() as usize;
+    let _: usize = a.abs() as _;
+    let _ = a.abs() as usize;
+
+    let a: i64 = -3;
+    let _ = a.abs() as usize;
+    let _ = a.abs() as u8;
+    let _ = a.abs() as u16;
+    let _ = a.abs() as u32;
+    let _ = a.abs() as u64;
+    let _ = a.abs() as u128;
+
+    let a: isize = -3;
+    let _ = a.abs() as usize;
+    let _ = a.abs() as u8;
+    let _ = a.abs() as u16;
+    let _ = a.abs() as u32;
+    let _ = a.abs() as u64;
+    let _ = a.abs() as u128;
 }
diff --git a/tests/ui/cast_abs_to_unsigned.stderr b/tests/ui/cast_abs_to_unsigned.stderr
index eb12857357a..02c24e10659 100644
--- a/tests/ui/cast_abs_to_unsigned.stderr
+++ b/tests/ui/cast_abs_to_unsigned.stderr
@@ -6,5 +6,95 @@ LL |     let y: u32 = x.abs() as u32;
    |
    = note: `-D clippy::cast-abs-to-unsigned` implied by `-D warnings`
 
-error: aborting due to previous error
+error: casting the result of `i32::abs()` to usize
+  --> $DIR/cast_abs_to_unsigned.rs:10:20
+   |
+LL |     let _: usize = a.abs() as usize;
+   |                    ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `i32::abs()` to usize
+  --> $DIR/cast_abs_to_unsigned.rs:11:20
+   |
+LL |     let _: usize = a.abs() as _;
+   |                    ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `i32::abs()` to usize
+  --> $DIR/cast_abs_to_unsigned.rs:12:13
+   |
+LL |     let _ = a.abs() as usize;
+   |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `i64::abs()` to usize
+  --> $DIR/cast_abs_to_unsigned.rs:15:13
+   |
+LL |     let _ = a.abs() as usize;
+   |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `i64::abs()` to u8
+  --> $DIR/cast_abs_to_unsigned.rs:16:13
+   |
+LL |     let _ = a.abs() as u8;
+   |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `i64::abs()` to u16
+  --> $DIR/cast_abs_to_unsigned.rs:17:13
+   |
+LL |     let _ = a.abs() as u16;
+   |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `i64::abs()` to u32
+  --> $DIR/cast_abs_to_unsigned.rs:18:13
+   |
+LL |     let _ = a.abs() as u32;
+   |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `i64::abs()` to u64
+  --> $DIR/cast_abs_to_unsigned.rs:19:13
+   |
+LL |     let _ = a.abs() as u64;
+   |             ^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `i64::abs()` to u128
+  --> $DIR/cast_abs_to_unsigned.rs:20:13
+   |
+LL |     let _ = a.abs() as u128;
+   |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `isize::abs()` to usize
+  --> $DIR/cast_abs_to_unsigned.rs:23:13
+   |
+LL |     let _ = a.abs() as usize;
+   |             ^^^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `isize::abs()` to u8
+  --> $DIR/cast_abs_to_unsigned.rs:24:13
+   |
+LL |     let _ = a.abs() as u8;
+   |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `isize::abs()` to u16
+  --> $DIR/cast_abs_to_unsigned.rs:25:13
+   |
+LL |     let _ = a.abs() as u16;
+   |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `isize::abs()` to u32
+  --> $DIR/cast_abs_to_unsigned.rs:26:13
+   |
+LL |     let _ = a.abs() as u32;
+   |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `isize::abs()` to u64
+  --> $DIR/cast_abs_to_unsigned.rs:27:13
+   |
+LL |     let _ = a.abs() as u64;
+   |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: casting the result of `isize::abs()` to u128
+  --> $DIR/cast_abs_to_unsigned.rs:28:13
+   |
+LL |     let _ = a.abs() as u128;
+   |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
+
+error: aborting due to 16 previous errors
 
diff --git a/tests/ui/collapsible_match2.rs b/tests/ui/collapsible_match2.rs
index 542e6948427..c8fb0a39e95 100644
--- a/tests/ui/collapsible_match2.rs
+++ b/tests/ui/collapsible_match2.rs
@@ -57,7 +57,7 @@ fn lint_cases(opt_opt: Option<Option<u32>>, res_opt: Result<Option<u32>, String>
 
     // ref pattern and deref
     match Some(&[1]) {
-        Some(ref s) => match &*s {
+        Some(ref s) => match s {
             [n] => foo(n),
             _ => (),
         },
diff --git a/tests/ui/collapsible_match2.stderr b/tests/ui/collapsible_match2.stderr
index 46b645aea13..fe64e469379 100644
--- a/tests/ui/collapsible_match2.stderr
+++ b/tests/ui/collapsible_match2.stderr
@@ -78,7 +78,7 @@ LL |             [n] => foo(n),
 error: this `match` can be collapsed into the outer `match`
   --> $DIR/collapsible_match2.rs:60:24
    |
-LL |           Some(ref s) => match &*s {
+LL |           Some(ref s) => match s {
    |  ________________________^
 LL | |             [n] => foo(n),
 LL | |             _ => (),
@@ -88,7 +88,7 @@ LL | |         },
 help: the outer pattern can be modified to include the inner pattern
   --> $DIR/collapsible_match2.rs:60:14
    |
-LL |         Some(ref s) => match &*s {
+LL |         Some(ref s) => match s {
    |              ^^^^^ replace this binding
 LL |             [n] => foo(n),
    |             ^^^ with this pattern
diff --git a/tests/ui/crashes/ice-8850.rs b/tests/ui/crashes/ice-8850.rs
new file mode 100644
index 00000000000..f2747ab2239
--- /dev/null
+++ b/tests/ui/crashes/ice-8850.rs
@@ -0,0 +1,27 @@
+fn fn_pointer_static() -> usize {
+    static FN: fn() -> usize = || 1;
+    let res = FN() + 1;
+    res
+}
+
+fn fn_pointer_const() -> usize {
+    const FN: fn() -> usize = || 1;
+    let res = FN() + 1;
+    res
+}
+
+fn deref_to_dyn_fn() -> usize {
+    struct Derefs;
+    impl std::ops::Deref for Derefs {
+        type Target = dyn Fn() -> usize;
+
+        fn deref(&self) -> &Self::Target {
+            &|| 2
+        }
+    }
+    static FN: Derefs = Derefs;
+    let res = FN() + 1;
+    res
+}
+
+fn main() {}
diff --git a/tests/ui/crashes/ice-8850.stderr b/tests/ui/crashes/ice-8850.stderr
new file mode 100644
index 00000000000..620fd1edaf7
--- /dev/null
+++ b/tests/ui/crashes/ice-8850.stderr
@@ -0,0 +1,45 @@
+error: returning the result of a `let` binding from a block
+  --> $DIR/ice-8850.rs:4:5
+   |
+LL |     let res = FN() + 1;
+   |     ------------------- unnecessary `let` binding
+LL |     res
+   |     ^^^
+   |
+   = note: `-D clippy::let-and-return` implied by `-D warnings`
+help: return the expression directly
+   |
+LL ~     
+LL ~     FN() + 1
+   |
+
+error: returning the result of a `let` binding from a block
+  --> $DIR/ice-8850.rs:10:5
+   |
+LL |     let res = FN() + 1;
+   |     ------------------- unnecessary `let` binding
+LL |     res
+   |     ^^^
+   |
+help: return the expression directly
+   |
+LL ~     
+LL ~     FN() + 1
+   |
+
+error: returning the result of a `let` binding from a block
+  --> $DIR/ice-8850.rs:24:5
+   |
+LL |     let res = FN() + 1;
+   |     ------------------- unnecessary `let` binding
+LL |     res
+   |     ^^^
+   |
+help: return the expression directly
+   |
+LL ~     
+LL ~     FN() + 1
+   |
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/dbg_macro.stderr b/tests/ui/dbg_macro.stderr
index a3e7a7162e5..e6a65b46d97 100644
--- a/tests/ui/dbg_macro.stderr
+++ b/tests/ui/dbg_macro.stderr
@@ -109,5 +109,38 @@ help: ensure to avoid having uses of it in version control
 LL |         2;
    |         ~
 
-error: aborting due to 10 previous errors
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:47:5
+   |
+LL |     dbg!(1);
+   |     ^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |     1;
+   |     ~
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:52:5
+   |
+LL |     dbg!(1);
+   |     ^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |     1;
+   |     ~
+
+error: `dbg!` macro is intended as a debugging tool
+  --> $DIR/dbg_macro.rs:58:9
+   |
+LL |         dbg!(1);
+   |         ^^^^^^^
+   |
+help: ensure to avoid having uses of it in version control
+   |
+LL |         1;
+   |         ~
+
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/debug_assert_with_mut_call.rs b/tests/ui/debug_assert_with_mut_call.rs
index c5de4125565..46faa0a7b91 100644
--- a/tests/ui/debug_assert_with_mut_call.rs
+++ b/tests/ui/debug_assert_with_mut_call.rs
@@ -1,7 +1,7 @@
 #![feature(custom_inner_attributes)]
 #![rustfmt::skip]
 #![warn(clippy::debug_assert_with_mut_call)]
-#![allow(clippy::redundant_closure_call)]
+#![allow(clippy::redundant_closure_call, clippy::get_first)]
 
 
 struct S;
diff --git a/tests/ui/deref_by_slicing.fixed b/tests/ui/deref_by_slicing.fixed
index b26276218b7..257393e56ff 100644
--- a/tests/ui/deref_by_slicing.fixed
+++ b/tests/ui/deref_by_slicing.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::deref_by_slicing)]
+#![allow(clippy::borrow_deref_ref)]
 
 use std::io::Read;
 
diff --git a/tests/ui/deref_by_slicing.rs b/tests/ui/deref_by_slicing.rs
index 6aa1408ba17..e288046f927 100644
--- a/tests/ui/deref_by_slicing.rs
+++ b/tests/ui/deref_by_slicing.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::deref_by_slicing)]
+#![allow(clippy::borrow_deref_ref)]
 
 use std::io::Read;
 
diff --git a/tests/ui/deref_by_slicing.stderr b/tests/ui/deref_by_slicing.stderr
index ffd76de378d..8f042ef47eb 100644
--- a/tests/ui/deref_by_slicing.stderr
+++ b/tests/ui/deref_by_slicing.stderr
@@ -1,5 +1,5 @@
 error: slicing when dereferencing would work
-  --> $DIR/deref_by_slicing.rs:9:13
+  --> $DIR/deref_by_slicing.rs:10:13
    |
 LL |     let _ = &vec[..];
    |             ^^^^^^^^ help: dereference the original value instead: `&*vec`
@@ -7,49 +7,49 @@ LL |     let _ = &vec[..];
    = note: `-D clippy::deref-by-slicing` implied by `-D warnings`
 
 error: slicing when dereferencing would work
-  --> $DIR/deref_by_slicing.rs:10:13
+  --> $DIR/deref_by_slicing.rs:11:13
    |
 LL |     let _ = &mut vec[..];
    |             ^^^^^^^^^^^^ help: dereference the original value instead: `&mut *vec`
 
 error: slicing when dereferencing would work
-  --> $DIR/deref_by_slicing.rs:13:13
+  --> $DIR/deref_by_slicing.rs:14:13
    |
 LL |     let _ = &ref_vec[..];
    |             ^^^^^^^^^^^^ help: dereference the original value instead: `&**ref_vec`
 
 error: slicing when dereferencing would work
-  --> $DIR/deref_by_slicing.rs:14:21
+  --> $DIR/deref_by_slicing.rs:15:21
    |
 LL |     let mut_slice = &mut ref_vec[..];
    |                     ^^^^^^^^^^^^^^^^ help: dereference the original value instead: `&mut **ref_vec`
 
 error: slicing when dereferencing would work
-  --> $DIR/deref_by_slicing.rs:15:13
+  --> $DIR/deref_by_slicing.rs:16:13
    |
 LL |     let _ = &mut mut_slice[..]; // Err, re-borrows slice
    |             ^^^^^^^^^^^^^^^^^^ help: reborrow the original value instead: `&mut *mut_slice`
 
 error: slicing when dereferencing would work
-  --> $DIR/deref_by_slicing.rs:18:13
+  --> $DIR/deref_by_slicing.rs:19:13
    |
 LL |     let _ = &s[..];
    |             ^^^^^^ help: dereference the original value instead: `&*s`
 
 error: slicing when dereferencing would work
-  --> $DIR/deref_by_slicing.rs:21:18
+  --> $DIR/deref_by_slicing.rs:22:18
    |
 LL |     let _ = &mut &S[..]; // Err, re-borrows slice
    |                  ^^^^^^ help: reborrow the original value instead: `&*S`
 
 error: slicing when dereferencing would work
-  --> $DIR/deref_by_slicing.rs:25:13
+  --> $DIR/deref_by_slicing.rs:26:13
    |
 LL |     let _ = &slice_ref[..]; // Err, derefs slice
    |             ^^^^^^^^^^^^^^ help: dereference the original value instead: `*slice_ref`
 
 error: slicing when dereferencing would work
-  --> $DIR/deref_by_slicing.rs:28:13
+  --> $DIR/deref_by_slicing.rs:29:13
    |
 LL |     let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice
    |             ^^^^^^^^^^^^ help: reborrow the original value instead: `(&*bytes)`
diff --git a/tests/ui/derive_partial_eq_without_eq.fixed b/tests/ui/derive_partial_eq_without_eq.fixed
index 7d4d1b3b649..012780258fc 100644
--- a/tests/ui/derive_partial_eq_without_eq.fixed
+++ b/tests/ui/derive_partial_eq_without_eq.fixed
@@ -95,4 +95,10 @@ enum EnumNotEq {
 #[derive(Debug, PartialEq, Eq, Clone)]
 struct RustFixWithOtherDerives;
 
+#[derive(PartialEq)]
+struct Generic<T>(T);
+
+#[derive(PartialEq, Eq)]
+struct GenericPhantom<T>(core::marker::PhantomData<T>);
+
 fn main() {}
diff --git a/tests/ui/derive_partial_eq_without_eq.rs b/tests/ui/derive_partial_eq_without_eq.rs
index ab4e1df1ca4..fc8285b0c6b 100644
--- a/tests/ui/derive_partial_eq_without_eq.rs
+++ b/tests/ui/derive_partial_eq_without_eq.rs
@@ -95,4 +95,10 @@ enum EnumNotEq {
 #[derive(Debug, PartialEq, Clone)]
 struct RustFixWithOtherDerives;
 
+#[derive(PartialEq)]
+struct Generic<T>(T);
+
+#[derive(PartialEq, Eq)]
+struct GenericPhantom<T>(core::marker::PhantomData<T>);
+
 fn main() {}
diff --git a/tests/ui/doc_link_with_quotes.rs b/tests/ui/doc_link_with_quotes.rs
new file mode 100644
index 00000000000..ab52fb1a4a6
--- /dev/null
+++ b/tests/ui/doc_link_with_quotes.rs
@@ -0,0 +1,12 @@
+#![warn(clippy::doc_link_with_quotes)]
+
+fn main() {
+    foo()
+}
+
+/// Calls ['bar']
+pub fn foo() {
+    bar()
+}
+
+pub fn bar() {}
diff --git a/tests/ui/doc_link_with_quotes.stderr b/tests/ui/doc_link_with_quotes.stderr
new file mode 100644
index 00000000000..bf6d57d8afe
--- /dev/null
+++ b/tests/ui/doc_link_with_quotes.stderr
@@ -0,0 +1,10 @@
+error: possible intra-doc link using quotes instead of backticks
+  --> $DIR/doc_link_with_quotes.rs:7:1
+   |
+LL | /// Calls ['bar']
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::doc-link-with-quotes` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/empty_line_after_outer_attribute.rs b/tests/ui/empty_line_after_outer_attribute.rs
index 3e92bca986a..d15c84d7438 100644
--- a/tests/ui/empty_line_after_outer_attribute.rs
+++ b/tests/ui/empty_line_after_outer_attribute.rs
@@ -5,6 +5,9 @@
 #![rustfmt::skip]
 
 #[macro_use]
+extern crate clap;
+
+#[macro_use]
 extern crate proc_macro_attr;
 
 // This should produce a warning
@@ -110,4 +113,11 @@ pub trait Bazz {
     }
 }
 
+#[derive(clap::Parser)]
+#[clap(after_help = "This ia a help message.
+
+You're welcome.
+")]
+pub struct Args;
+
 fn main() {}
diff --git a/tests/ui/empty_line_after_outer_attribute.stderr b/tests/ui/empty_line_after_outer_attribute.stderr
index 594fca44a32..acc3edef9b9 100644
--- a/tests/ui/empty_line_after_outer_attribute.stderr
+++ b/tests/ui/empty_line_after_outer_attribute.stderr
@@ -1,5 +1,5 @@
 error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
-  --> $DIR/empty_line_after_outer_attribute.rs:11:1
+  --> $DIR/empty_line_after_outer_attribute.rs:14:1
    |
 LL | / #[crate_type = "lib"]
 LL | |
@@ -10,7 +10,7 @@ LL | | fn with_one_newline_and_comment() { assert!(true) }
    = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings`
 
 error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
-  --> $DIR/empty_line_after_outer_attribute.rs:23:1
+  --> $DIR/empty_line_after_outer_attribute.rs:26:1
    |
 LL | / #[crate_type = "lib"]
 LL | |
@@ -18,7 +18,7 @@ LL | | fn with_one_newline() { assert!(true) }
    | |_
 
 error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
-  --> $DIR/empty_line_after_outer_attribute.rs:28:1
+  --> $DIR/empty_line_after_outer_attribute.rs:31:1
    |
 LL | / #[crate_type = "lib"]
 LL | |
@@ -27,7 +27,7 @@ LL | | fn with_two_newlines() { assert!(true) }
    | |_
 
 error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
-  --> $DIR/empty_line_after_outer_attribute.rs:35:1
+  --> $DIR/empty_line_after_outer_attribute.rs:38:1
    |
 LL | / #[crate_type = "lib"]
 LL | |
@@ -35,7 +35,7 @@ LL | | enum Baz {
    | |_
 
 error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
-  --> $DIR/empty_line_after_outer_attribute.rs:43:1
+  --> $DIR/empty_line_after_outer_attribute.rs:46:1
    |
 LL | / #[crate_type = "lib"]
 LL | |
@@ -43,7 +43,7 @@ LL | | struct Foo {
    | |_
 
 error: found an empty line after an outer attribute. Perhaps you forgot to add a `!` to make it an inner attribute?
-  --> $DIR/empty_line_after_outer_attribute.rs:51:1
+  --> $DIR/empty_line_after_outer_attribute.rs:54:1
    |
 LL | / #[crate_type = "lib"]
 LL | |
diff --git a/tests/ui/expect_tool_lint_rfc_2383.rs b/tests/ui/expect_tool_lint_rfc_2383.rs
index 28b37f96e91..985835ffa65 100644
--- a/tests/ui/expect_tool_lint_rfc_2383.rs
+++ b/tests/ui/expect_tool_lint_rfc_2383.rs
@@ -22,9 +22,9 @@ mod rustc_ok {
 
         #[expect(illegal_floating_point_literal_pattern)]
         match x {
-            5.0 => {}
-            6.0 => {}
-            _ => {}
+            5.0 => {},
+            6.0 => {},
+            _ => {},
         }
     }
 }
@@ -38,9 +38,9 @@ mod rustc_warn {
 
         #[expect(illegal_floating_point_literal_pattern)]
         match x {
-            5 => {}
-            6 => {}
-            _ => {}
+            5 => {},
+            6 => {},
+            _ => {},
         }
     }
 }
diff --git a/tests/ui/explicit_deref_methods.fixed b/tests/ui/explicit_deref_methods.fixed
index 3de2a51ffa5..92f27e68549 100644
--- a/tests/ui/explicit_deref_methods.fixed
+++ b/tests/ui/explicit_deref_methods.fixed
@@ -1,6 +1,11 @@
 // run-rustfix
 
-#![allow(unused_variables, clippy::clone_double_ref, clippy::needless_borrow)]
+#![allow(
+    unused_variables,
+    clippy::clone_double_ref,
+    clippy::needless_borrow,
+    clippy::borrow_deref_ref
+)]
 #![warn(clippy::explicit_deref_methods)]
 
 use std::ops::{Deref, DerefMut};
diff --git a/tests/ui/explicit_deref_methods.rs b/tests/ui/explicit_deref_methods.rs
index a08d7596422..d118607f992 100644
--- a/tests/ui/explicit_deref_methods.rs
+++ b/tests/ui/explicit_deref_methods.rs
@@ -1,6 +1,11 @@
 // run-rustfix
 
-#![allow(unused_variables, clippy::clone_double_ref, clippy::needless_borrow)]
+#![allow(
+    unused_variables,
+    clippy::clone_double_ref,
+    clippy::needless_borrow,
+    clippy::borrow_deref_ref
+)]
 #![warn(clippy::explicit_deref_methods)]
 
 use std::ops::{Deref, DerefMut};
diff --git a/tests/ui/explicit_deref_methods.stderr b/tests/ui/explicit_deref_methods.stderr
index 8035d77d18d..8e8b358972b 100644
--- a/tests/ui/explicit_deref_methods.stderr
+++ b/tests/ui/explicit_deref_methods.stderr
@@ -1,5 +1,5 @@
 error: explicit `deref` method call
-  --> $DIR/explicit_deref_methods.rs:30:19
+  --> $DIR/explicit_deref_methods.rs:35:19
    |
 LL |     let b: &str = a.deref();
    |                   ^^^^^^^^^ help: try this: `&*a`
@@ -7,67 +7,67 @@ LL |     let b: &str = a.deref();
    = note: `-D clippy::explicit-deref-methods` implied by `-D warnings`
 
 error: explicit `deref_mut` method call
-  --> $DIR/explicit_deref_methods.rs:32:23
+  --> $DIR/explicit_deref_methods.rs:37:23
    |
 LL |     let b: &mut str = a.deref_mut();
    |                       ^^^^^^^^^^^^^ help: try this: `&mut **a`
 
 error: explicit `deref` method call
-  --> $DIR/explicit_deref_methods.rs:35:39
+  --> $DIR/explicit_deref_methods.rs:40:39
    |
 LL |     let b: String = format!("{}, {}", a.deref(), a.deref());
    |                                       ^^^^^^^^^ help: try this: `&*a`
 
 error: explicit `deref` method call
-  --> $DIR/explicit_deref_methods.rs:35:50
+  --> $DIR/explicit_deref_methods.rs:40:50
    |
 LL |     let b: String = format!("{}, {}", a.deref(), a.deref());
    |                                                  ^^^^^^^^^ help: try this: `&*a`
 
 error: explicit `deref` method call
-  --> $DIR/explicit_deref_methods.rs:37:20
+  --> $DIR/explicit_deref_methods.rs:42:20
    |
 LL |     println!("{}", a.deref());
    |                    ^^^^^^^^^ help: try this: `&*a`
 
 error: explicit `deref` method call
-  --> $DIR/explicit_deref_methods.rs:40:11
+  --> $DIR/explicit_deref_methods.rs:45:11
    |
 LL |     match a.deref() {
    |           ^^^^^^^^^ help: try this: `&*a`
 
 error: explicit `deref` method call
-  --> $DIR/explicit_deref_methods.rs:44:28
+  --> $DIR/explicit_deref_methods.rs:49:28
    |
 LL |     let b: String = concat(a.deref());
    |                            ^^^^^^^^^ help: try this: `&*a`
 
 error: explicit `deref` method call
-  --> $DIR/explicit_deref_methods.rs:46:13
+  --> $DIR/explicit_deref_methods.rs:51:13
    |
 LL |     let b = just_return(a).deref();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)`
 
 error: explicit `deref` method call
-  --> $DIR/explicit_deref_methods.rs:48:28
+  --> $DIR/explicit_deref_methods.rs:53:28
    |
 LL |     let b: String = concat(just_return(a).deref());
    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `just_return(a)`
 
 error: explicit `deref` method call
-  --> $DIR/explicit_deref_methods.rs:50:19
+  --> $DIR/explicit_deref_methods.rs:55:19
    |
 LL |     let b: &str = a.deref().deref();
    |                   ^^^^^^^^^^^^^^^^^ help: try this: `&**a`
 
 error: explicit `deref` method call
-  --> $DIR/explicit_deref_methods.rs:53:13
+  --> $DIR/explicit_deref_methods.rs:58:13
    |
 LL |     let b = opt_a.unwrap().deref();
    |             ^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&*opt_a.unwrap()`
 
 error: explicit `deref` method call
-  --> $DIR/explicit_deref_methods.rs:79:31
+  --> $DIR/explicit_deref_methods.rs:84:31
    |
 LL |     let b: &str = expr_deref!(a.deref());
    |                               ^^^^^^^^^ help: try this: `&*a`
diff --git a/tests/ui/forget_ref.rs b/tests/ui/forget_ref.rs
index 6c8c4c9c0ed..031b415f56f 100644
--- a/tests/ui/forget_ref.rs
+++ b/tests/ui/forget_ref.rs
@@ -1,6 +1,7 @@
 #![warn(clippy::forget_ref)]
 #![allow(clippy::toplevel_ref_arg)]
 #![allow(clippy::unnecessary_wraps, clippy::forget_non_drop)]
+#![allow(clippy::borrow_deref_ref)]
 
 use std::mem::forget;
 
diff --git a/tests/ui/forget_ref.stderr b/tests/ui/forget_ref.stderr
index 73409388ed1..df5cd8cacdb 100644
--- a/tests/ui/forget_ref.stderr
+++ b/tests/ui/forget_ref.stderr
@@ -1,108 +1,108 @@
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:10:5
+  --> $DIR/forget_ref.rs:11:5
    |
 LL |     forget(&SomeStruct);
    |     ^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::forget-ref` implied by `-D warnings`
 note: argument has type `&SomeStruct`
-  --> $DIR/forget_ref.rs:10:12
+  --> $DIR/forget_ref.rs:11:12
    |
 LL |     forget(&SomeStruct);
    |            ^^^^^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:13:5
+  --> $DIR/forget_ref.rs:14:5
    |
 LL |     forget(&owned);
    |     ^^^^^^^^^^^^^^
    |
 note: argument has type `&SomeStruct`
-  --> $DIR/forget_ref.rs:13:12
+  --> $DIR/forget_ref.rs:14:12
    |
 LL |     forget(&owned);
    |            ^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:14:5
+  --> $DIR/forget_ref.rs:15:5
    |
 LL |     forget(&&owned);
    |     ^^^^^^^^^^^^^^^
    |
 note: argument has type `&&SomeStruct`
-  --> $DIR/forget_ref.rs:14:12
+  --> $DIR/forget_ref.rs:15:12
    |
 LL |     forget(&&owned);
    |            ^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:15:5
+  --> $DIR/forget_ref.rs:16:5
    |
 LL |     forget(&mut owned);
    |     ^^^^^^^^^^^^^^^^^^
    |
 note: argument has type `&mut SomeStruct`
-  --> $DIR/forget_ref.rs:15:12
+  --> $DIR/forget_ref.rs:16:12
    |
 LL |     forget(&mut owned);
    |            ^^^^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:19:5
+  --> $DIR/forget_ref.rs:20:5
    |
 LL |     forget(&*reference1);
    |     ^^^^^^^^^^^^^^^^^^^^
    |
 note: argument has type `&SomeStruct`
-  --> $DIR/forget_ref.rs:19:12
+  --> $DIR/forget_ref.rs:20:12
    |
 LL |     forget(&*reference1);
    |            ^^^^^^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:22:5
+  --> $DIR/forget_ref.rs:23:5
    |
 LL |     forget(reference2);
    |     ^^^^^^^^^^^^^^^^^^
    |
 note: argument has type `&mut SomeStruct`
-  --> $DIR/forget_ref.rs:22:12
+  --> $DIR/forget_ref.rs:23:12
    |
 LL |     forget(reference2);
    |            ^^^^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:25:5
+  --> $DIR/forget_ref.rs:26:5
    |
 LL |     forget(reference3);
    |     ^^^^^^^^^^^^^^^^^^
    |
 note: argument has type `&SomeStruct`
-  --> $DIR/forget_ref.rs:25:12
+  --> $DIR/forget_ref.rs:26:12
    |
 LL |     forget(reference3);
    |            ^^^^^^^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:30:5
+  --> $DIR/forget_ref.rs:31:5
    |
 LL |     forget(&val);
    |     ^^^^^^^^^^^^
    |
 note: argument has type `&T`
-  --> $DIR/forget_ref.rs:30:12
+  --> $DIR/forget_ref.rs:31:12
    |
 LL |     forget(&val);
    |            ^^^^
 
 error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing
-  --> $DIR/forget_ref.rs:38:5
+  --> $DIR/forget_ref.rs:39:5
    |
 LL |     std::mem::forget(&SomeStruct);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: argument has type `&SomeStruct`
-  --> $DIR/forget_ref.rs:38:22
+  --> $DIR/forget_ref.rs:39:22
    |
 LL |     std::mem::forget(&SomeStruct);
    |                      ^^^^^^^^^^^
diff --git a/tests/ui/get_first.fixed b/tests/ui/get_first.fixed
new file mode 100644
index 00000000000..def58afa4fb
--- /dev/null
+++ b/tests/ui/get_first.fixed
@@ -0,0 +1,42 @@
+// run-rustfix
+#![warn(clippy::get_first)]
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::collections::VecDeque;
+
+struct Bar {
+    arr: [u32; 3],
+}
+
+impl Bar {
+    fn get(&self, pos: usize) -> Option<&u32> {
+        self.arr.get(pos)
+    }
+}
+
+fn main() {
+    let x = vec![2, 3, 5];
+    let _ = x.first(); // Use x.first()
+    let _ = x.get(1);
+    let _ = x[0];
+
+    let y = [2, 3, 5];
+    let _ = y.first(); // Use y.first()
+    let _ = y.get(1);
+    let _ = y[0];
+
+    let z = &[2, 3, 5];
+    let _ = z.first(); // Use z.first()
+    let _ = z.get(1);
+    let _ = z[0];
+
+    let vecdeque: VecDeque<_> = x.iter().cloned().collect();
+    let hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]);
+    let btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(0, 'a'), (1, 'b')]);
+    let _ = vecdeque.get(0); // Do not lint, because VecDeque is not slice.
+    let _ = hashmap.get(&0); // Do not lint, because HashMap is not slice.
+    let _ = btreemap.get(&0); // Do not lint, because BTreeMap is not slice.
+
+    let bar = Bar { arr: [0, 1, 2] };
+    let _ = bar.get(0); // Do not lint, because Bar is struct.
+}
diff --git a/tests/ui/get_first.rs b/tests/ui/get_first.rs
new file mode 100644
index 00000000000..85a381854cd
--- /dev/null
+++ b/tests/ui/get_first.rs
@@ -0,0 +1,42 @@
+// run-rustfix
+#![warn(clippy::get_first)]
+use std::collections::BTreeMap;
+use std::collections::HashMap;
+use std::collections::VecDeque;
+
+struct Bar {
+    arr: [u32; 3],
+}
+
+impl Bar {
+    fn get(&self, pos: usize) -> Option<&u32> {
+        self.arr.get(pos)
+    }
+}
+
+fn main() {
+    let x = vec![2, 3, 5];
+    let _ = x.get(0); // Use x.first()
+    let _ = x.get(1);
+    let _ = x[0];
+
+    let y = [2, 3, 5];
+    let _ = y.get(0); // Use y.first()
+    let _ = y.get(1);
+    let _ = y[0];
+
+    let z = &[2, 3, 5];
+    let _ = z.get(0); // Use z.first()
+    let _ = z.get(1);
+    let _ = z[0];
+
+    let vecdeque: VecDeque<_> = x.iter().cloned().collect();
+    let hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]);
+    let btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(0, 'a'), (1, 'b')]);
+    let _ = vecdeque.get(0); // Do not lint, because VecDeque is not slice.
+    let _ = hashmap.get(&0); // Do not lint, because HashMap is not slice.
+    let _ = btreemap.get(&0); // Do not lint, because BTreeMap is not slice.
+
+    let bar = Bar { arr: [0, 1, 2] };
+    let _ = bar.get(0); // Do not lint, because Bar is struct.
+}
diff --git a/tests/ui/get_first.stderr b/tests/ui/get_first.stderr
new file mode 100644
index 00000000000..466beff9c92
--- /dev/null
+++ b/tests/ui/get_first.stderr
@@ -0,0 +1,22 @@
+error: accessing first element with `x.get(0)`
+  --> $DIR/get_first.rs:19:13
+   |
+LL |     let _ = x.get(0); // Use x.first()
+   |             ^^^^^^^^ help: try: `x.first()`
+   |
+   = note: `-D clippy::get-first` implied by `-D warnings`
+
+error: accessing first element with `y.get(0)`
+  --> $DIR/get_first.rs:24:13
+   |
+LL |     let _ = y.get(0); // Use y.first()
+   |             ^^^^^^^^ help: try: `y.first()`
+
+error: accessing first element with `z.get(0)`
+  --> $DIR/get_first.rs:29:13
+   |
+LL |     let _ = z.get(0); // Use z.first()
+   |             ^^^^^^^^ help: try: `z.first()`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/get_last_with_len.fixed b/tests/ui/get_last_with_len.fixed
index c8b363f9c38..1e90b37687a 100644
--- a/tests/ui/get_last_with_len.fixed
+++ b/tests/ui/get_last_with_len.fixed
@@ -1,10 +1,13 @@
 // run-rustfix
 
 #![warn(clippy::get_last_with_len)]
+#![allow(unused)]
+
+use std::collections::VecDeque;
 
 fn dont_use_last() {
     let x = vec![2, 3, 5];
-    let _ = x.last(); // ~ERROR Use x.last()
+    let _ = x.last();
 }
 
 fn indexing_two_from_end() {
@@ -23,9 +26,24 @@ fn use_last_with_different_vec_length() {
     let _ = x.get(y.len() - 1);
 }
 
+struct S {
+    field: Vec<usize>,
+}
+
+fn in_field(s: &S) {
+    let _ = s.field.last();
+}
+
 fn main() {
-    dont_use_last();
-    indexing_two_from_end();
-    index_into_last();
-    use_last_with_different_vec_length();
+    let slice = &[1, 2, 3];
+    let _ = slice.last();
+
+    let array = [4, 5, 6];
+    let _ = array.last();
+
+    let deq = VecDeque::from([7, 8, 9]);
+    let _ = deq.back();
+
+    let nested = [[1]];
+    let _ = nested[0].last();
 }
diff --git a/tests/ui/get_last_with_len.rs b/tests/ui/get_last_with_len.rs
index bf9cb2d7e0c..d63a731bd52 100644
--- a/tests/ui/get_last_with_len.rs
+++ b/tests/ui/get_last_with_len.rs
@@ -1,10 +1,13 @@
 // run-rustfix
 
 #![warn(clippy::get_last_with_len)]
+#![allow(unused)]
+
+use std::collections::VecDeque;
 
 fn dont_use_last() {
     let x = vec![2, 3, 5];
-    let _ = x.get(x.len() - 1); // ~ERROR Use x.last()
+    let _ = x.get(x.len() - 1);
 }
 
 fn indexing_two_from_end() {
@@ -23,9 +26,24 @@ fn use_last_with_different_vec_length() {
     let _ = x.get(y.len() - 1);
 }
 
+struct S {
+    field: Vec<usize>,
+}
+
+fn in_field(s: &S) {
+    let _ = s.field.get(s.field.len() - 1);
+}
+
 fn main() {
-    dont_use_last();
-    indexing_two_from_end();
-    index_into_last();
-    use_last_with_different_vec_length();
+    let slice = &[1, 2, 3];
+    let _ = slice.get(slice.len() - 1);
+
+    let array = [4, 5, 6];
+    let _ = array.get(array.len() - 1);
+
+    let deq = VecDeque::from([7, 8, 9]);
+    let _ = deq.get(deq.len() - 1);
+
+    let nested = [[1]];
+    let _ = nested[0].get(nested[0].len() - 1);
 }
diff --git a/tests/ui/get_last_with_len.stderr b/tests/ui/get_last_with_len.stderr
index 55baf87384a..ac8dd6c2e41 100644
--- a/tests/ui/get_last_with_len.stderr
+++ b/tests/ui/get_last_with_len.stderr
@@ -1,10 +1,40 @@
 error: accessing last element with `x.get(x.len() - 1)`
-  --> $DIR/get_last_with_len.rs:7:13
+  --> $DIR/get_last_with_len.rs:10:13
    |
-LL |     let _ = x.get(x.len() - 1); // ~ERROR Use x.last()
+LL |     let _ = x.get(x.len() - 1);
    |             ^^^^^^^^^^^^^^^^^^ help: try: `x.last()`
    |
    = note: `-D clippy::get-last-with-len` implied by `-D warnings`
 
-error: aborting due to previous error
+error: accessing last element with `s.field.get(s.field.len() - 1)`
+  --> $DIR/get_last_with_len.rs:34:13
+   |
+LL |     let _ = s.field.get(s.field.len() - 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.field.last()`
+
+error: accessing last element with `slice.get(slice.len() - 1)`
+  --> $DIR/get_last_with_len.rs:39:13
+   |
+LL |     let _ = slice.get(slice.len() - 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `slice.last()`
+
+error: accessing last element with `array.get(array.len() - 1)`
+  --> $DIR/get_last_with_len.rs:42:13
+   |
+LL |     let _ = array.get(array.len() - 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `array.last()`
+
+error: accessing last element with `deq.get(deq.len() - 1)`
+  --> $DIR/get_last_with_len.rs:45:13
+   |
+LL |     let _ = deq.get(deq.len() - 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^ help: try: `deq.back()`
+
+error: accessing last element with `nested[0].get(nested[0].len() - 1)`
+  --> $DIR/get_last_with_len.rs:48:13
+   |
+LL |     let _ = nested[0].get(nested[0].len() - 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `nested[0].last()`
+
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed
index 8f165d67589..5827fc7d76e 100644
--- a/tests/ui/get_unwrap.fixed
+++ b/tests/ui/get_unwrap.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(unused_mut, clippy::from_iter_instead_of_collect)]
+#![allow(unused_mut, clippy::from_iter_instead_of_collect, clippy::get_first)]
 #![warn(clippy::unwrap_used)]
 #![deny(clippy::get_unwrap)]
 
diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs
index 786749daa74..a2a323c14fb 100644
--- a/tests/ui/get_unwrap.rs
+++ b/tests/ui/get_unwrap.rs
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(unused_mut, clippy::from_iter_instead_of_collect)]
+#![allow(unused_mut, clippy::from_iter_instead_of_collect, clippy::get_first)]
 #![warn(clippy::unwrap_used)]
 #![deny(clippy::get_unwrap)]
 
diff --git a/tests/ui/identity_op.fixed b/tests/ui/identity_op.fixed
new file mode 100644
index 00000000000..5f9cebe212a
--- /dev/null
+++ b/tests/ui/identity_op.fixed
@@ -0,0 +1,119 @@
+// run-rustfix
+
+#![warn(clippy::identity_op)]
+#![allow(
+    clippy::eq_op,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::op_ref,
+    clippy::double_parens,
+    unused
+)]
+
+use std::fmt::Write as _;
+
+const ONE: i64 = 1;
+const NEG_ONE: i64 = -1;
+const ZERO: i64 = 0;
+
+struct A(String);
+
+impl std::ops::Shl<i32> for A {
+    type Output = A;
+    fn shl(mut self, other: i32) -> Self {
+        let _ = write!(self.0, "{}", other);
+        self
+    }
+}
+
+struct Length(u8);
+struct Meter;
+
+impl core::ops::Mul<Meter> for u8 {
+    type Output = Length;
+    fn mul(self, _: Meter) -> Length {
+        Length(self)
+    }
+}
+
+#[rustfmt::skip]
+fn main() {
+    let x = 0;
+
+    x;
+    x;
+    x + 1;
+    x;
+    1 + x;
+    x - ZERO; //no error, as we skip lookups (for now)
+    x;
+    ((ZERO)) | x; //no error, as we skip lookups (for now)
+
+    x;
+    x;
+    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;
+
+    let u: u8 = 0;
+    u;
+
+    1 << 0; // no error, this case is allowed, see issue 3430
+    42;
+    1;
+    42;
+    &x;
+    x;
+
+    let mut a = A("".into());
+    let b = a << 0; // no error: non-integer
+
+    1 * Meter; // no error: non-integer
+
+    2;
+    -2;
+    2 + x;
+    -2 + x;
+    x + 1;
+    (x + 1) % 3; // no error
+    4 % 3; // no error
+    4 % -3; // no error
+
+    // See #8724
+    let a = 0;
+    let b = true;
+    (if b { 1 } else { 2 });
+    (if b { 1 } else { 2 }) + if b { 3 } else { 4 };
+    (match a { 0 => 10, _ => 20 });
+    (match a { 0 => 10, _ => 20 }) + match a { 0 => 30, _ => 40 };
+    (if b { 1 } else { 2 }) + match a { 0 => 30, _ => 40 };
+    (match a { 0 => 10, _ => 20 }) + if b { 3 } else { 4 };
+    (if b { 1 } else { 2 });
+
+    ({ a }) + 3;
+    ({ a } * 2);
+    (loop { let mut c = 0; if c == 10 { break c; } c += 1; }) + { a * 2 };
+
+    fn f(_: i32) {
+        todo!();
+    }
+    f(a + { 8 * 5 });
+    f(if b { 1 } else { 2 } + 3);
+    const _: i32 = { 2 * 4 } + 3;
+    const _: i32 = { 1 + 2 * 3 } + 3;
+
+    a as usize;
+    let _ = a as usize;
+    ({ a } as usize);
+
+    2 * { a };
+    (({ a } + 4));
+    1;
+}
+
+pub fn decide(a: bool, b: bool) -> u32 {
+    (if a { 1 } else { 2 }) + if b { 3 } else { 5 }
+}
diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs
index fec54d00ccb..ca799c9cfac 100644
--- a/tests/ui/identity_op.rs
+++ b/tests/ui/identity_op.rs
@@ -1,3 +1,15 @@
+// run-rustfix
+
+#![warn(clippy::identity_op)]
+#![allow(
+    clippy::eq_op,
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::op_ref,
+    clippy::double_parens,
+    unused
+)]
+
 use std::fmt::Write as _;
 
 const ONE: i64 = 1;
@@ -24,14 +36,6 @@ impl core::ops::Mul<Meter> for u8 {
     }
 }
 
-#[allow(
-    clippy::eq_op,
-    clippy::no_effect,
-    clippy::unnecessary_operation,
-    clippy::op_ref,
-    clippy::double_parens
-)]
-#[warn(clippy::identity_op)]
 #[rustfmt::skip]
 fn main() {
     let x = 0;
@@ -82,29 +86,34 @@ fn main() {
     let a = 0;
     let b = true;
     0 + if b { 1 } else { 2 };
-    0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }; // no error
+    0 + if b { 1 } else { 2 } + if b { 3 } else { 4 };
     0 + match a { 0 => 10, _ => 20 };
-    0 + match a { 0 => 10, _ => 20 } + match a { 0 => 30, _ => 40 }; // no error
-    0 + if b { 1 } else { 2 } + match a { 0 => 30, _ => 40 }; // no error
-    0 + match a { 0 => 10, _ => 20 } + if b { 3 } else { 4 }; // no error
-    
-    0 + if b { 0 + 1 } else { 2 };
-    0 + match a { 0 =>  0 + 10, _ => 20 };
-    0 + if b { 0 + 1 } else { 2 } + match a { 0 => 0 + 30, _ => 40 };
-
-    let _ = 0 + if 0 + 1 > 0 { 1 } else { 2 } + if 0 + 1 > 0 { 3 } else { 4 };
-    let _ = 0 + match 0 + 1 { 0 => 10, _ => 20 } + match 0 + 1  { 0 => 30, _ => 40 };
-
-    0 + if b { 1 } else { 2 } + if b { 3 } else { 4 } + 0;
-    
-    0 + { a } + 3; // no error
-    0 + loop { let mut c = 0; if c == 10 { break c; } c += 1; } + { a * 2 }; // no error
-    
+    0 + match a { 0 => 10, _ => 20 } + match a { 0 => 30, _ => 40 };
+    0 + if b { 1 } else { 2 } + match a { 0 => 30, _ => 40 };
+    0 + match a { 0 => 10, _ => 20 } + if b { 3 } else { 4 };
+    (if b { 1 } else { 2 }) + 0;
+
+    0 + { a } + 3;
+    0 + { a } * 2;
+    0 + loop { let mut c = 0; if c == 10 { break c; } c += 1; } + { a * 2 };
+
     fn f(_: i32) {
         todo!();
     }
     f(1 * a + { 8 * 5 });
-    f(0 + if b { 1 } else { 2 } + 3); // no error
+    f(0 + if b { 1 } else { 2 } + 3);
     const _: i32 = { 2 * 4 } + 0 + 3;
-    const _: i32 = 0 + { 1 + 2 * 3 } + 3; // no error
+    const _: i32 = 0 + { 1 + 2 * 3 } + 3;
+
+    0 + a as usize;
+    let _ = 0 + a as usize;
+    0 + { a } as usize;
+
+    2 * (0 + { a });
+    1 * ({ a } + 4);
+    1 * 1;
+}
+
+pub fn decide(a: bool, b: bool) -> u32 {
+    0 + if a { 1 } else { 2 } + if b { 3 } else { 5 }
 }
diff --git a/tests/ui/identity_op.stderr b/tests/ui/identity_op.stderr
index d8cb65839cb..1a104a20b84 100644
--- a/tests/ui/identity_op.stderr
+++ b/tests/ui/identity_op.stderr
@@ -1,202 +1,238 @@
-error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:39:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:43:5
    |
 LL |     x + 0;
-   |     ^^^^^
+   |     ^^^^^ help: consider reducing it to: `x`
    |
    = note: `-D clippy::identity-op` implied by `-D warnings`
 
-error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:40:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:44:5
    |
 LL |     x + (1 - 1);
-   |     ^^^^^^^^^^^
+   |     ^^^^^^^^^^^ help: consider reducing it to: `x`
 
-error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:42:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:46:5
    |
 LL |     0 + x;
-   |     ^^^^^
+   |     ^^^^^ help: consider reducing it to: `x`
 
-error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:45:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:49:5
    |
 LL |     x | (0);
-   |     ^^^^^^^
+   |     ^^^^^^^ help: consider reducing it to: `x`
 
-error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:48:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:52:5
    |
 LL |     x * 1;
-   |     ^^^^^
+   |     ^^^^^ help: consider reducing it to: `x`
 
-error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:49:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:53:5
    |
 LL |     1 * x;
-   |     ^^^^^
+   |     ^^^^^ help: consider reducing it to: `x`
 
-error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:55:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:59:5
    |
 LL |     -1 & x;
-   |     ^^^^^^
+   |     ^^^^^^ help: consider reducing it to: `x`
 
-error: the operation is ineffective. Consider reducing it to `u`
-  --> $DIR/identity_op.rs:58:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:62:5
    |
 LL |     u & 255;
-   |     ^^^^^^^
+   |     ^^^^^^^ help: consider reducing it to: `u`
 
-error: the operation is ineffective. Consider reducing it to `42`
-  --> $DIR/identity_op.rs:61:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:65:5
    |
 LL |     42 << 0;
-   |     ^^^^^^^
+   |     ^^^^^^^ help: consider reducing it to: `42`
 
-error: the operation is ineffective. Consider reducing it to `1`
-  --> $DIR/identity_op.rs:62:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:66:5
    |
 LL |     1 >> 0;
-   |     ^^^^^^
+   |     ^^^^^^ help: consider reducing it to: `1`
 
-error: the operation is ineffective. Consider reducing it to `42`
-  --> $DIR/identity_op.rs:63:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:67:5
    |
 LL |     42 >> 0;
-   |     ^^^^^^^
+   |     ^^^^^^^ help: consider reducing it to: `42`
 
-error: the operation is ineffective. Consider reducing it to `&x`
-  --> $DIR/identity_op.rs:64:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:68:5
    |
 LL |     &x >> 0;
-   |     ^^^^^^^
+   |     ^^^^^^^ help: consider reducing it to: `&x`
 
-error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:65:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:69:5
    |
 LL |     x >> &0;
-   |     ^^^^^^^
+   |     ^^^^^^^ help: consider reducing it to: `x`
 
-error: the operation is ineffective. Consider reducing it to `2`
-  --> $DIR/identity_op.rs:72:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:76:5
    |
 LL |     2 % 3;
-   |     ^^^^^
+   |     ^^^^^ help: consider reducing it to: `2`
 
-error: the operation is ineffective. Consider reducing it to `-2`
-  --> $DIR/identity_op.rs:73:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:77:5
    |
 LL |     -2 % 3;
-   |     ^^^^^^
+   |     ^^^^^^ help: consider reducing it to: `-2`
 
-error: the operation is ineffective. Consider reducing it to `2`
-  --> $DIR/identity_op.rs:74:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:78:5
    |
 LL |     2 % -3 + x;
-   |     ^^^^^^
+   |     ^^^^^^ help: consider reducing it to: `2`
 
-error: the operation is ineffective. Consider reducing it to `-2`
-  --> $DIR/identity_op.rs:75:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:79:5
    |
 LL |     -2 % -3 + x;
-   |     ^^^^^^^
+   |     ^^^^^^^ help: consider reducing it to: `-2`
 
-error: the operation is ineffective. Consider reducing it to `1`
-  --> $DIR/identity_op.rs:76:9
+error: this operation has no effect
+  --> $DIR/identity_op.rs:80:9
    |
 LL |     x + 1 % 3;
-   |         ^^^^^
+   |         ^^^^^ help: consider reducing it to: `1`
 
-error: the operation is ineffective. Consider reducing it to `if b { 1 } else { 2 }`
-  --> $DIR/identity_op.rs:84:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:88:5
    |
 LL |     0 + if b { 1 } else { 2 };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
 
-error: the operation is ineffective. Consider reducing it to `match a { 0 => 10, _ => 20 }`
-  --> $DIR/identity_op.rs:86:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:89: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:90:5
    |
 LL |     0 + match a { 0 => 10, _ => 20 };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })`
 
-error: the operation is ineffective. Consider reducing it to `if b { 0 + 1 } else { 2 }`
+error: this operation has no effect
   --> $DIR/identity_op.rs:91:5
    |
-LL |     0 + if b { 0 + 1 } else { 2 };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     0 + match a { 0 => 10, _ => 20 } + match a { 0 => 30, _ => 40 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })`
 
-error: the operation is ineffective. Consider reducing it to `1`
-  --> $DIR/identity_op.rs:91:16
+error: this operation has no effect
+  --> $DIR/identity_op.rs:92:5
    |
-LL |     0 + if b { 0 + 1 } else { 2 };
-   |                ^^^^^
+LL |     0 + if b { 1 } else { 2 } + match a { 0 => 30, _ => 40 };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
 
-error: the operation is ineffective. Consider reducing it to `match a { 0 =>  0 + 10, _ => 20 }`
-  --> $DIR/identity_op.rs:92:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:93: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:94: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:96:5
    |
-LL |     0 + match a { 0 =>  0 + 10, _ => 20 };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     0 + { a } + 3;
+   |     ^^^^^^^^^ help: consider reducing it to: `({ a })`
 
-error: the operation is ineffective. Consider reducing it to `10`
-  --> $DIR/identity_op.rs:92:25
+error: this operation has no effect
+  --> $DIR/identity_op.rs:97:5
    |
-LL |     0 + match a { 0 =>  0 + 10, _ => 20 };
-   |                         ^^^^^^
+LL |     0 + { a } * 2;
+   |     ^^^^^^^^^^^^^ help: consider reducing it to: `({ a } * 2)`
 
-error: the operation is ineffective. Consider reducing it to `1`
-  --> $DIR/identity_op.rs:93:16
+error: this operation has no effect
+  --> $DIR/identity_op.rs:98:5
    |
-LL |     0 + if b { 0 + 1 } else { 2 } + match a { 0 => 0 + 30, _ => 40 };
-   |                ^^^^^
+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: the operation is ineffective. Consider reducing it to `30`
-  --> $DIR/identity_op.rs:93:52
+error: this operation has no effect
+  --> $DIR/identity_op.rs:103:7
    |
-LL |     0 + if b { 0 + 1 } else { 2 } + match a { 0 => 0 + 30, _ => 40 };
-   |                                                    ^^^^^^
+LL |     f(1 * a + { 8 * 5 });
+   |       ^^^^^ help: consider reducing it to: `a`
 
-error: the operation is ineffective. Consider reducing it to `1`
-  --> $DIR/identity_op.rs:95:20
+error: this operation has no effect
+  --> $DIR/identity_op.rs:104:7
    |
-LL |     let _ = 0 + if 0 + 1 > 0 { 1 } else { 2 } + if 0 + 1 > 0 { 3 } else { 4 };
-   |                    ^^^^^
+LL |     f(0 + if b { 1 } else { 2 } + 3);
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `if b { 1 } else { 2 }`
 
-error: the operation is ineffective. Consider reducing it to `1`
-  --> $DIR/identity_op.rs:95:52
+error: this operation has no effect
+  --> $DIR/identity_op.rs:105:20
    |
-LL |     let _ = 0 + if 0 + 1 > 0 { 1 } else { 2 } + if 0 + 1 > 0 { 3 } else { 4 };
-   |                                                    ^^^^^
+LL |     const _: i32 = { 2 * 4 } + 0 + 3;
+   |                    ^^^^^^^^^^^^^ help: consider reducing it to: `{ 2 * 4 }`
 
-error: the operation is ineffective. Consider reducing it to `1`
-  --> $DIR/identity_op.rs:96:23
+error: this operation has no effect
+  --> $DIR/identity_op.rs:106:20
    |
-LL |     let _ = 0 + match 0 + 1 { 0 => 10, _ => 20 } + match 0 + 1  { 0 => 30, _ => 40 };
-   |                       ^^^^^
+LL |     const _: i32 = 0 + { 1 + 2 * 3 } + 3;
+   |                    ^^^^^^^^^^^^^^^^^ help: consider reducing it to: `{ 1 + 2 * 3 }`
 
-error: the operation is ineffective. Consider reducing it to `1`
-  --> $DIR/identity_op.rs:96:58
+error: this operation has no effect
+  --> $DIR/identity_op.rs:108:5
    |
-LL |     let _ = 0 + match 0 + 1 { 0 => 10, _ => 20 } + match 0 + 1  { 0 => 30, _ => 40 };
-   |                                                          ^^^^^
+LL |     0 + a as usize;
+   |     ^^^^^^^^^^^^^^ help: consider reducing it to: `a as usize`
 
-error: the operation is ineffective. Consider reducing it to `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }`
-  --> $DIR/identity_op.rs:98:5
+error: this operation has no effect
+  --> $DIR/identity_op.rs:109:13
    |
-LL |     0 + if b { 1 } else { 2 } + if b { 3 } else { 4 } + 0;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _ = 0 + a as usize;
+   |             ^^^^^^^^^^^^^^ help: consider reducing it to: `a as usize`
 
-error: the operation is ineffective. Consider reducing it to `a`
-  --> $DIR/identity_op.rs:106:7
+error: this operation has no effect
+  --> $DIR/identity_op.rs:110:5
    |
-LL |     f(1 * a + { 8 * 5 });
-   |       ^^^^^
+LL |     0 + { a } as usize;
+   |     ^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `({ a } as usize)`
 
-error: the operation is ineffective. Consider reducing it to `{ 2 * 4 }`
-  --> $DIR/identity_op.rs:108:20
+error: this operation has no effect
+  --> $DIR/identity_op.rs:112:9
    |
-LL |     const _: i32 = { 2 * 4 } + 0 + 3;
-   |                    ^^^^^^^^^^^^^
+LL |     2 * (0 + { a });
+   |         ^^^^^^^^^^^ help: consider reducing it to: `{ a }`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:113:5
+   |
+LL |     1 * ({ a } + 4);
+   |     ^^^^^^^^^^^^^^^ help: consider reducing it to: `(({ a } + 4))`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:114:5
+   |
+LL |     1 * 1;
+   |     ^^^^^ help: consider reducing it to: `1`
+
+error: this operation has no effect
+  --> $DIR/identity_op.rs:118: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 33 previous errors
+error: aborting due to 39 previous errors
 
diff --git a/tests/ui/implicit_clone.fixed b/tests/ui/implicit_clone.fixed
new file mode 100644
index 00000000000..33770fc2a2c
--- /dev/null
+++ b/tests/ui/implicit_clone.fixed
@@ -0,0 +1,118 @@
+// run-rustfix
+#![warn(clippy::implicit_clone)]
+#![allow(clippy::clone_on_copy, clippy::redundant_clone)]
+use std::borrow::Borrow;
+use std::ffi::{OsStr, OsString};
+use std::path::PathBuf;
+
+fn return_owned_from_slice(slice: &[u32]) -> Vec<u32> {
+    slice.to_owned()
+}
+
+pub fn own_same<T>(v: T) -> T
+where
+    T: ToOwned<Owned = T>,
+{
+    v.to_owned()
+}
+
+pub fn own_same_from_ref<T>(v: &T) -> T
+where
+    T: ToOwned<Owned = T>,
+{
+    v.to_owned()
+}
+
+pub fn own_different<T, U>(v: T) -> U
+where
+    T: ToOwned<Owned = U>,
+{
+    v.to_owned()
+}
+
+#[derive(Copy, Clone)]
+struct Kitten;
+impl Kitten {
+    // badly named method
+    fn to_vec(self) -> Kitten {
+        Kitten {}
+    }
+}
+impl Borrow<BorrowedKitten> for Kitten {
+    fn borrow(&self) -> &BorrowedKitten {
+        static VALUE: BorrowedKitten = BorrowedKitten {};
+        &VALUE
+    }
+}
+
+struct BorrowedKitten;
+impl ToOwned for BorrowedKitten {
+    type Owned = Kitten;
+    fn to_owned(&self) -> Kitten {
+        Kitten {}
+    }
+}
+
+mod weird {
+    #[allow(clippy::ptr_arg)]
+    pub fn to_vec(v: &Vec<u32>) -> Vec<u32> {
+        v.clone()
+    }
+}
+
+fn main() {
+    let vec = vec![5];
+    let _ = return_owned_from_slice(&vec);
+    let _ = vec.clone();
+    let _ = vec.clone();
+
+    let vec_ref = &vec;
+    let _ = return_owned_from_slice(vec_ref);
+    let _ = vec_ref.clone();
+    let _ = vec_ref.clone();
+
+    // we expect no lint for this
+    let _ = weird::to_vec(&vec);
+
+    // we expect no lints for this
+    let slice: &[u32] = &[1, 2, 3, 4, 5];
+    let _ = return_owned_from_slice(slice);
+    let _ = slice.to_owned();
+    let _ = slice.to_vec();
+
+    let str = "hello world".to_string();
+    let _ = str.clone();
+
+    // testing w/ an arbitrary type
+    let kitten = Kitten {};
+    let _ = kitten.clone();
+    let _ = own_same_from_ref(&kitten);
+    // this shouln't lint
+    let _ = kitten.to_vec();
+
+    // we expect no lints for this
+    let borrowed = BorrowedKitten {};
+    let _ = borrowed.to_owned();
+
+    let pathbuf = PathBuf::new();
+    let _ = pathbuf.clone();
+    let _ = pathbuf.clone();
+
+    let os_string = OsString::from("foo");
+    let _ = os_string.clone();
+    let _ = os_string.clone();
+
+    // we expect no lints for this
+    let os_str = OsStr::new("foo");
+    let _ = os_str.to_owned();
+    let _ = os_str.to_os_string();
+
+    // issue #8227
+    let pathbuf_ref = &pathbuf;
+    let pathbuf_ref = &pathbuf_ref;
+    let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&PathBuf`
+    let _ = (*pathbuf_ref).clone();
+    let pathbuf_ref = &pathbuf_ref;
+    let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
+    let _ = (**pathbuf_ref).clone();
+}
diff --git a/tests/ui/implicit_clone.rs b/tests/ui/implicit_clone.rs
index 2549c9f32f9..fc896525bd2 100644
--- a/tests/ui/implicit_clone.rs
+++ b/tests/ui/implicit_clone.rs
@@ -1,5 +1,6 @@
+// run-rustfix
 #![warn(clippy::implicit_clone)]
-#![allow(clippy::redundant_clone)]
+#![allow(clippy::clone_on_copy, clippy::redundant_clone)]
 use std::borrow::Borrow;
 use std::ffi::{OsStr, OsString};
 use std::path::PathBuf;
diff --git a/tests/ui/implicit_clone.stderr b/tests/ui/implicit_clone.stderr
index 0f412424190..92c1aa58aff 100644
--- a/tests/ui/implicit_clone.stderr
+++ b/tests/ui/implicit_clone.stderr
@@ -1,5 +1,5 @@
 error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:65:13
+  --> $DIR/implicit_clone.rs:66:13
    |
 LL |     let _ = vec.to_owned();
    |             ^^^^^^^^^^^^^^ help: consider using: `vec.clone()`
@@ -7,67 +7,67 @@ LL |     let _ = vec.to_owned();
    = note: `-D clippy::implicit-clone` implied by `-D warnings`
 
 error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type
-  --> $DIR/implicit_clone.rs:66:13
+  --> $DIR/implicit_clone.rs:67:13
    |
 LL |     let _ = vec.to_vec();
    |             ^^^^^^^^^^^^ help: consider using: `vec.clone()`
 
 error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:70:13
+  --> $DIR/implicit_clone.rs:71:13
    |
 LL |     let _ = vec_ref.to_owned();
    |             ^^^^^^^^^^^^^^^^^^ help: consider using: `vec_ref.clone()`
 
 error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type
-  --> $DIR/implicit_clone.rs:71:13
+  --> $DIR/implicit_clone.rs:72:13
    |
 LL |     let _ = vec_ref.to_vec();
    |             ^^^^^^^^^^^^^^^^ help: consider using: `vec_ref.clone()`
 
 error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:83:13
+  --> $DIR/implicit_clone.rs:84:13
    |
 LL |     let _ = str.to_owned();
    |             ^^^^^^^^^^^^^^ help: consider using: `str.clone()`
 
 error: implicitly cloning a `Kitten` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:87:13
+  --> $DIR/implicit_clone.rs:88:13
    |
 LL |     let _ = kitten.to_owned();
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `kitten.clone()`
 
 error: implicitly cloning a `PathBuf` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:97:13
+  --> $DIR/implicit_clone.rs:98:13
    |
 LL |     let _ = pathbuf.to_owned();
    |             ^^^^^^^^^^^^^^^^^^ help: consider using: `pathbuf.clone()`
 
 error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type
-  --> $DIR/implicit_clone.rs:98:13
+  --> $DIR/implicit_clone.rs:99:13
    |
 LL |     let _ = pathbuf.to_path_buf();
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `pathbuf.clone()`
 
 error: implicitly cloning a `OsString` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:101:13
+  --> $DIR/implicit_clone.rs:102:13
    |
 LL |     let _ = os_string.to_owned();
    |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `os_string.clone()`
 
 error: implicitly cloning a `OsString` by calling `to_os_string` on its dereferenced type
-  --> $DIR/implicit_clone.rs:102:13
+  --> $DIR/implicit_clone.rs:103:13
    |
 LL |     let _ = os_string.to_os_string();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `os_string.clone()`
 
 error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type
-  --> $DIR/implicit_clone.rs:113:13
+  --> $DIR/implicit_clone.rs:114:13
    |
 LL |     let _ = pathbuf_ref.to_path_buf();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(*pathbuf_ref).clone()`
 
 error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type
-  --> $DIR/implicit_clone.rs:116:13
+  --> $DIR/implicit_clone.rs:117:13
    |
 LL |     let _ = pathbuf_ref.to_path_buf();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(**pathbuf_ref).clone()`
diff --git a/tests/ui/issue_2356.fixed b/tests/ui/issue_2356.fixed
new file mode 100644
index 00000000000..942e99fa878
--- /dev/null
+++ b/tests/ui/issue_2356.fixed
@@ -0,0 +1,26 @@
+// run-rustfix
+#![deny(clippy::while_let_on_iterator)]
+#![allow(unused_mut)]
+
+use std::iter::Iterator;
+
+struct Foo;
+
+impl Foo {
+    fn foo1<I: Iterator<Item = usize>>(mut it: I) {
+        while let Some(_) = it.next() {
+            println!("{:?}", it.size_hint());
+        }
+    }
+
+    fn foo2<I: Iterator<Item = usize>>(mut it: I) {
+        for e in it {
+            println!("{:?}", e);
+        }
+    }
+}
+
+fn main() {
+    Foo::foo1(vec![].into_iter());
+    Foo::foo2(vec![].into_iter());
+}
diff --git a/tests/ui/issue_2356.rs b/tests/ui/issue_2356.rs
index da580a1839a..b000234ea59 100644
--- a/tests/ui/issue_2356.rs
+++ b/tests/ui/issue_2356.rs
@@ -1,4 +1,6 @@
+// run-rustfix
 #![deny(clippy::while_let_on_iterator)]
+#![allow(unused_mut)]
 
 use std::iter::Iterator;
 
diff --git a/tests/ui/issue_2356.stderr b/tests/ui/issue_2356.stderr
index 51b872e21c0..4e3ff7522e0 100644
--- a/tests/ui/issue_2356.stderr
+++ b/tests/ui/issue_2356.stderr
@@ -1,11 +1,11 @@
 error: this loop could be written as a `for` loop
-  --> $DIR/issue_2356.rs:15:9
+  --> $DIR/issue_2356.rs:17:9
    |
 LL |         while let Some(e) = it.next() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for e in it`
    |
 note: the lint level is defined here
-  --> $DIR/issue_2356.rs:1:9
+  --> $DIR/issue_2356.rs:2:9
    |
 LL | #![deny(clippy::while_let_on_iterator)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/iter_next_slice.fixed b/tests/ui/iter_next_slice.fixed
index 11ffc8edb14..f612d26aaab 100644
--- a/tests/ui/iter_next_slice.fixed
+++ b/tests/ui/iter_next_slice.fixed
@@ -6,8 +6,8 @@ fn main() {
     let s = [1, 2, 3];
     let v = vec![1, 2, 3];
 
-    let _ = s.get(0);
-    // Should be replaced by s.get(0)
+    let _ = s.first();
+    // Should be replaced by s.first()
 
     let _ = s.get(2);
     // Should be replaced by s.get(2)
@@ -15,8 +15,8 @@ fn main() {
     let _ = v.get(5);
     // Should be replaced by v.get(5)
 
-    let _ = v.get(0);
-    // Should be replaced by v.get(0)
+    let _ = v.first();
+    // Should be replaced by v.first()
 
     let o = Some(5);
     o.iter().next();
diff --git a/tests/ui/iter_next_slice.rs b/tests/ui/iter_next_slice.rs
index e0d3aabd54a..5195f1c8667 100644
--- a/tests/ui/iter_next_slice.rs
+++ b/tests/ui/iter_next_slice.rs
@@ -7,7 +7,7 @@ fn main() {
     let v = vec![1, 2, 3];
 
     let _ = s.iter().next();
-    // Should be replaced by s.get(0)
+    // Should be replaced by s.first()
 
     let _ = s[2..].iter().next();
     // Should be replaced by s.get(2)
@@ -16,7 +16,7 @@ fn main() {
     // Should be replaced by v.get(5)
 
     let _ = v.iter().next();
-    // Should be replaced by v.get(0)
+    // Should be replaced by v.first()
 
     let o = Some(5);
     o.iter().next();
diff --git a/tests/ui/iter_next_slice.stderr b/tests/ui/iter_next_slice.stderr
index a78d2c2d5e8..d8b89061ff8 100644
--- a/tests/ui/iter_next_slice.stderr
+++ b/tests/ui/iter_next_slice.stderr
@@ -2,7 +2,7 @@ error: using `.iter().next()` on an array
   --> $DIR/iter_next_slice.rs:9:13
    |
 LL |     let _ = s.iter().next();
-   |             ^^^^^^^^^^^^^^^ help: try calling: `s.get(0)`
+   |             ^^^^^^^^^^^^^^^ help: try calling: `s.first()`
    |
    = note: `-D clippy::iter-next-slice` implied by `-D warnings`
 
@@ -22,7 +22,7 @@ error: using `.iter().next()` on an array
   --> $DIR/iter_next_slice.rs:18:13
    |
 LL |     let _ = v.iter().next();
-   |             ^^^^^^^^^^^^^^^ help: try calling: `v.get(0)`
+   |             ^^^^^^^^^^^^^^^ help: try calling: `v.first()`
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs
index cee9e2372c2..23152a13322 100644
--- a/tests/ui/large_enum_variant.rs
+++ b/tests/ui/large_enum_variant.rs
@@ -98,6 +98,38 @@ struct Struct2 {
     a: [i32; 8000],
 }
 
+#[derive(Copy, Clone)]
+enum CopyableLargeEnum {
+    A(bool),
+    B([u128; 4000]),
+}
+
+enum ManuallyCopyLargeEnum {
+    A(bool),
+    B([u128; 4000]),
+}
+
+impl Clone for ManuallyCopyLargeEnum {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl Copy for ManuallyCopyLargeEnum {}
+
+enum SomeGenericPossiblyCopyEnum<T> {
+    A(bool, std::marker::PhantomData<T>),
+    B([u64; 4000]),
+}
+
+impl<T: Copy> Clone for SomeGenericPossiblyCopyEnum<T> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<T: Copy> Copy for SomeGenericPossiblyCopyEnum<T> {}
+
 fn main() {
     large_enum_variant!();
 }
diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr
index cbf2ac972e2..0248327262d 100644
--- a/tests/ui/large_enum_variant.stderr
+++ b/tests/ui/large_enum_variant.stderr
@@ -127,5 +127,71 @@ help: consider boxing the large fields to reduce the total size of the enum
 LL |     B(Box<Struct2>),
    |       ~~~~~~~~~~~~
 
-error: aborting due to 8 previous errors
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:104:5
+   |
+LL |     B([u128; 4000]),
+   |     ^^^^^^^^^^^^^^^ this variant is 64000 bytes
+   |
+note: and the second-largest variant is 1 bytes:
+  --> $DIR/large_enum_variant.rs:103:5
+   |
+LL |     A(bool),
+   |     ^^^^^^^
+note: boxing a variant would require the type no longer be `Copy`
+  --> $DIR/large_enum_variant.rs:102:6
+   |
+LL | enum CopyableLargeEnum {
+   |      ^^^^^^^^^^^^^^^^^
+help: consider boxing the large fields to reduce the total size of the enum
+  --> $DIR/large_enum_variant.rs:104:5
+   |
+LL |     B([u128; 4000]),
+   |     ^^^^^^^^^^^^^^^
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:109:5
+   |
+LL |     B([u128; 4000]),
+   |     ^^^^^^^^^^^^^^^ this variant is 64000 bytes
+   |
+note: and the second-largest variant is 1 bytes:
+  --> $DIR/large_enum_variant.rs:108:5
+   |
+LL |     A(bool),
+   |     ^^^^^^^
+note: boxing a variant would require the type no longer be `Copy`
+  --> $DIR/large_enum_variant.rs:107:6
+   |
+LL | enum ManuallyCopyLargeEnum {
+   |      ^^^^^^^^^^^^^^^^^^^^^
+help: consider boxing the large fields to reduce the total size of the enum
+  --> $DIR/large_enum_variant.rs:109:5
+   |
+LL |     B([u128; 4000]),
+   |     ^^^^^^^^^^^^^^^
+
+error: large size difference between variants
+  --> $DIR/large_enum_variant.rs:122:5
+   |
+LL |     B([u64; 4000]),
+   |     ^^^^^^^^^^^^^^ this variant is 32000 bytes
+   |
+note: and the second-largest variant is 1 bytes:
+  --> $DIR/large_enum_variant.rs:121:5
+   |
+LL |     A(bool, std::marker::PhantomData<T>),
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: boxing a variant would require the type no longer be `Copy`
+  --> $DIR/large_enum_variant.rs:120:6
+   |
+LL | enum SomeGenericPossiblyCopyEnum<T> {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider boxing the large fields to reduce the total size of the enum
+  --> $DIR/large_enum_variant.rs:122:5
+   |
+LL |     B([u64; 4000]),
+   |     ^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
 
diff --git a/tests/ui/map_flatten_fixable.fixed b/tests/ui/map_flatten_fixable.fixed
index fec3a95edd6..928e5bd509c 100644
--- a/tests/ui/map_flatten_fixable.fixed
+++ b/tests/ui/map_flatten_fixable.fixed
@@ -28,4 +28,41 @@ fn main() {
 
     // mapping to Result on Result
     let _: Result<_, &str> = (Ok(Ok(1))).and_then(|x| x);
+
+    issue8734();
+    issue8878();
+}
+
+fn issue8734() {
+    //     let _ = [0u8, 1, 2, 3]
+    //         .into_iter()
+    //         .map(|n| match n {
+    //             1 => [n
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)],
+    //             n => [n],
+    //         })
+    //         .flatten();
+}
+
+#[allow(clippy::bind_instead_of_map)] // map + flatten will be suggested to `and_then`, but afterwards `map` is suggested again
+#[rustfmt::skip] // whitespace is important for this one
+fn issue8878() {
+    std::collections::HashMap::<u32, u32>::new()
+        .get(&0)
+        .and_then(|_| {
+// we need some newlines
+// so that the span is big enough
+// we need some newlines
+// so that the span is big enough
+// for a splitted output of the diagnostic
+            Some("")
+ // whitespace beforehand is important as well
+        });
 }
diff --git a/tests/ui/map_flatten_fixable.rs b/tests/ui/map_flatten_fixable.rs
index aa1f76e335a..4345c6eee74 100644
--- a/tests/ui/map_flatten_fixable.rs
+++ b/tests/ui/map_flatten_fixable.rs
@@ -28,4 +28,40 @@ fn main() {
 
     // mapping to Result on Result
     let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
+
+    issue8734();
+    issue8878();
+}
+
+fn issue8734() {
+    //     let _ = [0u8, 1, 2, 3]
+    //         .into_iter()
+    //         .map(|n| match n {
+    //             1 => [n
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)
+    //                 .saturating_add(1)],
+    //             n => [n],
+    //         })
+    //         .flatten();
+}
+
+#[allow(clippy::bind_instead_of_map)] // map + flatten will be suggested to `and_then`, but afterwards `map` is suggested again
+#[rustfmt::skip] // whitespace is important for this one
+fn issue8878() {
+    std::collections::HashMap::<u32, u32>::new()
+        .get(&0)
+        .map(|_| {
+// we need some newlines
+// so that the span is big enough
+// for a splitted output of the diagnostic
+            Some("")
+ // whitespace beforehand is important as well
+        })
+        .flatten();
 }
diff --git a/tests/ui/map_flatten_fixable.stderr b/tests/ui/map_flatten_fixable.stderr
index c91c73846b6..828e24acaad 100644
--- a/tests/ui/map_flatten_fixable.stderr
+++ b/tests/ui/map_flatten_fixable.stderr
@@ -76,5 +76,31 @@ help: try replacing `map` with `and_then`, and remove the `.flatten()`
 LL |     let _: Result<_, &str> = (Ok(Ok(1))).and_then(|x| x);
    |                                          ~~~~~~~~~~~~~~~
 
-error: aborting due to 7 previous errors
+error: called `map(..).flatten()` on `Option`
+  --> $DIR/map_flatten_fixable.rs:59:10
+   |
+LL |           .map(|_| {
+   |  __________^
+LL | | // we need some newlines
+LL | | // so that the span is big enough
+LL | | // for a splitted output of the diagnostic
+...  |
+LL | |         })
+LL | |         .flatten();
+   | |__________________^
+   |
+help: try replacing `map` with `and_then`
+   |
+LL ~         .and_then(|_| {
+LL + // we need some newlines
+LL + // so that the span is big enough
+   |
+help: and remove the `.flatten()`
+   |
+LL +             Some("")
+LL +  // whitespace beforehand is important as well
+LL ~         });
+   |
+
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/match_ref_pats.fixed b/tests/ui/match_ref_pats.fixed
new file mode 100644
index 00000000000..1b6c2d92412
--- /dev/null
+++ b/tests/ui/match_ref_pats.fixed
@@ -0,0 +1,118 @@
+// run-rustfix
+#![warn(clippy::match_ref_pats)]
+#![allow(dead_code, unused_variables, clippy::equatable_if_let, clippy::enum_variant_names)]
+
+fn ref_pats() {
+    {
+        let v = &Some(0);
+        match *v {
+            Some(v) => println!("{:?}", v),
+            None => println!("none"),
+        }
+        match v {
+            // This doesn't trigger; we have a different pattern.
+            &Some(v) => println!("some"),
+            other => println!("other"),
+        }
+    }
+    let tup = &(1, 2);
+    match tup {
+        &(v, 1) => println!("{}", v),
+        _ => println!("none"),
+    }
+    // Special case: using `&` both in expr and pats.
+    let w = Some(0);
+    match w {
+        Some(v) => println!("{:?}", v),
+        None => println!("none"),
+    }
+    // False positive: only wildcard pattern.
+    let w = Some(0);
+    #[allow(clippy::match_single_binding)]
+    match w {
+        _ => println!("none"),
+    }
+
+    let a = &Some(0);
+    if a.is_none() {
+        println!("none");
+    }
+
+    let b = Some(0);
+    if b.is_none() {
+        println!("none");
+    }
+}
+
+mod ice_3719 {
+    macro_rules! foo_variant(
+        ($idx:expr) => (Foo::get($idx).unwrap())
+    );
+
+    enum Foo {
+        A,
+        B,
+    }
+
+    impl Foo {
+        fn get(idx: u8) -> Option<&'static Self> {
+            match idx {
+                0 => Some(&Foo::A),
+                1 => Some(&Foo::B),
+                _ => None,
+            }
+        }
+    }
+
+    fn ice_3719() {
+        // ICE #3719
+        match foo_variant!(0) {
+            &Foo::A => println!("A"),
+            _ => println!("Wild"),
+        }
+    }
+}
+
+mod issue_7740 {
+    macro_rules! foobar_variant(
+        ($idx:expr) => (FooBar::get($idx).unwrap())
+    );
+
+    enum FooBar {
+        Foo,
+        Bar,
+        FooBar,
+        BarFoo,
+    }
+
+    impl FooBar {
+        fn get(idx: u8) -> Option<&'static Self> {
+            match idx {
+                0 => Some(&FooBar::Foo),
+                1 => Some(&FooBar::Bar),
+                2 => Some(&FooBar::FooBar),
+                3 => Some(&FooBar::BarFoo),
+                _ => None,
+            }
+        }
+    }
+
+    fn issue_7740() {
+        // Issue #7740
+        match *foobar_variant!(0) {
+            FooBar::Foo => println!("Foo"),
+            FooBar::Bar => println!("Bar"),
+            FooBar::FooBar => println!("FooBar"),
+            _ => println!("Wild"),
+        }
+
+        // This shouldn't trigger
+        if let &FooBar::BarFoo = foobar_variant!(3) {
+            println!("BarFoo");
+        } else {
+            println!("Wild");
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/match_ref_pats.rs b/tests/ui/match_ref_pats.rs
index 7e3674ab8c9..68dfac4e2e9 100644
--- a/tests/ui/match_ref_pats.rs
+++ b/tests/ui/match_ref_pats.rs
@@ -1,5 +1,6 @@
+// run-rustfix
 #![warn(clippy::match_ref_pats)]
-#![allow(clippy::equatable_if_let, clippy::enum_variant_names)]
+#![allow(dead_code, unused_variables, clippy::equatable_if_let, clippy::enum_variant_names)]
 
 fn ref_pats() {
     {
diff --git a/tests/ui/match_ref_pats.stderr b/tests/ui/match_ref_pats.stderr
index 901820077e2..353f7399d9c 100644
--- a/tests/ui/match_ref_pats.stderr
+++ b/tests/ui/match_ref_pats.stderr
@@ -1,5 +1,5 @@
 error: you don't need to add `&` to all patterns
-  --> $DIR/match_ref_pats.rs:7:9
+  --> $DIR/match_ref_pats.rs:8:9
    |
 LL | /         match v {
 LL | |             &Some(v) => println!("{:?}", v),
@@ -16,7 +16,7 @@ LL ~             None => println!("none"),
    |
 
 error: you don't need to add `&` to both the expression and the patterns
-  --> $DIR/match_ref_pats.rs:24:5
+  --> $DIR/match_ref_pats.rs:25:5
    |
 LL | /     match &w {
 LL | |         &Some(v) => println!("{:?}", v),
@@ -32,7 +32,7 @@ LL ~         None => println!("none"),
    |
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/match_ref_pats.rs:36:12
+  --> $DIR/match_ref_pats.rs:37:12
    |
 LL |     if let &None = a {
    |     -------^^^^^---- help: try this: `if a.is_none()`
@@ -40,13 +40,13 @@ LL |     if let &None = a {
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/match_ref_pats.rs:41:12
+  --> $DIR/match_ref_pats.rs:42:12
    |
 LL |     if let &None = &b {
    |     -------^^^^^----- help: try this: `if b.is_none()`
 
 error: you don't need to add `&` to all patterns
-  --> $DIR/match_ref_pats.rs:101:9
+  --> $DIR/match_ref_pats.rs:102:9
    |
 LL | /         match foobar_variant!(0) {
 LL | |             &FooBar::Foo => println!("Foo"),
diff --git a/tests/ui/match_str_case_mismatch.fixed b/tests/ui/match_str_case_mismatch.fixed
new file mode 100644
index 00000000000..e436bcf495f
--- /dev/null
+++ b/tests/ui/match_str_case_mismatch.fixed
@@ -0,0 +1,186 @@
+// run-rustfix
+#![warn(clippy::match_str_case_mismatch)]
+#![allow(dead_code)]
+
+// Valid
+
+fn as_str_match() {
+    let var = "BAR";
+
+    match var.to_ascii_lowercase().as_str() {
+        "foo" => {},
+        "bar" => {},
+        _ => {},
+    }
+}
+
+fn non_alphabetic() {
+    let var = "~!@#$%^&*()-_=+FOO";
+
+    match var.to_ascii_lowercase().as_str() {
+        "1234567890" => {},
+        "~!@#$%^&*()-_=+foo" => {},
+        "\n\r\t\x7F" => {},
+        _ => {},
+    }
+}
+
+fn unicode_cased() {
+    let var = "ВОДЫ";
+
+    match var.to_lowercase().as_str() {
+        "水" => {},
+        "νερό" => {},
+        "воды" => {},
+        "물" => {},
+        _ => {},
+    }
+}
+
+fn titlecase() {
+    let var = "BarDz";
+
+    match var.to_lowercase().as_str() {
+        "foolj" => {},
+        "bardz" => {},
+        _ => {},
+    }
+}
+
+fn no_case_equivalent() {
+    let var = "barʁ";
+
+    match var.to_uppercase().as_str() {
+        "FOOɕ" => {},
+        "BARʁ" => {},
+        _ => {},
+    }
+}
+
+fn addrof_unary_match() {
+    let var = "BAR";
+
+    match &*var.to_ascii_lowercase() {
+        "foo" => {},
+        "bar" => {},
+        _ => {},
+    }
+}
+
+fn alternating_chain() {
+    let var = "BAR";
+
+    match &*var
+        .to_ascii_lowercase()
+        .to_uppercase()
+        .to_lowercase()
+        .to_ascii_uppercase()
+    {
+        "FOO" => {},
+        "BAR" => {},
+        _ => {},
+    }
+}
+
+fn unrelated_method() {
+    struct Item {
+        a: String,
+    }
+
+    impl Item {
+        #[allow(clippy::wrong_self_convention)]
+        fn to_lowercase(self) -> String {
+            self.a
+        }
+    }
+
+    let item = Item { a: String::from("BAR") };
+
+    match &*item.to_lowercase() {
+        "FOO" => {},
+        "BAR" => {},
+        _ => {},
+    }
+}
+
+// Invalid
+
+fn as_str_match_mismatch() {
+    let var = "BAR";
+
+    match var.to_ascii_lowercase().as_str() {
+        "foo" => {},
+        "bar" => {},
+        _ => {},
+    }
+}
+
+fn non_alphabetic_mismatch() {
+    let var = "~!@#$%^&*()-_=+FOO";
+
+    match var.to_ascii_lowercase().as_str() {
+        "1234567890" => {},
+        "~!@#$%^&*()-_=+foo" => {},
+        "\n\r\t\x7F" => {},
+        _ => {},
+    }
+}
+
+fn unicode_cased_mismatch() {
+    let var = "ВОДЫ";
+
+    match var.to_lowercase().as_str() {
+        "水" => {},
+        "νερό" => {},
+        "воды" => {},
+        "물" => {},
+        _ => {},
+    }
+}
+
+fn titlecase_mismatch() {
+    let var = "BarDz";
+
+    match var.to_lowercase().as_str() {
+        "foolj" => {},
+        "bardz" => {},
+        _ => {},
+    }
+}
+
+fn no_case_equivalent_mismatch() {
+    let var = "barʁ";
+
+    match var.to_uppercase().as_str() {
+        "FOOɕ" => {},
+        "BARʁ" => {},
+        _ => {},
+    }
+}
+
+fn addrof_unary_match_mismatch() {
+    let var = "BAR";
+
+    match &*var.to_ascii_lowercase() {
+        "foo" => {},
+        "bar" => {},
+        _ => {},
+    }
+}
+
+fn alternating_chain_mismatch() {
+    let var = "BAR";
+
+    match &*var
+        .to_ascii_lowercase()
+        .to_uppercase()
+        .to_lowercase()
+        .to_ascii_uppercase()
+    {
+        "FOO" => {},
+        "BAR" => {},
+        _ => {},
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/match_str_case_mismatch.rs b/tests/ui/match_str_case_mismatch.rs
index ac555c87d83..92e2a000ade 100644
--- a/tests/ui/match_str_case_mismatch.rs
+++ b/tests/ui/match_str_case_mismatch.rs
@@ -1,4 +1,6 @@
+// run-rustfix
 #![warn(clippy::match_str_case_mismatch)]
+#![allow(dead_code)]
 
 // Valid
 
diff --git a/tests/ui/match_str_case_mismatch.stderr b/tests/ui/match_str_case_mismatch.stderr
index 92baa40ef28..197520a3d60 100644
--- a/tests/ui/match_str_case_mismatch.stderr
+++ b/tests/ui/match_str_case_mismatch.stderr
@@ -1,5 +1,5 @@
 error: this `match` arm has a differing case than its expression
-  --> $DIR/match_str_case_mismatch.rs:111:9
+  --> $DIR/match_str_case_mismatch.rs:113:9
    |
 LL |         "Bar" => {},
    |         ^^^^^
@@ -11,7 +11,7 @@ LL |         "bar" => {},
    |         ~~~~~
 
 error: this `match` arm has a differing case than its expression
-  --> $DIR/match_str_case_mismatch.rs:121:9
+  --> $DIR/match_str_case_mismatch.rs:123:9
    |
 LL |         "~!@#$%^&*()-_=+Foo" => {},
    |         ^^^^^^^^^^^^^^^^^^^^
@@ -22,7 +22,7 @@ LL |         "~!@#$%^&*()-_=+foo" => {},
    |         ~~~~~~~~~~~~~~~~~~~~
 
 error: this `match` arm has a differing case than its expression
-  --> $DIR/match_str_case_mismatch.rs:133:9
+  --> $DIR/match_str_case_mismatch.rs:135:9
    |
 LL |         "Воды" => {},
    |         ^^^^^^
@@ -33,7 +33,7 @@ LL |         "воды" => {},
    |         ~~~~~~
 
 error: this `match` arm has a differing case than its expression
-  --> $DIR/match_str_case_mismatch.rs:144:9
+  --> $DIR/match_str_case_mismatch.rs:146:9
    |
 LL |         "barDz" => {},
    |         ^^^^^^
@@ -44,7 +44,7 @@ LL |         "bardz" => {},
    |         ~~~~~~
 
 error: this `match` arm has a differing case than its expression
-  --> $DIR/match_str_case_mismatch.rs:154:9
+  --> $DIR/match_str_case_mismatch.rs:156:9
    |
 LL |         "bARʁ" => {},
    |         ^^^^^^
@@ -55,7 +55,7 @@ LL |         "BARʁ" => {},
    |         ~~~~~~
 
 error: this `match` arm has a differing case than its expression
-  --> $DIR/match_str_case_mismatch.rs:164:9
+  --> $DIR/match_str_case_mismatch.rs:166:9
    |
 LL |         "Bar" => {},
    |         ^^^^^
@@ -66,7 +66,7 @@ LL |         "bar" => {},
    |         ~~~~~
 
 error: this `match` arm has a differing case than its expression
-  --> $DIR/match_str_case_mismatch.rs:179:9
+  --> $DIR/match_str_case_mismatch.rs:181:9
    |
 LL |         "bAR" => {},
    |         ^^^^^
diff --git a/tests/ui/mismatching_type_param_order.rs b/tests/ui/mismatching_type_param_order.rs
new file mode 100644
index 00000000000..8f286c9304c
--- /dev/null
+++ b/tests/ui/mismatching_type_param_order.rs
@@ -0,0 +1,60 @@
+#![warn(clippy::mismatching_type_param_order)]
+#![allow(clippy::blacklisted_name)]
+
+fn main() {
+    struct Foo<A, B> {
+        x: A,
+        y: B,
+    }
+
+    // lint on both params
+    impl<B, A> Foo<B, A> {}
+
+    // lint on the 2nd param
+    impl<C, A> Foo<C, A> {}
+
+    // should not lint
+    impl<A, B> Foo<A, B> {}
+
+    struct FooLifetime<'l, 'm, A, B> {
+        x: &'l A,
+        y: &'m B,
+    }
+
+    // should not lint on lifetimes
+    impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {}
+
+    struct Bar {
+        x: i32,
+    }
+
+    // should not lint
+    impl Bar {}
+
+    // also works for enums
+    enum FooEnum<A, B, C> {
+        X(A),
+        Y(B),
+        Z(C),
+    }
+
+    impl<C, A, B> FooEnum<C, A, B> {}
+
+    // also works for unions
+    union FooUnion<A: Copy, B>
+    where
+        B: Copy,
+    {
+        x: A,
+        y: B,
+    }
+
+    impl<B: Copy, A> FooUnion<B, A> where A: Copy {}
+
+    impl<A, B> FooUnion<A, B>
+    where
+        A: Copy,
+        B: Copy,
+    {
+    }
+}
diff --git a/tests/ui/mismatching_type_param_order.stderr b/tests/ui/mismatching_type_param_order.stderr
new file mode 100644
index 00000000000..cb720256c50
--- /dev/null
+++ b/tests/ui/mismatching_type_param_order.stderr
@@ -0,0 +1,83 @@
+error: `Foo` has a similarly named generic type parameter `B` in its declaration, but in a different order
+  --> $DIR/mismatching_type_param_order.rs:11:20
+   |
+LL |     impl<B, A> Foo<B, A> {}
+   |                    ^
+   |
+   = note: `-D clippy::mismatching-type-param-order` implied by `-D warnings`
+   = help: try `A`, or a name that does not conflict with `Foo`'s generic params
+
+error: `Foo` has a similarly named generic type parameter `A` in its declaration, but in a different order
+  --> $DIR/mismatching_type_param_order.rs:11:23
+   |
+LL |     impl<B, A> Foo<B, A> {}
+   |                       ^
+   |
+   = help: try `B`, or a name that does not conflict with `Foo`'s generic params
+
+error: `Foo` has a similarly named generic type parameter `A` in its declaration, but in a different order
+  --> $DIR/mismatching_type_param_order.rs:14:23
+   |
+LL |     impl<C, A> Foo<C, A> {}
+   |                       ^
+   |
+   = help: try `B`, or a name that does not conflict with `Foo`'s generic params
+
+error: `FooLifetime` has a similarly named generic type parameter `B` in its declaration, but in a different order
+  --> $DIR/mismatching_type_param_order.rs:25:44
+   |
+LL |     impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {}
+   |                                            ^
+   |
+   = help: try `A`, or a name that does not conflict with `FooLifetime`'s generic params
+
+error: `FooLifetime` has a similarly named generic type parameter `A` in its declaration, but in a different order
+  --> $DIR/mismatching_type_param_order.rs:25:47
+   |
+LL |     impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {}
+   |                                               ^
+   |
+   = help: try `B`, or a name that does not conflict with `FooLifetime`'s generic params
+
+error: `FooEnum` has a similarly named generic type parameter `C` in its declaration, but in a different order
+  --> $DIR/mismatching_type_param_order.rs:41:27
+   |
+LL |     impl<C, A, B> FooEnum<C, A, B> {}
+   |                           ^
+   |
+   = help: try `A`, or a name that does not conflict with `FooEnum`'s generic params
+
+error: `FooEnum` has a similarly named generic type parameter `A` in its declaration, but in a different order
+  --> $DIR/mismatching_type_param_order.rs:41:30
+   |
+LL |     impl<C, A, B> FooEnum<C, A, B> {}
+   |                              ^
+   |
+   = help: try `B`, or a name that does not conflict with `FooEnum`'s generic params
+
+error: `FooEnum` has a similarly named generic type parameter `B` in its declaration, but in a different order
+  --> $DIR/mismatching_type_param_order.rs:41:33
+   |
+LL |     impl<C, A, B> FooEnum<C, A, B> {}
+   |                                 ^
+   |
+   = help: try `C`, or a name that does not conflict with `FooEnum`'s generic params
+
+error: `FooUnion` has a similarly named generic type parameter `B` in its declaration, but in a different order
+  --> $DIR/mismatching_type_param_order.rs:52:31
+   |
+LL |     impl<B: Copy, A> FooUnion<B, A> where A: Copy {}
+   |                               ^
+   |
+   = help: try `A`, or a name that does not conflict with `FooUnion`'s generic params
+
+error: `FooUnion` has a similarly named generic type parameter `A` in its declaration, but in a different order
+  --> $DIR/mismatching_type_param_order.rs:52:34
+   |
+LL |     impl<B: Copy, A> FooUnion<B, A> where A: Copy {}
+   |                                  ^
+   |
+   = help: try `B`, or a name that does not conflict with `FooUnion`'s generic params
+
+error: aborting due to 10 previous errors
+
diff --git a/tests/ui/modulo_one.rs b/tests/ui/modulo_one.rs
index 678a312f66e..adff08e5d1e 100644
--- a/tests/ui/modulo_one.rs
+++ b/tests/ui/modulo_one.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::modulo_one)]
-#![allow(clippy::no_effect, clippy::unnecessary_operation)]
+#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::identity_op)]
 
 static STATIC_ONE: usize = 2 - 1;
 static STATIC_NEG_ONE: i64 = 1 - 2;
diff --git a/tests/ui/modulo_one.stderr b/tests/ui/modulo_one.stderr
index 03f460897fc..04ecdef5e99 100644
--- a/tests/ui/modulo_one.stderr
+++ b/tests/ui/modulo_one.stderr
@@ -38,14 +38,6 @@ error: any number modulo -1 will panic/overflow or result in 0
 LL |     i32::MIN % (-1); // also caught by rustc
    |     ^^^^^^^^^^^^^^^
 
-error: the operation is ineffective. Consider reducing it to `1`
-  --> $DIR/modulo_one.rs:13:22
-   |
-LL |     const ONE: u32 = 1 * 1;
-   |                      ^^^^^
-   |
-   = note: `-D clippy::identity-op` implied by `-D warnings`
-
 error: any number modulo 1 will be 0
   --> $DIR/modulo_one.rs:17:5
    |
@@ -64,5 +56,5 @@ error: any number modulo -1 will panic/overflow or result in 0
 LL |     INT_MIN % NEG_ONE; // also caught by rustc
    |     ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 10 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed
new file mode 100644
index 00000000000..fee8e3030b8
--- /dev/null
+++ b/tests/ui/needless_late_init.fixed
@@ -0,0 +1,273 @@
+// run-rustfix
+#![feature(let_chains)]
+#![allow(
+    unused,
+    clippy::assign_op_pattern,
+    clippy::blocks_in_if_conditions,
+    clippy::let_and_return,
+    clippy::let_unit_value,
+    clippy::nonminimal_bool
+)]
+
+use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
+use std::rc::Rc;
+
+struct SignificantDrop;
+impl std::ops::Drop for SignificantDrop {
+    fn drop(&mut self) {
+        println!("dropped");
+    }
+}
+
+fn simple() {
+    
+    let a = "zero";
+
+    
+    
+    let b = 1;
+    let c = 2;
+
+    
+    let d: usize = 1;
+
+    
+    let e = format!("{}", d);
+}
+
+fn main() {
+    
+    let n = 1;
+    let a = match n {
+        1 => "one",
+        _ => {
+            "two"
+        },
+    };
+
+    
+    let b = if n == 3 {
+        "four"
+    } else {
+        "five"
+    };
+
+    
+    let d = if true {
+        let temp = 5;
+        temp
+    } else {
+        15
+    };
+
+    
+    let e = if true {
+        format!("{} {}", a, b)
+    } else {
+        format!("{}", n)
+    };
+
+    
+    let f = match 1 {
+        1 => "three",
+        _ => return,
+    }; // has semi
+
+    
+    let g: usize = if true {
+        5
+    } else {
+        panic!();
+    };
+
+    // Drop order only matters if both are significant
+    
+    let y = SignificantDrop;
+    let x = 1;
+
+    
+    let y = 1;
+    let x = SignificantDrop;
+
+    
+    // types that should be considered insignificant
+    let y = 1;
+    let y = "2";
+    let y = String::new();
+    let y = vec![3.0];
+    let y = HashMap::<usize, usize>::new();
+    let y = BTreeMap::<usize, usize>::new();
+    let y = HashSet::<usize>::new();
+    let y = BTreeSet::<usize>::new();
+    let y = Box::new(4);
+    let x = SignificantDrop;
+}
+
+async fn in_async() -> &'static str {
+    async fn f() -> &'static str {
+        "one"
+    }
+
+    
+    let n = 1;
+    let a = match n {
+        1 => f().await,
+        _ => {
+            "two"
+        },
+    };
+
+    a
+}
+
+const fn in_const() -> &'static str {
+    const fn f() -> &'static str {
+        "one"
+    }
+
+    
+    let n = 1;
+    let a = match n {
+        1 => f(),
+        _ => {
+            "two"
+        },
+    };
+
+    a
+}
+
+fn does_not_lint() {
+    let z;
+    if false {
+        z = 1;
+    }
+
+    let x;
+    let y;
+    if true {
+        x = 1;
+    } else {
+        y = 1;
+    }
+
+    let mut x;
+    if true {
+        x = 5;
+        x = 10 / x;
+    } else {
+        x = 2;
+    }
+
+    let x;
+    let _ = match 1 {
+        1 => x = 10,
+        _ => x = 20,
+    };
+
+    // using tuples would be possible, but not always preferable
+    let x;
+    let y;
+    if true {
+        x = 1;
+        y = 2;
+    } else {
+        x = 3;
+        y = 4;
+    }
+
+    // could match with a smarter heuristic to avoid multiple assignments
+    let x;
+    if true {
+        let mut y = 5;
+        y = 6;
+        x = y;
+    } else {
+        x = 2;
+    }
+
+    let (x, y);
+    if true {
+        x = 1;
+    } else {
+        x = 2;
+    }
+    y = 3;
+
+    macro_rules! assign {
+        ($i:ident) => {
+            $i = 1;
+        };
+    }
+    let x;
+    assign!(x);
+
+    let x;
+    if true {
+        assign!(x);
+    } else {
+        x = 2;
+    }
+
+    macro_rules! in_macro {
+        () => {
+            let x;
+            x = 1;
+
+            let x;
+            if true {
+                x = 1;
+            } else {
+                x = 2;
+            }
+        };
+    }
+    in_macro!();
+
+    // ignore if-lets - https://github.com/rust-lang/rust-clippy/issues/8613
+    let x;
+    if let Some(n) = Some("v") {
+        x = 1;
+    } else {
+        x = 2;
+    }
+
+    let x;
+    if true && let Some(n) = Some("let chains too") {
+        x = 1;
+    } else {
+        x = 2;
+    }
+
+    // ignore mut bindings
+    // https://github.com/shepmaster/twox-hash/blob/b169c16d86eb8ea4a296b0acb9d00ca7e3c3005f/src/sixty_four.rs#L88-L93
+    // https://github.com/dtolnay/thiserror/blob/21c26903e29cb92ba1a7ff11e82ae2001646b60d/tests/test_generics.rs#L91-L100
+    let mut x: usize;
+    x = 1;
+    x = 2;
+    x = 3;
+
+    // should not move the declaration if `x` has a significant drop, and there
+    // is another binding with a significant drop between it and the first usage
+    let x;
+    let y = SignificantDrop;
+    x = SignificantDrop;
+}
+
+#[rustfmt::skip]
+fn issue8911() -> u32 {
+    let x;
+    match 1 {
+        _ if { x = 1; false } => return 1,
+        _ => return 2,
+    }
+
+    let x;
+    if { x = 1; true } {
+        return 1;
+    } else {
+        return 2;
+    }
+
+    3
+}
diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs
index 54e66b391b8..402d9f9ef7f 100644
--- a/tests/ui/needless_late_init.rs
+++ b/tests/ui/needless_late_init.rs
@@ -1,5 +1,13 @@
+// run-rustfix
 #![feature(let_chains)]
-#![allow(unused, clippy::nonminimal_bool, clippy::let_unit_value)]
+#![allow(
+    unused,
+    clippy::assign_op_pattern,
+    clippy::blocks_in_if_conditions,
+    clippy::let_and_return,
+    clippy::let_unit_value,
+    clippy::nonminimal_bool
+)]
 
 use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
 use std::rc::Rc;
@@ -11,6 +19,22 @@ impl std::ops::Drop for SignificantDrop {
     }
 }
 
+fn simple() {
+    let a;
+    a = "zero";
+
+    let b;
+    let c;
+    b = 1;
+    c = 2;
+
+    let d: usize;
+    d = 1;
+
+    let e;
+    e = format!("{}", d);
+}
+
 fn main() {
     let a;
     let n = 1;
@@ -229,3 +253,21 @@ fn does_not_lint() {
     let y = SignificantDrop;
     x = SignificantDrop;
 }
+
+#[rustfmt::skip]
+fn issue8911() -> u32 {
+    let x;
+    match 1 {
+        _ if { x = 1; false } => return 1,
+        _ => return 2,
+    }
+
+    let x;
+    if { x = 1; true } {
+        return 1;
+    } else {
+        return 2;
+    }
+
+    3
+}
diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr
index d33a117b288..f320b5b9cbb 100644
--- a/tests/ui/needless_late_init.stderr
+++ b/tests/ui/needless_late_init.stderr
@@ -1,12 +1,79 @@
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:15:5
+  --> $DIR/needless_late_init.rs:23:5
    |
 LL |     let a;
-   |     ^^^^^^
+   |     ^^^^^^ created here
+LL |     a = "zero";
+   |     ^^^^^^^^^^ initialised here
    |
    = note: `-D clippy::needless-late-init` implied by `-D warnings`
 help: declare `a` here
    |
+LL |     let a = "zero";
+   |     ~~~~~
+
+error: unneeded late initialization
+  --> $DIR/needless_late_init.rs:26:5
+   |
+LL |     let b;
+   |     ^^^^^^ created here
+LL |     let c;
+LL |     b = 1;
+   |     ^^^^^ initialised here
+   |
+help: declare `b` here
+   |
+LL |     let b = 1;
+   |     ~~~~~
+
+error: unneeded late initialization
+  --> $DIR/needless_late_init.rs:27:5
+   |
+LL |     let c;
+   |     ^^^^^^ created here
+LL |     b = 1;
+LL |     c = 2;
+   |     ^^^^^ initialised here
+   |
+help: declare `c` here
+   |
+LL |     let c = 2;
+   |     ~~~~~
+
+error: unneeded late initialization
+  --> $DIR/needless_late_init.rs:31:5
+   |
+LL |     let d: usize;
+   |     ^^^^^^^^^^^^^ created here
+LL |     d = 1;
+   |     ^^^^^ initialised here
+   |
+help: declare `d` here
+   |
+LL |     let d: usize = 1;
+   |     ~~~~~~~~~~~~
+
+error: unneeded late initialization
+  --> $DIR/needless_late_init.rs:34:5
+   |
+LL |     let e;
+   |     ^^^^^^ created here
+LL |     e = format!("{}", d);
+   |     ^^^^^^^^^^^^^^^^^^^^ initialised here
+   |
+help: declare `e` here
+   |
+LL |     let e = format!("{}", d);
+   |     ~~~~~
+
+error: unneeded late initialization
+  --> $DIR/needless_late_init.rs:39:5
+   |
+LL |     let a;
+   |     ^^^^^^
+   |
+help: declare `a` here
+   |
 LL |     let a = match n {
    |     +++++++
 help: remove the assignments from the `match` arms
@@ -21,7 +88,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:24:5
+  --> $DIR/needless_late_init.rs:48:5
    |
 LL |     let b;
    |     ^^^^^^
@@ -42,7 +109,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:31:5
+  --> $DIR/needless_late_init.rs:55:5
    |
 LL |     let d;
    |     ^^^^^^
@@ -63,7 +130,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:39:5
+  --> $DIR/needless_late_init.rs:63:5
    |
 LL |     let e;
    |     ^^^^^^
@@ -84,7 +151,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:46:5
+  --> $DIR/needless_late_init.rs:70:5
    |
 LL |     let f;
    |     ^^^^^^
@@ -100,7 +167,7 @@ LL +         1 => "three",
    | 
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:52:5
+  --> $DIR/needless_late_init.rs:76:5
    |
 LL |     let g: usize;
    |     ^^^^^^^^^^^^^
@@ -120,7 +187,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:60:5
+  --> $DIR/needless_late_init.rs:84:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -134,7 +201,7 @@ LL |     let x = 1;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:64:5
+  --> $DIR/needless_late_init.rs:88:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -148,7 +215,7 @@ LL |     let x = SignificantDrop;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:68:5
+  --> $DIR/needless_late_init.rs:92:5
    |
 LL |     let x;
    |     ^^^^^^ created here
@@ -162,7 +229,7 @@ LL |     let x = SignificantDrop;
    |     ~~~~~
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:87:5
+  --> $DIR/needless_late_init.rs:111:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -183,7 +250,7 @@ LL |     };
    |      +
 
 error: unneeded late initialization
-  --> $DIR/needless_late_init.rs:104:5
+  --> $DIR/needless_late_init.rs:128:5
    |
 LL |     let a;
    |     ^^^^^^
@@ -203,5 +270,5 @@ help: add a semicolon after the `match` expression
 LL |     };
    |      +
 
-error: aborting due to 11 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/tests/ui/needless_late_init_fixable.fixed b/tests/ui/needless_late_init_fixable.fixed
deleted file mode 100644
index 724477e8691..00000000000
--- a/tests/ui/needless_late_init_fixable.fixed
+++ /dev/null
@@ -1,19 +0,0 @@
-// run-rustfix
-
-#![allow(unused, clippy::assign_op_pattern)]
-
-fn main() {
-    
-    let a = "zero";
-
-    
-    
-    let b = 1;
-    let c = 2;
-
-    
-    let d: usize = 1;
-
-    
-    let e = format!("{}", d);
-}
diff --git a/tests/ui/needless_late_init_fixable.rs b/tests/ui/needless_late_init_fixable.rs
deleted file mode 100644
index 3e6bd363672..00000000000
--- a/tests/ui/needless_late_init_fixable.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// run-rustfix
-
-#![allow(unused, clippy::assign_op_pattern)]
-
-fn main() {
-    let a;
-    a = "zero";
-
-    let b;
-    let c;
-    b = 1;
-    c = 2;
-
-    let d: usize;
-    d = 1;
-
-    let e;
-    e = format!("{}", d);
-}
diff --git a/tests/ui/needless_late_init_fixable.stderr b/tests/ui/needless_late_init_fixable.stderr
deleted file mode 100644
index 8c664309e3e..00000000000
--- a/tests/ui/needless_late_init_fixable.stderr
+++ /dev/null
@@ -1,70 +0,0 @@
-error: unneeded late initialization
-  --> $DIR/needless_late_init_fixable.rs:6:5
-   |
-LL |     let a;
-   |     ^^^^^^ created here
-LL |     a = "zero";
-   |     ^^^^^^^^^^ initialised here
-   |
-   = note: `-D clippy::needless-late-init` implied by `-D warnings`
-help: declare `a` here
-   |
-LL |     let a = "zero";
-   |     ~~~~~
-
-error: unneeded late initialization
-  --> $DIR/needless_late_init_fixable.rs:9:5
-   |
-LL |     let b;
-   |     ^^^^^^ created here
-LL |     let c;
-LL |     b = 1;
-   |     ^^^^^ initialised here
-   |
-help: declare `b` here
-   |
-LL |     let b = 1;
-   |     ~~~~~
-
-error: unneeded late initialization
-  --> $DIR/needless_late_init_fixable.rs:10:5
-   |
-LL |     let c;
-   |     ^^^^^^ created here
-LL |     b = 1;
-LL |     c = 2;
-   |     ^^^^^ initialised here
-   |
-help: declare `c` here
-   |
-LL |     let c = 2;
-   |     ~~~~~
-
-error: unneeded late initialization
-  --> $DIR/needless_late_init_fixable.rs:14:5
-   |
-LL |     let d: usize;
-   |     ^^^^^^^^^^^^^ created here
-LL |     d = 1;
-   |     ^^^^^ initialised here
-   |
-help: declare `d` here
-   |
-LL |     let d: usize = 1;
-   |     ~~~~~~~~~~~~
-
-error: unneeded late initialization
-  --> $DIR/needless_late_init_fixable.rs:17:5
-   |
-LL |     let e;
-   |     ^^^^^^ created here
-LL |     e = format!("{}", d);
-   |     ^^^^^^^^^^^^^^^^^^^^ initialised here
-   |
-help: declare `e` here
-   |
-LL |     let e = format!("{}", d);
-   |     ~~~~~
-
-error: aborting due to 5 previous errors
-
diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs
index 1456204ca86..fc686b1dac0 100644
--- a/tests/ui/needless_lifetimes.rs
+++ b/tests/ui/needless_lifetimes.rs
@@ -4,7 +4,8 @@
     clippy::boxed_local,
     clippy::needless_pass_by_value,
     clippy::unnecessary_wraps,
-    dyn_drop
+    dyn_drop,
+    clippy::get_first
 )]
 
 fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
diff --git a/tests/ui/needless_lifetimes.stderr b/tests/ui/needless_lifetimes.stderr
index a488bc01fff..3c428fd4674 100644
--- a/tests/ui/needless_lifetimes.stderr
+++ b/tests/ui/needless_lifetimes.stderr
@@ -1,5 +1,5 @@
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:10:1
+  --> $DIR/needless_lifetimes.rs:11:1
    |
 LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,181 +7,181 @@ LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
    = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:12:1
+  --> $DIR/needless_lifetimes.rs:13:1
    |
 LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:22:1
+  --> $DIR/needless_lifetimes.rs:23:1
    |
 LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:56:1
+  --> $DIR/needless_lifetimes.rs:57:1
    |
 LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:61:1
+  --> $DIR/needless_lifetimes.rs:62:1
    |
 LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:73:1
+  --> $DIR/needless_lifetimes.rs:74:1
    |
 LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:97:1
+  --> $DIR/needless_lifetimes.rs:98:1
    |
 LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:127:5
+  --> $DIR/needless_lifetimes.rs:128:5
    |
 LL |     fn self_and_out<'s>(&'s self) -> &'s u8 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:136:5
+  --> $DIR/needless_lifetimes.rs:137:5
    |
 LL |     fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:155:1
+  --> $DIR/needless_lifetimes.rs:156:1
    |
 LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:185:1
+  --> $DIR/needless_lifetimes.rs:186:1
    |
 LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:191:1
+  --> $DIR/needless_lifetimes.rs:192:1
    |
 LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:210:1
+  --> $DIR/needless_lifetimes.rs:211:1
    |
 LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:218:1
+  --> $DIR/needless_lifetimes.rs:219:1
    |
 LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:254:1
+  --> $DIR/needless_lifetimes.rs:255:1
    |
 LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:261:9
+  --> $DIR/needless_lifetimes.rs:262:9
    |
 LL |         fn needless_lt<'a>(x: &'a u8) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:265:9
+  --> $DIR/needless_lifetimes.rs:266:9
    |
 LL |         fn needless_lt<'a>(_x: &'a u8) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:278:9
+  --> $DIR/needless_lifetimes.rs:279:9
    |
 LL |         fn baz<'a>(&'a self) -> impl Foo + 'a {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:310:5
+  --> $DIR/needless_lifetimes.rs:311:5
    |
 LL |     fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:319:5
+  --> $DIR/needless_lifetimes.rs:320:5
    |
 LL |     fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:331:5
+  --> $DIR/needless_lifetimes.rs:332:5
    |
 LL |     fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:346:5
+  --> $DIR/needless_lifetimes.rs:347:5
    |
 LL |     fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:359:5
+  --> $DIR/needless_lifetimes.rs:360:5
    |
 LL |     fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:362:5
+  --> $DIR/needless_lifetimes.rs:363:5
    |
 LL |     fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:384:9
+  --> $DIR/needless_lifetimes.rs:385:9
    |
 LL |         fn implicit<'a>(&'a self) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:387:9
+  --> $DIR/needless_lifetimes.rs:388:9
    |
 LL |         fn implicit_mut<'a>(&'a mut self) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:398:9
+  --> $DIR/needless_lifetimes.rs:399:9
    |
 LL |         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:404:9
+  --> $DIR/needless_lifetimes.rs:405:9
    |
 LL |         fn implicit<'a>(&'a self) -> &'a ();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:405:9
+  --> $DIR/needless_lifetimes.rs:406:9
    |
 LL |         fn implicit_provided<'a>(&'a self) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:414:9
+  --> $DIR/needless_lifetimes.rs:415:9
    |
 LL |         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:415:9
+  --> $DIR/needless_lifetimes.rs:416:9
    |
 LL |         fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/needless_return.fixed b/tests/ui/needless_return.fixed
index 603d438d558..7c828430b78 100644
--- a/tests/ui/needless_return.fixed
+++ b/tests/ui/needless_return.fixed
@@ -53,7 +53,7 @@ fn test_closure() {
 }
 
 fn test_macro_call() -> i32 {
-    return the_answer!();
+    the_answer!()
 }
 
 fn test_void_fun() {
@@ -175,7 +175,7 @@ async fn async_test_closure() {
 }
 
 async fn async_test_macro_call() -> i32 {
-    return the_answer!();
+    the_answer!()
 }
 
 async fn async_test_void_fun() {
@@ -223,4 +223,10 @@ fn let_else() {
     let Some(1) = Some(1) else { return };
 }
 
+fn needless_return_macro() -> String {
+    let _ = "foo";
+    let _ = "bar";
+    format!("Hello {}", "world!")
+}
+
 fn main() {}
diff --git a/tests/ui/needless_return.rs b/tests/ui/needless_return.rs
index c6c8cb9ec15..fe82af00e67 100644
--- a/tests/ui/needless_return.rs
+++ b/tests/ui/needless_return.rs
@@ -223,4 +223,10 @@ fn let_else() {
     let Some(1) = Some(1) else { return };
 }
 
+fn needless_return_macro() -> String {
+    let _ = "foo";
+    let _ = "bar";
+    return format!("Hello {}", "world!");
+}
+
 fn main() {}
diff --git a/tests/ui/needless_return.stderr b/tests/ui/needless_return.stderr
index 5bc787c56a6..4c8be47b025 100644
--- a/tests/ui/needless_return.stderr
+++ b/tests/ui/needless_return.stderr
@@ -49,6 +49,12 @@ LL |     let _ = || return true;
    |                ^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
+  --> $DIR/needless_return.rs:56:5
+   |
+LL |     return the_answer!();
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `the_answer!()`
+
+error: unneeded `return` statement
   --> $DIR/needless_return.rs:60:5
    |
 LL |     return;
@@ -169,6 +175,12 @@ LL |     let _ = || return true;
    |                ^^^^^^^^^^^ help: remove `return`: `true`
 
 error: unneeded `return` statement
+  --> $DIR/needless_return.rs:178:5
+   |
+LL |     return the_answer!();
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `the_answer!()`
+
+error: unneeded `return` statement
   --> $DIR/needless_return.rs:182:5
    |
 LL |     return;
@@ -204,5 +216,11 @@ error: unneeded `return` statement
 LL |         return String::new();
    |         ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
 
-error: aborting due to 34 previous errors
+error: unneeded `return` statement
+  --> $DIR/needless_return.rs:229:5
+   |
+LL |     return format!("Hello {}", "world!");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `format!("Hello {}", "world!")`
+
+error: aborting due to 37 previous errors
 
diff --git a/tests/ui/no_effect_replace.rs b/tests/ui/no_effect_replace.rs
new file mode 100644
index 00000000000..ad17d53f789
--- /dev/null
+++ b/tests/ui/no_effect_replace.rs
@@ -0,0 +1,51 @@
+#![warn(clippy::no_effect_replace)]
+
+fn main() {
+    let _ = "12345".replace('1', "1");
+    let _ = "12345".replace("12", "12");
+    let _ = String::new().replace("12", "12");
+
+    let _ = "12345".replacen('1', "1", 1);
+    let _ = "12345".replacen("12", "12", 1);
+    let _ = String::new().replacen("12", "12", 1);
+
+    let _ = "12345".replace("12", "22");
+    let _ = "12345".replacen("12", "22", 1);
+
+    let mut x = X::default();
+    let _ = "hello".replace(&x.f(), &x.f());
+    let _ = "hello".replace(&x.f(), &x.ff());
+
+    let _ = "hello".replace(&y(), &y());
+    let _ = "hello".replace(&y(), &z());
+
+    let _ = Replaceme.replace("a", "a");
+}
+
+#[derive(Default)]
+struct X {}
+
+impl X {
+    fn f(&mut self) -> String {
+        "he".to_string()
+    }
+
+    fn ff(&mut self) -> String {
+        "hh".to_string()
+    }
+}
+
+fn y() -> String {
+    "he".to_string()
+}
+
+fn z() -> String {
+    "hh".to_string()
+}
+
+struct Replaceme;
+impl Replaceme {
+    pub fn replace(&mut self, a: &str, b: &str) -> Self {
+        Self
+    }
+}
diff --git a/tests/ui/no_effect_replace.stderr b/tests/ui/no_effect_replace.stderr
new file mode 100644
index 00000000000..53a28aa73b7
--- /dev/null
+++ b/tests/ui/no_effect_replace.stderr
@@ -0,0 +1,52 @@
+error: replacing text with itself
+  --> $DIR/no_effect_replace.rs:4:13
+   |
+LL |     let _ = "12345".replace('1', "1");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::no-effect-replace` implied by `-D warnings`
+
+error: replacing text with itself
+  --> $DIR/no_effect_replace.rs:5:13
+   |
+LL |     let _ = "12345".replace("12", "12");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: replacing text with itself
+  --> $DIR/no_effect_replace.rs:6:13
+   |
+LL |     let _ = String::new().replace("12", "12");
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: replacing text with itself
+  --> $DIR/no_effect_replace.rs:8:13
+   |
+LL |     let _ = "12345".replacen('1', "1", 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: replacing text with itself
+  --> $DIR/no_effect_replace.rs:9:13
+   |
+LL |     let _ = "12345".replacen("12", "12", 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: replacing text with itself
+  --> $DIR/no_effect_replace.rs:10:13
+   |
+LL |     let _ = String::new().replacen("12", "12", 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: replacing text with itself
+  --> $DIR/no_effect_replace.rs:16:13
+   |
+LL |     let _ = "hello".replace(&x.f(), &x.f());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: replacing text with itself
+  --> $DIR/no_effect_replace.rs:19:13
+   |
+LL |     let _ = "hello".replace(&y(), &y());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/nonminimal_bool_methods.fixed b/tests/ui/nonminimal_bool_methods.fixed
new file mode 100644
index 00000000000..aad44089de4
--- /dev/null
+++ b/tests/ui/nonminimal_bool_methods.fixed
@@ -0,0 +1,111 @@
+// run-rustfix
+#![allow(unused, clippy::diverging_sub_expression)]
+#![warn(clippy::nonminimal_bool)]
+
+fn methods_with_negation() {
+    let a: Option<i32> = unimplemented!();
+    let b: Result<i32, i32> = unimplemented!();
+    let _ = a.is_some();
+    let _ = a.is_none();
+    let _ = a.is_none();
+    let _ = a.is_some();
+    let _ = b.is_err();
+    let _ = b.is_ok();
+    let _ = b.is_ok();
+    let _ = b.is_err();
+    let c = false;
+    let _ = a.is_none() || c;
+    let _ = a.is_none() && c;
+    let _ = !(!c ^ c) || a.is_none();
+    let _ = (!c ^ c) || a.is_none();
+    let _ = !c ^ c || a.is_none();
+}
+
+// Simplified versions of https://github.com/rust-lang/rust-clippy/issues/2638
+// clippy::nonminimal_bool should only check the built-in Result and Some type, not
+// any other types like the following.
+enum CustomResultOk<E> {
+    Ok,
+    Err(E),
+}
+enum CustomResultErr<E> {
+    Ok,
+    Err(E),
+}
+enum CustomSomeSome<T> {
+    Some(T),
+    None,
+}
+enum CustomSomeNone<T> {
+    Some(T),
+    None,
+}
+
+impl<E> CustomResultOk<E> {
+    pub fn is_ok(&self) -> bool {
+        true
+    }
+}
+
+impl<E> CustomResultErr<E> {
+    pub fn is_err(&self) -> bool {
+        true
+    }
+}
+
+impl<T> CustomSomeSome<T> {
+    pub fn is_some(&self) -> bool {
+        true
+    }
+}
+
+impl<T> CustomSomeNone<T> {
+    pub fn is_none(&self) -> bool {
+        true
+    }
+}
+
+fn dont_warn_for_custom_methods_with_negation() {
+    let res = CustomResultOk::Err("Error");
+    // Should not warn and suggest 'is_err()' because the type does not
+    // implement is_err().
+    if !res.is_ok() {}
+
+    let res = CustomResultErr::Err("Error");
+    // Should not warn and suggest 'is_ok()' because the type does not
+    // implement is_ok().
+    if !res.is_err() {}
+
+    let res = CustomSomeSome::Some("thing");
+    // Should not warn and suggest 'is_none()' because the type does not
+    // implement is_none().
+    if !res.is_some() {}
+
+    let res = CustomSomeNone::Some("thing");
+    // Should not warn and suggest 'is_some()' because the type does not
+    // implement is_some().
+    if !res.is_none() {}
+}
+
+// Only Built-in Result and Some types should suggest the negated alternative
+fn warn_for_built_in_methods_with_negation() {
+    let res: Result<usize, usize> = Ok(1);
+    if res.is_err() {}
+    if res.is_ok() {}
+
+    let res = Some(1);
+    if res.is_none() {}
+    if res.is_some() {}
+}
+
+#[allow(clippy::neg_cmp_op_on_partial_ord)]
+fn dont_warn_for_negated_partial_ord_comparison() {
+    let a: f64 = unimplemented!();
+    let b: f64 = unimplemented!();
+    let _ = !(a < b);
+    let _ = !(a <= b);
+    let _ = !(a > b);
+    let _ = !(a >= b);
+}
+
+fn main() {}
diff --git a/tests/ui/nonminimal_bool_methods.rs b/tests/ui/nonminimal_bool_methods.rs
index d0a289b7ea4..b9074da8427 100644
--- a/tests/ui/nonminimal_bool_methods.rs
+++ b/tests/ui/nonminimal_bool_methods.rs
@@ -1,3 +1,4 @@
+// run-rustfix
 #![allow(unused, clippy::diverging_sub_expression)]
 #![warn(clippy::nonminimal_bool)]
 
diff --git a/tests/ui/nonminimal_bool_methods.stderr b/tests/ui/nonminimal_bool_methods.stderr
index a2df889d623..21b84db8589 100644
--- a/tests/ui/nonminimal_bool_methods.stderr
+++ b/tests/ui/nonminimal_bool_methods.stderr
@@ -1,5 +1,5 @@
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:8:13
+  --> $DIR/nonminimal_bool_methods.rs:9:13
    |
 LL |     let _ = !a.is_some();
    |             ^^^^^^^^^^^^ help: try: `a.is_none()`
@@ -7,73 +7,73 @@ LL |     let _ = !a.is_some();
    = note: `-D clippy::nonminimal-bool` implied by `-D warnings`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:10:13
+  --> $DIR/nonminimal_bool_methods.rs:11:13
    |
 LL |     let _ = !a.is_none();
    |             ^^^^^^^^^^^^ help: try: `a.is_some()`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:12:13
+  --> $DIR/nonminimal_bool_methods.rs:13:13
    |
 LL |     let _ = !b.is_err();
    |             ^^^^^^^^^^^ help: try: `b.is_ok()`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:14:13
+  --> $DIR/nonminimal_bool_methods.rs:15:13
    |
 LL |     let _ = !b.is_ok();
    |             ^^^^^^^^^^ help: try: `b.is_err()`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:16:13
+  --> $DIR/nonminimal_bool_methods.rs:17:13
    |
 LL |     let _ = !(a.is_some() && !c);
    |             ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() || c`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:17:13
+  --> $DIR/nonminimal_bool_methods.rs:18:13
    |
 LL |     let _ = !(a.is_some() || !c);
    |             ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() && c`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:18:26
+  --> $DIR/nonminimal_bool_methods.rs:19:26
    |
 LL |     let _ = !(!c ^ c) || !a.is_some();
    |                          ^^^^^^^^^^^^ help: try: `a.is_none()`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:19:25
+  --> $DIR/nonminimal_bool_methods.rs:20:25
    |
 LL |     let _ = (!c ^ c) || !a.is_some();
    |                         ^^^^^^^^^^^^ help: try: `a.is_none()`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:20:23
+  --> $DIR/nonminimal_bool_methods.rs:21:23
    |
 LL |     let _ = !c ^ c || !a.is_some();
    |                       ^^^^^^^^^^^^ help: try: `a.is_none()`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:92:8
+  --> $DIR/nonminimal_bool_methods.rs:93:8
    |
 LL |     if !res.is_ok() {}
    |        ^^^^^^^^^^^^ help: try: `res.is_err()`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:93:8
+  --> $DIR/nonminimal_bool_methods.rs:94:8
    |
 LL |     if !res.is_err() {}
    |        ^^^^^^^^^^^^^ help: try: `res.is_ok()`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:96:8
+  --> $DIR/nonminimal_bool_methods.rs:97:8
    |
 LL |     if !res.is_some() {}
    |        ^^^^^^^^^^^^^^ help: try: `res.is_none()`
 
 error: this boolean expression can be simplified
-  --> $DIR/nonminimal_bool_methods.rs:97:8
+  --> $DIR/nonminimal_bool_methods.rs:98:8
    |
 LL |     if !res.is_none() {}
    |        ^^^^^^^^^^^^^^ help: try: `res.is_some()`
diff --git a/tests/ui/range_contains.fixed b/tests/ui/range_contains.fixed
index f4977199711..85d021b2f25 100644
--- a/tests/ui/range_contains.fixed
+++ b/tests/ui/range_contains.fixed
@@ -49,6 +49,13 @@ fn main() {
     x >= 10 && x <= -10;
     (-3. ..=3.).contains(&y);
     y >= 3. && y <= -3.;
+
+    // Fix #8745
+    let z = 42;
+    (0..=10).contains(&x) && (0..=10).contains(&z);
+    !(0..10).contains(&x) || !(0..10).contains(&z);
+    // Make sure operators in parens don't give a breaking suggestion
+    ((x % 2 == 0) || (x < 0)) || (x >= 10);
 }
 
 // Fix #6373
diff --git a/tests/ui/range_contains.rs b/tests/ui/range_contains.rs
index 9e2180b0c99..9a7a75dc132 100644
--- a/tests/ui/range_contains.rs
+++ b/tests/ui/range_contains.rs
@@ -49,6 +49,13 @@ fn main() {
     x >= 10 && x <= -10;
     y >= -3. && y <= 3.;
     y >= 3. && y <= -3.;
+
+    // Fix #8745
+    let z = 42;
+    (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
+    (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
+    // Make sure operators in parens don't give a breaking suggestion
+    ((x % 2 == 0) || (x < 0)) || (x >= 10);
 }
 
 // Fix #6373
diff --git a/tests/ui/range_contains.stderr b/tests/ui/range_contains.stderr
index 1817ee1715d..936859db5a1 100644
--- a/tests/ui/range_contains.stderr
+++ b/tests/ui/range_contains.stderr
@@ -96,5 +96,29 @@ error: manual `RangeInclusive::contains` implementation
 LL |     y >= -3. && y <= 3.;
    |     ^^^^^^^^^^^^^^^^^^^ help: use: `(-3. ..=3.).contains(&y)`
 
-error: aborting due to 16 previous errors
+error: manual `RangeInclusive::contains` implementation
+  --> $DIR/range_contains.rs:55:30
+   |
+LL |     (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
+   |                              ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&z)`
+
+error: manual `RangeInclusive::contains` implementation
+  --> $DIR/range_contains.rs:55:5
+   |
+LL |     (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10);
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&x)`
+
+error: manual `!Range::contains` implementation
+  --> $DIR/range_contains.rs:56:29
+   |
+LL |     (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
+   |                             ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&z)`
+
+error: manual `!Range::contains` implementation
+  --> $DIR/range_contains.rs:56:5
+   |
+LL |     (x < 0) || (x >= 10) || (z < 0) || (z >= 10);
+   |     ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&x)`
+
+error: aborting due to 20 previous errors
 
diff --git a/tests/ui/rc_buffer.fixed b/tests/ui/rc_buffer.fixed
new file mode 100644
index 00000000000..8910c01b1fc
--- /dev/null
+++ b/tests/ui/rc_buffer.fixed
@@ -0,0 +1,28 @@
+// run-rustfix
+#![warn(clippy::rc_buffer)]
+#![allow(dead_code, unused_imports)]
+
+use std::cell::RefCell;
+use std::ffi::OsString;
+use std::path::PathBuf;
+use std::rc::Rc;
+
+struct S {
+    // triggers lint
+    bad1: Rc<str>,
+    bad2: Rc<std::path::Path>,
+    bad3: Rc<[u8]>,
+    bad4: Rc<std::ffi::OsStr>,
+    // does not trigger lint
+    good1: Rc<RefCell<String>>,
+}
+
+// triggers lint
+fn func_bad1(_: Rc<str>) {}
+fn func_bad2(_: Rc<std::path::Path>) {}
+fn func_bad3(_: Rc<[u8]>) {}
+fn func_bad4(_: Rc<std::ffi::OsStr>) {}
+// does not trigger lint
+fn func_good1(_: Rc<RefCell<String>>) {}
+
+fn main() {}
diff --git a/tests/ui/rc_buffer.rs b/tests/ui/rc_buffer.rs
index 1fa98643936..1e63a43262e 100644
--- a/tests/ui/rc_buffer.rs
+++ b/tests/ui/rc_buffer.rs
@@ -1,4 +1,6 @@
+// run-rustfix
 #![warn(clippy::rc_buffer)]
+#![allow(dead_code, unused_imports)]
 
 use std::cell::RefCell;
 use std::ffi::OsString;
diff --git a/tests/ui/rc_buffer.stderr b/tests/ui/rc_buffer.stderr
index e4cc169af07..9ed028e3df4 100644
--- a/tests/ui/rc_buffer.stderr
+++ b/tests/ui/rc_buffer.stderr
@@ -1,5 +1,5 @@
 error: usage of `Rc<T>` when T is a buffer type
-  --> $DIR/rc_buffer.rs:10:11
+  --> $DIR/rc_buffer.rs:12:11
    |
 LL |     bad1: Rc<String>,
    |           ^^^^^^^^^^ help: try: `Rc<str>`
@@ -7,43 +7,43 @@ LL |     bad1: Rc<String>,
    = note: `-D clippy::rc-buffer` implied by `-D warnings`
 
 error: usage of `Rc<T>` when T is a buffer type
-  --> $DIR/rc_buffer.rs:11:11
+  --> $DIR/rc_buffer.rs:13:11
    |
 LL |     bad2: Rc<PathBuf>,
    |           ^^^^^^^^^^^ help: try: `Rc<std::path::Path>`
 
 error: usage of `Rc<T>` when T is a buffer type
-  --> $DIR/rc_buffer.rs:12:11
+  --> $DIR/rc_buffer.rs:14:11
    |
 LL |     bad3: Rc<Vec<u8>>,
    |           ^^^^^^^^^^^ help: try: `Rc<[u8]>`
 
 error: usage of `Rc<T>` when T is a buffer type
-  --> $DIR/rc_buffer.rs:13:11
+  --> $DIR/rc_buffer.rs:15:11
    |
 LL |     bad4: Rc<OsString>,
    |           ^^^^^^^^^^^^ help: try: `Rc<std::ffi::OsStr>`
 
 error: usage of `Rc<T>` when T is a buffer type
-  --> $DIR/rc_buffer.rs:19:17
+  --> $DIR/rc_buffer.rs:21:17
    |
 LL | fn func_bad1(_: Rc<String>) {}
    |                 ^^^^^^^^^^ help: try: `Rc<str>`
 
 error: usage of `Rc<T>` when T is a buffer type
-  --> $DIR/rc_buffer.rs:20:17
+  --> $DIR/rc_buffer.rs:22:17
    |
 LL | fn func_bad2(_: Rc<PathBuf>) {}
    |                 ^^^^^^^^^^^ help: try: `Rc<std::path::Path>`
 
 error: usage of `Rc<T>` when T is a buffer type
-  --> $DIR/rc_buffer.rs:21:17
+  --> $DIR/rc_buffer.rs:23:17
    |
 LL | fn func_bad3(_: Rc<Vec<u8>>) {}
    |                 ^^^^^^^^^^^ help: try: `Rc<[u8]>`
 
 error: usage of `Rc<T>` when T is a buffer type
-  --> $DIR/rc_buffer.rs:22:17
+  --> $DIR/rc_buffer.rs:24:17
    |
 LL | fn func_bad4(_: Rc<OsString>) {}
    |                 ^^^^^^^^^^^^ help: try: `Rc<std::ffi::OsStr>`
diff --git a/tests/ui/rc_buffer_arc.fixed b/tests/ui/rc_buffer_arc.fixed
new file mode 100644
index 00000000000..13dd6f5fcd1
--- /dev/null
+++ b/tests/ui/rc_buffer_arc.fixed
@@ -0,0 +1,27 @@
+// run-rustfix
+#![warn(clippy::rc_buffer)]
+#![allow(dead_code, unused_imports)]
+
+use std::ffi::OsString;
+use std::path::PathBuf;
+use std::sync::{Arc, Mutex};
+
+struct S {
+    // triggers lint
+    bad1: Arc<str>,
+    bad2: Arc<std::path::Path>,
+    bad3: Arc<[u8]>,
+    bad4: Arc<std::ffi::OsStr>,
+    // does not trigger lint
+    good1: Arc<Mutex<String>>,
+}
+
+// triggers lint
+fn func_bad1(_: Arc<str>) {}
+fn func_bad2(_: Arc<std::path::Path>) {}
+fn func_bad3(_: Arc<[u8]>) {}
+fn func_bad4(_: Arc<std::ffi::OsStr>) {}
+// does not trigger lint
+fn func_good1(_: Arc<Mutex<String>>) {}
+
+fn main() {}
diff --git a/tests/ui/rc_buffer_arc.rs b/tests/ui/rc_buffer_arc.rs
index 5d586584817..1a521bfeb7c 100644
--- a/tests/ui/rc_buffer_arc.rs
+++ b/tests/ui/rc_buffer_arc.rs
@@ -1,4 +1,6 @@
+// run-rustfix
 #![warn(clippy::rc_buffer)]
+#![allow(dead_code, unused_imports)]
 
 use std::ffi::OsString;
 use std::path::PathBuf;
diff --git a/tests/ui/rc_buffer_arc.stderr b/tests/ui/rc_buffer_arc.stderr
index 8252270d2ac..911feea7352 100644
--- a/tests/ui/rc_buffer_arc.stderr
+++ b/tests/ui/rc_buffer_arc.stderr
@@ -1,5 +1,5 @@
 error: usage of `Arc<T>` when T is a buffer type
-  --> $DIR/rc_buffer_arc.rs:9:11
+  --> $DIR/rc_buffer_arc.rs:11:11
    |
 LL |     bad1: Arc<String>,
    |           ^^^^^^^^^^^ help: try: `Arc<str>`
@@ -7,43 +7,43 @@ LL |     bad1: Arc<String>,
    = note: `-D clippy::rc-buffer` implied by `-D warnings`
 
 error: usage of `Arc<T>` when T is a buffer type
-  --> $DIR/rc_buffer_arc.rs:10:11
+  --> $DIR/rc_buffer_arc.rs:12:11
    |
 LL |     bad2: Arc<PathBuf>,
    |           ^^^^^^^^^^^^ help: try: `Arc<std::path::Path>`
 
 error: usage of `Arc<T>` when T is a buffer type
-  --> $DIR/rc_buffer_arc.rs:11:11
+  --> $DIR/rc_buffer_arc.rs:13:11
    |
 LL |     bad3: Arc<Vec<u8>>,
    |           ^^^^^^^^^^^^ help: try: `Arc<[u8]>`
 
 error: usage of `Arc<T>` when T is a buffer type
-  --> $DIR/rc_buffer_arc.rs:12:11
+  --> $DIR/rc_buffer_arc.rs:14:11
    |
 LL |     bad4: Arc<OsString>,
    |           ^^^^^^^^^^^^^ help: try: `Arc<std::ffi::OsStr>`
 
 error: usage of `Arc<T>` when T is a buffer type
-  --> $DIR/rc_buffer_arc.rs:18:17
+  --> $DIR/rc_buffer_arc.rs:20:17
    |
 LL | fn func_bad1(_: Arc<String>) {}
    |                 ^^^^^^^^^^^ help: try: `Arc<str>`
 
 error: usage of `Arc<T>` when T is a buffer type
-  --> $DIR/rc_buffer_arc.rs:19:17
+  --> $DIR/rc_buffer_arc.rs:21:17
    |
 LL | fn func_bad2(_: Arc<PathBuf>) {}
    |                 ^^^^^^^^^^^^ help: try: `Arc<std::path::Path>`
 
 error: usage of `Arc<T>` when T is a buffer type
-  --> $DIR/rc_buffer_arc.rs:20:17
+  --> $DIR/rc_buffer_arc.rs:22:17
    |
 LL | fn func_bad3(_: Arc<Vec<u8>>) {}
    |                 ^^^^^^^^^^^^ help: try: `Arc<[u8]>`
 
 error: usage of `Arc<T>` when T is a buffer type
-  --> $DIR/rc_buffer_arc.rs:21:17
+  --> $DIR/rc_buffer_arc.rs:23:17
    |
 LL | fn func_bad4(_: Arc<OsString>) {}
    |                 ^^^^^^^^^^^^^ help: try: `Arc<std::ffi::OsStr>`
diff --git a/tests/ui/rc_clone_in_vec_init/arc.stderr b/tests/ui/rc_clone_in_vec_init/arc.stderr
index ce84186c8e3..cd7d91e1206 100644
--- a/tests/ui/rc_clone_in_vec_init/arc.stderr
+++ b/tests/ui/rc_clone_in_vec_init/arc.stderr
@@ -1,4 +1,4 @@
-error: calling `Arc::new` in `vec![elem; len]`
+error: initializing a reference-counted pointer in `vec![elem; len]`
   --> $DIR/arc.rs:7:13
    |
 LL |     let v = vec![Arc::new("x".to_string()); 2];
@@ -10,19 +10,19 @@ help: consider initializing each `Arc` element individually
    |
 LL ~     let v = {
 LL +         let mut v = Vec::with_capacity(2);
-LL +         (0..2).for_each(|_| v.push(Arc::new("x".to_string())));
+LL +         (0..2).for_each(|_| v.push(Arc::new(..)));
 LL +         v
 LL ~     };
    |
 help: or if this is intentional, consider extracting the `Arc` initialization to a variable
    |
 LL ~     let v = {
-LL +         let data = Arc::new("x".to_string());
+LL +         let data = Arc::new(..);
 LL +         vec![data; 2]
 LL ~     };
    |
 
-error: calling `Arc::new` in `vec![elem; len]`
+error: initializing a reference-counted pointer in `vec![elem; len]`
   --> $DIR/arc.rs:15:21
    |
 LL |             let v = vec![Arc::new("x".to_string()); 2];
@@ -33,19 +33,19 @@ help: consider initializing each `Arc` element individually
    |
 LL ~             let v = {
 LL +                 let mut v = Vec::with_capacity(2);
-LL +                 (0..2).for_each(|_| v.push(Arc::new("x".to_string())));
+LL +                 (0..2).for_each(|_| v.push(Arc::new(..)));
 LL +                 v
 LL ~             };
    |
 help: or if this is intentional, consider extracting the `Arc` initialization to a variable
    |
 LL ~             let v = {
-LL +                 let data = Arc::new("x".to_string());
+LL +                 let data = Arc::new(..);
 LL +                 vec![data; 2]
 LL ~             };
    |
 
-error: calling `Arc::new` in `vec![elem; len]`
+error: initializing a reference-counted pointer in `vec![elem; len]`
   --> $DIR/arc.rs:21:13
    |
 LL |       let v = vec![
@@ -75,7 +75,7 @@ LL +         vec![data; 2]
 LL ~     };
    |
 
-error: calling `Arc::new` in `vec![elem; len]`
+error: initializing a reference-counted pointer in `vec![elem; len]`
   --> $DIR/arc.rs:30:14
    |
 LL |       let v1 = vec![
diff --git a/tests/ui/rc_clone_in_vec_init/rc.stderr b/tests/ui/rc_clone_in_vec_init/rc.stderr
index 0f5cc0cf98f..fe861afe054 100644
--- a/tests/ui/rc_clone_in_vec_init/rc.stderr
+++ b/tests/ui/rc_clone_in_vec_init/rc.stderr
@@ -1,4 +1,4 @@
-error: calling `Rc::new` in `vec![elem; len]`
+error: initializing a reference-counted pointer in `vec![elem; len]`
   --> $DIR/rc.rs:8:13
    |
 LL |     let v = vec![Rc::new("x".to_string()); 2];
@@ -10,19 +10,19 @@ help: consider initializing each `Rc` element individually
    |
 LL ~     let v = {
 LL +         let mut v = Vec::with_capacity(2);
-LL +         (0..2).for_each(|_| v.push(Rc::new("x".to_string())));
+LL +         (0..2).for_each(|_| v.push(Rc::new(..)));
 LL +         v
 LL ~     };
    |
 help: or if this is intentional, consider extracting the `Rc` initialization to a variable
    |
 LL ~     let v = {
-LL +         let data = Rc::new("x".to_string());
+LL +         let data = Rc::new(..);
 LL +         vec![data; 2]
 LL ~     };
    |
 
-error: calling `Rc::new` in `vec![elem; len]`
+error: initializing a reference-counted pointer in `vec![elem; len]`
   --> $DIR/rc.rs:16:21
    |
 LL |             let v = vec![Rc::new("x".to_string()); 2];
@@ -33,19 +33,19 @@ help: consider initializing each `Rc` element individually
    |
 LL ~             let v = {
 LL +                 let mut v = Vec::with_capacity(2);
-LL +                 (0..2).for_each(|_| v.push(Rc::new("x".to_string())));
+LL +                 (0..2).for_each(|_| v.push(Rc::new(..)));
 LL +                 v
 LL ~             };
    |
 help: or if this is intentional, consider extracting the `Rc` initialization to a variable
    |
 LL ~             let v = {
-LL +                 let data = Rc::new("x".to_string());
+LL +                 let data = Rc::new(..);
 LL +                 vec![data; 2]
 LL ~             };
    |
 
-error: calling `Rc::new` in `vec![elem; len]`
+error: initializing a reference-counted pointer in `vec![elem; len]`
   --> $DIR/rc.rs:22:13
    |
 LL |       let v = vec![
@@ -75,7 +75,7 @@ LL +         vec![data; 2]
 LL ~     };
    |
 
-error: calling `Rc::new` in `vec![elem; len]`
+error: initializing a reference-counted pointer in `vec![elem; len]`
   --> $DIR/rc.rs:31:14
    |
 LL |       let v1 = vec![
diff --git a/tests/ui/rc_clone_in_vec_init/weak.rs b/tests/ui/rc_clone_in_vec_init/weak.rs
new file mode 100644
index 00000000000..693c9b553c5
--- /dev/null
+++ b/tests/ui/rc_clone_in_vec_init/weak.rs
@@ -0,0 +1,83 @@
+#![warn(clippy::rc_clone_in_vec_init)]
+use std::rc::{Rc, Weak as UnSyncWeak};
+use std::sync::{Arc, Mutex, Weak as SyncWeak};
+
+fn main() {}
+
+fn should_warn_simple_case() {
+    let v = vec![SyncWeak::<u32>::new(); 2];
+    let v2 = vec![UnSyncWeak::<u32>::new(); 2];
+
+    let v = vec![Rc::downgrade(&Rc::new("x".to_string())); 2];
+    let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2];
+}
+
+fn should_warn_simple_case_with_big_indentation() {
+    if true {
+        let k = 1;
+        dbg!(k);
+        if true {
+            let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2];
+            let v2 = vec![Rc::downgrade(&Rc::new("x".to_string())); 2];
+        }
+    }
+}
+
+fn should_warn_complex_case() {
+    let v = vec![
+        Arc::downgrade(&Arc::new(Mutex::new({
+            let x = 1;
+            dbg!(x);
+            x
+        })));
+        2
+    ];
+
+    let v1 = vec![
+        Rc::downgrade(&Rc::new(Mutex::new({
+            let x = 1;
+            dbg!(x);
+            x
+        })));
+        2
+    ];
+}
+
+fn should_not_warn_custom_weak() {
+    #[derive(Clone)]
+    struct Weak;
+
+    impl Weak {
+        fn new() -> Self {
+            Weak
+        }
+    }
+
+    let v = vec![Weak::new(); 2];
+}
+
+fn should_not_warn_vec_from_elem_but_not_weak() {
+    let v = vec![String::new(); 2];
+    let v1 = vec![1; 2];
+    let v2 = vec![
+        Box::new(Arc::downgrade(&Arc::new({
+            let y = 3;
+            dbg!(y);
+            y
+        })));
+        2
+    ];
+    let v3 = vec![
+        Box::new(Rc::downgrade(&Rc::new({
+            let y = 3;
+            dbg!(y);
+            y
+        })));
+        2
+    ];
+}
+
+fn should_not_warn_vec_macro_but_not_from_elem() {
+    let v = vec![Arc::downgrade(&Arc::new("x".to_string()))];
+    let v = vec![Rc::downgrade(&Rc::new("x".to_string()))];
+}
diff --git a/tests/ui/rc_clone_in_vec_init/weak.stderr b/tests/ui/rc_clone_in_vec_init/weak.stderr
new file mode 100644
index 00000000000..4a21946ccdf
--- /dev/null
+++ b/tests/ui/rc_clone_in_vec_init/weak.stderr
@@ -0,0 +1,201 @@
+error: initializing a reference-counted pointer in `vec![elem; len]`
+  --> $DIR/weak.rs:8:13
+   |
+LL |     let v = vec![SyncWeak::<u32>::new(); 2];
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::rc-clone-in-vec-init` implied by `-D warnings`
+   = note: each element will point to the same `Weak` instance
+help: consider initializing each `Weak` element individually
+   |
+LL ~     let v = {
+LL +         let mut v = Vec::with_capacity(2);
+LL +         (0..2).for_each(|_| v.push(SyncWeak::<u32>::new(..)));
+LL +         v
+LL ~     };
+   |
+help: or if this is intentional, consider extracting the `Weak` initialization to a variable
+   |
+LL ~     let v = {
+LL +         let data = SyncWeak::<u32>::new(..);
+LL +         vec![data; 2]
+LL ~     };
+   |
+
+error: initializing a reference-counted pointer in `vec![elem; len]`
+  --> $DIR/weak.rs:9:14
+   |
+LL |     let v2 = vec![UnSyncWeak::<u32>::new(); 2];
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: each element will point to the same `Weak` instance
+help: consider initializing each `Weak` element individually
+   |
+LL ~     let v2 = {
+LL +         let mut v = Vec::with_capacity(2);
+LL +         (0..2).for_each(|_| v.push(UnSyncWeak::<u32>::new(..)));
+LL +         v
+LL ~     };
+   |
+help: or if this is intentional, consider extracting the `Weak` initialization to a variable
+   |
+LL ~     let v2 = {
+LL +         let data = UnSyncWeak::<u32>::new(..);
+LL +         vec![data; 2]
+LL ~     };
+   |
+
+error: initializing a reference-counted pointer in `vec![elem; len]`
+  --> $DIR/weak.rs:11:13
+   |
+LL |     let v = vec![Rc::downgrade(&Rc::new("x".to_string())); 2];
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: each element will point to the same `Weak` instance
+help: consider initializing each `Weak` element individually
+   |
+LL ~     let v = {
+LL +         let mut v = Vec::with_capacity(2);
+LL +         (0..2).for_each(|_| v.push(Rc::downgrade(..)));
+LL +         v
+LL ~     };
+   |
+help: or if this is intentional, consider extracting the `Weak` initialization to a variable
+   |
+LL ~     let v = {
+LL +         let data = Rc::downgrade(..);
+LL +         vec![data; 2]
+LL ~     };
+   |
+
+error: initializing a reference-counted pointer in `vec![elem; len]`
+  --> $DIR/weak.rs:12:13
+   |
+LL |     let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2];
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: each element will point to the same `Weak` instance
+help: consider initializing each `Weak` element individually
+   |
+LL ~     let v = {
+LL +         let mut v = Vec::with_capacity(2);
+LL +         (0..2).for_each(|_| v.push(Arc::downgrade(..)));
+LL +         v
+LL ~     };
+   |
+help: or if this is intentional, consider extracting the `Weak` initialization to a variable
+   |
+LL ~     let v = {
+LL +         let data = Arc::downgrade(..);
+LL +         vec![data; 2]
+LL ~     };
+   |
+
+error: initializing a reference-counted pointer in `vec![elem; len]`
+  --> $DIR/weak.rs:20:21
+   |
+LL |             let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2];
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: each element will point to the same `Weak` instance
+help: consider initializing each `Weak` element individually
+   |
+LL ~             let v = {
+LL +                 let mut v = Vec::with_capacity(2);
+LL +                 (0..2).for_each(|_| v.push(Arc::downgrade(..)));
+LL +                 v
+LL ~             };
+   |
+help: or if this is intentional, consider extracting the `Weak` initialization to a variable
+   |
+LL ~             let v = {
+LL +                 let data = Arc::downgrade(..);
+LL +                 vec![data; 2]
+LL ~             };
+   |
+
+error: initializing a reference-counted pointer in `vec![elem; len]`
+  --> $DIR/weak.rs:21:22
+   |
+LL |             let v2 = vec![Rc::downgrade(&Rc::new("x".to_string())); 2];
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: each element will point to the same `Weak` instance
+help: consider initializing each `Weak` element individually
+   |
+LL ~             let v2 = {
+LL +                 let mut v = Vec::with_capacity(2);
+LL +                 (0..2).for_each(|_| v.push(Rc::downgrade(..)));
+LL +                 v
+LL ~             };
+   |
+help: or if this is intentional, consider extracting the `Weak` initialization to a variable
+   |
+LL ~             let v2 = {
+LL +                 let data = Rc::downgrade(..);
+LL +                 vec![data; 2]
+LL ~             };
+   |
+
+error: initializing a reference-counted pointer in `vec![elem; len]`
+  --> $DIR/weak.rs:27:13
+   |
+LL |       let v = vec![
+   |  _____________^
+LL | |         Arc::downgrade(&Arc::new(Mutex::new({
+LL | |             let x = 1;
+LL | |             dbg!(x);
+...  |
+LL | |         2
+LL | |     ];
+   | |_____^
+   |
+   = note: each element will point to the same `Weak` instance
+help: consider initializing each `Weak` element individually
+   |
+LL ~     let v = {
+LL +         let mut v = Vec::with_capacity(2);
+LL +         (0..2).for_each(|_| v.push(Arc::downgrade(..)));
+LL +         v
+LL ~     };
+   |
+help: or if this is intentional, consider extracting the `Weak` initialization to a variable
+   |
+LL ~     let v = {
+LL +         let data = Arc::downgrade(..);
+LL +         vec![data; 2]
+LL ~     };
+   |
+
+error: initializing a reference-counted pointer in `vec![elem; len]`
+  --> $DIR/weak.rs:36:14
+   |
+LL |       let v1 = vec![
+   |  ______________^
+LL | |         Rc::downgrade(&Rc::new(Mutex::new({
+LL | |             let x = 1;
+LL | |             dbg!(x);
+...  |
+LL | |         2
+LL | |     ];
+   | |_____^
+   |
+   = note: each element will point to the same `Weak` instance
+help: consider initializing each `Weak` element individually
+   |
+LL ~     let v1 = {
+LL +         let mut v = Vec::with_capacity(2);
+LL +         (0..2).for_each(|_| v.push(Rc::downgrade(..)));
+LL +         v
+LL ~     };
+   |
+help: or if this is intentional, consider extracting the `Weak` initialization to a variable
+   |
+LL ~     let v1 = {
+LL +         let data = Rc::downgrade(..);
+LL +         vec![data; 2]
+LL ~     };
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/recursive_format_impl.rs b/tests/ui/recursive_format_impl.rs
index f72fc77ab99..cb6ba36b14c 100644
--- a/tests/ui/recursive_format_impl.rs
+++ b/tests/ui/recursive_format_impl.rs
@@ -2,7 +2,8 @@
 #![allow(
     clippy::inherent_to_string_shadow_display,
     clippy::to_string_in_format_args,
-    clippy::deref_addrof
+    clippy::deref_addrof,
+    clippy::borrow_deref_ref
 )]
 
 use std::fmt;
diff --git a/tests/ui/recursive_format_impl.stderr b/tests/ui/recursive_format_impl.stderr
index 1a717ac92d8..84ce69df566 100644
--- a/tests/ui/recursive_format_impl.stderr
+++ b/tests/ui/recursive_format_impl.stderr
@@ -1,5 +1,5 @@
 error: using `self.to_string` in `fmt::Display` implementation will cause infinite recursion
-  --> $DIR/recursive_format_impl.rs:29:25
+  --> $DIR/recursive_format_impl.rs:30:25
    |
 LL |         write!(f, "{}", self.to_string())
    |                         ^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |         write!(f, "{}", self.to_string())
    = note: `-D clippy::recursive-format-impl` implied by `-D warnings`
 
 error: using `self` as `Display` in `impl Display` will cause infinite recursion
-  --> $DIR/recursive_format_impl.rs:73:9
+  --> $DIR/recursive_format_impl.rs:74:9
    |
 LL |         write!(f, "{}", self)
    |         ^^^^^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL |         write!(f, "{}", self)
    = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: using `self` as `Display` in `impl Display` will cause infinite recursion
-  --> $DIR/recursive_format_impl.rs:82:9
+  --> $DIR/recursive_format_impl.rs:83:9
    |
 LL |         write!(f, "{}", &self)
    |         ^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL |         write!(f, "{}", &self)
    = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: using `self` as `Debug` in `impl Debug` will cause infinite recursion
-  --> $DIR/recursive_format_impl.rs:88:9
+  --> $DIR/recursive_format_impl.rs:89:9
    |
 LL |         write!(f, "{:?}", &self)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -31,7 +31,7 @@ LL |         write!(f, "{:?}", &self)
    = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: using `self` as `Display` in `impl Display` will cause infinite recursion
-  --> $DIR/recursive_format_impl.rs:97:9
+  --> $DIR/recursive_format_impl.rs:98:9
    |
 LL |         write!(f, "{}", &&&self)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL |         write!(f, "{}", &&&self)
    = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: using `self` as `Display` in `impl Display` will cause infinite recursion
-  --> $DIR/recursive_format_impl.rs:171:9
+  --> $DIR/recursive_format_impl.rs:172:9
    |
 LL |         write!(f, "{}", &*self)
    |         ^^^^^^^^^^^^^^^^^^^^^^^
@@ -47,7 +47,7 @@ LL |         write!(f, "{}", &*self)
    = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: using `self` as `Debug` in `impl Debug` will cause infinite recursion
-  --> $DIR/recursive_format_impl.rs:177:9
+  --> $DIR/recursive_format_impl.rs:178:9
    |
 LL |         write!(f, "{:?}", &*self)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -55,7 +55,7 @@ LL |         write!(f, "{:?}", &*self)
    = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: using `self` as `Display` in `impl Display` will cause infinite recursion
-  --> $DIR/recursive_format_impl.rs:193:9
+  --> $DIR/recursive_format_impl.rs:194:9
    |
 LL |         write!(f, "{}", *self)
    |         ^^^^^^^^^^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL |         write!(f, "{}", *self)
    = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: using `self` as `Display` in `impl Display` will cause infinite recursion
-  --> $DIR/recursive_format_impl.rs:209:9
+  --> $DIR/recursive_format_impl.rs:210:9
    |
 LL |         write!(f, "{}", **&&*self)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -71,7 +71,7 @@ LL |         write!(f, "{}", **&&*self)
    = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: using `self` as `Display` in `impl Display` will cause infinite recursion
-  --> $DIR/recursive_format_impl.rs:225:9
+  --> $DIR/recursive_format_impl.rs:226:9
    |
 LL |         write!(f, "{}", &&**&&*self)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/shadow.rs b/tests/ui/shadow.rs
index a394ef8f25c..1fa9fc749a9 100644
--- a/tests/ui/shadow.rs
+++ b/tests/ui/shadow.rs
@@ -88,4 +88,11 @@ pub async fn foo2(_a: i32, _b: i64) {
     let _b = _a;
 }
 
+fn ice_8748() {
+    let _ = [0; {
+        let x = 1;
+        if let Some(x) = Some(1) { x } else { 1 }
+    }];
+}
+
 fn main() {}
diff --git a/tests/ui/significant_drop_in_scrutinee.rs b/tests/ui/significant_drop_in_scrutinee.rs
index f83a6dd0eb2..4347610f393 100644
--- a/tests/ui/significant_drop_in_scrutinee.rs
+++ b/tests/ui/significant_drop_in_scrutinee.rs
@@ -7,8 +7,10 @@
 #![allow(unused_assignments)]
 #![allow(dead_code)]
 
+use std::num::ParseIntError;
 use std::ops::Deref;
 use std::sync::atomic::{AtomicU64, Ordering};
+use std::sync::RwLock;
 use std::sync::{Mutex, MutexGuard};
 
 struct State {}
@@ -552,4 +554,41 @@ fn should_not_cause_stack_overflow() {
     }
 }
 
+fn should_not_produce_lint_for_try_desugar() -> Result<u64, ParseIntError> {
+    // TryDesugar (i.e. using `?` for a Result type) will turn into a match but is out of scope
+    // for this lint
+    let rwlock = RwLock::new("1".to_string());
+    let result = rwlock.read().unwrap().parse::<u64>()?;
+    println!("{}", result);
+    rwlock.write().unwrap().push('2');
+    Ok(result)
+}
+
+struct ResultReturner {
+    s: String,
+}
+
+impl ResultReturner {
+    fn to_number(&self) -> Result<i64, ParseIntError> {
+        self.s.parse::<i64>()
+    }
+}
+
+fn should_trigger_lint_for_non_ref_move_and_clone_suggestion() {
+    let rwlock = RwLock::<ResultReturner>::new(ResultReturner { s: "1".to_string() });
+    match rwlock.read().unwrap().to_number() {
+        Ok(n) => println!("Converted to number: {}", n),
+        Err(e) => println!("Could not convert {} to number", e),
+    };
+}
+
+fn should_trigger_lint_for_read_write_lock_for_loop() {
+    // For-in loops desugar to match expressions and are prone to the type of deadlock this lint is
+    // designed to look for.
+    let rwlock = RwLock::<Vec<String>>::new(vec!["1".to_string()]);
+    for s in rwlock.read().unwrap().iter() {
+        println!("{}", s);
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/significant_drop_in_scrutinee.stderr b/tests/ui/significant_drop_in_scrutinee.stderr
index af160564985..303f3c1df03 100644
--- a/tests/ui/significant_drop_in_scrutinee.stderr
+++ b/tests/ui/significant_drop_in_scrutinee.stderr
@@ -1,5 +1,5 @@
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:57:11
+  --> $DIR/significant_drop_in_scrutinee.rs:59:11
    |
 LL |     match mutex.lock().unwrap().foo() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:130:11
+  --> $DIR/significant_drop_in_scrutinee.rs:132:11
    |
 LL |     match s.lock_m().get_the_value() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:151:11
+  --> $DIR/significant_drop_in_scrutinee.rs:153:11
    |
 LL |     match s.lock_m_m().get_the_value() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:199:11
+  --> $DIR/significant_drop_in_scrutinee.rs:201:11
    |
 LL |     match counter.temp_increment().len() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:222:16
+  --> $DIR/significant_drop_in_scrutinee.rs:224:16
    |
 LL |         match (mutex1.lock().unwrap().s.len(), true) {
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL ~         match (value, true) {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:231:22
+  --> $DIR/significant_drop_in_scrutinee.rs:233:22
    |
 LL |         match (true, mutex1.lock().unwrap().s.len(), true) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL ~         match (true, value, true) {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:241:16
+  --> $DIR/significant_drop_in_scrutinee.rs:243:16
    |
 LL |         match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -84,7 +84,7 @@ LL ~         match (value, true, mutex2.lock().unwrap().s.len()) {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:241:54
+  --> $DIR/significant_drop_in_scrutinee.rs:243:54
    |
 LL |         match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) {
    |                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -96,19 +96,19 @@ LL ~         match (mutex1.lock().unwrap().s.len(), true, value) {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:252:15
+  --> $DIR/significant_drop_in_scrutinee.rs:254:15
    |
 LL |         match mutex3.lock().unwrap().s.as_str() {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:262:22
+  --> $DIR/significant_drop_in_scrutinee.rs:264:22
    |
 LL |         match (true, mutex3.lock().unwrap().s.as_str()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:281:11
+  --> $DIR/significant_drop_in_scrutinee.rs:283:11
    |
 LL |     match mutex.lock().unwrap().s.len() > 1 {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -120,7 +120,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:288:11
+  --> $DIR/significant_drop_in_scrutinee.rs:290:11
    |
 LL |     match 1 < mutex.lock().unwrap().s.len() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -132,7 +132,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:306:11
+  --> $DIR/significant_drop_in_scrutinee.rs:308:11
    |
 LL |     match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:317:11
+  --> $DIR/significant_drop_in_scrutinee.rs:319:11
    |
 LL |     match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -156,7 +156,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:352:11
+  --> $DIR/significant_drop_in_scrutinee.rs:354:11
    |
 LL |     match get_mutex_guard().s.len() > 1 {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -168,7 +168,7 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:369:11
+  --> $DIR/significant_drop_in_scrutinee.rs:371:11
    |
 LL |       match match i {
    |  ___________^
@@ -191,7 +191,7 @@ LL +     .len()
  ...
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:395:11
+  --> $DIR/significant_drop_in_scrutinee.rs:397:11
    |
 LL |       match if i > 1 {
    |  ___________^
@@ -214,7 +214,7 @@ LL +     .s
  ...
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:449:11
+  --> $DIR/significant_drop_in_scrutinee.rs:451:11
    |
 LL |     match s.lock().deref().deref() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -226,13 +226,13 @@ LL ~     match value {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:477:11
+  --> $DIR/significant_drop_in_scrutinee.rs:479:11
    |
 LL |     match s.lock().deref().deref() {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:496:11
+  --> $DIR/significant_drop_in_scrutinee.rs:498:11
    |
 LL |     match mutex.lock().unwrap().i = i {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -244,7 +244,7 @@ LL ~     match () {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:502:11
+  --> $DIR/significant_drop_in_scrutinee.rs:504:11
    |
 LL |     match i = mutex.lock().unwrap().i {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -256,7 +256,7 @@ LL ~     match () {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:508:11
+  --> $DIR/significant_drop_in_scrutinee.rs:510:11
    |
 LL |     match mutex.lock().unwrap().i += 1 {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -268,7 +268,7 @@ LL ~     match () {
    |
 
 error: temporary with significant drop in match scrutinee
-  --> $DIR/significant_drop_in_scrutinee.rs:514:11
+  --> $DIR/significant_drop_in_scrutinee.rs:516:11
    |
 LL |     match i += mutex.lock().unwrap().i {
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -279,5 +279,17 @@ LL ~     i += mutex.lock().unwrap().i;
 LL ~     match () {
    |
 
-error: aborting due to 23 previous errors
+error: temporary with significant drop in match scrutinee
+  --> $DIR/significant_drop_in_scrutinee.rs:579:11
+   |
+LL |     match rwlock.read().unwrap().to_number() {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: temporary with significant drop in for loop
+  --> $DIR/significant_drop_in_scrutinee.rs:589:14
+   |
+LL |     for s in rwlock.read().unwrap().iter() {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 25 previous errors
 
diff --git a/tests/ui/suspicious_operation_groupings.fixed b/tests/ui/suspicious_operation_groupings.fixed
new file mode 100644
index 00000000000..ede8a39fed7
--- /dev/null
+++ b/tests/ui/suspicious_operation_groupings.fixed
@@ -0,0 +1,209 @@
+// run-rustfix
+#![warn(clippy::suspicious_operation_groupings)]
+#![allow(dead_code, unused_parens, clippy::eq_op)]
+
+struct Vec3 {
+    x: f64,
+    y: f64,
+    z: f64,
+}
+
+impl Eq for Vec3 {}
+
+impl PartialEq for Vec3 {
+    fn eq(&self, other: &Self) -> bool {
+        // This should trigger the lint because `self.x` is compared to `other.y`
+        self.x == other.x && self.y == other.y && self.z == other.z
+    }
+}
+
+struct S {
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+}
+
+fn buggy_ab_cmp(s1: &S, s2: &S) -> bool {
+    // There's no `s1.b`
+    s1.a < s2.a && s1.b < s2.b
+}
+
+struct SaOnly {
+    a: i32,
+}
+
+impl S {
+    fn a(&self) -> i32 {
+        0
+    }
+}
+
+fn do_not_give_bad_suggestions_for_this_unusual_expr(s1: &S, s2: &SaOnly) -> bool {
+    // This is superficially similar to `buggy_ab_cmp`, but we should not suggest
+    // `s2.b` since that is invalid.
+    s1.a < s2.a && s1.a() < s1.b
+}
+
+fn do_not_give_bad_suggestions_for_this_macro_expr(s1: &S, s2: &SaOnly) -> bool {
+    macro_rules! s1 {
+        () => {
+            S {
+                a: 1,
+                b: 1,
+                c: 1,
+                d: 1,
+            }
+        };
+    }
+
+    // This is superficially similar to `buggy_ab_cmp`, but we should not suggest
+    // `s2.b` since that is invalid.
+    s1.a < s2.a && s1!().a < s1.b
+}
+
+fn do_not_give_bad_suggestions_for_this_incorrect_expr(s1: &S, s2: &SaOnly) -> bool {
+    // There's two `s1.b`, but we should not suggest `s2.b` since that is invalid
+    s1.a < s2.a && s1.b < s1.b
+}
+
+fn permissable(s1: &S, s2: &S) -> bool {
+    // Something like this seems like it might actually be what is desired.
+    s1.a == s2.b
+}
+
+fn non_boolean_operators(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.c`
+    s1.a * s2.a + s1.b * s2.b + s1.c * s2.c + s1.d * s2.d
+}
+
+fn odd_number_of_pairs(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.b`
+    s1.a * s2.a + s1.b * s2.b + s1.c * s2.c
+}
+
+fn not_caught_by_eq_op_middle_change_left(s1: &S, s2: &S) -> i32 {
+    // There's no `s1.b`
+    s1.a * s2.a + s1.b * s2.b + s1.c * s2.c
+}
+
+fn not_caught_by_eq_op_middle_change_right(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.b`
+    s1.a * s2.a + s1.b * s2.b + s1.c * s2.c
+}
+
+fn not_caught_by_eq_op_start(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.a`
+    s1.a * s2.a + s1.b * s2.b + s1.c * s2.c
+}
+
+fn not_caught_by_eq_op_end(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.c`
+    s1.a * s2.a + s1.b * s2.b + s1.c * s2.c
+}
+
+fn the_cross_product_should_not_lint(s1: &S, s2: &S) -> (i32, i32, i32) {
+    (
+        s1.b * s2.c - s1.c * s2.b,
+        s1.c * s2.a - s1.a * s2.c,
+        s1.a * s2.b - s1.b * s2.a,
+    )
+}
+
+fn outer_parens_simple(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.b`
+    (s1.a * s2.a + s1.b * s2.b)
+}
+
+fn outer_parens(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.c`
+    (s1.a * s2.a + s1.b * s2.b + s1.c * s2.c + s1.d * s2.d)
+}
+
+fn inner_parens(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.c`
+    (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.c) + (s1.d * s2.d)
+}
+
+fn outer_and_some_inner_parens(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.c`
+    ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.c) + (s1.d * s2.d))
+}
+
+fn all_parens_balanced_tree(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.c`
+    (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.c) + (s1.d * s2.d)))
+}
+
+fn all_parens_left_tree(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.c`
+    (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.c)) + (s1.d * s2.d))
+}
+
+fn all_parens_right_tree(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.c`
+    ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.c) + (s1.d * s2.d)))
+}
+
+fn inside_other_binop_expression(s1: &S, s2: &S) -> i32 {
+    // There's no `s1.b`
+    (s1.a * s2.a + s1.b * s2.b) / 2
+}
+
+fn inside_function_call(s1: &S, s2: &S) -> i32 {
+    // There's no `s1.b`
+    i32::swap_bytes(s1.a * s2.a + s1.b * s2.b)
+}
+
+fn inside_larger_boolean_expression(s1: &S, s2: &S) -> bool {
+    // There's no `s1.c`
+    s1.a > 0 && s1.b > 0 && s1.c == s2.c && s1.d == s2.d
+}
+
+fn inside_larger_boolean_expression_with_unsorted_ops(s1: &S, s2: &S) -> bool {
+    // There's no `s1.c`
+    s1.a > 0 && s1.c == s2.c && s1.b > 0 && s1.d == s2.d
+}
+
+struct Nested {
+    inner: ((i32,), (i32,), (i32,)),
+}
+
+fn changed_middle_ident(n1: &Nested, n2: &Nested) -> bool {
+    // There's no `n2.inner.2.0`
+    (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0
+}
+
+// `eq_op` should catch this one.
+fn changed_initial_ident(n1: &Nested, n2: &Nested) -> bool {
+    // There's no `n2.inner.0.0`
+    (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0
+}
+
+fn inside_fn_with_similar_expression(s1: &S, s2: &S, strict: bool) -> bool {
+    if strict {
+        s1.a < s2.a && s1.b < s2.b
+    } else {
+        // There's no `s1.b` in this subexpression
+        s1.a <= s2.a && s1.b <= s2.b
+    }
+}
+
+fn inside_an_if_statement(s1: &mut S, s2: &S) {
+    // There's no `s1.b`
+    if s1.a < s2.a && s1.b < s2.b {
+        s1.c = s2.c;
+    }
+}
+
+fn maximum_unary_minus_right_tree(s1: &S, s2: &S) -> i32 {
+    // There's no `s2.c`
+    -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.c) + -(-s1.d * -s2.d)))
+}
+
+fn unary_minus_and_an_if_expression(s1: &S, s2: &S) -> i32 {
+    // There's no `s1.b`
+    -(if -s1.a < -s2.a && -s1.b < -s2.b { s1.c } else { s2.a })
+}
+
+fn main() {}
diff --git a/tests/ui/suspicious_operation_groupings.rs b/tests/ui/suspicious_operation_groupings.rs
index 3201d5de0f3..26ce97bb37f 100644
--- a/tests/ui/suspicious_operation_groupings.rs
+++ b/tests/ui/suspicious_operation_groupings.rs
@@ -1,5 +1,6 @@
+// run-rustfix
 #![warn(clippy::suspicious_operation_groupings)]
-#![allow(clippy::eq_op)]
+#![allow(dead_code, unused_parens, clippy::eq_op)]
 
 struct Vec3 {
     x: f64,
diff --git a/tests/ui/suspicious_operation_groupings.stderr b/tests/ui/suspicious_operation_groupings.stderr
index baf9bc74b00..29f229245fe 100644
--- a/tests/ui/suspicious_operation_groupings.stderr
+++ b/tests/ui/suspicious_operation_groupings.stderr
@@ -1,5 +1,5 @@
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:15:9
+  --> $DIR/suspicious_operation_groupings.rs:16:9
    |
 LL |         self.x == other.y && self.y == other.y && self.z == other.z
    |         ^^^^^^^^^^^^^^^^^ help: did you mean: `self.x == other.x`
@@ -7,151 +7,151 @@ LL |         self.x == other.y && self.y == other.y && self.z == other.z
    = note: `-D clippy::suspicious-operation-groupings` implied by `-D warnings`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:28:20
+  --> $DIR/suspicious_operation_groupings.rs:29:20
    |
 LL |     s1.a < s2.a && s1.a < s2.b
    |                    ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:76:33
+  --> $DIR/suspicious_operation_groupings.rs:77:33
    |
 LL |     s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d
    |                                 ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:81:19
+  --> $DIR/suspicious_operation_groupings.rs:82:19
    |
 LL |     s1.a * s2.a + s1.b * s2.c + s1.c * s2.c
    |                   ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:81:19
+  --> $DIR/suspicious_operation_groupings.rs:82:19
    |
 LL |     s1.a * s2.a + s1.b * s2.c + s1.c * s2.c
    |                   ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:86:19
+  --> $DIR/suspicious_operation_groupings.rs:87:19
    |
 LL |     s1.a * s2.a + s2.b * s2.b + s1.c * s2.c
    |                   ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:91:19
+  --> $DIR/suspicious_operation_groupings.rs:92:19
    |
 LL |     s1.a * s2.a + s1.b * s1.b + s1.c * s2.c
    |                   ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:96:5
+  --> $DIR/suspicious_operation_groupings.rs:97:5
    |
 LL |     s1.a * s1.a + s1.b * s2.b + s1.c * s2.c
    |     ^^^^^^^^^^^ help: did you mean: `s1.a * s2.a`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:101:33
+  --> $DIR/suspicious_operation_groupings.rs:102:33
    |
 LL |     s1.a * s2.a + s1.b * s2.b + s1.c * s1.c
    |                                 ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:114:20
+  --> $DIR/suspicious_operation_groupings.rs:115:20
    |
 LL |     (s1.a * s2.a + s1.b * s1.b)
    |                    ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:119:34
+  --> $DIR/suspicious_operation_groupings.rs:120:34
    |
 LL |     (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d)
    |                                  ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:124:38
+  --> $DIR/suspicious_operation_groupings.rs:125:38
    |
 LL |     (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)
    |                                      ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:129:39
+  --> $DIR/suspicious_operation_groupings.rs:130:39
    |
 LL |     ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))
    |                                       ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:134:42
+  --> $DIR/suspicious_operation_groupings.rs:135:42
    |
 LL |     (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d)))
    |                                          ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:134:42
+  --> $DIR/suspicious_operation_groupings.rs:135:42
    |
 LL |     (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d)))
    |                                          ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:139:40
+  --> $DIR/suspicious_operation_groupings.rs:140:40
    |
 LL |     (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d))
    |                                        ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:144:40
+  --> $DIR/suspicious_operation_groupings.rs:145:40
    |
 LL |     ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)))
    |                                        ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:149:20
+  --> $DIR/suspicious_operation_groupings.rs:150:20
    |
 LL |     (s1.a * s2.a + s2.b * s2.b) / 2
    |                    ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:154:35
+  --> $DIR/suspicious_operation_groupings.rs:155:35
    |
 LL |     i32::swap_bytes(s1.a * s2.a + s2.b * s2.b)
    |                                   ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:159:29
+  --> $DIR/suspicious_operation_groupings.rs:160:29
    |
 LL |     s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d
    |                             ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:164:17
+  --> $DIR/suspicious_operation_groupings.rs:165:17
    |
 LL |     s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d
    |                 ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:173:77
+  --> $DIR/suspicious_operation_groupings.rs:174:77
    |
 LL |     (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0
    |                                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `(n1.inner.2).0 == (n2.inner.2).0`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:187:25
+  --> $DIR/suspicious_operation_groupings.rs:188:25
    |
 LL |         s1.a <= s2.a && s1.a <= s2.b
    |                         ^^^^^^^^^^^^ help: did you mean: `s1.b <= s2.b`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:193:23
+  --> $DIR/suspicious_operation_groupings.rs:194:23
    |
 LL |     if s1.a < s2.a && s1.a < s2.b {
    |                       ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:200:48
+  --> $DIR/suspicious_operation_groupings.rs:201:48
    |
 LL |     -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d)))
    |                                                ^^^^^^^^^^^^^ help: did you mean: `-s1.c * -s2.c`
 
 error: this sequence of operators looks suspiciously like a bug
-  --> $DIR/suspicious_operation_groupings.rs:205:27
+  --> $DIR/suspicious_operation_groupings.rs:206:27
    |
 LL |     -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a })
    |                           ^^^^^^^^^^^^^ help: did you mean: `-s1.b < -s2.b`
diff --git a/tests/ui/swap_ptr_to_ref.fixed b/tests/ui/swap_ptr_to_ref.fixed
new file mode 100644
index 00000000000..596b6ee919b
--- /dev/null
+++ b/tests/ui/swap_ptr_to_ref.fixed
@@ -0,0 +1,24 @@
+// run-rustfix
+
+#![warn(clippy::swap_ptr_to_ref)]
+
+use core::ptr::addr_of_mut;
+
+fn main() {
+    let mut x = 0u32;
+    let y: *mut _ = &mut x;
+    let z: *mut _ = &mut x;
+
+    unsafe {
+        core::ptr::swap(y, z);
+        core::ptr::swap(y, &mut x);
+        core::ptr::swap(&mut x, y);
+        core::ptr::swap(addr_of_mut!(x), addr_of_mut!(x));
+    }
+
+    let y = &mut x;
+    let mut z = 0u32;
+    let z = &mut z;
+
+    core::mem::swap(y, z);
+}
diff --git a/tests/ui/swap_ptr_to_ref.rs b/tests/ui/swap_ptr_to_ref.rs
new file mode 100644
index 00000000000..282f571211d
--- /dev/null
+++ b/tests/ui/swap_ptr_to_ref.rs
@@ -0,0 +1,24 @@
+// run-rustfix
+
+#![warn(clippy::swap_ptr_to_ref)]
+
+use core::ptr::addr_of_mut;
+
+fn main() {
+    let mut x = 0u32;
+    let y: *mut _ = &mut x;
+    let z: *mut _ = &mut x;
+
+    unsafe {
+        core::mem::swap(&mut *y, &mut *z);
+        core::mem::swap(&mut *y, &mut x);
+        core::mem::swap(&mut x, &mut *y);
+        core::mem::swap(&mut *addr_of_mut!(x), &mut *addr_of_mut!(x));
+    }
+
+    let y = &mut x;
+    let mut z = 0u32;
+    let z = &mut z;
+
+    core::mem::swap(y, z);
+}
diff --git a/tests/ui/swap_ptr_to_ref.stderr b/tests/ui/swap_ptr_to_ref.stderr
new file mode 100644
index 00000000000..401ce070869
--- /dev/null
+++ b/tests/ui/swap_ptr_to_ref.stderr
@@ -0,0 +1,28 @@
+error: call to `core::mem::swap` with a parameter derived from a raw pointer
+  --> $DIR/swap_ptr_to_ref.rs:13:9
+   |
+LL |         core::mem::swap(&mut *y, &mut *z);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use ptr::swap: `core::ptr::swap(y, z)`
+   |
+   = note: `-D clippy::swap-ptr-to-ref` implied by `-D warnings`
+
+error: call to `core::mem::swap` with a parameter derived from a raw pointer
+  --> $DIR/swap_ptr_to_ref.rs:14:9
+   |
+LL |         core::mem::swap(&mut *y, &mut x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use ptr::swap: `core::ptr::swap(y, &mut x)`
+
+error: call to `core::mem::swap` with a parameter derived from a raw pointer
+  --> $DIR/swap_ptr_to_ref.rs:15:9
+   |
+LL |         core::mem::swap(&mut x, &mut *y);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use ptr::swap: `core::ptr::swap(&mut x, y)`
+
+error: call to `core::mem::swap` with a parameter derived from a raw pointer
+  --> $DIR/swap_ptr_to_ref.rs:16:9
+   |
+LL |         core::mem::swap(&mut *addr_of_mut!(x), &mut *addr_of_mut!(x));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use ptr::swap: `core::ptr::swap(addr_of_mut!(x), addr_of_mut!(x))`
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/swap_ptr_to_ref_unfixable.rs b/tests/ui/swap_ptr_to_ref_unfixable.rs
new file mode 100644
index 00000000000..66ea7c6529b
--- /dev/null
+++ b/tests/ui/swap_ptr_to_ref_unfixable.rs
@@ -0,0 +1,18 @@
+#![warn(clippy::swap_ptr_to_ref)]
+
+macro_rules! addr_of_mut_to_ref {
+    ($e:expr) => {
+        &mut *core::ptr::addr_of_mut!($e)
+    };
+}
+
+fn main() {
+    let mut x = 0u32;
+    let y: *mut _ = &mut x;
+
+    unsafe {
+        core::mem::swap(addr_of_mut_to_ref!(x), &mut *y);
+        core::mem::swap(&mut *y, addr_of_mut_to_ref!(x));
+        core::mem::swap(addr_of_mut_to_ref!(x), addr_of_mut_to_ref!(x));
+    }
+}
diff --git a/tests/ui/swap_ptr_to_ref_unfixable.stderr b/tests/ui/swap_ptr_to_ref_unfixable.stderr
new file mode 100644
index 00000000000..c261205d556
--- /dev/null
+++ b/tests/ui/swap_ptr_to_ref_unfixable.stderr
@@ -0,0 +1,22 @@
+error: call to `core::mem::swap` with a parameter derived from a raw pointer
+  --> $DIR/swap_ptr_to_ref_unfixable.rs:14:9
+   |
+LL |         core::mem::swap(addr_of_mut_to_ref!(x), &mut *y);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::swap-ptr-to-ref` implied by `-D warnings`
+
+error: call to `core::mem::swap` with a parameter derived from a raw pointer
+  --> $DIR/swap_ptr_to_ref_unfixable.rs:15:9
+   |
+LL |         core::mem::swap(&mut *y, addr_of_mut_to_ref!(x));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: call to `core::mem::swap` with a parameter derived from a raw pointer
+  --> $DIR/swap_ptr_to_ref_unfixable.rs:16:9
+   |
+LL |         core::mem::swap(addr_of_mut_to_ref!(x), addr_of_mut_to_ref!(x));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/temporary_assignment.rs b/tests/ui/temporary_assignment.rs
index b4a931043b0..ac4c1bc6597 100644
--- a/tests/ui/temporary_assignment.rs
+++ b/tests/ui/temporary_assignment.rs
@@ -1,5 +1,4 @@
 #![warn(clippy::temporary_assignment)]
-#![allow(const_item_mutation)]
 
 use std::ops::{Deref, DerefMut};
 
diff --git a/tests/ui/temporary_assignment.stderr b/tests/ui/temporary_assignment.stderr
index 4cc32c79f05..7d79901a28d 100644
--- a/tests/ui/temporary_assignment.stderr
+++ b/tests/ui/temporary_assignment.stderr
@@ -1,5 +1,5 @@
 error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:48:5
+  --> $DIR/temporary_assignment.rs:47:5
    |
 LL |     Struct { field: 0 }.field = 1;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     Struct { field: 0 }.field = 1;
    = note: `-D clippy::temporary-assignment` implied by `-D warnings`
 
 error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:49:5
+  --> $DIR/temporary_assignment.rs:48:5
    |
 LL | /     MultiStruct {
 LL | |         structure: Struct { field: 0 },
@@ -17,13 +17,13 @@ LL | |     .field = 1;
    | |______________^
 
 error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:54:5
+  --> $DIR/temporary_assignment.rs:53:5
    |
 LL |     ArrayStruct { array: [0] }.array[0] = 1;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:55:5
+  --> $DIR/temporary_assignment.rs:54:5
    |
 LL |     (0, 0).0 = 1;
    |     ^^^^^^^^^^^^
diff --git a/tests/ui/transmute.rs b/tests/ui/transmute.rs
index 5b688ce4d64..001c910239a 100644
--- a/tests/ui/transmute.rs
+++ b/tests/ui/transmute.rs
@@ -16,7 +16,8 @@ fn my_vec() -> MyVec<i32> {
 #[allow(clippy::needless_lifetimes, clippy::transmute_ptr_to_ptr)]
 #[warn(clippy::useless_transmute)]
 unsafe fn _generic<'a, T, U: 'a>(t: &'a T) {
-    let _: &'a T = core::intrinsics::transmute(t);
+    // FIXME: should lint
+    // let _: &'a T = core::intrinsics::transmute(t);
 
     let _: &'a U = core::intrinsics::transmute(t);
 
@@ -48,6 +49,22 @@ fn useless() {
 
         let _ = (1 + 1_usize) as *const usize;
     }
+
+    unsafe fn _f<'a, 'b>(x: &'a u32) -> &'b u32 {
+        std::mem::transmute(x)
+    }
+
+    unsafe fn _f2<'a, 'b>(x: *const (dyn Iterator<Item = u32> + 'a)) -> *const (dyn Iterator<Item = u32> + 'b) {
+        std::mem::transmute(x)
+    }
+
+    unsafe fn _f3<'a, 'b>(x: fn(&'a u32)) -> fn(&'b u32) {
+        std::mem::transmute(x)
+    }
+
+    unsafe fn _f4<'a, 'b>(x: std::borrow::Cow<'a, str>) -> std::borrow::Cow<'b, str> {
+        std::mem::transmute(x)
+    }
 }
 
 struct Usize(usize);
diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr
index 72a386e8fa6..008b4a981d7 100644
--- a/tests/ui/transmute.stderr
+++ b/tests/ui/transmute.stderr
@@ -1,73 +1,67 @@
-error: transmute from a type (`&T`) to itself
-  --> $DIR/transmute.rs:19:20
-   |
-LL |     let _: &'a T = core::intrinsics::transmute(t);
-   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::useless-transmute` implied by `-D warnings`
-
 error: transmute from a reference to a pointer
-  --> $DIR/transmute.rs:23:23
+  --> $DIR/transmute.rs:24:23
    |
 LL |     let _: *const T = core::intrinsics::transmute(t);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
+   |
+   = note: `-D clippy::useless-transmute` implied by `-D warnings`
 
 error: transmute from a reference to a pointer
-  --> $DIR/transmute.rs:25:21
+  --> $DIR/transmute.rs:26:21
    |
 LL |     let _: *mut T = core::intrinsics::transmute(t);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
 
 error: transmute from a reference to a pointer
-  --> $DIR/transmute.rs:27:23
+  --> $DIR/transmute.rs:28:23
    |
 LL |     let _: *const U = core::intrinsics::transmute(t);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:33:27
+  --> $DIR/transmute.rs:34:27
    |
 LL |         let _: Vec<i32> = core::intrinsics::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:35:27
+  --> $DIR/transmute.rs:36:27
    |
 LL |         let _: Vec<i32> = core::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:37:27
+  --> $DIR/transmute.rs:38:27
    |
 LL |         let _: Vec<i32> = std::intrinsics::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:39:27
+  --> $DIR/transmute.rs:40:27
    |
 LL |         let _: Vec<i32> = std::mem::transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`std::vec::Vec<i32>`) to itself
-  --> $DIR/transmute.rs:41:27
+  --> $DIR/transmute.rs:42:27
    |
 LL |         let _: Vec<i32> = my_transmute(my_vec());
    |                           ^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from an integer to a pointer
-  --> $DIR/transmute.rs:43:31
+  --> $DIR/transmute.rs:44:31
    |
 LL |         let _: *const usize = std::mem::transmute(5_isize);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize`
 
 error: transmute from an integer to a pointer
-  --> $DIR/transmute.rs:47:31
+  --> $DIR/transmute.rs:48:31
    |
 LL |         let _: *const usize = std::mem::transmute(1 + 1usize);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize`
 
 error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
-  --> $DIR/transmute.rs:62:24
+  --> $DIR/transmute.rs:79:24
    |
 LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -75,25 +69,25 @@ LL |         let _: Usize = core::intrinsics::transmute(int_const_ptr);
    = note: `-D clippy::crosspointer-transmute` implied by `-D warnings`
 
 error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
-  --> $DIR/transmute.rs:64:24
+  --> $DIR/transmute.rs:81:24
    |
 LL |         let _: Usize = core::intrinsics::transmute(int_mut_ptr);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
-  --> $DIR/transmute.rs:66:31
+  --> $DIR/transmute.rs:83:31
    |
 LL |         let _: *const Usize = core::intrinsics::transmute(my_int());
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
-  --> $DIR/transmute.rs:68:29
+  --> $DIR/transmute.rs:85:29
    |
 LL |         let _: *mut Usize = core::intrinsics::transmute(my_int());
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: transmute from a `u32` to a `char`
-  --> $DIR/transmute.rs:74:28
+  --> $DIR/transmute.rs:91:28
    |
 LL |     let _: char = unsafe { std::mem::transmute(0_u32) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_u32).unwrap()`
@@ -101,13 +95,13 @@ LL |     let _: char = unsafe { std::mem::transmute(0_u32) };
    = note: `-D clippy::transmute-int-to-char` implied by `-D warnings`
 
 error: transmute from a `i32` to a `char`
-  --> $DIR/transmute.rs:75:28
+  --> $DIR/transmute.rs:92:28
    |
 LL |     let _: char = unsafe { std::mem::transmute(0_i32) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::char::from_u32(0_i32 as u32).unwrap()`
 
 error: transmute from a `u8` to a `bool`
-  --> $DIR/transmute.rs:84:28
+  --> $DIR/transmute.rs:101:28
    |
 LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0`
@@ -115,7 +109,7 @@ LL |     let _: bool = unsafe { std::mem::transmute(0_u8) };
    = note: `-D clippy::transmute-int-to-bool` implied by `-D warnings`
 
 error: transmute from a `u32` to a `f32`
-  --> $DIR/transmute.rs:90:31
+  --> $DIR/transmute.rs:107:31
    |
 LL |         let _: f32 = unsafe { std::mem::transmute(0_u32) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
@@ -123,25 +117,25 @@ LL |         let _: f32 = unsafe { std::mem::transmute(0_u32) };
    = note: `-D clippy::transmute-int-to-float` implied by `-D warnings`
 
 error: transmute from a `i32` to a `f32`
-  --> $DIR/transmute.rs:91:31
+  --> $DIR/transmute.rs:108:31
    |
 LL |         let _: f32 = unsafe { std::mem::transmute(0_i32) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
 
 error: transmute from a `u64` to a `f64`
-  --> $DIR/transmute.rs:92:31
+  --> $DIR/transmute.rs:109:31
    |
 LL |         let _: f64 = unsafe { std::mem::transmute(0_u64) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)`
 
 error: transmute from a `i64` to a `f64`
-  --> $DIR/transmute.rs:93:31
+  --> $DIR/transmute.rs:110:31
    |
 LL |         let _: f64 = unsafe { std::mem::transmute(0_i64) };
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
 
 error: transmute from a `u8` to a `[u8; 1]`
-  --> $DIR/transmute.rs:113:30
+  --> $DIR/transmute.rs:130:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0u8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
@@ -149,85 +143,85 @@ LL |             let _: [u8; 1] = std::mem::transmute(0u8);
    = note: `-D clippy::transmute-num-to-bytes` implied by `-D warnings`
 
 error: transmute from a `u32` to a `[u8; 4]`
-  --> $DIR/transmute.rs:114:30
+  --> $DIR/transmute.rs:131:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0u32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
 
 error: transmute from a `u128` to a `[u8; 16]`
-  --> $DIR/transmute.rs:115:31
+  --> $DIR/transmute.rs:132:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0u128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
 
 error: transmute from a `i8` to a `[u8; 1]`
-  --> $DIR/transmute.rs:116:30
+  --> $DIR/transmute.rs:133:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0i8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
 
 error: transmute from a `i32` to a `[u8; 4]`
-  --> $DIR/transmute.rs:117:30
+  --> $DIR/transmute.rs:134:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0i32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
 
 error: transmute from a `i128` to a `[u8; 16]`
-  --> $DIR/transmute.rs:118:31
+  --> $DIR/transmute.rs:135:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0i128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
 
 error: transmute from a `f32` to a `[u8; 4]`
-  --> $DIR/transmute.rs:119:30
+  --> $DIR/transmute.rs:136:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0.0f32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
 
 error: transmute from a `f64` to a `[u8; 8]`
-  --> $DIR/transmute.rs:120:30
+  --> $DIR/transmute.rs:137:30
    |
 LL |             let _: [u8; 8] = std::mem::transmute(0.0f64);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
 
 error: transmute from a `u8` to a `[u8; 1]`
-  --> $DIR/transmute.rs:125:30
+  --> $DIR/transmute.rs:142:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0u8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
 
 error: transmute from a `u32` to a `[u8; 4]`
-  --> $DIR/transmute.rs:126:30
+  --> $DIR/transmute.rs:143:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0u32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
 
 error: transmute from a `u128` to a `[u8; 16]`
-  --> $DIR/transmute.rs:127:31
+  --> $DIR/transmute.rs:144:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0u128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
 
 error: transmute from a `i8` to a `[u8; 1]`
-  --> $DIR/transmute.rs:128:30
+  --> $DIR/transmute.rs:145:30
    |
 LL |             let _: [u8; 1] = std::mem::transmute(0i8);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
 
 error: transmute from a `i32` to a `[u8; 4]`
-  --> $DIR/transmute.rs:129:30
+  --> $DIR/transmute.rs:146:30
    |
 LL |             let _: [u8; 4] = std::mem::transmute(0i32);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
 
 error: transmute from a `i128` to a `[u8; 16]`
-  --> $DIR/transmute.rs:130:31
+  --> $DIR/transmute.rs:147:31
    |
 LL |             let _: [u8; 16] = std::mem::transmute(0i128);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
 
 error: transmute from a `&[u8]` to a `&str`
-  --> $DIR/transmute.rs:140:28
+  --> $DIR/transmute.rs:157:28
    |
 LL |     let _: &str = unsafe { std::mem::transmute(B) };
    |                            ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()`
@@ -235,16 +229,16 @@ LL |     let _: &str = unsafe { std::mem::transmute(B) };
    = note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings`
 
 error: transmute from a `&mut [u8]` to a `&mut str`
-  --> $DIR/transmute.rs:141:32
+  --> $DIR/transmute.rs:158:32
    |
 LL |     let _: &mut str = unsafe { std::mem::transmute(mb) };
    |                                ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
 
 error: transmute from a `&[u8]` to a `&str`
-  --> $DIR/transmute.rs:142:30
+  --> $DIR/transmute.rs:159:30
    |
 LL |     const _: &str = unsafe { std::mem::transmute(B) };
    |                              ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)`
 
-error: aborting due to 39 previous errors
+error: aborting due to 38 previous errors
 
diff --git a/tests/ui/transmute_undefined_repr.rs b/tests/ui/transmute_undefined_repr.rs
index b06ed4a9173..ebcaa7a84cf 100644
--- a/tests/ui/transmute_undefined_repr.rs
+++ b/tests/ui/transmute_undefined_repr.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::transmute_undefined_repr)]
-#![allow(clippy::unit_arg, clippy::transmute_ptr_to_ref)]
+#![allow(clippy::unit_arg, clippy::transmute_ptr_to_ref, clippy::useless_transmute)]
 
 use core::any::TypeId;
 use core::ffi::c_void;
diff --git a/tests/ui/unicode.fixed b/tests/ui/unicode.fixed
new file mode 100644
index 00000000000..328cda369e1
--- /dev/null
+++ b/tests/ui/unicode.fixed
@@ -0,0 +1,36 @@
+// run-rustfix
+#[warn(clippy::invisible_characters)]
+fn zero() {
+    print!("Here >\u{200B}< is a ZWS, and \u{200B}another");
+    print!("This\u{200B}is\u{200B}fine");
+    print!("Here >\u{AD}< is a SHY, and \u{AD}another");
+    print!("This\u{ad}is\u{ad}fine");
+    print!("Here >\u{2060}< is a WJ, and \u{2060}another");
+    print!("This\u{2060}is\u{2060}fine");
+}
+
+#[warn(clippy::unicode_not_nfc)]
+fn canon() {
+    print!("̀àh?");
+    print!("a\u{0300}h?"); // also ok
+}
+
+#[warn(clippy::non_ascii_literal)]
+fn uni() {
+    print!("\u{dc}ben!");
+    print!("\u{DC}ben!"); // this is ok
+}
+
+// issue 8013
+#[warn(clippy::non_ascii_literal)]
+fn single_quote() {
+    const _EMPTY_BLOCK: char = '\u{25b1}';
+    const _FULL_BLOCK: char = '\u{25b0}';
+}
+
+fn main() {
+    zero();
+    uni();
+    canon();
+    single_quote();
+}
diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs
index e0a4eadce33..7828d6bcbea 100644
--- a/tests/ui/unicode.rs
+++ b/tests/ui/unicode.rs
@@ -1,3 +1,4 @@
+// run-rustfix
 #[warn(clippy::invisible_characters)]
 fn zero() {
     print!("Here >​< is a ZWS, and ​another");
diff --git a/tests/ui/unicode.stderr b/tests/ui/unicode.stderr
index 3f54e3880e7..01d3f3c0296 100644
--- a/tests/ui/unicode.stderr
+++ b/tests/ui/unicode.stderr
@@ -1,5 +1,5 @@
 error: invisible character detected
-  --> $DIR/unicode.rs:3:12
+  --> $DIR/unicode.rs:4:12
    |
 LL |     print!("Here >​< is a ZWS, and ​another");
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{200B}< is a ZWS, and /u{200B}another"`
@@ -7,19 +7,19 @@ LL |     print!("Here >​< is a ZWS, and ​another");
    = note: `-D clippy::invisible-characters` implied by `-D warnings`
 
 error: invisible character detected
-  --> $DIR/unicode.rs:5:12
+  --> $DIR/unicode.rs:6:12
    |
 LL |     print!("Here >­< is a SHY, and ­another");
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{AD}< is a SHY, and /u{AD}another"`
 
 error: invisible character detected
-  --> $DIR/unicode.rs:7:12
+  --> $DIR/unicode.rs:8:12
    |
 LL |     print!("Here >⁠< is a WJ, and ⁠another");
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{2060}< is a WJ, and /u{2060}another"`
 
 error: non-NFC Unicode sequence detected
-  --> $DIR/unicode.rs:13:12
+  --> $DIR/unicode.rs:14:12
    |
 LL |     print!("̀àh?");
    |            ^^^^^ help: consider replacing the string with: `"̀àh?"`
@@ -27,7 +27,7 @@ LL |     print!("̀àh?");
    = note: `-D clippy::unicode-not-nfc` implied by `-D warnings`
 
 error: literal non-ASCII character detected
-  --> $DIR/unicode.rs:19:12
+  --> $DIR/unicode.rs:20:12
    |
 LL |     print!("Üben!");
    |            ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"`
@@ -35,13 +35,13 @@ LL |     print!("Üben!");
    = note: `-D clippy::non-ascii-literal` implied by `-D warnings`
 
 error: literal non-ASCII character detected
-  --> $DIR/unicode.rs:26:32
+  --> $DIR/unicode.rs:27:32
    |
 LL |     const _EMPTY_BLOCK: char = '▱';
    |                                ^^^ help: consider replacing the string with: `'/u{25b1}'`
 
 error: literal non-ASCII character detected
-  --> $DIR/unicode.rs:27:31
+  --> $DIR/unicode.rs:28:31
    |
 LL |     const _FULL_BLOCK: char = '▰';
    |                               ^^^ help: consider replacing the string with: `'/u{25b0}'`
diff --git a/tests/ui/unit_arg_empty_blocks.fixed b/tests/ui/unit_arg_empty_blocks.fixed
new file mode 100644
index 00000000000..9400e93cac8
--- /dev/null
+++ b/tests/ui/unit_arg_empty_blocks.fixed
@@ -0,0 +1,30 @@
+// run-rustfix
+#![warn(clippy::unit_arg)]
+#![allow(clippy::no_effect, unused_must_use, unused_variables)]
+
+use std::fmt::Debug;
+
+fn foo<T: Debug>(t: T) {
+    println!("{:?}", t);
+}
+
+fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) {
+    println!("{:?}, {:?}, {:?}", t1, t2, t3);
+}
+
+fn bad() {
+    foo(());
+    foo3((), 2, 2);
+    foo(0);
+    taking_two_units((), ());
+    foo(0);
+    foo(1);
+    taking_three_units((), (), ());
+}
+
+fn taking_two_units(a: (), b: ()) {}
+fn taking_three_units(a: (), b: (), c: ()) {}
+
+fn main() {
+    bad();
+}
diff --git a/tests/ui/unit_arg_empty_blocks.rs b/tests/ui/unit_arg_empty_blocks.rs
index 18a31eb3dee..5f52b6c5315 100644
--- a/tests/ui/unit_arg_empty_blocks.rs
+++ b/tests/ui/unit_arg_empty_blocks.rs
@@ -1,3 +1,4 @@
+// run-rustfix
 #![warn(clippy::unit_arg)]
 #![allow(clippy::no_effect, unused_must_use, unused_variables)]
 
diff --git a/tests/ui/unit_arg_empty_blocks.stderr b/tests/ui/unit_arg_empty_blocks.stderr
index 39072c9a8cc..d35e931697d 100644
--- a/tests/ui/unit_arg_empty_blocks.stderr
+++ b/tests/ui/unit_arg_empty_blocks.stderr
@@ -1,5 +1,5 @@
 error: passing a unit value to a function
-  --> $DIR/unit_arg_empty_blocks.rs:15:5
+  --> $DIR/unit_arg_empty_blocks.rs:16:5
    |
 LL |     foo({});
    |     ^^^^--^
@@ -9,7 +9,7 @@ LL |     foo({});
    = note: `-D clippy::unit-arg` implied by `-D warnings`
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg_empty_blocks.rs:16:5
+  --> $DIR/unit_arg_empty_blocks.rs:17:5
    |
 LL |     foo3({}, 2, 2);
    |     ^^^^^--^^^^^^^
@@ -17,7 +17,7 @@ LL |     foo3({}, 2, 2);
    |          help: use a unit literal instead: `()`
 
 error: passing unit values to a function
-  --> $DIR/unit_arg_empty_blocks.rs:17:5
+  --> $DIR/unit_arg_empty_blocks.rs:18:5
    |
 LL |     taking_two_units({}, foo(0));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL ~     taking_two_units((), ());
    |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg_empty_blocks.rs:18:5
+  --> $DIR/unit_arg_empty_blocks.rs:19:5
    |
 LL |     taking_three_units({}, foo(0), foo(1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed
new file mode 100644
index 00000000000..b352b285c86
--- /dev/null
+++ b/tests/ui/unnecessary_cast.fixed
@@ -0,0 +1,91 @@
+// run-rustfix
+#![warn(clippy::unnecessary_cast)]
+#![allow(
+    unused_must_use,
+    clippy::borrow_as_ptr,
+    clippy::no_effect,
+    clippy::nonstandard_macro_braces,
+    clippy::unnecessary_operation
+)]
+
+#[rustfmt::skip]
+fn main() {
+    // Test cast_unnecessary
+    1_i32;
+    1_f32;
+    false;
+    &1i32 as &i32;
+
+    -1_i32;
+    - 1_i32;
+    -1_f32;
+    1_i32;
+    1_f32;
+
+    // macro version
+    macro_rules! foo {
+        ($a:ident, $b:ident) => {
+            #[allow(unused)]
+            pub fn $a() -> $b {
+                1 as $b
+            }
+        };
+    }
+    foo!(a, i32);
+    foo!(b, f32);
+    foo!(c, f64);
+
+    // do not lint cast to cfg-dependant type
+    1 as std::os::raw::c_char;
+
+    // do not lint cast to alias type
+    1 as I32Alias;
+    &1 as &I32Alias;
+}
+
+type I32Alias = i32;
+
+mod fixable {
+    #![allow(dead_code)]
+
+    fn main() {
+        // casting integer literal to float is unnecessary
+        100_f32;
+        100_f64;
+        100_f64;
+        let _ = -100_f32;
+        let _ = -100_f64;
+        let _ = -100_f64;
+        100_f32;
+        100_f64;
+        // Should not trigger
+        #[rustfmt::skip]
+        let v = vec!(1);
+        &v as &[i32];
+        0x10 as f32;
+        0o10 as f32;
+        0b10 as f32;
+        0x11 as f64;
+        0o11 as f64;
+        0b11 as f64;
+
+        1_u32;
+        0x10_i32;
+        0b10_usize;
+        0o73_u16;
+        1_000_000_000_u32;
+
+        1.0_f64;
+        0.5_f32;
+
+        1.0 as u16;
+
+        let _ = -1_i32;
+        let _ = -1.0_f32;
+
+        let _ = 1 as I32Alias;
+        let _ = &1 as &I32Alias;
+    }
+
+    type I32Alias = i32;
+}
diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs
index 62c3e963686..6c8cc3effe8 100644
--- a/tests/ui/unnecessary_cast.rs
+++ b/tests/ui/unnecessary_cast.rs
@@ -1,5 +1,12 @@
+// run-rustfix
 #![warn(clippy::unnecessary_cast)]
-#![allow(clippy::no_effect)]
+#![allow(
+    unused_must_use,
+    clippy::borrow_as_ptr,
+    clippy::no_effect,
+    clippy::nonstandard_macro_braces,
+    clippy::unnecessary_operation
+)]
 
 #[rustfmt::skip]
 fn main() {
@@ -37,3 +44,48 @@ fn main() {
 }
 
 type I32Alias = i32;
+
+mod fixable {
+    #![allow(dead_code)]
+
+    fn main() {
+        // casting integer literal to float is unnecessary
+        100 as f32;
+        100 as f64;
+        100_i32 as f64;
+        let _ = -100 as f32;
+        let _ = -100 as f64;
+        let _ = -100_i32 as f64;
+        100. as f32;
+        100. as f64;
+        // Should not trigger
+        #[rustfmt::skip]
+        let v = vec!(1);
+        &v as &[i32];
+        0x10 as f32;
+        0o10 as f32;
+        0b10 as f32;
+        0x11 as f64;
+        0o11 as f64;
+        0b11 as f64;
+
+        1 as u32;
+        0x10 as i32;
+        0b10 as usize;
+        0o73 as u16;
+        1_000_000_000 as u32;
+
+        1.0 as f64;
+        0.5 as f32;
+
+        1.0 as u16;
+
+        let _ = -1 as i32;
+        let _ = -1.0 as f32;
+
+        let _ = 1 as I32Alias;
+        let _ = &1 as &I32Alias;
+    }
+
+    type I32Alias = i32;
+}
diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr
index a5a93c6110c..bad45f0025b 100644
--- a/tests/ui/unnecessary_cast.stderr
+++ b/tests/ui/unnecessary_cast.stderr
@@ -1,5 +1,5 @@
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:7:5
+  --> $DIR/unnecessary_cast.rs:14:5
    |
 LL |     1i32 as i32;
    |     ^^^^^^^^^^^ help: try: `1_i32`
@@ -7,46 +7,148 @@ LL |     1i32 as i32;
    = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:8:5
+  --> $DIR/unnecessary_cast.rs:15:5
    |
 LL |     1f32 as f32;
    |     ^^^^^^^^^^^ help: try: `1_f32`
 
 error: casting to the same type is unnecessary (`bool` -> `bool`)
-  --> $DIR/unnecessary_cast.rs:9:5
+  --> $DIR/unnecessary_cast.rs:16:5
    |
 LL |     false as bool;
    |     ^^^^^^^^^^^^^ help: try: `false`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:12:5
+  --> $DIR/unnecessary_cast.rs:19:5
    |
 LL |     -1_i32 as i32;
    |     ^^^^^^^^^^^^^ help: try: `-1_i32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:13:5
+  --> $DIR/unnecessary_cast.rs:20:5
    |
 LL |     - 1_i32 as i32;
    |     ^^^^^^^^^^^^^^ help: try: `- 1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:14:5
+  --> $DIR/unnecessary_cast.rs:21:5
    |
 LL |     -1f32 as f32;
    |     ^^^^^^^^^^^^ help: try: `-1_f32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:15:5
+  --> $DIR/unnecessary_cast.rs:22:5
    |
 LL |     1_i32 as i32;
    |     ^^^^^^^^^^^^ help: try: `1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:16:5
+  --> $DIR/unnecessary_cast.rs:23:5
    |
 LL |     1_f32 as f32;
    |     ^^^^^^^^^^^^ help: try: `1_f32`
 
-error: aborting due to 8 previous errors
+error: casting integer literal to `f32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:53:9
+   |
+LL |         100 as f32;
+   |         ^^^^^^^^^^ help: try: `100_f32`
+
+error: casting integer literal to `f64` is unnecessary
+  --> $DIR/unnecessary_cast.rs:54:9
+   |
+LL |         100 as f64;
+   |         ^^^^^^^^^^ help: try: `100_f64`
+
+error: casting integer literal to `f64` is unnecessary
+  --> $DIR/unnecessary_cast.rs:55:9
+   |
+LL |         100_i32 as f64;
+   |         ^^^^^^^^^^^^^^ help: try: `100_f64`
+
+error: casting integer literal to `f32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:56:17
+   |
+LL |         let _ = -100 as f32;
+   |                 ^^^^^^^^^^^ help: try: `-100_f32`
+
+error: casting integer literal to `f64` is unnecessary
+  --> $DIR/unnecessary_cast.rs:57:17
+   |
+LL |         let _ = -100 as f64;
+   |                 ^^^^^^^^^^^ help: try: `-100_f64`
+
+error: casting integer literal to `f64` is unnecessary
+  --> $DIR/unnecessary_cast.rs:58:17
+   |
+LL |         let _ = -100_i32 as f64;
+   |                 ^^^^^^^^^^^^^^^ help: try: `-100_f64`
+
+error: casting float literal to `f32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:59:9
+   |
+LL |         100. as f32;
+   |         ^^^^^^^^^^^ help: try: `100_f32`
+
+error: casting float literal to `f64` is unnecessary
+  --> $DIR/unnecessary_cast.rs:60:9
+   |
+LL |         100. as f64;
+   |         ^^^^^^^^^^^ help: try: `100_f64`
+
+error: casting integer literal to `u32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:72:9
+   |
+LL |         1 as u32;
+   |         ^^^^^^^^ help: try: `1_u32`
+
+error: casting integer literal to `i32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:73:9
+   |
+LL |         0x10 as i32;
+   |         ^^^^^^^^^^^ help: try: `0x10_i32`
+
+error: casting integer literal to `usize` is unnecessary
+  --> $DIR/unnecessary_cast.rs:74:9
+   |
+LL |         0b10 as usize;
+   |         ^^^^^^^^^^^^^ help: try: `0b10_usize`
+
+error: casting integer literal to `u16` is unnecessary
+  --> $DIR/unnecessary_cast.rs:75:9
+   |
+LL |         0o73 as u16;
+   |         ^^^^^^^^^^^ help: try: `0o73_u16`
+
+error: casting integer literal to `u32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:76:9
+   |
+LL |         1_000_000_000 as u32;
+   |         ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32`
+
+error: casting float literal to `f64` is unnecessary
+  --> $DIR/unnecessary_cast.rs:78:9
+   |
+LL |         1.0 as f64;
+   |         ^^^^^^^^^^ help: try: `1.0_f64`
+
+error: casting float literal to `f32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:79:9
+   |
+LL |         0.5 as f32;
+   |         ^^^^^^^^^^ help: try: `0.5_f32`
+
+error: casting integer literal to `i32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:83:17
+   |
+LL |         let _ = -1 as i32;
+   |                 ^^^^^^^^^ help: try: `-1_i32`
+
+error: casting float literal to `f32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:84:17
+   |
+LL |         let _ = -1.0 as f32;
+   |                 ^^^^^^^^^^^ help: try: `-1.0_f32`
+
+error: aborting due to 25 previous errors
 
diff --git a/tests/ui/unnecessary_cast_fixable.fixed b/tests/ui/unnecessary_cast_fixable.fixed
deleted file mode 100644
index 36800c5340d..00000000000
--- a/tests/ui/unnecessary_cast_fixable.fixed
+++ /dev/null
@@ -1,50 +0,0 @@
-// run-rustfix
-
-#![warn(clippy::unnecessary_cast)]
-#![allow(
-    clippy::no_effect,
-    clippy::unnecessary_operation,
-    clippy::nonstandard_macro_braces,
-    clippy::borrow_as_ptr
-)]
-
-fn main() {
-    // casting integer literal to float is unnecessary
-    100_f32;
-    100_f64;
-    100_f64;
-    let _ = -100_f32;
-    let _ = -100_f64;
-    let _ = -100_f64;
-    100_f32;
-    100_f64;
-    // Should not trigger
-    #[rustfmt::skip]
-    let v = vec!(1);
-    &v as &[i32];
-    0x10 as f32;
-    0o10 as f32;
-    0b10 as f32;
-    0x11 as f64;
-    0o11 as f64;
-    0b11 as f64;
-
-    1_u32;
-    0x10_i32;
-    0b10_usize;
-    0o73_u16;
-    1_000_000_000_u32;
-
-    1.0_f64;
-    0.5_f32;
-
-    1.0 as u16;
-
-    let _ = -1_i32;
-    let _ = -1.0_f32;
-
-    let _ = 1 as I32Alias;
-    let _ = &1 as &I32Alias;
-}
-
-type I32Alias = i32;
diff --git a/tests/ui/unnecessary_cast_fixable.rs b/tests/ui/unnecessary_cast_fixable.rs
deleted file mode 100644
index d4b6bb952ab..00000000000
--- a/tests/ui/unnecessary_cast_fixable.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// run-rustfix
-
-#![warn(clippy::unnecessary_cast)]
-#![allow(
-    clippy::no_effect,
-    clippy::unnecessary_operation,
-    clippy::nonstandard_macro_braces,
-    clippy::borrow_as_ptr
-)]
-
-fn main() {
-    // casting integer literal to float is unnecessary
-    100 as f32;
-    100 as f64;
-    100_i32 as f64;
-    let _ = -100 as f32;
-    let _ = -100 as f64;
-    let _ = -100_i32 as f64;
-    100. as f32;
-    100. as f64;
-    // Should not trigger
-    #[rustfmt::skip]
-    let v = vec!(1);
-    &v as &[i32];
-    0x10 as f32;
-    0o10 as f32;
-    0b10 as f32;
-    0x11 as f64;
-    0o11 as f64;
-    0b11 as f64;
-
-    1 as u32;
-    0x10 as i32;
-    0b10 as usize;
-    0o73 as u16;
-    1_000_000_000 as u32;
-
-    1.0 as f64;
-    0.5 as f32;
-
-    1.0 as u16;
-
-    let _ = -1 as i32;
-    let _ = -1.0 as f32;
-
-    let _ = 1 as I32Alias;
-    let _ = &1 as &I32Alias;
-}
-
-type I32Alias = i32;
diff --git a/tests/ui/unnecessary_cast_fixable.stderr b/tests/ui/unnecessary_cast_fixable.stderr
deleted file mode 100644
index a281143281b..00000000000
--- a/tests/ui/unnecessary_cast_fixable.stderr
+++ /dev/null
@@ -1,106 +0,0 @@
-error: casting integer literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:13:5
-   |
-LL |     100 as f32;
-   |     ^^^^^^^^^^ help: try: `100_f32`
-   |
-   = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
-
-error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:14:5
-   |
-LL |     100 as f64;
-   |     ^^^^^^^^^^ help: try: `100_f64`
-
-error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:15:5
-   |
-LL |     100_i32 as f64;
-   |     ^^^^^^^^^^^^^^ help: try: `100_f64`
-
-error: casting integer literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:16:13
-   |
-LL |     let _ = -100 as f32;
-   |             ^^^^^^^^^^^ help: try: `-100_f32`
-
-error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:17:13
-   |
-LL |     let _ = -100 as f64;
-   |             ^^^^^^^^^^^ help: try: `-100_f64`
-
-error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:18:13
-   |
-LL |     let _ = -100_i32 as f64;
-   |             ^^^^^^^^^^^^^^^ help: try: `-100_f64`
-
-error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:19:5
-   |
-LL |     100. as f32;
-   |     ^^^^^^^^^^^ help: try: `100_f32`
-
-error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:20:5
-   |
-LL |     100. as f64;
-   |     ^^^^^^^^^^^ help: try: `100_f64`
-
-error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:32:5
-   |
-LL |     1 as u32;
-   |     ^^^^^^^^ help: try: `1_u32`
-
-error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:33:5
-   |
-LL |     0x10 as i32;
-   |     ^^^^^^^^^^^ help: try: `0x10_i32`
-
-error: casting integer literal to `usize` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:34:5
-   |
-LL |     0b10 as usize;
-   |     ^^^^^^^^^^^^^ help: try: `0b10_usize`
-
-error: casting integer literal to `u16` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:35:5
-   |
-LL |     0o73 as u16;
-   |     ^^^^^^^^^^^ help: try: `0o73_u16`
-
-error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:36:5
-   |
-LL |     1_000_000_000 as u32;
-   |     ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32`
-
-error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:38:5
-   |
-LL |     1.0 as f64;
-   |     ^^^^^^^^^^ help: try: `1.0_f64`
-
-error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:39:5
-   |
-LL |     0.5 as f32;
-   |     ^^^^^^^^^^ help: try: `0.5_f32`
-
-error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:43:13
-   |
-LL |     let _ = -1 as i32;
-   |             ^^^^^^^^^ help: try: `-1_i32`
-
-error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:44:13
-   |
-LL |     let _ = -1.0 as f32;
-   |             ^^^^^^^^^^^ help: try: `-1.0_f32`
-
-error: aborting due to 17 previous errors
-
diff --git a/tests/ui/unused_rounding.fixed b/tests/ui/unused_rounding.fixed
new file mode 100644
index 00000000000..54f85806ac3
--- /dev/null
+++ b/tests/ui/unused_rounding.fixed
@@ -0,0 +1,9 @@
+// run-rustfix
+#![warn(clippy::unused_rounding)]
+
+fn main() {
+    let _ = 1f32;
+    let _ = 1.0f64;
+    let _ = 1.00f32;
+    let _ = 2e-54f64.floor();
+}
diff --git a/tests/ui/unused_rounding.rs b/tests/ui/unused_rounding.rs
new file mode 100644
index 00000000000..8d007bc4a1d
--- /dev/null
+++ b/tests/ui/unused_rounding.rs
@@ -0,0 +1,9 @@
+// run-rustfix
+#![warn(clippy::unused_rounding)]
+
+fn main() {
+    let _ = 1f32.ceil();
+    let _ = 1.0f64.floor();
+    let _ = 1.00f32.round();
+    let _ = 2e-54f64.floor();
+}
diff --git a/tests/ui/unused_rounding.stderr b/tests/ui/unused_rounding.stderr
new file mode 100644
index 00000000000..6cfb02e0402
--- /dev/null
+++ b/tests/ui/unused_rounding.stderr
@@ -0,0 +1,22 @@
+error: used the `ceil` method with a whole number float
+  --> $DIR/unused_rounding.rs:5:13
+   |
+LL |     let _ = 1f32.ceil();
+   |             ^^^^^^^^^^^ help: remove the `ceil` method call: `1f32`
+   |
+   = note: `-D clippy::unused-rounding` implied by `-D warnings`
+
+error: used the `floor` method with a whole number float
+  --> $DIR/unused_rounding.rs:6:13
+   |
+LL |     let _ = 1.0f64.floor();
+   |             ^^^^^^^^^^^^^^ help: remove the `floor` method call: `1.0f64`
+
+error: used the `round` method with a whole number float
+  --> $DIR/unused_rounding.rs:7:13
+   |
+LL |     let _ = 1.00f32.round();
+   |             ^^^^^^^^^^^^^^^ help: remove the `round` method call: `1.00f32`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/use_self.fixed b/tests/ui/use_self.fixed
index 3e62ffe74fe..4f80aaecc90 100644
--- a/tests/ui/use_self.fixed
+++ b/tests/ui/use_self.fixed
@@ -542,3 +542,69 @@ mod use_self_in_pat {
         }
     }
 }
+
+mod issue8845 {
+    pub enum Something {
+        Num(u8),
+        TupleNums(u8, u8),
+        StructNums { one: u8, two: u8 },
+    }
+
+    struct Foo(u8);
+
+    struct Bar {
+        x: u8,
+        y: usize,
+    }
+
+    impl Something {
+        fn get_value(&self) -> u8 {
+            match self {
+                Self::Num(n) => *n,
+                Self::TupleNums(n, _m) => *n,
+                Self::StructNums { one, two: _ } => *one,
+            }
+        }
+
+        fn use_crate(&self) -> u8 {
+            match self {
+                Self::Num(n) => *n,
+                Self::TupleNums(n, _m) => *n,
+                Self::StructNums { one, two: _ } => *one,
+            }
+        }
+
+        fn imported_values(&self) -> u8 {
+            use Something::*;
+            match self {
+                Num(n) => *n,
+                TupleNums(n, _m) => *n,
+                StructNums { one, two: _ } => *one,
+            }
+        }
+    }
+
+    impl Foo {
+        fn get_value(&self) -> u8 {
+            let Self(x) = self;
+            *x
+        }
+
+        fn use_crate(&self) -> u8 {
+            let Self(x) = self;
+            *x
+        }
+    }
+
+    impl Bar {
+        fn get_value(&self) -> u8 {
+            let Self { x, .. } = self;
+            *x
+        }
+
+        fn use_crate(&self) -> u8 {
+            let Self { x, .. } = self;
+            *x
+        }
+    }
+}
diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs
index da2faddee12..52da72db53c 100644
--- a/tests/ui/use_self.rs
+++ b/tests/ui/use_self.rs
@@ -542,3 +542,69 @@ mod use_self_in_pat {
         }
     }
 }
+
+mod issue8845 {
+    pub enum Something {
+        Num(u8),
+        TupleNums(u8, u8),
+        StructNums { one: u8, two: u8 },
+    }
+
+    struct Foo(u8);
+
+    struct Bar {
+        x: u8,
+        y: usize,
+    }
+
+    impl Something {
+        fn get_value(&self) -> u8 {
+            match self {
+                Something::Num(n) => *n,
+                Something::TupleNums(n, _m) => *n,
+                Something::StructNums { one, two: _ } => *one,
+            }
+        }
+
+        fn use_crate(&self) -> u8 {
+            match self {
+                crate::issue8845::Something::Num(n) => *n,
+                crate::issue8845::Something::TupleNums(n, _m) => *n,
+                crate::issue8845::Something::StructNums { one, two: _ } => *one,
+            }
+        }
+
+        fn imported_values(&self) -> u8 {
+            use Something::*;
+            match self {
+                Num(n) => *n,
+                TupleNums(n, _m) => *n,
+                StructNums { one, two: _ } => *one,
+            }
+        }
+    }
+
+    impl Foo {
+        fn get_value(&self) -> u8 {
+            let Foo(x) = self;
+            *x
+        }
+
+        fn use_crate(&self) -> u8 {
+            let crate::issue8845::Foo(x) = self;
+            *x
+        }
+    }
+
+    impl Bar {
+        fn get_value(&self) -> u8 {
+            let Bar { x, .. } = self;
+            *x
+        }
+
+        fn use_crate(&self) -> u8 {
+            let crate::issue8845::Bar { x, .. } = self;
+            *x
+        }
+    }
+}
diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr
index 34d98618253..f06bb959b3b 100644
--- a/tests/ui/use_self.stderr
+++ b/tests/ui/use_self.stderr
@@ -186,5 +186,65 @@ error: unnecessary structure name repetition
 LL |             if let Foo::Bar = self {
    |                    ^^^ help: use the applicable keyword: `Self`
 
-error: aborting due to 31 previous errors
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:563:17
+   |
+LL |                 Something::Num(n) => *n,
+   |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:564:17
+   |
+LL |                 Something::TupleNums(n, _m) => *n,
+   |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:565:17
+   |
+LL |                 Something::StructNums { one, two: _ } => *one,
+   |                 ^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:571:17
+   |
+LL |                 crate::issue8845::Something::Num(n) => *n,
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:572:17
+   |
+LL |                 crate::issue8845::Something::TupleNums(n, _m) => *n,
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:573:17
+   |
+LL |                 crate::issue8845::Something::StructNums { one, two: _ } => *one,
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:589:17
+   |
+LL |             let Foo(x) = self;
+   |                 ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:594:17
+   |
+LL |             let crate::issue8845::Foo(x) = self;
+   |                 ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:601:17
+   |
+LL |             let Bar { x, .. } = self;
+   |                 ^^^ help: use the applicable keyword: `Self`
+
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:606:17
+   |
+LL |             let crate::issue8845::Bar { x, .. } = self;
+   |                 ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self`
+
+error: aborting due to 41 previous errors
 
diff --git a/util/gh-pages/script.js b/util/gh-pages/script.js
index bf4ce79b2cb..6909fbcae09 100644
--- a/util/gh-pages/script.js
+++ b/util/gh-pages/script.js
@@ -232,6 +232,9 @@
                     return true;
                 }
                 searchStr = searchStr.toLowerCase();
+                if (searchStr.startsWith("clippy::")) {
+                    searchStr = searchStr.slice(8);
+                }
 
                 // Search by id
                 if (lint.id.indexOf(searchStr.replace("-", "_")) !== -1) {
@@ -343,17 +346,23 @@ function setTheme(theme, store) {
     let enableNight = false;
     let enableAyu = false;
 
-    if (theme == "ayu") {
-        enableAyu = true;
-    } else if (theme == "coal" || theme == "navy") {
-        enableNight = true;
-    } else if (theme == "rust") {
-        enableHighlight = true;
-    } else {
-        enableHighlight = true;
-        // this makes sure that an unknown theme request gets set to a known one
-        theme = "light";
+    switch(theme) {
+        case "ayu":
+            enableAyu = true;
+            break;
+        case "coal":
+        case "navy":
+            enableNight = true;
+            break;
+        case "rust":
+            enableHighlight = true;
+            break;
+        default:
+            enableHighlight = true;
+            theme = "light";
+            break;
     }
+
     document.getElementsByTagName("body")[0].className = theme;
 
     document.getElementById("styleHighlight").disabled = !enableHighlight;
@@ -368,4 +377,10 @@ function setTheme(theme, store) {
 }
 
 // loading the theme after the initial load
-setTheme(localStorage.getItem('clippy-lint-list-theme'), false);
+const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
+const theme = localStorage.getItem('clippy-lint-list-theme');
+if (prefersDark.matches && !theme) {
+    setTheme("coal", false);
+} else {
+    setTheme(theme, false);
+}