about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-06-09 20:56:54 +0000
committerbors <bors@rust-lang.org>2020-06-09 20:56:54 +0000
commit283522400b5c13dfdf2b7e608e63a70ee8e3d7af (patch)
tree2aa4775e0ce4256904378821fd66c8e337d1a307
parentfeb3536eba10c2e4585d066629598f03d5ddc7c6 (diff)
parent41c845efd9c241be1bc506a433b25f5357e5beb5 (diff)
downloadrust-283522400b5c13dfdf2b7e608e63a70ee8e3d7af.tar.gz
rust-283522400b5c13dfdf2b7e608e63a70ee8e3d7af.zip
Auto merge of #72972 - lzutao:clippy, r=Manishearth
Pull changes from rust-lang/rust-clippy
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml3
-rw-r--r--src/tools/clippy/CHANGELOG.md87
-rw-r--r--src/tools/clippy/CONTRIBUTING.md36
-rw-r--r--src/tools/clippy/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs3
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs16
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/ra_setup.rs90
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml4
-rw-r--r--src/tools/clippy/clippy_lints/src/assign_ops.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_lock.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs78
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/double_parens.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_bounds.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/duration_subsec.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_variants.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/eq_op.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/eval_order_dependence.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/format.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/formatting.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/functions.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/int_plus_one.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/integer_division.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_statements.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/let_and_return.rs141
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/loops.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/matches.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs178
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/mutex_atomic.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrow.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_update.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/new_without_default.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/reference.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs82
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/single_component_path_imports.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/types.rs142
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs267
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs407
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs14
-rwxr-xr-xsrc/tools/clippy/clippy_lints/src/utils/ast_utils.rs526
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/hir_utils.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/paths.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/verbose_file_reads.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_div_zero.rs6
-rw-r--r--src/tools/clippy/doc/changelog_update.md12
-rw-r--r--src/tools/clippy/doc/common_tools_writing_lints.md48
-rw-r--r--src/tools/clippy/doc/release.md88
-rw-r--r--src/tools/clippy/src/lintlist/mod.rs34
-rw-r--r--src/tools/clippy/tests/compile-test.rs9
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml2
-rw-r--r--src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml2
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml2
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml2
-rw-r--r--src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml2
-rw-r--r--src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml2
-rw-r--r--src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml2
-rw-r--r--src/tools/clippy/tests/ui/checked_conversions.fixed106
-rw-r--r--src/tools/clippy/tests/ui/checked_conversions.rs106
-rw-r--r--src/tools/clippy/tests/ui/checked_conversions.stderr98
-rw-r--r--src/tools/clippy/tests/ui/checked_conversions.stdout0
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3969.rs51
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3969.stderr22
-rw-r--r--src/tools/clippy/tests/ui/crashes/regressions.rs4
-rw-r--r--src/tools/clippy/tests/ui/into_iter_on_ref.fixed2
-rw-r--r--src/tools/clippy/tests/ui/into_iter_on_ref.rs2
-rw-r--r--src/tools/clippy/tests/ui/into_iter_on_ref.stderr8
-rw-r--r--src/tools/clippy/tests/ui/iter_next_slice.fixed24
-rw-r--r--src/tools/clippy/tests/ui/iter_next_slice.rs24
-rw-r--r--src/tools/clippy/tests/ui/iter_next_slice.stderr28
-rw-r--r--src/tools/clippy/tests/ui/len_zero.fixed8
-rw-r--r--src/tools/clippy/tests/ui/len_zero.rs8
-rw-r--r--src/tools/clippy/tests/ui/len_zero_ranges.fixed14
-rw-r--r--src/tools/clippy/tests/ui/len_zero_ranges.rs14
-rw-r--r--src/tools/clippy/tests/ui/len_zero_ranges.stderr10
-rw-r--r--src/tools/clippy/tests/ui/let_and_return.rs138
-rw-r--r--src/tools/clippy/tests/ui/let_and_return.stderr (renamed from src/tools/clippy/tests/ui/let_return.stderr)4
-rw-r--r--src/tools/clippy/tests/ui/let_return.rs70
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.fixed2
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.stderr16
-rw-r--r--src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs1
-rw-r--r--src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr8
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed4
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr18
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed8
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs8
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr16
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs5
-rw-r--r--src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr18
-rw-r--r--src/tools/clippy/tests/ui/string_lit_as_bytes.fixed2
-rw-r--r--src/tools/clippy/tests/ui/string_lit_as_bytes.rs2
-rw-r--r--src/tools/clippy/tests/ui/string_lit_as_bytes.stderr4
-rw-r--r--src/tools/clippy/tests/ui/unit_arg.fixed64
-rw-r--r--src/tools/clippy/tests/ui/unit_arg.rs27
-rw-r--r--src/tools/clippy/tests/ui/unit_arg.stderr178
-rw-r--r--src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs26
-rw-r--r--src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr51
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_sort_by.fixed26
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_sort_by.rs26
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_sort_by.stderr46
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns.fixed33
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns.rs33
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns.stderr179
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns2.fixed18
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns2.rs18
-rw-r--r--src/tools/clippy/tests/ui/unnested_or_patterns2.stderr91
-rw-r--r--src/tools/clippy/tests/ui/vec_resize_to_zero.rs15
-rw-r--r--src/tools/clippy/tests/ui/vec_resize_to_zero.stderr13
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed3
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs3
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr10
143 files changed, 3943 insertions, 914 deletions
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 3958ba01246..0c80394f03e 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -232,7 +232,8 @@ jobs:
       matrix:
         integration:
         - 'rust-lang/cargo'
-        - 'rust-lang/rls'
+        # FIXME: re-enable once fmt_macros is renamed in RLS
+        # - 'rust-lang/rls'
         - 'rust-lang/chalk'
         - 'rust-lang/rustfmt'
         - 'Marwes/combine'
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 2ac9057199f..adc945a6944 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,88 @@ document.
 
 ## Unreleased / In Rust Nightly
 
-[891e1a8...master](https://github.com/rust-lang/rust-clippy/compare/891e1a8...master)
+[7ea7cd1...master](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...master)
+
+## Rust 1.45
+
+Current beta, release 2020-07-16
+
+[891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1)
+
+### New lints
+
+* [`match_wildcard_for_single_variants`] [#5582](https://github.com/rust-lang/rust-clippy/pull/5582)
+* [`unsafe_derive_deserialize`] [#5493](https://github.com/rust-lang/rust-clippy/pull/5493)
+* [`if_let_mutex`] [#5332](https://github.com/rust-lang/rust-clippy/pull/5332)
+* [`mismatched_target_os`] [#5506](https://github.com/rust-lang/rust-clippy/pull/5506)
+* [`await_holding_lock`] [#5439](https://github.com/rust-lang/rust-clippy/pull/5439)
+* [`match_on_vec_items`] [#5522](https://github.com/rust-lang/rust-clippy/pull/5522)
+* [`manual_async_fn`] [#5576](https://github.com/rust-lang/rust-clippy/pull/5576)
+* [`reversed_empty_ranges`] [#5583](https://github.com/rust-lang/rust-clippy/pull/5583)
+* [`manual_non_exhaustive`] [#5550](https://github.com/rust-lang/rust-clippy/pull/5550)
+
+### Moves and Deprecations
+
+* Downgrade [`match_bool`] to pedantic [#5408](https://github.com/rust-lang/rust-clippy/pull/5408)
+* Downgrade [`match_wild_err_arm`] to pedantic and update help messages. [#5622](https://github.com/rust-lang/rust-clippy/pull/5622)
+* Downgrade [`useless_let_if_seq`] to nursery. [#5599](https://github.com/rust-lang/rust-clippy/pull/5599)
+* Generalize `option_and_then_some` and rename to [`bind_instead_of_map`]. [#5529](https://github.com/rust-lang/rust-clippy/pull/5529)
+* Rename `identity_conversion` to [`useless_conversion`]. [#5568](https://github.com/rust-lang/rust-clippy/pull/5568)
+* Merge `block_in_if_condition_expr` and `block_in_if_condition_stmt` into [`blocks_in_if_conditions`].
+[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
+* Merge `option_map_unwrap_or`, `option_map_unwrap_or_else` and `result_map_unwrap_or_else` into [`map_unwrap_or`].
+[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
+* Merge `option_unwrap_used` and `result_unwrap_used` into [`unwrap_used`].
+[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
+* Merge `option_expect_used` and `result_expect_used` into [`expect_used`].
+[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
+* Merge `for_loop_over_option` and `for_loop_over_result` into [`for_loops_over_fallibles`].
+[#5563](https://github.com/rust-lang/rust-clippy/pull/5563)
+
+### Enhancements
+
+* Avoid running cargo lints when not enabled to improve performance. [#5505](https://github.com/rust-lang/rust-clippy/pull/5505)
+* Extend [`useless_conversion`] with `TryFrom` and `TryInto`. [#5631](https://github.com/rust-lang/rust-clippy/pull/5631)
+* Lint also in type parameters and where clauses in [`unused_unit`]. [#5592](https://github.com/rust-lang/rust-clippy/pull/5592)
+* Do not suggest deriving `Default` in [`new_without_default`]. [#5616](https://github.com/rust-lang/rust-clippy/pull/5616)
+
+### False Positive Fixes
+
+* [`while_let_on_iterator`] [#5525](https://github.com/rust-lang/rust-clippy/pull/5525)
+* [`empty_line_after_outer_attr`] [#5609](https://github.com/rust-lang/rust-clippy/pull/5609)
+* [`unnecessary_unwrap`] [#5558](https://github.com/rust-lang/rust-clippy/pull/5558)
+* [`comparison_chain`] [#5596](https://github.com/rust-lang/rust-clippy/pull/5596)
+* Don't trigger [`used_underscore_binding`] in await desugaring. [#5535](https://github.com/rust-lang/rust-clippy/pull/5535)
+* Don't trigger [`borrowed_box`] on mutable references. [#5491](https://github.com/rust-lang/rust-clippy/pull/5491)
+* Allow `1 << 0` in [`identity_op`]. [#5602](https://github.com/rust-lang/rust-clippy/pull/5602)
+* Allow `use super::*;` glob imports in [`wildcard_imports`]. [#5564](https://github.com/rust-lang/rust-clippy/pull/5564)
+* Whitelist more words in [`doc_markdown`]. [#5611](https://github.com/rust-lang/rust-clippy/pull/5611)
+* Skip dev and build deps in [`multiple_crate_versions`]. [#5636](https://github.com/rust-lang/rust-clippy/pull/5636)
+* Honor `allow` attribute on arguments in [`ptr_arg`]. [#5647](https://github.com/rust-lang/rust-clippy/pull/5647)
+* Honor lint level attributes for [`redundant_field_names`], [`just_underscores_and_digits`], [`many_single_char_names`]
+and [`similar_names`]. [#5651](https://github.com/rust-lang/rust-clippy/pull/5651)
+* Ignore calls to `len` in [`or_fun_call`]. [#4429](https://github.com/rust-lang/rust-clippy/pull/4429)
+
+### Suggestion Improvements
+
+* Simplify suggestions in [`manual_memcpy`]. [#5536](https://github.com/rust-lang/rust-clippy/pull/5536)
+* Fix suggestion in [`redundant_pattern_matching`] for macros. [#5511](https://github.com/rust-lang/rust-clippy/pull/5511)
+* Avoid suggesting `copied()` for mutable references in [`map_clone`]. [#5530](https://github.com/rust-lang/rust-clippy/pull/5530)
+* Improve help message for [`clone_double_ref`]. [#5547](https://github.com/rust-lang/rust-clippy/pull/5547)
+
+### ICE Fixes
+
+* Fix ICE caused in unwrap module. [#5590](https://github.com/rust-lang/rust-clippy/pull/5590)
+* Fix ICE on rustc test issue-69020-assoc-const-arith-overflow.rs [#5499](https://github.com/rust-lang/rust-clippy/pull/5499)
+
+### Documentation
+
+* Clarify the documentation of [`unnecessary_mut_passed`]. [#5639](https://github.com/rust-lang/rust-clippy/pull/5639)
+* Extend example for [`unneeded_field_pattern`]. [#5541](https://github.com/rust-lang/rust-clippy/pull/5541)
 
 ## Rust 1.44
 
-Current beta, release 2020-06-04
+Current stable, released 2020-06-04
 
 [204bb9b...891e1a8](https://github.com/rust-lang/rust-clippy/compare/204bb9b...891e1a8)
 
@@ -93,7 +170,7 @@ Current beta, release 2020-06-04
 
 ## Rust 1.43
 
-Current stable, released 2020-04-23
+Released 2020-04-23
 
 [4ee1206...204bb9b](https://github.com/rust-lang/rust-clippy/compare/4ee1206...204bb9b)
 
@@ -1401,6 +1478,7 @@ Released 2018-09-13
 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements
 [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
 [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
+[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice
 [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
 [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
 [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
@@ -1601,9 +1679,11 @@ Released 2018-09-13
 [`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
 [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
+[`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
 [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
 [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern
 [`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern
+[`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns
 [`unreachable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreachable
 [`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal
 [`unsafe_derive_deserialize`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_derive_deserialize
@@ -1630,6 +1710,7 @@ Released 2018-09-13
 [`useless_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_transmute
 [`useless_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_vec
 [`vec_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_box
+[`vec_resize_to_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#vec_resize_to_zero
 [`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
 [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
 [`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md
index 0f47ac98fd2..9f7bdcb1be7 100644
--- a/src/tools/clippy/CONTRIBUTING.md
+++ b/src/tools/clippy/CONTRIBUTING.md
@@ -12,14 +12,16 @@ anything, feel free to ask questions on issues or visit the `#clippy` on [Discor
 
 All contributors are expected to follow the [Rust Code of Conduct].
 
-* [Getting started](#getting-started)
-  * [Finding something to fix/improve](#finding-something-to-fiximprove)
-* [Writing code](#writing-code)
-* [How Clippy works](#how-clippy-works)
-* [Fixing nightly build failures](#fixing-build-failures-caused-by-rust)
-* [Issue and PR Triage](#issue-and-pr-triage)
-* [Bors and Homu](#bors-and-homu)
-* [Contributions](#contributions)
+- [Contributing to Clippy](#contributing-to-clippy)
+  - [Getting started](#getting-started)
+    - [Finding something to fix/improve](#finding-something-to-fiximprove)
+  - [Writing code](#writing-code)
+  - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work)
+  - [How Clippy works](#how-clippy-works)
+  - [Fixing build failures caused by Rust](#fixing-build-failures-caused-by-rust)
+  - [Issue and PR triage](#issue-and-pr-triage)
+  - [Bors and Homu](#bors-and-homu)
+  - [Contributions](#contributions)
 
 [Discord]: https://discord.gg/rust-lang
 [Rust Code of Conduct]: https://www.rust-lang.org/policies/code-of-conduct
@@ -91,6 +93,24 @@ quick read.
 [rfc_stability]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#stability-guarantees
 [rfc_lint_cats]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories
 
+## Getting code-completion for rustc internals to work
+
+Unfortunately, [`rust-analyzer`][ra_homepage] does not (yet?) understand how Clippy uses compiler-internals 
+using `extern crate` and it also needs to be able to read the source files of the rustc-compiler which are not 
+available via a `rustup` component at the time of writing.  
+To work around this, you need to have a copy of the [rustc-repo][rustc_repo] available which can be obtained via  
+`git clone https://github.com/rust-lang/rust/`.  
+Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies 
+which rust-analyzer will be able to understand.  
+Run `cargo dev ra-setup --repo-path <repo-path>` where `<repo-path>` is an absolute path to the rustc repo 
+you just cloned.  
+The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to 
+Clippys `Cargo.toml`s and should allow rust-analyzer to understand most of the types that Clippy uses.
+Just make sure to remove the dependencies again before finally making a pull request!
+
+[ra_homepage]: https://rust-analyzer.github.io/
+[rustc_repo]: https://github.com/rust-lang/rust/
+
 ## How Clippy works
 
 [`clippy_lints/src/lib.rs`][lint_crate_entry] imports all the different lint modules and registers in the [`LintStore`].
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 6999b6bd740..836897927b0 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -37,7 +37,7 @@ tempfile = { version = "3.1.0", optional = true }
 lazy_static = "1.0"
 
 [dev-dependencies]
-cargo_metadata = "0.9.0"
+cargo_metadata = "0.9.1"
 compiletest_rs = { version = "0.5.0", features = ["tmp"] }
 tester = "0.7"
 lazy_static = "1.0"
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 6fdd282c684..5baa31d5cde 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -11,6 +11,7 @@ use walkdir::WalkDir;
 
 pub mod fmt;
 pub mod new_lint;
+pub mod ra_setup;
 pub mod stderr_length_check;
 pub mod update_lints;
 
@@ -400,7 +401,7 @@ fn test_replace_region_no_changes() {
         changed: false,
         new_lines: "123\n456\n789".to_string(),
     };
-    let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, || vec![]);
+    let result = replace_region_in_text(text, r#"^\s*123$"#, r#"^\s*456"#, false, Vec::new);
     assert_eq!(expected, result);
 }
 
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index d99235f7c07..281037ae37c 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -1,7 +1,7 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 
 use clap::{App, Arg, SubCommand};
-use clippy_dev::{fmt, new_lint, stderr_length_check, update_lints};
+use clippy_dev::{fmt, new_lint, ra_setup, stderr_length_check, update_lints};
 
 fn main() {
     let matches = App::new("Clippy developer tooling")
@@ -87,6 +87,19 @@ fn main() {
             SubCommand::with_name("limit_stderr_length")
                 .about("Ensures that stderr files do not grow longer than a certain amount of lines."),
         )
+        .subcommand(
+            SubCommand::with_name("ra-setup")
+                .about("Alter dependencies so rust-analyzer can find rustc internals")
+                .arg(
+                    Arg::with_name("rustc-repo-path")
+                        .long("repo-path")
+                        .short("r")
+                        .help("The path to a rustc repo that will be used for setting the dependencies")
+                        .takes_value(true)
+                        .value_name("path")
+                        .required(true),
+                ),
+        )
         .get_matches();
 
     match matches.subcommand() {
@@ -115,6 +128,7 @@ fn main() {
         ("limit_stderr_length", _) => {
             stderr_length_check::check();
         },
+        ("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")),
         _ => {},
     }
 }
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index c0b2dac2f60..1e032a7bc20 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -147,6 +147,8 @@ fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
 name = "{}"
 version = "0.1.0"
 publish = false
+
+[workspace]
 "#,
         hint, lint_name
     )
diff --git a/src/tools/clippy/clippy_dev/src/ra_setup.rs b/src/tools/clippy/clippy_dev/src/ra_setup.rs
new file mode 100644
index 00000000000..8617445c8a6
--- /dev/null
+++ b/src/tools/clippy/clippy_dev/src/ra_setup.rs
@@ -0,0 +1,90 @@
+#![allow(clippy::filter_map)]
+
+use std::fs;
+use std::fs::File;
+use std::io::prelude::*;
+use std::path::PathBuf;
+
+// This module takes an absolute path to a rustc repo and alters the dependencies to point towards
+// the respective rustc subcrates instead of using extern crate xyz.
+// This allows rust analyzer to analyze rustc internals and show proper information inside clippy
+// code. See https://github.com/rust-analyzer/rust-analyzer/issues/3517 and https://github.com/rust-lang/rust-clippy/issues/5514 for details
+
+pub fn run(rustc_path: Option<&str>) {
+    // we can unwrap here because the arg is required here
+    let rustc_path = PathBuf::from(rustc_path.unwrap());
+    assert!(rustc_path.is_dir(), "path is not a directory");
+    let rustc_source_basedir = rustc_path.join("src");
+    assert!(
+        rustc_source_basedir.is_dir(),
+        "are you sure the path leads to a rustc repo?"
+    );
+
+    let clippy_root_manifest = fs::read_to_string("Cargo.toml").expect("failed to read ./Cargo.toml");
+    let clippy_root_lib_rs = fs::read_to_string("src/driver.rs").expect("failed to read ./src/driver.rs");
+    inject_deps_into_manifest(
+        &rustc_source_basedir,
+        "Cargo.toml",
+        &clippy_root_manifest,
+        &clippy_root_lib_rs,
+    )
+    .expect("Failed to inject deps into ./Cargo.toml");
+
+    let clippy_lints_manifest =
+        fs::read_to_string("clippy_lints/Cargo.toml").expect("failed to read ./clippy_lints/Cargo.toml");
+    let clippy_lints_lib_rs =
+        fs::read_to_string("clippy_lints/src/lib.rs").expect("failed to read ./clippy_lints/src/lib.rs");
+    inject_deps_into_manifest(
+        &rustc_source_basedir,
+        "clippy_lints/Cargo.toml",
+        &clippy_lints_manifest,
+        &clippy_lints_lib_rs,
+    )
+    .expect("Failed to inject deps into ./clippy_lints/Cargo.toml");
+}
+
+fn inject_deps_into_manifest(
+    rustc_source_dir: &PathBuf,
+    manifest_path: &str,
+    cargo_toml: &str,
+    lib_rs: &str,
+) -> std::io::Result<()> {
+    let extern_crates = lib_rs
+        .lines()
+        // get the deps
+        .filter(|line| line.starts_with("extern crate"))
+        // we have something like "extern crate foo;", we only care about the "foo"
+        //              ↓          ↓
+        // extern crate rustc_middle;
+        .map(|s| &s[13..(s.len() - 1)]);
+
+    let new_deps = extern_crates.map(|dep| {
+        // format the dependencies that are going to be put inside the Cargo.toml
+        format!(
+            "{dep} = {{ path = \"{source_path}/lib{dep}\" }}\n",
+            dep = dep,
+            source_path = rustc_source_dir.display()
+        )
+    });
+
+    // format a new [dependencies]-block with the new deps we need to inject
+    let mut all_deps = String::from("[dependencies]\n");
+    new_deps.for_each(|dep_line| {
+        all_deps.push_str(&dep_line);
+    });
+
+    // replace "[dependencies]" with
+    // [dependencies]
+    // dep1 = { path = ... }
+    // dep2 = { path = ... }
+    // etc
+    let new_manifest = cargo_toml.replacen("[dependencies]\n", &all_deps, 1);
+
+    // println!("{}", new_manifest);
+    let mut file = File::create(manifest_path)?;
+    file.write_all(new_manifest.as_bytes())?;
+
+    println!("Dependency paths injected: {}", manifest_path);
+
+    Ok(())
+}
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 76baf27fb2d..e959c1a6511 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -17,11 +17,11 @@ keywords = ["clippy", "lint", "plugin"]
 edition = "2018"
 
 [dependencies]
-cargo_metadata = "0.9.0"
+cargo_metadata = "0.9.1"
 if_chain = "1.0.0"
 itertools = "0.9"
 lazy_static = "1.0.2"
-pulldown-cmark = { version = "0.7", default-features = false }
+pulldown-cmark = { version = "0.7.1", default-features = false }
 quine-mc_cluskey = "0.2.2"
 regex-syntax = "0.6"
 serde = { version = "1.0", features = ["derive"] }
diff --git a/src/tools/clippy/clippy_lints/src/assign_ops.rs b/src/tools/clippy/clippy_lints/src/assign_ops.rs
index 05e2650d0b7..13e61fe98ba 100644
--- a/src/tools/clippy/clippy_lints/src/assign_ops.rs
+++ b/src/tools/clippy/clippy_lints/src/assign_ops.rs
@@ -24,7 +24,11 @@ declare_clippy_lint! {
     /// let mut a = 5;
     /// let b = 0;
     /// // ...
+    /// // Bad
     /// a = a + b;
+    ///
+    /// // Good
+    /// a += b;
     /// ```
     pub ASSIGN_OP_PATTERN,
     style,
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_lock.rs b/src/tools/clippy/clippy_lints/src/await_holding_lock.rs
index 832910763e6..a88f922d8e0 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_lock.rs
@@ -54,18 +54,13 @@ declare_lint_pass!(AwaitHoldingLock => [AWAIT_HOLDING_LOCK]);
 impl LateLintPass<'_, '_> for AwaitHoldingLock {
     fn check_body(&mut self, cx: &LateContext<'_, '_>, body: &'_ Body<'_>) {
         use AsyncGeneratorKind::{Block, Closure, Fn};
-        match body.generator_kind {
-            Some(GeneratorKind::Async(Block))
-            | Some(GeneratorKind::Async(Closure))
-            | Some(GeneratorKind::Async(Fn)) => {
-                let body_id = BodyId {
-                    hir_id: body.value.hir_id,
-                };
-                let def_id = cx.tcx.hir().body_owner_def_id(body_id);
-                let tables = cx.tcx.typeck_tables_of(def_id);
-                check_interior_types(cx, &tables.generator_interior_types, body.value.span);
-            },
-            _ => {},
+        if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind {
+            let body_id = BodyId {
+                hir_id: body.value.hir_id,
+            };
+            let def_id = cx.tcx.hir().body_owner_def_id(body_id);
+            let tables = cx.tcx.typeck_tables_of(def_id);
+            check_interior_types(cx, &tables.generator_interior_types, body.value.span);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs
index 16b46423c8f..c40a387d297 100644
--- a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs
@@ -36,13 +36,9 @@ declare_clippy_lint! {
     "common metadata is defined in `Cargo.toml`"
 }
 
-fn warning(cx: &LateContext<'_, '_>, message: &str) {
-    span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message);
-}
-
 fn missing_warning(cx: &LateContext<'_, '_>, package: &cargo_metadata::Package, field: &str) {
     let message = format!("package `{}` is missing `{}` metadata", package.name, field);
-    warning(cx, &message);
+    span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message);
 }
 
 fn is_empty_str(value: &Option<String>) -> bool {
@@ -66,12 +62,7 @@ impl LateLintPass<'_, '_> for CargoCommonMetadata {
             return;
         }
 
-        let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().no_deps().exec() {
-            metadata
-        } else {
-            warning(cx, "could not read cargo metadata");
-            return;
-        };
+        let metadata = unwrap_cargo_metadata!(cx, CARGO_COMMON_METADATA, false);
 
         for package in metadata.packages {
             if is_empty_vec(&package.authors) {
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index d9776dd50a8..e845ef99c7c 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -58,24 +58,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for CheckedConversions {
             }
         };
 
-        if_chain! {
-            if let Some(cv) = result;
-            if let Some(to_type) = cv.to_type;
-
-            then {
+        if let Some(cv) = result {
+            if let Some(to_type) = cv.to_type {
                 let mut applicability = Applicability::MachineApplicable;
-                let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut
-                                applicability);
+                let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability);
                 span_lint_and_sugg(
                     cx,
                     CHECKED_CONVERSIONS,
                     item.span,
                     "Checked cast can be simplified.",
                     "try",
-                    format!("{}::try_from({}).is_ok()",
-                            to_type,
-                            snippet),
-                    applicability
+                    format!("{}::try_from({}).is_ok()", to_type, snippet),
+                    applicability,
                 );
             }
         }
@@ -184,7 +178,7 @@ fn check_upper_bound<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
     if_chain! {
          if let ExprKind::Binary(ref op, ref left, ref right) = &expr.kind;
          if let Some((candidate, check)) = normalize_le_ge(op, left, right);
-         if let Some((from, to)) = get_types_from_cast(check, MAX_VALUE, INTS);
+         if let Some((from, to)) = get_types_from_cast(check, INTS, "max_value", "MAX");
 
          then {
              Conversion::try_new(candidate, from, to)
@@ -224,7 +218,7 @@ fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> O
 
 /// Check for `expr >= (to_type::MIN as from_type)`
 fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
-    if let Some((from, to)) = get_types_from_cast(check, MIN_VALUE, SINTS) {
+    if let Some((from, to)) = get_types_from_cast(check, SINTS, "min_value", "MIN") {
         Conversion::try_new(candidate, from, to)
     } else {
         None
@@ -232,10 +226,16 @@ fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Op
 }
 
 /// Tries to extract the from- and to-type from a cast expression
-fn get_types_from_cast<'a>(expr: &'a Expr<'_>, func: &'a str, types: &'a [&str]) -> Option<(&'a str, &'a str)> {
-    // `to_type::maxmin_value() as from_type`
+fn get_types_from_cast<'a>(
+    expr: &'a Expr<'_>,
+    types: &'a [&str],
+    func: &'a str,
+    assoc_const: &'a str,
+) -> Option<(&'a str, &'a str)> {
+    // `to_type::max_value() as from_type`
+    // or `to_type::MAX as from_type`
     let call_from_cast: Option<(&Expr<'_>, &str)> = if_chain! {
-        // to_type::maxmin_value(), from_type
+        // to_type::max_value(), from_type
         if let ExprKind::Cast(ref limit, ref from_type) = &expr.kind;
         if let TyKind::Path(ref from_type_path) = &from_type.kind;
         if let Some(from_sym) = int_ty_to_sym(from_type_path);
@@ -247,17 +247,17 @@ fn get_types_from_cast<'a>(expr: &'a Expr<'_>, func: &'a str, types: &'a [&str])
         }
     };
 
-    // `from_type::from(to_type::maxmin_value())`
+    // `from_type::from(to_type::max_value())`
     let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
         if_chain! {
-            // `from_type::from, to_type::maxmin_value()`
+            // `from_type::from, to_type::max_value()`
             if let ExprKind::Call(ref from_func, ref args) = &expr.kind;
-            // `to_type::maxmin_value()`
+            // `to_type::max_value()`
             if args.len() == 1;
             if let limit = &args[0];
             // `from_type::from`
             if let ExprKind::Path(ref path) = &from_func.kind;
-            if let Some(from_sym) = get_implementing_type(path, INTS, FROM);
+            if let Some(from_sym) = get_implementing_type(path, INTS, "from");
 
             then {
                 Some((limit, from_sym))
@@ -268,22 +268,26 @@ fn get_types_from_cast<'a>(expr: &'a Expr<'_>, func: &'a str, types: &'a [&str])
     });
 
     if let Some((limit, from_type)) = limit_from {
-        if_chain! {
-            if let ExprKind::Call(ref fun_name, _) = &limit.kind;
-            // `to_type, maxmin_value`
-            if let ExprKind::Path(ref path) = &fun_name.kind;
-            // `to_type`
-            if let Some(to_type) = get_implementing_type(path, types, func);
-
-            then {
-                Some((from_type, to_type))
-            } else {
-                None
-            }
+        match limit.kind {
+            // `from_type::from(_)`
+            ExprKind::Call(path, _) => {
+                if let ExprKind::Path(ref path) = path.kind {
+                    // `to_type`
+                    if let Some(to_type) = get_implementing_type(path, types, func) {
+                        return Some((from_type, to_type));
+                    }
+                }
+            },
+            // `to_type::MAX`
+            ExprKind::Path(ref path) => {
+                if let Some(to_type) = get_implementing_type(path, types, assoc_const) {
+                    return Some((from_type, to_type));
+                }
+            },
+            _ => {},
         }
-    } else {
-        None
-    }
+    };
+    None
 }
 
 /// Gets the type which implements the called function
@@ -336,10 +340,6 @@ fn normalize_le_ge<'a>(op: &BinOp, left: &'a Expr<'a>, right: &'a Expr<'a>) -> O
 }
 
 // Constants
-const FROM: &str = "from";
-const MAX_VALUE: &str = "max_value";
-const MIN_VALUE: &str = "min_value";
-
 const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"];
 const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"];
 const INTS: &[&str] = &["u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize"];
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 66722786eab..b6d50bdfa14 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -1,9 +1,9 @@
-use crate::utils::{get_parent_expr, higher, if_sequence, same_tys, snippet, span_lint_and_note, span_lint_and_then};
+use crate::utils::{get_parent_expr, higher, if_sequence, snippet, span_lint_and_note, span_lint_and_then};
 use crate::utils::{SpanlessEq, SpanlessHash};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{Arm, Block, Expr, ExprKind, MatchSource, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{Ty, TyS};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::Symbol;
 use std::collections::hash_map::Entry;
@@ -242,15 +242,11 @@ fn lint_same_fns_in_if_cond(cx: &LateContext<'_, '_>, conds: &[&Expr<'_>]) {
 
 /// Implementation of `MATCH_SAME_ARMS`.
 fn lint_match_arms<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &Expr<'_>) {
-    fn same_bindings<'tcx>(
-        cx: &LateContext<'_, 'tcx>,
-        lhs: &FxHashMap<Symbol, Ty<'tcx>>,
-        rhs: &FxHashMap<Symbol, Ty<'tcx>>,
-    ) -> bool {
+    fn same_bindings<'tcx>(lhs: &FxHashMap<Symbol, Ty<'tcx>>, rhs: &FxHashMap<Symbol, Ty<'tcx>>) -> bool {
         lhs.len() == rhs.len()
             && lhs
                 .iter()
-                .all(|(name, l_ty)| rhs.get(name).map_or(false, |r_ty| same_tys(cx, l_ty, r_ty)))
+                .all(|(name, l_ty)| rhs.get(name).map_or(false, |r_ty| TyS::same_type(l_ty, r_ty)))
     }
 
     if let ExprKind::Match(_, ref arms, MatchSource::Normal) = expr.kind {
@@ -269,7 +265,7 @@ fn lint_match_arms<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &Expr<'_>) {
             (min_index..=max_index).all(|index| arms[index].guard.is_none()) &&
                 SpanlessEq::new(cx).eq_expr(&lhs.body, &rhs.body) &&
                 // all patterns should have the same bindings
-                same_bindings(cx, &bindings(cx, &lhs.pat), &bindings(cx, &rhs.pat))
+                same_bindings(&bindings(cx, &lhs.pat), &bindings(cx, &rhs.pat))
         };
 
         let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs
index 7f2ff8b9b26..05517f6f9f0 100644
--- a/src/tools/clippy/clippy_lints/src/double_parens.rs
+++ b/src/tools/clippy/clippy_lints/src/double_parens.rs
@@ -13,10 +13,24 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust
+    /// // Bad
+    /// fn simple_double_parens() -> i32 {
+    ///     ((0))
+    /// }
+    ///
+    /// // Good
+    /// fn simple_no_parens() -> i32 {
+    ///     0
+    /// }
+    ///
+    /// // or
+    ///
     /// # fn foo(bar: usize) {}
-    /// ((0));
+    /// // Bad
     /// foo((0));
-    /// ((1, 2));
+    ///
+    /// // Good
+    /// foo(0);
     /// ```
     pub DOUBLE_PARENS,
     complexity,
diff --git a/src/tools/clippy/clippy_lints/src/drop_bounds.rs b/src/tools/clippy/clippy_lints/src/drop_bounds.rs
index f4966808279..5a7f759486e 100644
--- a/src/tools/clippy/clippy_lints/src/drop_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_bounds.rs
@@ -27,6 +27,10 @@ declare_clippy_lint! {
     /// ```rust
     /// fn foo<T: Drop>() {}
     /// ```
+    /// Could be written as:
+    /// ```rust
+    /// fn foo<T>() {}
+    /// ```
     pub DROP_BOUNDS,
     correctness,
     "Bounds of the form `T: Drop` are useless"
diff --git a/src/tools/clippy/clippy_lints/src/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/duration_subsec.rs
index b35a8facf8b..afefa250638 100644
--- a/src/tools/clippy/clippy_lints/src/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/duration_subsec.rs
@@ -22,8 +22,14 @@ declare_clippy_lint! {
     /// ```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;
+    ///
+    /// // Good
+    /// let _micros = dur.subsec_micros();
+    /// let _millis = dur.subsec_millis();
     /// ```
     pub DURATION_SUBSEC,
     complexity,
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs
index a5871cf0cd4..cb0fd59a2d4 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs
@@ -25,31 +25,47 @@ declare_clippy_lint! {
     ///     BattenbergCake,
     /// }
     /// ```
+    /// Could be written as:
+    /// ```rust
+    /// enum Cake {
+    ///     BlackForest,
+    ///     Hummingbird,
+    ///     Battenberg,
+    /// }
+    /// ```
     pub ENUM_VARIANT_NAMES,
     style,
     "enums where all variants share a prefix/postfix"
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Detects enumeration variants that are prefixed or suffixed
-    /// by the same characters.
+    /// **What it does:** Detects public enumeration variants that are
+    /// prefixed or suffixed by the same characters.
     ///
-    /// **Why is this bad?** Enumeration variant names should specify their variant,
+    /// **Why is this bad?** Public enumeration variant names should specify their variant,
     /// not repeat the enumeration name.
     ///
     /// **Known problems:** None.
     ///
     /// **Example:**
     /// ```rust
-    /// enum Cake {
+    /// pub enum Cake {
     ///     BlackForestCake,
     ///     HummingbirdCake,
     ///     BattenbergCake,
     /// }
     /// ```
+    /// Could be written as:
+    /// ```rust
+    /// pub enum Cake {
+    ///     BlackForest,
+    ///     Hummingbird,
+    ///     Battenberg,
+    /// }
+    /// ```
     pub PUB_ENUM_VARIANT_NAMES,
     pedantic,
-    "enums where all variants share a prefix/postfix"
+    "public enums where all variants share a prefix/postfix"
 }
 
 declare_clippy_lint! {
@@ -66,6 +82,12 @@ declare_clippy_lint! {
     ///     struct BlackForestCake;
     /// }
     /// ```
+    /// Could be written as:
+    /// ```rust
+    /// mod cake {
+    ///     struct BlackForest;
+    /// }
+    /// ```
     pub MODULE_NAME_REPETITIONS,
     pedantic,
     "type names prefixed/postfixed with their containing module's name"
diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs
index 4e1c1f13140..d7819d737ea 100644
--- a/src/tools/clippy/clippy_lints/src/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/eq_op.rs
@@ -39,7 +39,11 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```ignore
+    /// // Bad
     /// &x == y
+    ///
+    /// // Good
+    /// x == *y
     /// ```
     pub OP_REF,
     style,
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 1ec60a0e6e6..7227683aa5a 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -28,9 +28,16 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// # fn foo(bar: usize) {}
+    ///
+    /// // Bad
     /// let x = Box::new(1);
     /// foo(*x);
     /// println!("{}", *x);
+    ///
+    /// // Good
+    /// let x = 1;
+    /// foo(x);
+    /// println!("{}", x);
     /// ```
     pub BOXED_LOCAL,
     perf,
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index e3e1136b676..d093025fd3d 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -26,7 +26,11 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust,ignore
+    /// // Bad
     /// xs.map(|x| foo(x))
+    ///
+    /// // Good
+    /// xs.map(foo)
     /// ```
     /// where `foo(_)` is a plain function that takes the exact argument type of
     /// `x`.
diff --git a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
index 5206266ccf2..74144fb299d 100644
--- a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
+++ b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
@@ -21,11 +21,20 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// let mut x = 0;
+    ///
+    /// // Bad
     /// let a = {
     ///     x = 1;
     ///     1
     /// } + x;
     /// // Unclear whether a is 1 or 2.
+    ///
+    /// // Good
+    /// let tmp = {
+    ///     x = 1;
+    ///     1
+    /// };
+    /// let a = tmp + x;
     /// ```
     pub EVAL_ORDER_DEPENDENCE,
     complexity,
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index 17639cc2a06..92812816461 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -20,12 +20,31 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// struct Foo(i32);
+    ///
+    /// // Bad
     /// impl From<String> for Foo {
     ///     fn from(s: String) -> Self {
     ///         Foo(s.parse().unwrap())
     ///     }
     /// }
     /// ```
+    ///
+    /// ```rust
+    /// // Good
+    /// struct Foo(i32);
+    ///
+    /// use std::convert::TryFrom;
+    /// impl TryFrom<String> for Foo {
+    ///     type Error = ();
+    ///     fn try_from(s: String) -> Result<Self, Self::Error> {
+    ///         if let Ok(parsed) = s.parse() {
+    ///             Ok(Foo(parsed))
+    ///         } else {
+    ///             Err(())
+    ///         }
+    ///     }
+    /// }
+    /// ```
     pub FALLIBLE_IMPL_FROM,
     nursery,
     "Warn on impls of `From<..>` that contain `panic!()` or `unwrap()`"
@@ -120,7 +139,7 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
                         move |diag| {
                             diag.help(
                                 "`From` is intended for infallible conversions only. \
-                                 Use `TryFrom` if there's a possibility for the conversion to fail.");
+                                Use `TryFrom` if there's a possibility for the conversion to fail.");
                             diag.span_note(fpu.result, "potential failure(s)");
                         });
                 }
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 86317fb8bd5..3a912d92837 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -28,7 +28,6 @@ declare_clippy_lint! {
     /// **Example:**
     ///
     /// ```rust
-    ///
     /// let a = 3f32;
     /// let _ = a.powf(1.0 / 3.0);
     /// let _ = (1.0 + a).ln();
@@ -38,7 +37,6 @@ declare_clippy_lint! {
     /// is better expressed as
     ///
     /// ```rust
-    ///
     /// let a = 3f32;
     /// let _ = a.cbrt();
     /// let _ = a.ln_1p();
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index 5b092526ce4..1530538aa7d 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -25,9 +25,13 @@ declare_clippy_lint! {
     ///
     /// **Examples:**
     /// ```rust
+    ///
+    /// // Bad
     /// # let foo = "foo";
-    /// format!("foo");
     /// format!("{}", foo);
+    ///
+    /// // Good
+    /// format!("foo");
     /// ```
     pub USELESS_FORMAT,
     complexity,
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index eb4b7a826f2..156246fb8bb 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -112,12 +112,8 @@ declare_lint_pass!(Formatting => [
 impl EarlyLintPass for Formatting {
     fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
         for w in block.stmts.windows(2) {
-            match (&w[0].kind, &w[1].kind) {
-                (&StmtKind::Expr(ref first), &StmtKind::Expr(ref second))
-                | (&StmtKind::Expr(ref first), &StmtKind::Semi(ref second)) => {
-                    check_missing_else(cx, first, second);
-                },
-                _ => (),
+            if let (StmtKind::Expr(first), StmtKind::Expr(second) | StmtKind::Semi(second)) = (&w[0].kind, &w[1].kind) {
+                check_missing_else(cx, first, second);
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/functions.rs b/src/tools/clippy/clippy_lints/src/functions.rs
index c24a24733d7..325b6cf32a3 100644
--- a/src/tools/clippy/clippy_lints/src/functions.rs
+++ b/src/tools/clippy/clippy_lints/src/functions.rs
@@ -49,11 +49,11 @@ declare_clippy_lint! {
     /// **Known problems:** None.
     ///
     /// **Example:**
-    /// ``` rust
+    /// ```rust
     /// fn im_too_long() {
-    /// println!("");
-    /// // ... 100 more LoC
-    /// println!("");
+    ///     println!("");
+    ///     // ... 100 more LoC
+    ///     println!("");
     /// }
     /// ```
     pub TOO_MANY_LINES,
@@ -79,10 +79,16 @@ declare_clippy_lint! {
     /// `some_argument.get_raw_ptr()`).
     ///
     /// **Example:**
-    /// ```rust
+    /// ```rust,ignore
+    /// // Bad
     /// pub fn foo(x: *const u8) {
     ///     println!("{}", unsafe { *x });
     /// }
+    ///
+    /// // Good
+    /// pub unsafe fn foo(x: *const u8) {
+    ///     println!("{}", unsafe { *x });
+    /// }
     /// ```
     pub NOT_UNSAFE_PTR_ARG_DEREF,
     correctness,
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index 155a93de4fa..fdaf37e5e08 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -25,13 +25,6 @@ declare_clippy_lint! {
     /// if i != 0 {
     ///     i -= 1;
     /// }
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// let end: u32 = 10;
-    /// let start: u32 = 5;
-    ///
-    /// let mut i: u32 = end - start;
     ///
     /// // Good
     /// i = i.saturating_sub(1);
diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
index d5dbd495680..e91fb0c2f27 100644
--- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs
+++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
@@ -10,7 +10,6 @@ use crate::utils::{snippet_opt, span_lint_and_sugg};
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block
     ///
-    ///
     /// **Why is this bad?** Readability -- better to use `> y` instead of `>= y + 1`.
     ///
     /// **Known problems:** None.
diff --git a/src/tools/clippy/clippy_lints/src/integer_division.rs b/src/tools/clippy/clippy_lints/src/integer_division.rs
index fe34d33fe65..d537ef3f323 100644
--- a/src/tools/clippy/clippy_lints/src/integer_division.rs
+++ b/src/tools/clippy/clippy_lints/src/integer_division.rs
@@ -15,10 +15,13 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust
-    /// fn main() {
-    ///     let x = 3 / 2;
-    ///     println!("{}", x);
-    /// }
+    /// // Bad
+    /// let x = 3 / 2;
+    /// println!("{}", x);
+    ///
+    /// // Good
+    /// let x = 3f32 / 2f32;
+    /// println!("{}", x);
     /// ```
     pub INTEGER_DIVISION,
     restriction,
diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
index e7062b7c16b..c8576bcfcb4 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
@@ -16,6 +16,7 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust
+    /// // Bad
     /// fn foo() {
     ///     println!("cake");
     /// }
@@ -28,6 +29,21 @@ declare_clippy_lint! {
     ///     foo(); // prints "foo"
     /// }
     /// ```
+    ///
+    /// ```rust
+    /// // Good
+    /// fn foo() {
+    ///     println!("cake");
+    /// }
+    ///
+    /// fn main() {
+    ///     fn foo() {
+    ///         println!("foo");
+    ///     }
+    ///     foo(); // prints "foo"
+    ///     foo(); // prints "foo"
+    /// }
+    /// ```
     pub ITEMS_AFTER_STATEMENTS,
     pedantic,
     "blocks where an item comes after a statement"
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 2ec0b5a8d6f..f5bfede75a7 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -1,4 +1,4 @@
-use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{get_item_name, higher, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty};
 use rustc_ast::ast::LitKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -259,6 +259,17 @@ fn check_len(
 
 /// Checks if this type has an `is_empty` method.
 fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
+    /// Special case ranges until `range_is_empty` is stabilized. See issue 3807.
+    fn should_skip_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
+        higher::range(cx, expr).map_or(false, |_| {
+            !cx.tcx
+                .features()
+                .declared_lib_features
+                .iter()
+                .any(|(name, _)| name.as_str() == "range_is_empty")
+        })
+    }
+
     /// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
     fn is_is_empty(cx: &LateContext<'_, '_>, item: &ty::AssocItem) -> bool {
         if let ty::AssocKind::Fn = item.kind {
@@ -284,6 +295,10 @@ fn has_is_empty(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
         })
     }
 
+    if should_skip_range(cx, expr) {
+        return false;
+    }
+
     let ty = &walk_ptrs_ty(cx.tables.expr_ty(expr));
     match ty.kind {
         ty::Dynamic(ref tt, ..) => {
diff --git a/src/tools/clippy/clippy_lints/src/let_and_return.rs b/src/tools/clippy/clippy_lints/src/let_and_return.rs
new file mode 100644
index 00000000000..6d3fb317bcf
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/let_and_return.rs
@@ -0,0 +1,141 @@
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::{Block, Expr, ExprKind, PatKind, StmtKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::hir::map::Map;
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+use crate::utils::{in_macro, match_qpath, snippet_opt, span_lint_and_then};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for `let`-bindings, which are subsequently
+    /// returned.
+    ///
+    /// **Why is this bad?** It is just extraneous code. Remove it to make your code
+    /// more rusty.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// fn foo() -> String {
+    ///     let x = String::new();
+    ///     x
+    /// }
+    /// ```
+    /// instead, use
+    /// ```
+    /// fn foo() -> String {
+    ///     String::new()
+    /// }
+    /// ```
+    pub LET_AND_RETURN,
+    style,
+    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
+}
+
+declare_lint_pass!(LetReturn => [LET_AND_RETURN]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetReturn {
+    fn check_block(&mut self, cx: &LateContext<'a, 'tcx>, block: &'tcx Block<'_>) {
+        // we need both a let-binding stmt and an expr
+        if_chain! {
+            if let Some(retexpr) = block.expr;
+            if let Some(stmt) = block.stmts.iter().last();
+            if let StmtKind::Local(local) = &stmt.kind;
+            if local.ty.is_none();
+            if local.attrs.is_empty();
+            if let Some(initexpr) = &local.init;
+            if let PatKind::Binding(.., ident, _) = local.pat.kind;
+            if let ExprKind::Path(qpath) = &retexpr.kind;
+            if match_qpath(qpath, &[&*ident.name.as_str()]);
+            if !last_statement_borrows(cx, initexpr);
+            if !in_external_macro(cx.sess(), initexpr.span);
+            if !in_external_macro(cx.sess(), retexpr.span);
+            if !in_external_macro(cx.sess(), local.span);
+            if !in_macro(local.span);
+            then {
+                span_lint_and_then(
+                    cx,
+                    LET_AND_RETURN,
+                    retexpr.span,
+                    "returning the result of a `let` binding from a block",
+                    |err| {
+                        err.span_label(local.span, "unnecessary `let` binding");
+
+                        if let Some(snippet) = snippet_opt(cx, initexpr.span) {
+                            err.multipart_suggestion(
+                                "return the expression directly",
+                                vec![
+                                    (local.span, String::new()),
+                                    (retexpr.span, snippet),
+                                ],
+                                Applicability::MachineApplicable,
+                            );
+                        } else {
+                            err.span_help(initexpr.span, "this expression can be directly returned");
+                        }
+                    },
+                );
+            }
+        }
+    }
+}
+
+fn last_statement_borrows<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    let mut visitor = BorrowVisitor { cx, borrows: false };
+    walk_expr(&mut visitor, expr);
+    visitor.borrows
+}
+
+struct BorrowVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'a, 'tcx>,
+    borrows: bool,
+}
+
+impl BorrowVisitor<'_, '_> {
+    fn fn_def_id(&self, expr: &Expr<'_>) -> Option<DefId> {
+        match &expr.kind {
+            ExprKind::MethodCall(..) => self.cx.tables.type_dependent_def_id(expr.hir_id),
+            ExprKind::Call(
+                Expr {
+                    kind: ExprKind::Path(qpath),
+                    ..
+                },
+                ..,
+            ) => self.cx.tables.qpath_res(qpath, expr.hir_id).opt_def_id(),
+            _ => None,
+        }
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
+        if self.borrows {
+            return;
+        }
+
+        if let Some(def_id) = self.fn_def_id(expr) {
+            self.borrows = self
+                .cx
+                .tcx
+                .fn_sig(def_id)
+                .output()
+                .skip_binder()
+                .walk()
+                .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
+        }
+
+        walk_expr(self, expr);
+    }
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index b7d928d249f..cd258c7b506 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -1,5 +1,6 @@
 // error-pattern:cargo-clippy
 
+#![feature(bindings_after_at)]
 #![feature(box_syntax)]
 #![feature(box_patterns)]
 #![feature(or_patterns)]
@@ -12,6 +13,7 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![feature(crate_visibility_modifier)]
 #![feature(concat_idents)]
+#![feature(drain_filter)]
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
@@ -239,6 +241,7 @@ mod large_const_arrays;
 mod large_enum_variant;
 mod large_stack_arrays;
 mod len_zero;
+mod let_and_return;
 mod let_if_seq;
 mod let_underscore;
 mod lifetimes;
@@ -318,6 +321,8 @@ mod try_err;
 mod types;
 mod unicode;
 mod unnamed_address;
+mod unnecessary_sort_by;
+mod unnested_or_patterns;
 mod unsafe_removed_from_name;
 mod unused_io_amount;
 mod unused_self;
@@ -325,6 +330,7 @@ mod unwrap;
 mod use_self;
 mod useless_conversion;
 mod vec;
+mod vec_resize_to_zero;
 mod verbose_file_reads;
 mod wildcard_dependencies;
 mod wildcard_imports;
@@ -594,6 +600,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &large_stack_arrays::LARGE_STACK_ARRAYS,
         &len_zero::LEN_WITHOUT_IS_EMPTY,
         &len_zero::LEN_ZERO,
+        &let_and_return::LET_AND_RETURN,
         &let_if_seq::USELESS_LET_IF_SEQ,
         &let_underscore::LET_UNDERSCORE_LOCK,
         &let_underscore::LET_UNDERSCORE_MUST_USE,
@@ -664,6 +671,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &methods::INTO_ITER_ON_REF,
         &methods::ITERATOR_STEP_BY_ZERO,
         &methods::ITER_CLONED_COLLECT,
+        &methods::ITER_NEXT_SLICE,
         &methods::ITER_NTH,
         &methods::ITER_NTH_ZERO,
         &methods::ITER_SKIP_NEXT,
@@ -769,7 +777,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &regex::INVALID_REGEX,
         &regex::REGEX_MACRO,
         &regex::TRIVIAL_REGEX,
-        &returns::LET_AND_RETURN,
         &returns::NEEDLESS_RETURN,
         &returns::UNUSED_UNIT,
         &serde_api::SERDE_API_MISUSE,
@@ -832,6 +839,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &unicode::ZERO_WIDTH_SPACE,
         &unnamed_address::FN_ADDRESS_COMPARISONS,
         &unnamed_address::VTABLE_ADDRESS_COMPARISONS,
+        &unnecessary_sort_by::UNNECESSARY_SORT_BY,
+        &unnested_or_patterns::UNNESTED_OR_PATTERNS,
         &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
         &unused_io_amount::UNUSED_IO_AMOUNT,
         &unused_self::UNUSED_SELF,
@@ -847,6 +856,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &utils::internal_lints::OUTER_EXPN_EXPN_DATA,
         &utils::internal_lints::PRODUCE_ICE,
         &vec::USELESS_VEC,
+        &vec_resize_to_zero::VEC_RESIZE_TO_ZERO,
         &verbose_file_reads::VERBOSE_FILE_READS,
         &wildcard_dependencies::WILDCARD_DEPENDENCIES,
         &wildcard_imports::ENUM_GLOB_USE,
@@ -994,6 +1004,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
     store.register_late_pass(|| box redundant_clone::RedundantClone);
     store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
+    store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
     store.register_late_pass(|| box types::RefToMut);
     store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
     store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn);
@@ -1016,6 +1027,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| box formatting::Formatting);
     store.register_early_pass(|| box misc_early::MiscEarlyLints);
     store.register_early_pass(|| box returns::Return);
+    store.register_late_pass(|| box let_and_return::LetReturn);
     store.register_early_pass(|| box collapsible_if::CollapsibleIf);
     store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
     store.register_early_pass(|| box precedence::Precedence);
@@ -1062,10 +1074,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive);
     store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
     store.register_early_pass(|| box redundant_field_names::RedundantFieldNames);
+    store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
     let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
     store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
         single_char_binding_names_threshold,
     });
+    store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns);
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1164,6 +1178,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::CAST_POSSIBLE_TRUNCATION),
         LintId::of(&types::CAST_POSSIBLE_WRAP),
         LintId::of(&types::CAST_PRECISION_LOSS),
+        LintId::of(&types::CAST_PTR_ALIGNMENT),
         LintId::of(&types::CAST_SIGN_LOSS),
         LintId::of(&types::IMPLICIT_HASHER),
         LintId::of(&types::INVALID_UPCAST_COMPARISONS),
@@ -1257,6 +1272,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT),
         LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
         LintId::of(&len_zero::LEN_ZERO),
+        LintId::of(&let_and_return::LET_AND_RETURN),
         LintId::of(&let_underscore::LET_UNDERSCORE_LOCK),
         LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES),
         LintId::of(&lifetimes::NEEDLESS_LIFETIMES),
@@ -1303,6 +1319,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::INTO_ITER_ON_REF),
         LintId::of(&methods::ITERATOR_STEP_BY_ZERO),
         LintId::of(&methods::ITER_CLONED_COLLECT),
+        LintId::of(&methods::ITER_NEXT_SLICE),
         LintId::of(&methods::ITER_NTH),
         LintId::of(&methods::ITER_NTH_ZERO),
         LintId::of(&methods::ITER_SKIP_NEXT),
@@ -1381,7 +1398,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&regex::INVALID_REGEX),
         LintId::of(&regex::REGEX_MACRO),
         LintId::of(&regex::TRIVIAL_REGEX),
-        LintId::of(&returns::LET_AND_RETURN),
         LintId::of(&returns::NEEDLESS_RETURN),
         LintId::of(&returns::UNUSED_UNIT),
         LintId::of(&serde_api::SERDE_API_MISUSE),
@@ -1410,7 +1426,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
         LintId::of(&types::BORROWED_BOX),
         LintId::of(&types::BOX_VEC),
-        LintId::of(&types::CAST_PTR_ALIGNMENT),
         LintId::of(&types::CAST_REF_TO_MUT),
         LintId::of(&types::CHAR_LIT_AS_U8),
         LintId::of(&types::FN_TO_NUMERIC_CAST),
@@ -1424,12 +1439,15 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&unicode::ZERO_WIDTH_SPACE),
         LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
         LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
+        LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
+        LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
         LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
         LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
         LintId::of(&unwrap::PANICKING_UNWRAP),
         LintId::of(&unwrap::UNNECESSARY_UNWRAP),
         LintId::of(&useless_conversion::USELESS_CONVERSION),
         LintId::of(&vec::USELESS_VEC),
+        LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
         LintId::of(&write::PRINTLN_EMPTY_STRING),
         LintId::of(&write::PRINT_LITERAL),
         LintId::of(&write::PRINT_WITH_NEWLINE),
@@ -1464,6 +1482,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&inherent_to_string::INHERENT_TO_STRING),
         LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY),
         LintId::of(&len_zero::LEN_ZERO),
+        LintId::of(&let_and_return::LET_AND_RETURN),
         LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING),
         LintId::of(&loops::EMPTY_LOOP),
         LintId::of(&loops::FOR_KV_MAP),
@@ -1483,6 +1502,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&methods::CHARS_NEXT_CMP),
         LintId::of(&methods::INTO_ITER_ON_REF),
         LintId::of(&methods::ITER_CLONED_COLLECT),
+        LintId::of(&methods::ITER_NEXT_SLICE),
         LintId::of(&methods::ITER_NTH_ZERO),
         LintId::of(&methods::ITER_SKIP_NEXT),
         LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC),
@@ -1515,7 +1535,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
         LintId::of(&regex::REGEX_MACRO),
         LintId::of(&regex::TRIVIAL_REGEX),
-        LintId::of(&returns::LET_AND_RETURN),
         LintId::of(&returns::NEEDLESS_RETURN),
         LintId::of(&returns::UNUSED_UNIT),
         LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
@@ -1604,6 +1623,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::UNIT_ARG),
         LintId::of(&types::UNNECESSARY_CAST),
         LintId::of(&types::VEC_BOX),
+        LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
+        LintId::of(&unnested_or_patterns::UNNESTED_OR_PATTERNS),
         LintId::of(&unwrap::UNNECESSARY_UNWRAP),
         LintId::of(&useless_conversion::USELESS_CONVERSION),
         LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO),
@@ -1669,7 +1690,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&transmute::WRONG_TRANSMUTE),
         LintId::of(&transmuting_null::TRANSMUTING_NULL),
         LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
-        LintId::of(&types::CAST_PTR_ALIGNMENT),
         LintId::of(&types::CAST_REF_TO_MUT),
         LintId::of(&types::UNIT_CMP),
         LintId::of(&unicode::ZERO_WIDTH_SPACE),
@@ -1677,6 +1697,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
         LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
         LintId::of(&unwrap::PANICKING_UNWRAP),
+        LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO),
     ]);
 
     store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index ec7c4531ed7..7ba43562d7d 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -24,7 +24,11 @@ declare_clippy_lint! {
     /// **Example:**
     ///
     /// ```rust
+    /// // Bad
     /// let x: u64 = 61864918973511;
+    ///
+    /// // Good
+    /// let x: u64 = 61_864_918_973_511;
     /// ```
     pub UNREADABLE_LITERAL,
     pedantic,
@@ -44,7 +48,11 @@ declare_clippy_lint! {
     /// **Example:**
     ///
     /// ```rust
+    /// // Probably mistyped
     /// 2_32;
+    ///
+    /// // Good
+    /// 2_i32;
     /// ```
     pub MISTYPED_LITERAL_SUFFIXES,
     correctness,
@@ -63,7 +71,11 @@ declare_clippy_lint! {
     /// **Example:**
     ///
     /// ```rust
+    /// // Bad
     /// let x: u64 = 618_64_9189_73_511;
+    ///
+    /// // Good
+    /// let x: u64 = 61_864_918_973_511;
     /// ```
     pub INCONSISTENT_DIGIT_GROUPING,
     style,
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index 38a5829b3f7..57c62d73964 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -8,7 +8,7 @@ use crate::utils::{
     multispan_sugg, snippet, snippet_opt, snippet_with_applicability, span_lint, span_lint_and_help,
     span_lint_and_sugg, span_lint_and_then, SpanlessEq,
 };
-use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sugg};
+use crate::utils::{is_type_diagnostic_item, qpath_res, sugg};
 use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -24,10 +24,10 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::middle::region;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TyS};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use rustc_span::BytePos;
+use rustc_span::symbol::Symbol;
 use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase};
 use std::iter::{once, Iterator};
 use std::mem;
@@ -1256,7 +1256,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>, e
             } else if method_name == "into_iter" && match_trait_method(cx, arg, &paths::INTO_ITERATOR) {
                 let receiver_ty = cx.tables.expr_ty(&args[0]);
                 let receiver_ty_adjusted = cx.tables.expr_ty_adjusted(&args[0]);
-                if same_tys(cx, receiver_ty, receiver_ty_adjusted) {
+                if TyS::same_type(receiver_ty, receiver_ty_adjusted) {
                     let mut applicability = Applicability::MachineApplicable;
                     let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);
                     span_lint_and_sugg(
@@ -1277,7 +1277,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>, e
                             mutbl: Mutability::Not,
                         },
                     );
-                    if same_tys(cx, receiver_ty_adjusted, ref_receiver_ty) {
+                    if TyS::same_type(receiver_ty_adjusted, ref_receiver_ty) {
                         lint_iter_method(cx, args, arg, method_name)
                     }
                 }
@@ -2381,32 +2381,32 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, '
                 match_type(cx, ty, &paths::BTREEMAP) ||
                 is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) {
                 if method.ident.name == sym!(len) {
-                    let span = shorten_needless_collect_span(expr);
+                    let span = shorten_span(expr, sym!(collect));
                     span_lint_and_sugg(
                         cx,
                         NEEDLESS_COLLECT,
                         span,
                         NEEDLESS_COLLECT_MSG,
                         "replace with",
-                        ".count()".to_string(),
+                        "count()".to_string(),
                         Applicability::MachineApplicable,
                     );
                 }
                 if method.ident.name == sym!(is_empty) {
-                    let span = shorten_needless_collect_span(expr);
+                    let span = shorten_span(expr, sym!(iter));
                     span_lint_and_sugg(
                         cx,
                         NEEDLESS_COLLECT,
                         span,
                         NEEDLESS_COLLECT_MSG,
                         "replace with",
-                        ".next().is_none()".to_string(),
+                        "get(0).is_none()".to_string(),
                         Applicability::MachineApplicable,
                     );
                 }
                 if method.ident.name == sym!(contains) {
                     let contains_arg = snippet(cx, args[1].span, "??");
-                    let span = shorten_needless_collect_span(expr);
+                    let span = shorten_span(expr, sym!(collect));
                     span_lint_and_then(
                         cx,
                         NEEDLESS_COLLECT,
@@ -2422,7 +2422,7 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, '
                                 span,
                                 "replace with",
                                 format!(
-                                    ".any(|{}| x == {})",
+                                    "any(|{}| x == {})",
                                     arg, pred
                                 ),
                                 Applicability::MachineApplicable,
@@ -2435,13 +2435,13 @@ fn check_needless_collect<'a, 'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'a, '
     }
 }
 
-fn shorten_needless_collect_span(expr: &Expr<'_>) -> Span {
-    if_chain! {
-        if let ExprKind::MethodCall(_, _, ref args) = expr.kind;
-        if let ExprKind::MethodCall(_, ref span, _) = args[0].kind;
-        then {
-            return expr.span.with_lo(span.lo() - BytePos(1));
+fn shorten_span(expr: &Expr<'_>, target_fn_name: Symbol) -> Span {
+    let mut current_expr = expr;
+    while let ExprKind::MethodCall(ref path, ref span, ref args) = current_expr.kind {
+        if path.ident.name == target_fn_name {
+            return expr.span.with_lo(span.lo());
         }
+        current_expr = &args[0];
     }
     unreachable!()
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
index 94380acfcfd..6d7af45a472 100644
--- a/src/tools/clippy/clippy_lints/src/matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches.rs
@@ -36,10 +36,17 @@ declare_clippy_lint! {
     /// ```rust
     /// # fn bar(stool: &str) {}
     /// # let x = Some("abc");
+    ///
+    /// // Bad
     /// match x {
     ///     Some(ref foo) => bar(foo),
     ///     _ => (),
     /// }
+    ///
+    /// // Good
+    /// if let Some(ref foo) = x {
+    ///     bar(foo);
+    /// }
     /// ```
     pub SINGLE_MATCH,
     style,
@@ -97,11 +104,19 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust,ignore
+    /// // Bad
     /// match x {
     ///     &A(ref y) => foo(y),
     ///     &B => bar(),
     ///     _ => frob(&x),
     /// }
+    ///
+    /// // Good
+    /// match *x {
+    ///     A(ref y) => foo(y),
+    ///     B => bar(),
+    ///     _ => frob(x),
+    /// }
     /// ```
     pub MATCH_REF_PATS,
     style,
@@ -197,10 +212,15 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// let x: Option<()> = None;
+    ///
+    /// // Bad
     /// let r: Option<&()> = match x {
     ///     None => None,
     ///     Some(ref v) => Some(v),
     /// };
+    ///
+    /// // Good
+    /// let r: Option<&()> = x.as_ref();
     /// ```
     pub MATCH_AS_REF,
     complexity,
@@ -219,10 +239,18 @@ declare_clippy_lint! {
     /// ```rust
     /// # enum Foo { A(usize), B(usize) }
     /// # let x = Foo::B(1);
+    ///
+    /// // Bad
     /// match x {
     ///     Foo::A(_) => {},
     ///     _ => {},
     /// }
+    ///
+    /// // Good
+    /// match x {
+    ///     Foo::A(_) => {},
+    ///     Foo::B(_) => {},
+    /// }
     /// ```
     pub WILDCARD_ENUM_MATCH_ARM,
     restriction,
@@ -242,16 +270,14 @@ declare_clippy_lint! {
     /// ```rust
     /// # enum Foo { A, B, C }
     /// # let x = Foo::B;
+    /// // Bad
     /// match x {
     ///     Foo::A => {},
     ///     Foo::B => {},
     ///     _ => {},
     /// }
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// # enum Foo { A, B, C }
-    /// # let x = Foo::B;
+    ///
+    /// // Good
     /// match x {
     ///     Foo::A => {},
     ///     Foo::B => {},
@@ -273,10 +299,17 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust
+    /// // Bad
     /// match "foo" {
     ///     "a" => {},
     ///     "bar" | _ => {},
     /// }
+    ///
+    /// // Good
+    /// match "foo" {
+    ///     "a" => {},
+    ///     _ => {},
+    /// }
     /// ```
     pub WILDCARD_IN_OR_PATTERNS,
     complexity,
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
index aaed6d75048..4f5c06e785c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -57,7 +57,7 @@ pub fn lint(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, args: &[&[hir::Expr<
         );
     } else {
         match (mm, arith) {
-            (MinMax::Max, "add") | (MinMax::Max, "mul") | (MinMax::Min, "sub") => (),
+            (MinMax::Max, "add" | "mul") | (MinMax::Min, "sub") => (),
             _ => return,
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 52ca962e7ef..214cf0c130f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -18,7 +18,7 @@ use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TyS};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{sym, SymbolStr};
@@ -26,12 +26,12 @@ use rustc_span::symbol::{sym, SymbolStr};
 use crate::consts::{constant, Constant};
 use crate::utils::usage::mutated_variables;
 use crate::utils::{
-    get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, implements_trait, in_macro, is_copy,
+    get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro, is_copy,
     is_ctor_or_promotable_const_function, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment,
     match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths,
-    remove_blocks, return_ty, same_tys, single_segment_path, snippet, snippet_with_applicability,
-    snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
-    span_lint_and_then, sugg, walk_ptrs_ty, walk_ptrs_ty_depth, SpanlessEq,
+    remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite,
+    span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty,
+    walk_ptrs_ty_depth, SpanlessEq,
 };
 
 declare_clippy_lint! {
@@ -218,7 +218,12 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// # let x = Ok::<_, ()>(());
-    /// x.ok().expect("why did I do this again?")
+    ///
+    /// // Bad
+    /// x.ok().expect("why did I do this again?");
+    ///
+    /// // Good
+    /// x.expect("why did I do this again?");
     /// ```
     pub OK_EXPECT,
     style,
@@ -273,8 +278,12 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// # let opt = Some(1);
-    /// opt.map_or(None, |a| Some(a + 1))
-    /// # ;
+    ///
+    /// // Bad
+    /// opt.map_or(None, |a| Some(a + 1));
+    ///
+    /// // Good
+    /// opt.and_then(|a| Some(a + 1));
     /// ```
     pub OPTION_MAP_OR_NONE,
     style,
@@ -390,14 +399,19 @@ declare_clippy_lint! {
     /// **What it does:** Checks for usage of `_.map(_).flatten(_)`,
     ///
     /// **Why is this bad?** Readability, this can be written more concisely as a
-    /// single method call.
+    /// single method call using `_.flat_map(_)`
     ///
     /// **Known problems:**
     ///
     /// **Example:**
     /// ```rust
     /// let vec = vec![vec![1]];
+    ///
+    /// // Bad
     /// vec.iter().map(|x| x.iter()).flatten();
+    ///
+    /// // Good
+    /// vec.iter().flat_map(|x| x.iter());
     /// ```
     pub MAP_FLATTEN,
     pedantic,
@@ -417,7 +431,16 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// let vec = vec![1];
+    ///
+    /// // Bad
     /// vec.iter().filter(|x| **x == 0).map(|x| *x * 2);
+    ///
+    /// // Good
+    /// vec.iter().filter_map(|x| if *x == 0 {
+    ///     Some(*x * 2)
+    /// } else {
+    ///     None
+    /// });
     /// ```
     pub FILTER_MAP,
     pedantic,
@@ -634,7 +657,12 @@ declare_clippy_lint! {
     /// ```rust
     /// # use std::rc::Rc;
     /// let x = Rc::new(1);
+    ///
+    /// // Bad
     /// x.clone();
+    ///
+    /// // Good
+    /// Rc::clone(&x);
     /// ```
     pub CLONE_ON_REF_PTR,
     restriction,
@@ -741,7 +769,12 @@ declare_clippy_lint! {
     /// **Known problems:** Does not catch multi-byte unicode characters.
     ///
     /// **Example:**
-    /// `_.split("x")` could be `_.split('x')`
+    /// ```rust,ignore
+    /// // Bad
+    /// _.split("x");
+    ///
+    /// // Good
+    /// _.split('x');
     pub SINGLE_CHAR_PATTERN,
     perf,
     "using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
@@ -964,8 +997,8 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for usage of `.chars().last()` or
-    /// `.chars().next_back()` on a `str` to check if it ends with a given char.
+    /// **What it does:** Checks for usage of `_.chars().last()` or
+    /// `_.chars().next_back()` on a `str` to check if it ends with a given char.
     ///
     /// **Why is this bad?** Readability, this can be written more concisely as
     /// `_.ends_with(_)`.
@@ -975,8 +1008,12 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// # let name = "_";
-    /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-')
-    /// # ;
+    ///
+    /// // Bad
+    /// name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
+    ///
+    /// // Good
+    /// name.ends_with('_') || name.ends_with('-');
     /// ```
     pub CHARS_LAST_CMP,
     style,
@@ -1044,17 +1081,15 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
-    /// ```
-    /// As there is no transformation of the argument this could be written as:
-    /// ```rust
+    ///
+    /// // As there is no transformation of the argument this could be written as:
     /// let _ = (0..3).filter(|&x| x > 2);
     /// ```
     ///
     /// ```rust
     /// let _ = (0..4).filter_map(|x| Some(x + 1));
-    /// ```
-    /// As there is no conditional check on the argument this could be written as:
-    /// ```rust
+    ///
+    /// // As there is no conditional check on the argument this could be written as:
     /// let _ = (0..4).map(|x| x + 1);
     /// ```
     pub UNNECESSARY_FILTER_MAP,
@@ -1075,7 +1110,11 @@ declare_clippy_lint! {
     /// **Example:**
     ///
     /// ```rust
+    /// // Bad
     /// let _ = (&vec![3, 4, 5]).into_iter();
+    ///
+    /// // Good
+    /// let _ = (&vec![3, 4, 5]).iter();
     /// ```
     pub INTO_ITER_ON_REF,
     style,
@@ -1242,6 +1281,32 @@ declare_clippy_lint! {
     "using `as_ref().map(Deref::deref)`, which is more succinctly expressed as `as_deref()`"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of `iter().next()` on a Slice or an Array
+    ///
+    /// **Why is this bad?** These can be shortened into `.get()`
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// # let a = [1, 2, 3];
+    /// # let b = vec![1, 2, 3];
+    /// a[2..].iter().next();
+    /// b.iter().next();
+    /// ```
+    /// should be written as:
+    /// ```rust
+    /// # let a = [1, 2, 3];
+    /// # let b = vec![1, 2, 3];
+    /// a.get(2);
+    /// b.get(0);
+    /// ```
+    pub ITER_NEXT_SLICE,
+    style,
+    "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`"
+}
+
 declare_lint_pass!(Methods => [
     UNWRAP_USED,
     EXPECT_USED,
@@ -1273,6 +1338,7 @@ declare_lint_pass!(Methods => [
     FIND_MAP,
     MAP_FLATTEN,
     ITERATOR_STEP_BY_ZERO,
+    ITER_NEXT_SLICE,
     ITER_NTH,
     ITER_NTH_ZERO,
     ITER_SKIP_NEXT,
@@ -1320,6 +1386,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
             },
             ["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]),
             ["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]),
+            ["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]),
             ["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]),
             ["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]),
             ["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1]),
@@ -1336,9 +1403,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
                 lint_search_is_some(cx, expr, "rposition", arg_lists[1], arg_lists[0], method_spans[1])
             },
             ["extend", ..] => lint_extend(cx, expr, arg_lists[0]),
-            ["as_ptr", "unwrap"] | ["as_ptr", "expect"] => {
-                lint_cstring_as_ptr(cx, expr, &arg_lists[1][0], &arg_lists[0][0])
-            },
+            ["as_ptr", "unwrap" | "expect"] => lint_cstring_as_ptr(cx, expr, &arg_lists[1][0], &arg_lists[0][0]),
             ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false),
             ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true),
             ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]),
@@ -1351,12 +1416,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
             ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]),
             ["count", "map"] => lint_suspicious_map(cx, expr),
             ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr),
-            ["unwrap_or", arith @ "checked_add"]
-            | ["unwrap_or", arith @ "checked_sub"]
-            | ["unwrap_or", arith @ "checked_mul"] => {
+            ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => {
                 manual_saturating_arithmetic::lint(cx, expr, &arg_lists, &arith["checked_".len()..])
             },
-            ["add"] | ["offset"] | ["sub"] | ["wrapping_offset"] | ["wrapping_add"] | ["wrapping_sub"] => {
+            ["add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub"] => {
                 check_pointer_offset(cx, expr, arg_lists[0])
             },
             ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]),
@@ -1481,7 +1544,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
 
             let contains_self_ty = |ty: Ty<'tcx>| {
                 ty.walk().any(|inner| match inner.unpack() {
-                    GenericArgKind::Type(inner_ty) => same_tys(cx, self_ty, inner_ty),
+                    GenericArgKind::Type(inner_ty) => TyS::same_type(self_ty, inner_ty),
 
                     GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
                 })
@@ -1508,7 +1571,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Methods {
                 }
             }
 
-            if name == "new" && !same_tys(cx, ret_ty, self_ty) {
+            if name == "new" && !TyS::same_type(ret_ty, self_ty) {
                 span_lint(
                     cx,
                     NEW_RET_NO_SELF,
@@ -1762,8 +1825,7 @@ fn lint_expect_fun_call(
             hir::ExprKind::Call(fun, _) => {
                 if let hir::ExprKind::Path(ref p) = fun.kind {
                     match cx.tables.qpath_res(p, fun.hir_id) {
-                        hir::def::Res::Def(hir::def::DefKind::Fn, def_id)
-                        | hir::def::Res::Def(hir::def::DefKind::AssocFn, def_id) => matches!(
+                        hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
                             cx.tcx.fn_sig(def_id).output().skip_binder().kind,
                             ty::Ref(ty::ReStatic, ..)
                         ),
@@ -2199,6 +2261,60 @@ fn lint_step_by<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr<'_>, args
     }
 }
 
+fn lint_iter_next<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
+    let caller_expr = &iter_args[0];
+
+    // Skip lint if the `iter().next()` expression is a for loop argument,
+    // since it is already covered by `&loops::ITER_NEXT_LOOP`
+    let mut parent_expr_opt = get_parent_expr(cx, expr);
+    while let Some(parent_expr) = parent_expr_opt {
+        if higher::for_loop(parent_expr).is_some() {
+            return;
+        }
+        parent_expr_opt = get_parent_expr(cx, parent_expr);
+    }
+
+    if derefs_to_slice(cx, caller_expr, cx.tables.expr_ty(caller_expr)).is_some() {
+        // caller is a Slice
+        if_chain! {
+            if let hir::ExprKind::Index(ref caller_var, ref index_expr) = &caller_expr.kind;
+            if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen })
+                = higher::range(cx, index_expr);
+            if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind;
+            if let ast::LitKind::Int(start_idx, _) = start_lit.node;
+            then {
+                let mut applicability = Applicability::MachineApplicable;
+                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),
+                    applicability,
+                );
+            }
+        }
+    } else if is_type_diagnostic_item(cx, cx.tables.expr_ty(caller_expr), sym!(vec_type))
+        || matches!(&walk_ptrs_ty(cx.tables.expr_ty(caller_expr)).kind, ty::Array(_, _))
+    {
+        // caller is a Vec or an Array
+        let mut applicability = Applicability::MachineApplicable;
+        span_lint_and_sugg(
+            cx,
+            ITER_NEXT_SLICE,
+            expr.span,
+            "Using `.iter().next()` on an array",
+            "try calling",
+            format!(
+                "{}.get(0)",
+                snippet_with_applicability(cx, caller_expr.span, "..", &mut applicability)
+            ),
+            applicability,
+        );
+    }
+}
+
 fn lint_iter_nth<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
     expr: &hir::Expr<'_>,
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index e1d524c2231..f513161bbbc 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -38,10 +38,16 @@ declare_clippy_lint! {
     /// dereferences, e.g., changing `*x` to `x` within the function.
     ///
     /// **Example:**
-    /// ```rust
+    /// ```rust,ignore
+    /// // Bad
     /// fn foo(ref x: u8) -> bool {
     ///     true
     /// }
+    ///
+    /// // Good
+    /// fn foo(x: &u8) -> bool {
+    ///     true
+    /// }
     /// ```
     pub TOPLEVEL_REF_ARG,
     style,
@@ -60,7 +66,11 @@ declare_clippy_lint! {
     /// ```rust
     /// # let x = 1.0;
     ///
+    /// // Bad
     /// if x == f32::NAN { }
+    ///
+    /// // Good
+    /// if x.is_nan() { }
     /// ```
     pub CMP_NAN,
     correctness,
@@ -83,8 +93,15 @@ declare_clippy_lint! {
     /// ```rust
     /// let x = 1.2331f64;
     /// let y = 1.2332f64;
+    ///
+    /// // Bad
     /// if y == 1.23f64 { }
     /// if y != x {} // where both are floats
+    ///
+    /// // Good
+    /// let error = 0.01f64; // Use an epsilon for comparison
+    /// if (y - 1.23f64).abs() < error { }
+    /// if (y - x).abs() > error { }
     /// ```
     pub FLOAT_CMP,
     correctness,
@@ -191,7 +208,11 @@ declare_clippy_lint! {
     /// **Example:**
     ///
     /// ```rust
+    /// // Bad
     /// let a = 0 as *const u32;
+    ///
+    /// // Good
+    /// let a = std::ptr::null::<u32>();
     /// ```
     pub ZERO_PTR,
     style,
@@ -214,7 +235,13 @@ declare_clippy_lint! {
     /// ```rust
     /// let x: f64 = 1.0;
     /// const ONE: f64 = 1.00;
-    /// x == ONE;  // where both are floats
+    ///
+    /// // Bad
+    /// if x == ONE { }  // where both are floats
+    ///
+    /// // Good
+    /// let error = 0.1f64; // Use an epsilon for comparison
+    /// if (x - ONE).abs() < error { }
     /// ```
     pub FLOAT_CMP_CONST,
     restriction,
@@ -248,17 +275,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MiscLints {
             return;
         }
         for arg in iter_input_pats(decl, body) {
-            match arg.pat.kind {
-                PatKind::Binding(BindingAnnotation::Ref, ..) | PatKind::Binding(BindingAnnotation::RefMut, ..) => {
-                    span_lint(
-                        cx,
-                        TOPLEVEL_REF_ARG,
-                        arg.pat.span,
-                        "`ref` directly on a function argument is ignored. Consider using a reference type \
-                         instead.",
-                    );
-                },
-                _ => {},
+            if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind {
+                span_lint(
+                    cx,
+                    TOPLEVEL_REF_ARG,
+                    arg.pat.span,
+                    "`ref` directly on a function argument is ignored. \
+                    Consider using a reference type instead.",
+                );
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/misc_early.rs b/src/tools/clippy/clippy_lints/src/misc_early.rs
index 552222eba2e..ad39e59d067 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early.rs
@@ -59,7 +59,11 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust
+    /// // Bad
     /// fn foo(a: i32, _a: i32) {}
+    ///
+    /// // Good
+    /// fn bar(a: i32, _b: i32) {}
     /// ```
     pub DUPLICATE_UNDERSCORE_ARGUMENT,
     style,
@@ -77,7 +81,11 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust,ignore
-    /// (|| 42)()
+    /// // Bad
+    /// let a = (|| 42)()
+    ///
+    /// // Good
+    /// let a = 42
     /// ```
     pub REDUNDANT_CLOSURE_CALL,
     complexity,
@@ -112,7 +120,11 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust
+    /// // Bad
     /// let y = 0x1a9BAcD;
+    ///
+    /// // Good
+    /// let y = 0x1A9BACD;
     /// ```
     pub MIXED_CASE_HEX_LITERALS,
     style,
@@ -129,7 +141,11 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust
+    /// // Bad
     /// let y = 123832i32;
+    ///
+    /// // Good
+    /// let y = 123832_i32;
     /// ```
     pub UNSEPARATED_LITERAL_SUFFIX,
     pedantic,
@@ -207,9 +223,16 @@ declare_clippy_lint! {
     /// ```rust
     /// # let v = Some("abc");
     ///
+    /// // Bad
+    /// match v {
+    ///     Some(x) => (),
+    ///     y @ _ => (),
+    /// }
+    ///
+    /// // Good
     /// match v {
     ///     Some(x) => (),
-    ///     y @ _ => (), // easier written as `y`,
+    ///     y => (),
     /// }
     /// ```
     pub REDUNDANT_PATTERN,
@@ -235,16 +258,13 @@ declare_clippy_lint! {
     /// # struct TupleStruct(u32, u32, u32);
     /// # let t = TupleStruct(1, 2, 3);
     ///
+    /// // Bad
     /// match t {
     ///     TupleStruct(0, .., _) => (),
     ///     _ => (),
     /// }
-    /// ```
-    /// can be written as
-    /// ```rust
-    /// # struct TupleStruct(u32, u32, u32);
-    /// # let t = TupleStruct(1, 2, 3);
     ///
+    /// // Good
     /// match t {
     ///     TupleStruct(0, ..) => (),
     ///     _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs
index b6770804e18..6c42014b4c8 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_crate_versions.rs
@@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::DUMMY_SP;
 
-use cargo_metadata::{DependencyKind, MetadataCommand, Node, Package, PackageId};
+use cargo_metadata::{DependencyKind, Node, Package, PackageId};
 use if_chain::if_chain;
 use itertools::Itertools;
 
@@ -42,13 +42,7 @@ impl LateLintPass<'_, '_> for MultipleCrateVersions {
             return;
         }
 
-        let metadata = if let Ok(metadata) = MetadataCommand::new().exec() {
-            metadata
-        } else {
-            span_lint(cx, MULTIPLE_CRATE_VERSIONS, DUMMY_SP, "could not read cargo metadata");
-            return;
-        };
-
+        let metadata = unwrap_cargo_metadata!(cx, MULTIPLE_CRATE_VERSIONS, true);
         let local_name = cx.tcx.crate_name(LOCAL_CRATE).as_str();
         let mut packages = metadata.packages;
         packages.sort_by(|a, b| a.name.cmp(&b.name));
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index 67a1ac78a67..58a8e1a1064 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -16,7 +16,11 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```ignore
+    /// // Bad
     /// my_vec.push(&mut value)
+    ///
+    /// // Good
+    /// my_vec.push(&value)
     /// ```
     pub UNNECESSARY_MUT_PASSED,
     style,
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index 4e1a8be4892..78b15afc5a7 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -22,9 +22,15 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust
+    /// # let y = true;
+    ///
+    /// // Bad
     /// # use std::sync::Mutex;
-    /// # let y = 1;
     /// let x = Mutex::new(&y);
+    ///
+    /// // Good
+    /// # use std::sync::atomic::AtomicBool;
+    /// let x = AtomicBool::new(y);
     /// ```
     pub MUTEX_ATOMIC,
     perf,
@@ -46,6 +52,10 @@ declare_clippy_lint! {
     /// ```rust
     /// # use std::sync::Mutex;
     /// let x = Mutex::new(0usize);
+    ///
+    /// // Good
+    /// # use std::sync::atomic::AtomicUsize;
+    /// let x = AtomicUsize::new(0usize);
     /// ```
     pub MUTEX_INTEGER,
     nursery,
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index efa77db822d..15b129fa098 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -15,8 +15,7 @@ use rustc_span::Span;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for expressions of the form `if c { true } else {
-    /// false }`
-    /// (or vice versa) and suggest using the condition directly.
+    /// false }` (or vice versa) and suggests using the condition directly.
     ///
     /// **Why is this bad?** Redundant code.
     ///
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
index 9ee875d7516..5880d1d6102 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
@@ -18,12 +18,16 @@ declare_clippy_lint! {
     /// **Why is this bad?** Suggests that the receiver of the expression borrows
     /// the expression.
     ///
+    /// **Known problems:** None.
+    ///
     /// **Example:**
     /// ```rust
+    /// // Bad
     /// let x: &i32 = &&&&&&5;
-    /// ```
     ///
-    /// **Known problems:** None.
+    /// // Good
+    /// let x: &i32 = &5;
+    /// ```
     pub NEEDLESS_BORROW,
     nursery,
     "taking a reference that is going to be automatically dereferenced"
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index 28183810df4..a971d041ca6 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -424,7 +424,7 @@ fn erode_from_back(s: &str) -> String {
 }
 
 fn span_of_first_expr_in_block(block: &ast::Block) -> Option<Span> {
-    block.stmts.iter().next().map(|stmt| stmt.span)
+    block.stmts.get(0).map(|stmt| stmt.span)
 }
 
 #[cfg(test)]
diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs
index 4b2586877e5..d866bab2f64 100644
--- a/src/tools/clippy/clippy_lints/src/needless_update.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_update.rs
@@ -21,6 +21,16 @@ declare_clippy_lint! {
     /// #     z: i32,
     /// # }
     /// # let zero_point = Point { x: 0, y: 0, z: 0 };
+    ///
+    /// // Bad
+    /// Point {
+    ///     x: 1,
+    ///     y: 1,
+    ///     z: 1,
+    ///     ..zero_point
+    /// };
+    ///
+    /// // Ok
     /// Point {
     ///     x: 1,
     ///     y: 1,
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index e556e5d59c1..dd236535c18 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -1,13 +1,13 @@
 use crate::utils::paths;
 use crate::utils::sugg::DiagnosticBuilderExt;
-use crate::utils::{get_trait_def_id, return_ty, same_tys, span_lint_hir_and_then};
+use crate::utils::{get_trait_def_id, return_ty, span_lint_hir_and_then};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::HirIdSet;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{Ty, TyS};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
@@ -93,7 +93,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
                             let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id));
                             let self_ty = cx.tcx.type_of(self_def_id);
                             if_chain! {
-                                if same_tys(cx, self_ty, return_ty(cx, id));
+                                if TyS::same_type(self_ty, return_ty(cx, id));
                                 if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
                                 then {
                                     if self.impling_types.is_none() {
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index b8bfa676a16..2eacd3c80c4 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -147,7 +147,7 @@ fn reduce_expression<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option
             if let ExprKind::Path(ref qpath) = callee.kind {
                 let res = qpath_res(cx, qpath, callee.hir_id);
                 match res {
-                    Res::Def(DefKind::Struct, ..) | Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(..), _)
+                    Res::Def(DefKind::Struct | DefKind::Variant | DefKind::Ctor(..), ..)
                         if !has_drop(cx, cx.tables.expr_ty(expr)) =>
                     {
                         Some(args.iter().collect())
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 4eac571f966..c77b44e0c99 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -47,7 +47,11 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```ignore
+    /// // Bad
     /// fn foo(&Vec<u32>) { .. }
+    ///
+    /// // Good
+    /// fn foo(&[u32]) { .. }
     /// ```
     pub PTR_ARG,
     style,
@@ -65,9 +69,15 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```ignore
+    /// // Bad
     /// if x == ptr::null {
     ///     ..
     /// }
+    ///
+    /// // Good
+    /// if x.is_null() {
+    ///     ..
+    /// }
     /// ```
     pub CMP_NULL,
     style,
@@ -76,19 +86,16 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// **What it does:** This lint checks for functions that take immutable
-    /// references and return
-    /// mutable ones.
+    /// references and return mutable ones.
     ///
     /// **Why is this bad?** This is trivially unsound, as one can create two
-    /// mutable references
-    /// from the same (immutable!) source. This
-    /// [error](https://github.com/rust-lang/rust/issues/39465)
+    /// mutable references from the same (immutable!) source.
+    /// This [error](https://github.com/rust-lang/rust/issues/39465)
     /// actually lead to an interim Rust release 1.15.1.
     ///
     /// **Known problems:** To be on the conservative side, if there's at least one
-    /// mutable reference
-    /// with the output lifetime, this lint will not trigger. In practice, this
-    /// case is unlikely anyway.
+    /// mutable reference with the output lifetime, this lint will not trigger.
+    /// In practice, this case is unlikely anyway.
     ///
     /// **Example:**
     /// ```ignore
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index ea654467b86..e4361b00fb4 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -88,7 +88,7 @@ impl QuestionMark {
                         replacement_str,
                         applicability,
                     )
-               }
+                }
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 1eb26d97ed4..52e540d4e00 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -241,14 +241,26 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
 }
 
 fn check_reversed_empty_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
-    fn inside_indexing_expr<'a>(cx: &'a LateContext<'_, '_>, expr: &Expr<'_>) -> Option<&'a Expr<'a>> {
-        match get_parent_expr(cx, expr) {
-            parent_expr @ Some(Expr {
+    fn inside_indexing_expr(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
+        matches!(
+            get_parent_expr(cx, expr),
+            Some(Expr {
                 kind: ExprKind::Index(..),
                 ..
-            }) => parent_expr,
-            _ => None,
+            })
+        )
+    }
+
+    fn is_for_loop_arg(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
+        let mut cur_expr = expr;
+        while let Some(parent_expr) = get_parent_expr(cx, cur_expr) {
+            match higher::for_loop(parent_expr) {
+                Some((_, args, _)) if args.hir_id == expr.hir_id => return true,
+                _ => cur_expr = parent_expr,
+            }
         }
+
+        false
     }
 
     fn is_empty_range(limits: RangeLimits, ordering: Ordering) -> bool {
@@ -267,34 +279,18 @@ fn check_reversed_empty_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
         if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx);
         if is_empty_range(limits, ordering);
         then {
-            if let Some(parent_expr) = inside_indexing_expr(cx, expr) {
-                let (reason, outcome) = if ordering == Ordering::Equal {
-                    ("empty", "always yield an empty slice")
-                } else {
-                    ("reversed", "panic at run-time")
-                };
-
-                span_lint_and_then(
-                    cx,
-                    REVERSED_EMPTY_RANGES,
-                    expr.span,
-                    &format!("this range is {} and using it to index a slice will {}", reason, outcome),
-                    |diag| {
-                        if_chain! {
-                            if ordering == Ordering::Equal;
-                            if let ty::Slice(slice_ty) = cx.tables.expr_ty(parent_expr).kind;
-                            then {
-                                diag.span_suggestion(
-                                    parent_expr.span,
-                                    "if you want an empty slice, use",
-                                    format!("[] as &[{}]", slice_ty),
-                                    Applicability::MaybeIncorrect
-                                );
-                            }
-                        }
-                    }
-                );
-            } else {
+            if inside_indexing_expr(cx, expr) {
+                // Avoid linting `N..N` as it has proven to be useful, see #5689 and #5628 ...
+                if ordering != Ordering::Equal {
+                    span_lint(
+                        cx,
+                        REVERSED_EMPTY_RANGES,
+                        expr.span,
+                        "this range is reversed and using it to index a slice will panic at run-time",
+                    );
+                }
+            // ... except in for loop arguments for backwards compatibility with `reverse_range_loop`
+            } else if ordering != Ordering::Equal || is_for_loop_arg(cx, expr) {
                 span_lint_and_then(
                     cx,
                     REVERSED_EMPTY_RANGES,
diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs
index d5797468e9d..fe457aad50e 100644
--- a/src/tools/clippy/clippy_lints/src/reference.rs
+++ b/src/tools/clippy/clippy_lints/src/reference.rs
@@ -16,8 +16,13 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust,ignore
+    /// // Bad
     /// let a = f(*&mut b);
     /// let c = *&d;
+    ///
+    /// // Good
+    /// let a = f(b);
+    /// let c = d;
     /// ```
     pub DEREF_ADDROF,
     complexity,
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 30084e3e1ff..a2c35c42673 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -86,11 +86,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Regex {
             if let Some(span) = is_expn_of(expr.span, "regex");
             then {
                 if !self.spans.contains(&span) {
-                    span_lint(cx,
-                              REGEX_MACRO,
-                              span,
-                              "`regex!(_)` found. \
-                              Please use `Regex::new(_)`, which is faster for now.");
+                    span_lint(
+                        cx,
+                        REGEX_MACRO,
+                        span,
+                        "`regex!(_)` found. \
+                        Please use `Regex::new(_)`, which is faster for now."
+                    );
                     self.spans.insert(span);
                 }
                 self.last = Some(block.hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index 35464f629c3..3c939744173 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::BytePos;
 
-use crate::utils::{in_macro, match_path_ast, snippet_opt, span_lint_and_sugg, span_lint_and_then};
+use crate::utils::{snippet_opt, span_lint_and_sugg, span_lint_and_then};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for return statements at the end of a block.
@@ -37,33 +37,6 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for `let`-bindings, which are subsequently
-    /// returned.
-    ///
-    /// **Why is this bad?** It is just extraneous code. Remove it to make your code
-    /// more rusty.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// fn foo() -> String {
-    ///     let x = String::new();
-    ///     x
-    /// }
-    /// ```
-    /// instead, use
-    /// ```
-    /// fn foo() -> String {
-    ///     String::new()
-    /// }
-    /// ```
-    pub LET_AND_RETURN,
-    style,
-    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
-}
-
-declare_clippy_lint! {
     /// **What it does:** Checks for unit (`()`) expressions that can be removed.
     ///
     /// **Why is this bad?** Such expressions add no value, but can make the code
@@ -90,7 +63,7 @@ enum RetReplacement {
     Block,
 }
 
-declare_lint_pass!(Return => [NEEDLESS_RETURN, LET_AND_RETURN, UNUSED_UNIT]);
+declare_lint_pass!(Return => [NEEDLESS_RETURN, UNUSED_UNIT]);
 
 impl Return {
     // Check the final stmt or expr in a block for unnecessary return.
@@ -105,7 +78,7 @@ impl Return {
         }
     }
 
-    // Check a the final expression in a block if it's a return.
+    // Check the final expression in a block if it's a return.
     fn check_final_expr(
         &mut self,
         cx: &EarlyContext<'_>,
@@ -186,54 +159,6 @@ impl Return {
             },
         }
     }
-
-    // Check for "let x = EXPR; x"
-    fn check_let_return(cx: &EarlyContext<'_>, block: &ast::Block) {
-        let mut it = block.stmts.iter();
-
-        // we need both a let-binding stmt and an expr
-        if_chain! {
-            if let Some(retexpr) = it.next_back();
-            if let ast::StmtKind::Expr(ref retexpr) = retexpr.kind;
-            if let Some(stmt) = it.next_back();
-            if let ast::StmtKind::Local(ref local) = stmt.kind;
-            // don't lint in the presence of type inference
-            if local.ty.is_none();
-            if local.attrs.is_empty();
-            if let Some(ref initexpr) = local.init;
-            if let ast::PatKind::Ident(_, ident, _) = local.pat.kind;
-            if let ast::ExprKind::Path(_, ref path) = retexpr.kind;
-            if match_path_ast(path, &[&*ident.name.as_str()]);
-            if !in_external_macro(cx.sess(), initexpr.span);
-            if !in_external_macro(cx.sess(), retexpr.span);
-            if !in_external_macro(cx.sess(), local.span);
-            if !in_macro(local.span);
-            then {
-                span_lint_and_then(
-                    cx,
-                    LET_AND_RETURN,
-                    retexpr.span,
-                    "returning the result of a `let` binding from a block",
-                    |err| {
-                        err.span_label(local.span, "unnecessary `let` binding");
-
-                        if let Some(snippet) = snippet_opt(cx, initexpr.span) {
-                            err.multipart_suggestion(
-                                "return the expression directly",
-                                vec![
-                                    (local.span, String::new()),
-                                    (retexpr.span, snippet),
-                                ],
-                                Applicability::MachineApplicable,
-                            );
-                        } else {
-                            err.span_help(initexpr.span, "this expression can be directly returned");
-                        }
-                    },
-                );
-            }
-        }
-    }
 }
 
 impl EarlyLintPass for Return {
@@ -254,7 +179,6 @@ impl EarlyLintPass for Return {
     }
 
     fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
-        Self::check_let_return(cx, block);
         if_chain! {
             if let Some(ref stmt) = block.stmts.last();
             if let ast::StmtKind::Expr(ref expr) = stmt.kind;
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 11360b0ef84..68c36f91891 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -25,7 +25,12 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// # let x = 1;
+    ///
+    /// // Bad
     /// let x = &x;
+    ///
+    /// // Good
+    /// let y = &x; // use different variable name
     /// ```
     pub SHADOW_SAME,
     restriction,
@@ -77,7 +82,12 @@ declare_clippy_lint! {
     /// # let y = 1;
     /// # let z = 2;
     /// let x = y;
+    ///
+    /// // Bad
     /// let x = z; // shadows the earlier binding
+    ///
+    /// // Good
+    /// let w = z; // use different variable name
     /// ```
     pub SHADOW_UNRELATED,
     pedantic,
diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
index 8d767a7fec8..2e853e8301d 100644
--- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
@@ -16,7 +16,7 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     ///
-    /// ```rust, ignore
+    /// ```rust,ignore
     /// use regex;
     ///
     /// fn main() {
@@ -24,7 +24,7 @@ declare_clippy_lint! {
     /// }
     /// ```
     /// Better as
-    /// ```rust, ignore
+    /// ```rust,ignore
     /// fn main() {
     ///     regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
     /// }
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index fb3706be1c2..a7c4f2c2291 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -22,11 +22,17 @@ declare_clippy_lint! {
     /// ```rust
     /// # use core::iter::repeat;
     /// # let len = 4;
+    ///
+    /// // Bad
     /// let mut vec1 = Vec::with_capacity(len);
     /// vec1.resize(len, 0);
     ///
     /// let mut vec2 = Vec::with_capacity(len);
-    /// vec2.extend(repeat(0).take(len))
+    /// vec2.extend(repeat(0).take(len));
+    ///
+    /// // Good
+    /// let mut vec1 = vec![0; len];
+    /// let mut vec2 = vec![0; len];
     /// ```
     pub SLOW_VECTOR_INITIALIZATION,
     perf,
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 2c51271e312..f84566ef707 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -24,6 +24,10 @@ declare_clippy_lint! {
     /// ```rust
     /// let mut x = "Hello".to_owned();
     /// x = x + ", World";
+    ///
+    /// // More readable
+    /// x += ", World";
+    /// x.push_str(", World");
     /// ```
     pub STRING_ADD_ASSIGN,
     pedantic,
@@ -69,7 +73,11 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust
+    /// // Bad
     /// let bs = "a byte string".as_bytes();
+    ///
+    /// // Good
+    /// let bs = b"a byte string";
     /// ```
     pub STRING_LIT_AS_BYTES,
     style,
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index f1e223d9a48..a9e6fa329c0 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -71,8 +71,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for SuspiciousImpl {
                 if let hir::Node::Expr(e) = cx.tcx.hir().get(parent_expr) {
                     match e.kind {
                         hir::ExprKind::Binary(..)
-                        | hir::ExprKind::Unary(hir::UnOp::UnNot, _)
-                        | hir::ExprKind::Unary(hir::UnOp::UnNeg, _)
+                        | hir::ExprKind::Unary(hir::UnOp::UnNot | hir::UnOp::UnNeg, _)
                         | hir::ExprKind::AssignOp(..) => return,
                         _ => {},
                     }
@@ -191,8 +190,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BinaryExprVisitor {
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
         match expr.kind {
             hir::ExprKind::Binary(..)
-            | hir::ExprKind::Unary(hir::UnOp::UnNot, _)
-            | hir::ExprKind::Unary(hir::UnOp::UnNeg, _)
+            | hir::ExprKind::Unary(hir::UnOp::UnNot | hir::UnOp::UnNeg, _)
             | hir::ExprKind::AssignOp(..) => self.in_binary_expr = true,
             _ => {},
         }
diff --git a/src/tools/clippy/clippy_lints/src/transmute.rs b/src/tools/clippy/clippy_lints/src/transmute.rs
index e24d2c4f495..1869638f6ff 100644
--- a/src/tools/clippy/clippy_lints/src/transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute.rs
@@ -312,7 +312,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                         e.span,
                         &format!("transmute from a type (`{}`) to itself", from_ty),
                     ),
-                    (&ty::Ref(_, rty, rty_mutbl), &ty::RawPtr(ptr_ty)) => span_lint_and_then(
+                    (ty::Ref(_, rty, rty_mutbl), ty::RawPtr(ptr_ty)) => span_lint_and_then(
                         cx,
                         USELESS_TRANSMUTE,
                         e.span,
@@ -321,10 +321,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                             if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
                                 let rty_and_mut = ty::TypeAndMut {
                                     ty: rty,
-                                    mutbl: rty_mutbl,
+                                    mutbl: *rty_mutbl,
                                 };
 
-                                let sugg = if ptr_ty == rty_and_mut {
+                                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)
@@ -334,7 +334,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                             }
                         },
                     ),
-                    (&ty::Int(_), &ty::RawPtr(_)) | (&ty::Uint(_), &ty::RawPtr(_)) => span_lint_and_then(
+                    (ty::Int(_) | ty::Uint(_), ty::RawPtr(_)) => span_lint_and_then(
                         cx,
                         USELESS_TRANSMUTE,
                         e.span,
@@ -350,16 +350,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                             }
                         },
                     ),
-                    (&ty::Float(_), &ty::Ref(..))
-                    | (&ty::Float(_), &ty::RawPtr(_))
-                    | (&ty::Char, &ty::Ref(..))
-                    | (&ty::Char, &ty::RawPtr(_)) => span_lint(
+                    (ty::Float(_) | ty::Char, ty::Ref(..) | ty::RawPtr(_)) => span_lint(
                         cx,
                         WRONG_TRANSMUTE,
                         e.span,
                         &format!("transmute from a `{}` to a pointer", from_ty),
                     ),
-                    (&ty::RawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint(
+                    (ty::RawPtr(from_ptr), _) if from_ptr.ty == to_ty => span_lint(
                         cx,
                         CROSSPOINTER_TRANSMUTE,
                         e.span,
@@ -368,7 +365,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                             from_ty, to_ty
                         ),
                     ),
-                    (_, &ty::RawPtr(to_ptr)) if to_ptr.ty == from_ty => span_lint(
+                    (_, ty::RawPtr(to_ptr)) if to_ptr.ty == from_ty => span_lint(
                         cx,
                         CROSSPOINTER_TRANSMUTE,
                         e.span,
@@ -377,7 +374,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                             from_ty, to_ty
                         ),
                     ),
-                    (&ty::RawPtr(from_pty), &ty::Ref(_, to_ref_ty, mutbl)) => span_lint_and_then(
+                    (ty::RawPtr(from_pty), ty::Ref(_, to_ref_ty, mutbl)) => span_lint_and_then(
                         cx,
                         TRANSMUTE_PTR_TO_REF,
                         e.span,
@@ -388,13 +385,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                         ),
                         |diag| {
                             let arg = sugg::Sugg::hir(cx, &args[0], "..");
-                            let (deref, cast) = if mutbl == Mutability::Mut {
+                            let (deref, cast) = if *mutbl == Mutability::Mut {
                                 ("&mut *", "*mut")
                             } else {
                                 ("&*", "*const")
                             };
 
-                            let arg = if from_pty.ty == to_ref_ty {
+                            let arg = if from_pty.ty == *to_ref_ty {
                                 arg
                             } else {
                                 arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_ref_ty)))
@@ -408,7 +405,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                             );
                         },
                     ),
-                    (&ty::Int(ast::IntTy::I32), &ty::Char) | (&ty::Uint(ast::UintTy::U32), &ty::Char) => {
+                    (ty::Int(ast::IntTy::I32) | ty::Uint(ast::UintTy::U32), &ty::Char) => {
                         span_lint_and_then(
                             cx,
                             TRANSMUTE_INT_TO_CHAR,
@@ -430,13 +427,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                             },
                         )
                     },
-                    (&ty::Ref(_, ty_from, from_mutbl), &ty::Ref(_, ty_to, to_mutbl)) => {
+                    (ty::Ref(_, ty_from, from_mutbl), ty::Ref(_, ty_to, to_mutbl)) => {
                         if_chain! {
                             if let (&ty::Slice(slice_ty), &ty::Str) = (&ty_from.kind, &ty_to.kind);
                             if let ty::Uint(ast::UintTy::U8) = slice_ty.kind;
                             if from_mutbl == to_mutbl;
                             then {
-                                let postfix = if from_mutbl == Mutability::Mut {
+                                let postfix = if *from_mutbl == Mutability::Mut {
                                     "_mut"
                                 } else {
                                     ""
@@ -465,13 +462,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                                         |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
                                             let ty_from_and_mut = ty::TypeAndMut {
                                                 ty: ty_from,
-                                                mutbl: from_mutbl
+                                                mutbl: *from_mutbl
                                             };
-                                            let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: to_mutbl };
+                                            let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: *to_mutbl };
                                             let sugg_paren = arg
                                                 .as_ty(cx.tcx.mk_ptr(ty_from_and_mut))
                                                 .as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
-                                            let sugg = if to_mutbl == Mutability::Mut {
+                                            let sugg = if *to_mutbl == Mutability::Mut {
                                                 sugg_paren.mut_addr_deref()
                                             } else {
                                                 sugg_paren.addr_deref()
@@ -488,19 +485,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                             }
                         }
                     },
-                    (&ty::RawPtr(_), &ty::RawPtr(to_ty)) => span_lint_and_then(
+                    (ty::RawPtr(_), ty::RawPtr(to_ty)) => span_lint_and_then(
                         cx,
                         TRANSMUTE_PTR_TO_PTR,
                         e.span,
                         "transmute from a pointer to a pointer",
                         |diag| {
                             if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
-                                let sugg = arg.as_ty(cx.tcx.mk_ptr(to_ty));
+                                let sugg = arg.as_ty(cx.tcx.mk_ptr(*to_ty));
                                 diag.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified);
                             }
                         },
                     ),
-                    (&ty::Int(ast::IntTy::I8), &ty::Bool) | (&ty::Uint(ast::UintTy::U8), &ty::Bool) => {
+                    (ty::Int(ast::IntTy::I8) | ty::Uint(ast::UintTy::U8), ty::Bool) => {
                         span_lint_and_then(
                             cx,
                             TRANSMUTE_INT_TO_BOOL,
@@ -518,7 +515,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                             },
                         )
                     },
-                    (&ty::Int(_), &ty::Float(_)) | (&ty::Uint(_), &ty::Float(_)) => span_lint_and_then(
+                    (ty::Int(_) | ty::Uint(_), ty::Float(_)) => span_lint_and_then(
                         cx,
                         TRANSMUTE_INT_TO_FLOAT,
                         e.span,
@@ -541,7 +538,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                             );
                         },
                     ),
-                    (&ty::Float(float_ty), &ty::Int(_)) | (&ty::Float(float_ty), &ty::Uint(_)) => span_lint_and_then(
+                    (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) => span_lint_and_then(
                         cx,
                         TRANSMUTE_FLOAT_TO_INT,
                         e.span,
@@ -585,7 +582,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
                             );
                         },
                     ),
-                    (&ty::Adt(ref from_adt, ref from_substs), &ty::Adt(ref to_adt, ref to_substs)) => {
+                    (ty::Adt(from_adt, from_substs), ty::Adt(to_adt, to_substs)) => {
                         if from_adt.did != to_adt.did ||
                                 !COLLECTIONS.iter().any(|path| match_def_path(cx, to_adt.did, path)) {
                             return;
diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs
index 6ed9ff22e46..bc5fe44b30f 100644
--- a/src/tools/clippy/clippy_lints/src/types.rs
+++ b/src/tools/clippy/clippy_lints/src/types.rs
@@ -10,14 +10,14 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::{
-    BinOpKind, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem,
+    BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem,
     ImplItemKind, Item, ItemKind, Lifetime, Local, MatchSource, MutTy, Mutability, QPath, Stmt, StmtKind, TraitFn,
     TraitItem, TraitItemKind, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TypeckTables};
+use rustc_middle::ty::{self, InferTy, Ty, TyCtxt, TyS, TypeckTables};
 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::Span;
@@ -29,10 +29,10 @@ use rustc_typeck::hir_ty_to_ty;
 use crate::consts::{constant, Constant};
 use crate::utils::paths;
 use crate::utils::{
-    clip, comparisons, differing_macro_contexts, higher, in_constant, int_bits, is_type_diagnostic_item,
+    clip, comparisons, differing_macro_contexts, higher, in_constant, indent_of, int_bits, is_type_diagnostic_item,
     last_path_segment, match_def_path, match_path, method_chain_args, multispan_sugg, numeric_literal::NumericLiteral,
-    qpath_res, same_tys, sext, snippet, snippet_opt, snippet_with_applicability, snippet_with_macro_callsite,
-    span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext,
+    qpath_res, sext, snippet, snippet_block_with_applicability, snippet_opt, snippet_with_applicability,
+    snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, unsext,
 };
 
 declare_clippy_lint! {
@@ -779,24 +779,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg {
 
         match expr.kind {
             ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args) => {
-                for arg in args {
-                    if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) {
-                        if let ExprKind::Match(.., match_source) = &arg.kind {
-                            if *match_source == MatchSource::TryDesugar {
-                                continue;
+                let args_to_recover = args
+                    .iter()
+                    .filter(|arg| {
+                        if is_unit(cx.tables.expr_ty(arg)) && !is_unit_literal(arg) {
+                            if let ExprKind::Match(.., MatchSource::TryDesugar) = &arg.kind {
+                                false
+                            } else {
+                                true
                             }
+                        } else {
+                            false
                         }
-
-                        span_lint_and_sugg(
-                            cx,
-                            UNIT_ARG,
-                            arg.span,
-                            "passing a unit value to a function",
-                            "if you intended to pass a unit value, use a unit literal instead",
-                            "()".to_string(),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
+                    })
+                    .collect::<Vec<_>>();
+                if !args_to_recover.is_empty() {
+                    lint_unit_args(cx, expr, &args_to_recover);
                 }
             },
             _ => (),
@@ -804,6 +802,101 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitArg {
     }
 }
 
+fn lint_unit_args(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) {
+    let mut applicability = Applicability::MachineApplicable;
+    let (singular, plural) = if args_to_recover.len() > 1 {
+        ("", "s")
+    } else {
+        ("a ", "")
+    };
+    span_lint_and_then(
+        cx,
+        UNIT_ARG,
+        expr.span,
+        &format!("passing {}unit value{} to a function", singular, plural),
+        |db| {
+            let mut or = "";
+            args_to_recover
+                .iter()
+                .filter_map(|arg| {
+                    if_chain! {
+                        if let ExprKind::Block(block, _) = arg.kind;
+                        if block.expr.is_none();
+                        if let Some(last_stmt) = block.stmts.iter().last();
+                        if let StmtKind::Semi(last_expr) = last_stmt.kind;
+                        if let Some(snip) = snippet_opt(cx, last_expr.span);
+                        then {
+                            Some((
+                                last_stmt.span,
+                                snip,
+                            ))
+                        }
+                        else {
+                            None
+                        }
+                    }
+                })
+                .for_each(|(span, sugg)| {
+                    db.span_suggestion(
+                        span,
+                        "remove the semicolon from the last statement in the block",
+                        sugg,
+                        Applicability::MaybeIncorrect,
+                    );
+                    or = "or ";
+                });
+            let sugg = args_to_recover
+                .iter()
+                .filter(|arg| !is_empty_block(arg))
+                .enumerate()
+                .map(|(i, arg)| {
+                    let indent = if i == 0 {
+                        0
+                    } else {
+                        indent_of(cx, expr.span).unwrap_or(0)
+                    };
+                    format!(
+                        "{}{};",
+                        " ".repeat(indent),
+                        snippet_block_with_applicability(cx, arg.span, "..", Some(expr.span), &mut applicability)
+                    )
+                })
+                .collect::<Vec<String>>();
+            let mut and = "";
+            if !sugg.is_empty() {
+                let plural = if sugg.len() > 1 { "s" } else { "" };
+                db.span_suggestion(
+                    expr.span.with_hi(expr.span.lo()),
+                    &format!("{}move the expression{} in front of the call...", or, plural),
+                    format!("{}\n", sugg.join("\n")),
+                    applicability,
+                );
+                and = "...and "
+            }
+            db.multipart_suggestion(
+                &format!("{}use {}unit literal{} instead", and, singular, plural),
+                args_to_recover
+                    .iter()
+                    .map(|arg| (arg.span, "()".to_string()))
+                    .collect::<Vec<_>>(),
+                applicability,
+            );
+        },
+    );
+}
+
+fn is_empty_block(expr: &Expr<'_>) -> bool {
+    matches!(
+        expr.kind,
+        ExprKind::Block(
+            Block {
+                stmts: &[], expr: None, ..
+            },
+            _,
+        )
+    )
+}
+
 fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool {
     use rustc_span::hygiene::DesugaringKind;
     if let ExprKind::Call(ref callee, _) = expr.kind {
@@ -974,7 +1067,8 @@ declare_clippy_lint! {
     /// behavior.
     ///
     /// **Known problems:** Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
-    /// on the resulting pointer is fine.
+    /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
+    /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
     ///
     /// **Example:**
     /// ```rust
@@ -982,7 +1076,7 @@ declare_clippy_lint! {
     /// let _ = (&mut 1u8 as *mut u8) as *mut u16;
     /// ```
     pub CAST_PTR_ALIGNMENT,
-    correctness,
+    pedantic,
     "cast from a pointer to a more-strictly-aligned pointer"
 }
 
@@ -2462,7 +2556,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't
             if let ExprKind::Path(QPath::TypeRelative(ref ty, ref method)) = fun.kind;
             if let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind;
             then {
-                if !same_tys(self.cx, self.target.ty(), self.body.expr_ty(e)) {
+                if !TyS::same_type(self.target.ty(), self.body.expr_ty(e)) {
                     return;
                 }
 
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
new file mode 100644
index 00000000000..33d8331c292
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
@@ -0,0 +1,267 @@
+use crate::utils;
+use crate::utils::paths;
+use crate::utils::sugg::Sugg;
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::Ident;
+
+declare_clippy_lint! {
+    /// **What it does:**
+    /// Detects when people use `Vec::sort_by` and pass in a function
+    /// which compares the two arguments, either directly or indirectly.
+    ///
+    /// **Why is this bad?**
+    /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if
+    /// possible) than to use `Vec::sort_by` and and a more complicated
+    /// closure.
+    ///
+    /// **Known problems:**
+    /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't
+    /// imported by a use statement in the current frame, then a `use`
+    /// statement that imports it will need to be added (which this lint
+    /// can't do).
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// # struct A;
+    /// # impl A { fn foo(&self) {} }
+    /// # let mut vec: Vec<A> = Vec::new();
+    /// vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # struct A;
+    /// # impl A { fn foo(&self) {} }
+    /// # let mut vec: Vec<A> = Vec::new();
+    /// vec.sort_by_key(|a| a.foo());
+    /// ```
+    pub UNNECESSARY_SORT_BY,
+    complexity,
+    "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer"
+}
+
+declare_lint_pass!(UnnecessarySortBy => [UNNECESSARY_SORT_BY]);
+
+enum LintTrigger {
+    Sort(SortDetection),
+    SortByKey(SortByKeyDetection),
+}
+
+struct SortDetection {
+    vec_name: String,
+    unstable: bool,
+}
+
+struct SortByKeyDetection {
+    vec_name: String,
+    closure_arg: String,
+    closure_body: String,
+    reverse: bool,
+    unstable: bool,
+}
+
+/// Detect if the two expressions are mirrored (identical, except one
+/// contains a and the other replaces it with b)
+fn mirrored_exprs(
+    cx: &LateContext<'_, '_>,
+    a_expr: &Expr<'_>,
+    a_ident: &Ident,
+    b_expr: &Expr<'_>,
+    b_ident: &Ident,
+) -> bool {
+    match (&a_expr.kind, &b_expr.kind) {
+        // Two boxes with mirrored contents
+        (ExprKind::Box(left_expr), ExprKind::Box(right_expr)) => {
+            mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident)
+        },
+        // Two arrays with mirrored contents
+        (ExprKind::Array(left_exprs), ExprKind::Array(right_exprs)) => left_exprs
+            .iter()
+            .zip(right_exprs.iter())
+            .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)),
+        // The two exprs are function calls.
+        // Check to see that the function itself and its arguments are mirrored
+        (ExprKind::Call(left_expr, left_args), ExprKind::Call(right_expr, right_args)) => {
+            mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident)
+                && left_args
+                    .iter()
+                    .zip(right_args.iter())
+                    .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
+        },
+        // The two exprs are method calls.
+        // Check to see that the function is the same and the arguments are mirrored
+        // This is enough because the receiver of the method is listed in the arguments
+        (ExprKind::MethodCall(left_segment, _, left_args), ExprKind::MethodCall(right_segment, _, right_args)) => {
+            left_segment.ident == right_segment.ident
+                && left_args
+                    .iter()
+                    .zip(right_args.iter())
+                    .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident))
+        },
+        // Two tuples with mirrored contents
+        (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => left_exprs
+            .iter()
+            .zip(right_exprs.iter())
+            .all(|(left, right)| mirrored_exprs(cx, left, a_ident, right, b_ident)),
+        // Two binary ops, which are the same operation and which have mirrored arguments
+        (ExprKind::Binary(left_op, left_left, left_right), ExprKind::Binary(right_op, right_left, right_right)) => {
+            left_op.node == right_op.node
+                && mirrored_exprs(cx, left_left, a_ident, right_left, b_ident)
+                && mirrored_exprs(cx, left_right, a_ident, right_right, b_ident)
+        },
+        // Two unary ops, which are the same operation and which have the same argument
+        (ExprKind::Unary(left_op, left_expr), ExprKind::Unary(right_op, right_expr)) => {
+            left_op == right_op && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident)
+        },
+        // The two exprs are literals of some kind
+        (ExprKind::Lit(left_lit), ExprKind::Lit(right_lit)) => left_lit.node == right_lit.node,
+        (ExprKind::Cast(left, _), ExprKind::Cast(right, _)) => mirrored_exprs(cx, left, a_ident, right, b_ident),
+        (ExprKind::DropTemps(left_block), ExprKind::DropTemps(right_block)) => {
+            mirrored_exprs(cx, left_block, a_ident, right_block, b_ident)
+        },
+        (ExprKind::Field(left_expr, left_ident), ExprKind::Field(right_expr, right_ident)) => {
+            left_ident.name == right_ident.name && mirrored_exprs(cx, left_expr, a_ident, right_expr, right_ident)
+        },
+        // Two paths: either one is a and the other is b, or they're identical to each other
+        (
+            ExprKind::Path(QPath::Resolved(
+                _,
+                Path {
+                    segments: left_segments,
+                    ..
+                },
+            )),
+            ExprKind::Path(QPath::Resolved(
+                _,
+                Path {
+                    segments: right_segments,
+                    ..
+                },
+            )),
+        ) => {
+            (left_segments
+                .iter()
+                .zip(right_segments.iter())
+                .all(|(left, right)| left.ident == right.ident)
+                && left_segments
+                    .iter()
+                    .all(|seg| &seg.ident != a_ident && &seg.ident != b_ident))
+                || (left_segments.len() == 1
+                    && &left_segments[0].ident == a_ident
+                    && right_segments.len() == 1
+                    && &right_segments[0].ident == b_ident)
+        },
+        // Matching expressions, but one or both is borrowed
+        (
+            ExprKind::AddrOf(left_kind, Mutability::Not, left_expr),
+            ExprKind::AddrOf(right_kind, Mutability::Not, right_expr),
+        ) => left_kind == right_kind && mirrored_exprs(cx, left_expr, a_ident, right_expr, b_ident),
+        (_, ExprKind::AddrOf(_, Mutability::Not, right_expr)) => {
+            mirrored_exprs(cx, a_expr, a_ident, right_expr, b_ident)
+        },
+        (ExprKind::AddrOf(_, Mutability::Not, left_expr), _) => mirrored_exprs(cx, left_expr, a_ident, b_expr, b_ident),
+        _ => false,
+    }
+}
+
+fn detect_lint(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option<LintTrigger> {
+    if_chain! {
+        if let ExprKind::MethodCall(name_ident, _, args) = &expr.kind;
+        if let name = name_ident.ident.name.to_ident_string();
+        if name == "sort_by" || name == "sort_unstable_by";
+        if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
+        if utils::match_type(cx, &cx.tables.expr_ty(vec), &paths::VEC);
+        if let closure_body = cx.tcx.hir().body(*closure_body_id);
+        if let &[
+            Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
+            Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. }
+        ] = &closure_body.params;
+        if let ExprKind::MethodCall(method_path, _, [ref left_expr, ref right_expr]) = &closure_body.value.kind;
+        if method_path.ident.name.to_ident_string() == "cmp";
+        then {
+            let (closure_body, closure_arg, reverse) = if mirrored_exprs(
+                &cx,
+                &left_expr,
+                &left_ident,
+                &right_expr,
+                &right_ident
+            ) {
+                (Sugg::hir(cx, &left_expr, "..").to_string(), left_ident.name.to_string(), false)
+            } else if mirrored_exprs(&cx, &left_expr, &right_ident, &right_expr, &left_ident) {
+                (Sugg::hir(cx, &left_expr, "..").to_string(), right_ident.name.to_string(), true)
+            } else {
+                return None;
+            };
+            let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
+            let unstable = name == "sort_unstable_by";
+            if_chain! {
+                if let ExprKind::Path(QPath::Resolved(_, Path {
+                    segments: [PathSegment { ident: left_name, .. }], ..
+                })) = &left_expr.kind;
+                if left_name == left_ident;
+                then {
+                    Some(LintTrigger::Sort(SortDetection { vec_name, unstable }))
+                }
+                else {
+                    Some(LintTrigger::SortByKey(SortByKeyDetection {
+                        vec_name,
+                        unstable,
+                        closure_arg,
+                        closure_body,
+                        reverse
+                    }))
+                }
+            }
+        } else {
+            None
+        }
+    }
+}
+
+impl LateLintPass<'_, '_> for UnnecessarySortBy {
+    fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
+        match detect_lint(cx, expr) {
+            Some(LintTrigger::SortByKey(trigger)) => utils::span_lint_and_sugg(
+                cx,
+                UNNECESSARY_SORT_BY,
+                expr.span,
+                "use Vec::sort_by_key here instead",
+                "try",
+                format!(
+                    "{}.sort{}_by_key(|&{}| {})",
+                    trigger.vec_name,
+                    if trigger.unstable { "_unstable" } else { "" },
+                    trigger.closure_arg,
+                    if trigger.reverse {
+                        format!("Reverse({})", trigger.closure_body)
+                    } else {
+                        trigger.closure_body.to_string()
+                    },
+                ),
+                if trigger.reverse {
+                    Applicability::MaybeIncorrect
+                } else {
+                    Applicability::MachineApplicable
+                },
+            ),
+            Some(LintTrigger::Sort(trigger)) => utils::span_lint_and_sugg(
+                cx,
+                UNNECESSARY_SORT_BY,
+                expr.span,
+                "use Vec::sort here instead",
+                "try",
+                format!(
+                    "{}.sort{}()",
+                    trigger.vec_name,
+                    if trigger.unstable { "_unstable" } else { "" },
+                ),
+                Applicability::MachineApplicable,
+            ),
+            None => {},
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
new file mode 100644
index 00000000000..8c281126c32
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -0,0 +1,407 @@
+#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
+
+use crate::utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path};
+use crate::utils::{over, span_lint_and_then};
+use rustc_ast::ast::{self, Pat, PatKind, PatKind::*, DUMMY_NODE_ID};
+use rustc_ast::mut_visit::*;
+use rustc_ast::ptr::P;
+use rustc_ast_pretty::pprust;
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::DUMMY_SP;
+
+use std::cell::Cell;
+use std::mem;
+
+declare_clippy_lint! {
+    /// **What it does:**
+    ///
+    /// Checks for unnested or-patterns, e.g., `Some(0) | Some(2)` and
+    /// suggests replacing the pattern with a nested one, `Some(0 | 2)`.
+    ///
+    /// Another way to think of this is that it rewrites patterns in
+    /// *disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*.
+    ///
+    /// **Why is this bad?**
+    ///
+    /// In the example above, `Some` is repeated, which unncessarily complicates the pattern.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// fn main() {
+    ///     if let Some(0) | Some(2) = Some(0) {}
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// #![feature(or_patterns)]
+    ///
+    /// fn main() {
+    ///     if let Some(0 | 2) = Some(0) {}
+    /// }
+    /// ```
+    pub UNNESTED_OR_PATTERNS,
+    complexity,
+    "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`"
+}
+
+declare_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]);
+
+impl EarlyLintPass for UnnestedOrPatterns {
+    fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) {
+        lint_unnested_or_patterns(cx, &a.pat);
+    }
+
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
+        if let ast::ExprKind::Let(pat, _) = &e.kind {
+            lint_unnested_or_patterns(cx, pat);
+        }
+    }
+
+    fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) {
+        lint_unnested_or_patterns(cx, &p.pat);
+    }
+
+    fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) {
+        lint_unnested_or_patterns(cx, &l.pat);
+    }
+}
+
+fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
+    if !cx.sess.opts.unstable_features.is_nightly_build() {
+        // User cannot do `#![feature(or_patterns)]`, so bail.
+        return;
+    }
+
+    if let Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_) = pat.kind {
+        // This is a leaf pattern, so cloning is unprofitable.
+        return;
+    }
+
+    let mut pat = P(pat.clone());
+
+    // Nix all the paren patterns everywhere so that they aren't in our way.
+    remove_all_parens(&mut pat);
+
+    // Transform all unnested or-patterns into nested ones, and if there were none, quit.
+    if !unnest_or_patterns(&mut pat) {
+        return;
+    }
+
+    span_lint_and_then(cx, UNNESTED_OR_PATTERNS, pat.span, "unnested or-patterns", |db| {
+        insert_necessary_parens(&mut pat);
+        db.span_suggestion_verbose(
+            pat.span,
+            "nest the patterns",
+            pprust::pat_to_string(&pat),
+            Applicability::MachineApplicable,
+        );
+    });
+}
+
+/// Remove all `(p)` patterns in `pat`.
+fn remove_all_parens(pat: &mut P<Pat>) {
+    struct Visitor;
+    impl MutVisitor for Visitor {
+        fn visit_pat(&mut self, pat: &mut P<Pat>) {
+            noop_visit_pat(pat, self);
+            let inner = match &mut pat.kind {
+                Paren(i) => mem::replace(&mut i.kind, Wild),
+                _ => return,
+            };
+            pat.kind = inner;
+        }
+    }
+    Visitor.visit_pat(pat);
+}
+
+/// Insert parens where necessary according to Rust's precedence rules for patterns.
+fn insert_necessary_parens(pat: &mut P<Pat>) {
+    struct Visitor;
+    impl MutVisitor for Visitor {
+        fn visit_pat(&mut self, pat: &mut P<Pat>) {
+            use ast::{BindingMode::*, Mutability::*};
+            noop_visit_pat(pat, self);
+            let target = match &mut pat.kind {
+                // `i @ a | b`, `box a | b`, and `& mut? a | b`.
+                Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p,
+                Ref(p, Not) if matches!(p.kind, Ident(ByValue(Mut), ..)) => p, // `&(mut x)`
+                _ => return,
+            };
+            target.kind = Paren(P(take_pat(target)));
+        }
+    }
+    Visitor.visit_pat(pat);
+}
+
+/// Unnest or-patterns `p0 | ... | p1` in the pattern `pat`.
+/// For example, this would transform `Some(0) | FOO | Some(2)` into `Some(0 | 2) | FOO`.
+fn unnest_or_patterns(pat: &mut P<Pat>) -> bool {
+    struct Visitor {
+        changed: bool,
+    }
+    impl MutVisitor for Visitor {
+        fn visit_pat(&mut self, p: &mut P<Pat>) {
+            // This is a bottom up transformation, so recurse first.
+            noop_visit_pat(p, self);
+
+            // Don't have an or-pattern? Just quit early on.
+            let alternatives = match &mut p.kind {
+                Or(ps) => ps,
+                _ => return,
+            };
+
+            // Collapse or-patterns directly nested in or-patterns.
+            let mut idx = 0;
+            let mut this_level_changed = false;
+            while idx < alternatives.len() {
+                let inner = if let Or(ps) = &mut alternatives[idx].kind {
+                    mem::take(ps)
+                } else {
+                    idx += 1;
+                    continue;
+                };
+                this_level_changed = true;
+                alternatives.splice(idx..=idx, inner);
+            }
+
+            // Focus on `p_n` and then try to transform all `p_i` where `i > n`.
+            let mut focus_idx = 0;
+            while focus_idx < alternatives.len() {
+                this_level_changed |= transform_with_focus_on_idx(alternatives, focus_idx);
+                focus_idx += 1;
+            }
+            self.changed |= this_level_changed;
+
+            // Deal with `Some(Some(0)) | Some(Some(1))`.
+            if this_level_changed {
+                noop_visit_pat(p, self);
+            }
+        }
+    }
+
+    let mut visitor = Visitor { changed: false };
+    visitor.visit_pat(pat);
+    visitor.changed
+}
+
+/// Match `$scrutinee` against `$pat` and extract `$then` from it.
+/// Panics if there is no match.
+macro_rules! always_pat {
+    ($scrutinee:expr, $pat:pat => $then:expr) => {
+        match $scrutinee {
+            $pat => $then,
+            _ => unreachable!(),
+        }
+    };
+}
+
+/// Focus on `focus_idx` in `alternatives`,
+/// attempting to extend it with elements of the same constructor `C`
+/// in `alternatives[focus_idx + 1..]`.
+fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize) -> bool {
+    // Extract the kind; we'll need to make some changes in it.
+    let mut focus_kind = mem::replace(&mut alternatives[focus_idx].kind, PatKind::Wild);
+    // We'll focus on `alternatives[focus_idx]`,
+    // so we're draining from `alternatives[focus_idx + 1..]`.
+    let start = focus_idx + 1;
+
+    // We're trying to find whatever kind (~"constructor") we found in `alternatives[start..]`.
+    let changed = match &mut focus_kind {
+        // These pattern forms are "leafs" and do not have sub-patterns.
+        // Therefore they are not some form of constructor `C`,
+        // with which a pattern `C(p_0)` may be formed,
+        // which we would want to join with other `C(p_j)`s.
+        Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_)
+        // Dealt with elsewhere.
+        | Or(_) | Paren(_) => false,
+        // Transform `box x | ... | box y` into `box (x | y)`.
+        //
+        // The cases below until `Slice(...)` deal with *singleton* products.
+        // These patterns have the shape `C(p)`, and not e.g., `C(p0, ..., pn)`.
+        Box(target) => extend_with_matching(
+            target, start, alternatives,
+            |k| matches!(k, Box(_)),
+            |k| always_pat!(k, Box(p) => p),
+        ),
+        // Transform `&m x | ... | &m y` into `&m (x | y)`.
+        Ref(target, m1) => extend_with_matching(
+            target, start, alternatives,
+            |k| matches!(k, Ref(_, m2) if m1 == m2), // Mutabilities must match.
+            |k| always_pat!(k, Ref(p, _) => p),
+        ),
+        // Transform `b @ p0 | ... b @ p1` into `b @ (p0 | p1)`.
+        Ident(b1, i1, Some(target)) => extend_with_matching(
+            target, start, alternatives,
+            // Binding names must match.
+            |k| matches!(k, Ident(b2, i2, Some(_)) if b1 == b2 && eq_id(*i1, *i2)),
+            |k| always_pat!(k, Ident(_, _, Some(p)) => p),
+        ),
+        // Transform `[pre, x, post] | ... | [pre, y, post]` into `[pre, x | y, post]`.
+        Slice(ps1) => extend_with_matching_product(
+            ps1, start, alternatives,
+            |k, ps1, idx| matches!(k, Slice(ps2) if eq_pre_post(ps1, ps2, idx)),
+            |k| always_pat!(k, Slice(ps) => ps),
+        ),
+        // Transform `(pre, x, post) | ... | (pre, y, post)` into `(pre, x | y, post)`.
+        Tuple(ps1) => extend_with_matching_product(
+            ps1, start, alternatives,
+            |k, ps1, idx| matches!(k, Tuple(ps2) if eq_pre_post(ps1, ps2, idx)),
+            |k| always_pat!(k, Tuple(ps) => ps),
+        ),
+        // Transform `S(pre, x, post) | ... | S(pre, y, post)` into `S(pre, x | y, post)`.
+        TupleStruct(path1, ps1) => extend_with_matching_product(
+            ps1, start, alternatives,
+            |k, ps1, idx| matches!(
+                k,
+                TupleStruct(path2, ps2) if eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
+            ),
+            |k| always_pat!(k, TupleStruct(_, ps) => ps),
+        ),
+        // Transform a record pattern `S { fp_0, ..., fp_n }`.
+        Struct(path1, fps1, rest1) => extend_with_struct_pat(path1, fps1, *rest1, start, alternatives),
+    };
+
+    alternatives[focus_idx].kind = focus_kind;
+    changed
+}
+
+/// Here we focusing on a record pattern `S { fp_0, ..., fp_n }`.
+/// In particular, for a record pattern, the order in which the field patterns is irrelevant.
+/// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern
+/// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal.
+fn extend_with_struct_pat(
+    path1: &ast::Path,
+    fps1: &mut Vec<ast::FieldPat>,
+    rest1: bool,
+    start: usize,
+    alternatives: &mut Vec<P<Pat>>,
+) -> bool {
+    (0..fps1.len()).any(|idx| {
+        let pos_in_2 = Cell::new(None); // The element `k`.
+        let tail_or = drain_matching(
+            start,
+            alternatives,
+            |k| {
+                matches!(k, Struct(path2, fps2, rest2)
+                if rest1 == *rest2 // If one struct pattern has `..` so must the other.
+                && eq_path(path1, path2)
+                && fps1.len() == fps2.len()
+                && fps1.iter().enumerate().all(|(idx_1, fp1)| {
+                    if idx_1 == idx {
+                        // In the case of `k`, we merely require identical field names
+                        // so that we will transform into `ident_k: p1_k | p2_k`.
+                        let pos = fps2.iter().position(|fp2| eq_id(fp1.ident, fp2.ident));
+                        pos_in_2.set(pos);
+                        pos.is_some()
+                    } else {
+                        fps2.iter().any(|fp2| eq_field_pat(fp1, fp2))
+                    }
+                }))
+            },
+            // Extract `p2_k`.
+            |k| always_pat!(k, Struct(_, mut fps, _) => fps.swap_remove(pos_in_2.take().unwrap()).pat),
+        );
+        extend_with_tail_or(&mut fps1[idx].pat, tail_or)
+    })
+}
+
+/// Like `extend_with_matching` but for products with > 1 factor, e.g., `C(p_0, ..., p_n)`.
+/// Here, the idea is that we fixate on some `p_k` in `C`,
+/// allowing it to vary between two `targets` and `ps2` (returned by `extract`),
+/// while also requiring `ps1[..n] ~ ps2[..n]` (pre) and `ps1[n + 1..] ~ ps2[n + 1..]` (post),
+/// where `~` denotes semantic equality.
+fn extend_with_matching_product(
+    targets: &mut Vec<P<Pat>>,
+    start: usize,
+    alternatives: &mut Vec<P<Pat>>,
+    predicate: impl Fn(&PatKind, &[P<Pat>], usize) -> bool,
+    extract: impl Fn(PatKind) -> Vec<P<Pat>>,
+) -> bool {
+    (0..targets.len()).any(|idx| {
+        let tail_or = drain_matching(
+            start,
+            alternatives,
+            |k| predicate(k, targets, idx),
+            |k| extract(k).swap_remove(idx),
+        );
+        extend_with_tail_or(&mut targets[idx], tail_or)
+    })
+}
+
+/// Extract the pattern from the given one and replace it with `Wild`.
+/// This is meant for temporarily swapping out the pattern for manipulation.
+fn take_pat(from: &mut Pat) -> Pat {
+    let dummy = Pat {
+        id: DUMMY_NODE_ID,
+        kind: Wild,
+        span: DUMMY_SP,
+    };
+    mem::replace(from, dummy)
+}
+
+/// Extend `target` as an or-pattern with the alternatives
+/// in `tail_or` if there are any and return if there were.
+fn extend_with_tail_or(target: &mut Pat, tail_or: Vec<P<Pat>>) -> bool {
+    fn extend(target: &mut Pat, mut tail_or: Vec<P<Pat>>) {
+        match target {
+            // On an existing or-pattern in the target, append to it.
+            Pat { kind: Or(ps), .. } => ps.append(&mut tail_or),
+            // Otherwise convert the target to an or-pattern.
+            target => {
+                let mut init_or = vec![P(take_pat(target))];
+                init_or.append(&mut tail_or);
+                target.kind = Or(init_or);
+            },
+        }
+    }
+
+    let changed = !tail_or.is_empty();
+    if changed {
+        // Extend the target.
+        extend(target, tail_or);
+    }
+    changed
+}
+
+// Extract all inner patterns in `alternatives` matching our `predicate`.
+// Only elements beginning with `start` are considered for extraction.
+fn drain_matching(
+    start: usize,
+    alternatives: &mut Vec<P<Pat>>,
+    predicate: impl Fn(&PatKind) -> bool,
+    extract: impl Fn(PatKind) -> P<Pat>,
+) -> Vec<P<Pat>> {
+    let mut tail_or = vec![];
+    let mut idx = 0;
+    for pat in alternatives.drain_filter(|p| {
+        // Check if we should extract, but only if `idx >= start`.
+        idx += 1;
+        idx > start && predicate(&p.kind)
+    }) {
+        tail_or.push(extract(pat.into_inner().kind));
+    }
+    tail_or
+}
+
+fn extend_with_matching(
+    target: &mut Pat,
+    start: usize,
+    alternatives: &mut Vec<P<Pat>>,
+    predicate: impl Fn(&PatKind) -> bool,
+    extract: impl Fn(PatKind) -> P<Pat>,
+) -> bool {
+    extend_with_tail_or(target, drain_matching(start, alternatives, predicate, extract))
+}
+
+/// Are the patterns in `ps1` and `ps2` equal save for `ps1[idx]` compared to `ps2[idx]`?
+fn eq_pre_post(ps1: &[P<Pat>], ps2: &[P<Pat>], idx: usize) -> bool {
+    ps1[idx].is_rest() == ps2[idx].is_rest() // Avoid `[x, ..] | [x, 0]` => `[x, .. | 0]`.
+        && ps1.len() == ps2.len()
+        && over(&ps1[..idx], &ps2[..idx], |l, r| eq_pat(l, r))
+        && over(&ps1[idx + 1..], &ps2[idx + 1..], |l, r| eq_pat(l, r))
+}
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 8b971e7064b..036dd16a224 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -101,7 +101,7 @@ fn collect_unwrap_info<'a, 'tcx>(
 
     if let ExprKind::Binary(op, left, right) = &expr.kind {
         match (invert, op.node) {
-            (false, BinOpKind::And) | (false, BinOpKind::BitAnd) | (true, BinOpKind::Or) | (true, BinOpKind::BitOr) => {
+            (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) => {
                 let mut unwrap_info = collect_unwrap_info(cx, left, branch, invert);
                 unwrap_info.append(&mut collect_unwrap_info(cx, right, branch, invert));
                 return unwrap_info;
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 7fa97b24699..141035a980a 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -1,12 +1,12 @@
 use crate::utils::{
-    is_type_diagnostic_item, match_def_path, match_trait_method, paths, same_tys, snippet, snippet_with_macro_callsite,
+    is_type_diagnostic_item, match_def_path, match_trait_method, paths, snippet, snippet_with_macro_callsite,
     span_lint_and_help, span_lint_and_sugg,
 };
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, TyS};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
@@ -65,7 +65,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion {
                 if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" {
                     let a = cx.tables.expr_ty(e);
                     let b = cx.tables.expr_ty(&args[0]);
-                    if same_tys(cx, a, b) {
+                    if TyS::same_type(a, b) {
                         let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
                         span_lint_and_sugg(
                             cx,
@@ -81,7 +81,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion {
                 if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" {
                     let a = cx.tables.expr_ty(e);
                     let b = cx.tables.expr_ty(&args[0]);
-                    if same_tys(cx, a, b) {
+                    if TyS::same_type(a, b) {
                         let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
                         span_lint_and_sugg(
                             cx,
@@ -101,7 +101,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion {
                         if is_type_diagnostic_item(cx, a, sym!(result_type));
                         if let ty::Adt(_, substs) = a.kind;
                         if let Some(a_type) = substs.types().next();
-                        if same_tys(cx, a_type, b);
+                        if TyS::same_type(a_type, b);
 
                         then {
                             span_lint_and_help(
@@ -131,7 +131,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion {
                             if is_type_diagnostic_item(cx, a, sym!(result_type));
                             if let ty::Adt(_, substs) = a.kind;
                             if let Some(a_type) = substs.types().next();
-                            if same_tys(cx, a_type, b);
+                            if TyS::same_type(a_type, b);
 
                             then {
                                 let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
@@ -148,7 +148,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UselessConversion {
 
                         if_chain! {
                             if match_def_path(cx, def_id, &paths::FROM_FROM);
-                            if same_tys(cx, a, b);
+                            if TyS::same_type(a, b);
 
                             then {
                                 let sugg = snippet(cx, args[0].span.source_callsite(), "<expr>").into_owned();
diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
new file mode 100755
index 00000000000..dcf09da198e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs
@@ -0,0 +1,526 @@
+//! Utilities for manipulating and extracting information from `rustc_ast::ast`.
+//!
+//! - The `eq_foobar` functions test for semantic equality but ignores `NodeId`s and `Span`s.
+
+#![allow(clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use)]
+
+use crate::utils::{both, over};
+use rustc_ast::ast::{self, *};
+use rustc_ast::ptr::P;
+use rustc_span::symbol::Ident;
+use std::mem;
+
+/// Checks if each element in the first slice is contained within the latter as per `eq_fn`.
+pub fn unordered_over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
+    left.len() == right.len() && left.iter().all(|l| right.iter().any(|r| eq_fn(l, r)))
+}
+
+pub fn eq_id(l: Ident, r: Ident) -> bool {
+    l.name == r.name
+}
+
+pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
+    use PatKind::*;
+    match (&l.kind, &r.kind) {
+        (Paren(l), _) => eq_pat(l, r),
+        (_, Paren(r)) => eq_pat(l, r),
+        (Wild, Wild) | (Rest, Rest) => true,
+        (Lit(l), Lit(r)) => eq_expr(l, r),
+        (Ident(b1, i1, s1), Ident(b2, i2, s2)) => b1 == b2 && eq_id(*i1, *i2) && both(s1, s2, |l, r| eq_pat(l, r)),
+        (Range(lf, lt, le), Range(rf, rt, re)) => {
+            eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt) && eq_range_end(&le.node, &re.node)
+        },
+        (Box(l), Box(r))
+        | (Ref(l, Mutability::Not), Ref(r, Mutability::Not))
+        | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
+        (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
+        (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
+        (TupleStruct(lp, lfs), TupleStruct(rp, rfs)) => eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)),
+        (Struct(lp, lfs, lr), Struct(rp, rfs, rr)) => {
+            lr == rr && eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
+        },
+        (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)),
+        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
+        _ => false,
+    }
+}
+
+pub fn eq_range_end(l: &RangeEnd, r: &RangeEnd) -> bool {
+    match (l, r) {
+        (RangeEnd::Excluded, RangeEnd::Excluded) => true,
+        (RangeEnd::Included(l), RangeEnd::Included(r)) => {
+            matches!(l, RangeSyntax::DotDotEq) == matches!(r, RangeSyntax::DotDotEq)
+        },
+        _ => false,
+    }
+}
+
+pub fn eq_field_pat(l: &FieldPat, r: &FieldPat) -> bool {
+    l.is_placeholder == r.is_placeholder
+        && eq_id(l.ident, r.ident)
+        && eq_pat(&l.pat, &r.pat)
+        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
+}
+
+pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool {
+    l.position == r.position && eq_ty(&l.ty, &r.ty)
+}
+
+pub fn eq_path(l: &Path, r: &Path) -> bool {
+    over(&l.segments, &r.segments, |l, r| eq_path_seg(l, r))
+}
+
+pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool {
+    eq_id(l.ident, r.ident) && both(&l.args, &r.args, |l, r| eq_generic_args(l, r))
+}
+
+pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool {
+    match (l, r) {
+        (GenericArgs::AngleBracketed(l), GenericArgs::AngleBracketed(r)) => {
+            over(&l.args, &r.args, |l, r| eq_angle_arg(l, r))
+        },
+        (GenericArgs::Parenthesized(l), GenericArgs::Parenthesized(r)) => {
+            over(&l.inputs, &r.inputs, |l, r| eq_ty(l, r)) && eq_fn_ret_ty(&l.output, &r.output)
+        },
+        _ => false,
+    }
+}
+
+pub fn eq_angle_arg(l: &AngleBracketedArg, r: &AngleBracketedArg) -> bool {
+    match (l, r) {
+        (AngleBracketedArg::Arg(l), AngleBracketedArg::Arg(r)) => eq_generic_arg(l, r),
+        (AngleBracketedArg::Constraint(l), AngleBracketedArg::Constraint(r)) => eq_assoc_constraint(l, r),
+        _ => false,
+    }
+}
+
+pub fn eq_generic_arg(l: &GenericArg, r: &GenericArg) -> bool {
+    match (l, r) {
+        (GenericArg::Lifetime(l), GenericArg::Lifetime(r)) => eq_id(l.ident, r.ident),
+        (GenericArg::Type(l), GenericArg::Type(r)) => eq_ty(l, r),
+        (GenericArg::Const(l), GenericArg::Const(r)) => eq_expr(&l.value, &r.value),
+        _ => false,
+    }
+}
+
+pub fn eq_expr_opt(l: &Option<P<Expr>>, r: &Option<P<Expr>>) -> bool {
+    both(l, r, |l, r| eq_expr(l, r))
+}
+
+pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
+    use ExprKind::*;
+    if !over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) {
+        return false;
+    }
+    match (&l.kind, &r.kind) {
+        (Paren(l), _) => eq_expr(l, r),
+        (_, Paren(r)) => eq_expr(l, r),
+        (Err, Err) => true,
+        (Box(l), Box(r)) | (Try(l), Try(r)) | (Await(l), Await(r)) => eq_expr(l, r),
+        (Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)),
+        (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value),
+        (Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
+        (MethodCall(lc, la), MethodCall(rc, ra)) => eq_path_seg(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
+        (Binary(lo, ll, lr), Binary(ro, rl, rr)) => lo.node == ro.node && eq_expr(ll, rl) && eq_expr(lr, rr),
+        (Unary(lo, l), Unary(ro, r)) => mem::discriminant(lo) == mem::discriminant(ro) && eq_expr(l, r),
+        (Lit(l), Lit(r)) => l.kind == r.kind,
+        (Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt),
+        (Let(lp, le), Let(rp, re)) => eq_pat(lp, rp) && eq_expr(le, re),
+        (If(lc, lt, le), If(rc, rt, re)) => eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le, re),
+        (While(lc, lt, ll), While(rc, rt, rl)) => eq_label(ll, rl) && eq_expr(lc, rc) && eq_block(lt, rt),
+        (ForLoop(lp, li, lt, ll), ForLoop(rp, ri, rt, rl)) => {
+            eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt)
+        },
+        (Loop(lt, ll), Loop(rt, rl)) => eq_label(ll, rl) && eq_block(lt, rt),
+        (Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb),
+        (TryBlock(l), TryBlock(r)) => eq_block(l, r),
+        (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r),
+        (Break(ll, le), Break(rl, re)) => eq_label(ll, rl) && eq_expr_opt(le, re),
+        (Continue(ll), Continue(rl)) => eq_label(ll, rl),
+        (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2), Index(r1, r2)) => eq_expr(l1, r1) && eq_expr(l2, r2),
+        (AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv),
+        (Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp),
+        (Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, |l, r| eq_arm(l, r)),
+        (Closure(lc, la, lm, lf, lb, _), Closure(rc, ra, rm, rf, rb, _)) => {
+            lc == rc && la.is_async() == ra.is_async() && lm == rm && eq_fn_decl(lf, rf) && eq_expr(lb, rb)
+        },
+        (Async(lc, _, lb), Async(rc, _, rb)) => lc == rc && eq_block(lb, rb),
+        (Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt),
+        (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re),
+        (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
+        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
+        (Struct(lp, lfs, lb), Struct(rp, rfs, rb)) => {
+            eq_path(lp, rp) && eq_expr_opt(lb, rb) && unordered_over(lfs, rfs, |l, r| eq_field(l, r))
+        },
+        _ => false,
+    }
+}
+
+pub fn eq_field(l: &Field, r: &Field) -> bool {
+    l.is_placeholder == r.is_placeholder
+        && eq_id(l.ident, r.ident)
+        && eq_expr(&l.expr, &r.expr)
+        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
+}
+
+pub fn eq_arm(l: &Arm, r: &Arm) -> bool {
+    l.is_placeholder == r.is_placeholder
+        && eq_pat(&l.pat, &r.pat)
+        && eq_expr(&l.body, &r.body)
+        && eq_expr_opt(&l.guard, &r.guard)
+        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
+}
+
+pub fn eq_label(l: &Option<Label>, r: &Option<Label>) -> bool {
+    both(l, r, |l, r| eq_id(l.ident, r.ident))
+}
+
+pub fn eq_block(l: &Block, r: &Block) -> bool {
+    l.rules == r.rules && over(&l.stmts, &r.stmts, |l, r| eq_stmt(l, r))
+}
+
+pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool {
+    use StmtKind::*;
+    match (&l.kind, &r.kind) {
+        (Local(l), Local(r)) => {
+            eq_pat(&l.pat, &r.pat)
+                && both(&l.ty, &r.ty, |l, r| eq_ty(l, r))
+                && eq_expr_opt(&l.init, &r.init)
+                && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
+        },
+        (Item(l), Item(r)) => eq_item(l, r, eq_item_kind),
+        (Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r),
+        (Empty, Empty) => true,
+        (MacCall(l), MacCall(r)) => l.1 == r.1 && eq_mac_call(&l.0, &r.0) && over(&l.2, &r.2, |l, r| eq_attr(l, r)),
+        _ => false,
+    }
+}
+
+pub fn eq_item<K>(l: &Item<K>, r: &Item<K>, mut eq_kind: impl FnMut(&K, &K) -> bool) -> bool {
+    eq_id(l.ident, r.ident)
+        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
+        && eq_vis(&l.vis, &r.vis)
+        && eq_kind(&l.kind, &r.kind)
+}
+
+pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
+    use ItemKind::*;
+    match (l, r) {
+        (ExternCrate(l), ExternCrate(r)) => l == r,
+        (Use(l), Use(r)) => eq_use_tree(l, r),
+        (Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
+        (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
+        (Fn(ld, lf, lg, lb), Fn(rd, rf, rg, rb)) => {
+            eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
+        },
+        (Mod(l), Mod(r)) => l.inline == r.inline && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_item_kind)),
+        (ForeignMod(l), ForeignMod(r)) => {
+            both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r))
+                && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
+        },
+        (TyAlias(ld, lg, lb, lt), TyAlias(rd, rg, rb, rt)) => {
+            eq_defaultness(*ld, *rd)
+                && eq_generics(lg, rg)
+                && over(lb, rb, |l, r| eq_generic_bound(l, r))
+                && both(lt, rt, |l, r| eq_ty(l, r))
+        },
+        (Enum(le, lg), Enum(re, rg)) => {
+            over(&le.variants, &re.variants, |l, r| eq_variant(l, r)) && eq_generics(lg, rg)
+        },
+        (Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => {
+            eq_variant_data(lv, rv) && eq_generics(lg, rg)
+        },
+        (Trait(la, lu, lg, lb, li), Trait(ra, ru, rg, rb, ri)) => {
+            la == ra
+                && matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
+                && eq_generics(lg, rg)
+                && over(lb, rb, |l, r| eq_generic_bound(l, r))
+                && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
+        },
+        (TraitAlias(lg, lb), TraitAlias(rg, rb)) => eq_generics(lg, rg) && over(lb, rb, |l, r| eq_generic_bound(l, r)),
+        (
+            Impl {
+                unsafety: lu,
+                polarity: lp,
+                defaultness: ld,
+                constness: lc,
+                generics: lg,
+                of_trait: lot,
+                self_ty: lst,
+                items: li,
+            },
+            Impl {
+                unsafety: ru,
+                polarity: rp,
+                defaultness: rd,
+                constness: rc,
+                generics: rg,
+                of_trait: rot,
+                self_ty: rst,
+                items: ri,
+            },
+        ) => {
+            matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
+                && matches!(lp, ImplPolarity::Positive) == matches!(rp, ImplPolarity::Positive)
+                && eq_defaultness(*ld, *rd)
+                && matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No)
+                && eq_generics(lg, rg)
+                && both(lot, rot, |l, r| eq_path(&l.path, &r.path))
+                && eq_ty(lst, rst)
+                && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
+        },
+        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
+        (MacroDef(l), MacroDef(r)) => l.macro_rules == r.macro_rules && eq_mac_args(&l.body, &r.body),
+        _ => false,
+    }
+}
+
+pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
+    use ForeignItemKind::*;
+    match (l, r) {
+        (Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
+        (Fn(ld, lf, lg, lb), Fn(rd, rf, rg, rb)) => {
+            eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
+        },
+        (TyAlias(ld, lg, lb, lt), TyAlias(rd, rg, rb, rt)) => {
+            eq_defaultness(*ld, *rd)
+                && eq_generics(lg, rg)
+                && over(lb, rb, |l, r| eq_generic_bound(l, r))
+                && both(lt, rt, |l, r| eq_ty(l, r))
+        },
+        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
+        _ => false,
+    }
+}
+
+pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
+    use AssocItemKind::*;
+    match (l, r) {
+        (Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
+        (Fn(ld, lf, lg, lb), Fn(rd, rf, rg, rb)) => {
+            eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
+        },
+        (TyAlias(ld, lg, lb, lt), TyAlias(rd, rg, rb, rt)) => {
+            eq_defaultness(*ld, *rd)
+                && eq_generics(lg, rg)
+                && over(lb, rb, |l, r| eq_generic_bound(l, r))
+                && both(lt, rt, |l, r| eq_ty(l, r))
+        },
+        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
+        _ => false,
+    }
+}
+
+pub fn eq_variant(l: &Variant, r: &Variant) -> bool {
+    l.is_placeholder == r.is_placeholder
+        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
+        && eq_vis(&l.vis, &r.vis)
+        && eq_id(l.ident, r.ident)
+        && eq_variant_data(&l.data, &r.data)
+        && both(&l.disr_expr, &r.disr_expr, |l, r| eq_expr(&l.value, &r.value))
+}
+
+pub fn eq_variant_data(l: &VariantData, r: &VariantData) -> bool {
+    use VariantData::*;
+    match (l, r) {
+        (Unit(_), Unit(_)) => true,
+        (Struct(l, _), Struct(r, _)) | (Tuple(l, _), Tuple(r, _)) => over(l, r, |l, r| eq_struct_field(l, r)),
+        _ => false,
+    }
+}
+
+pub fn eq_struct_field(l: &StructField, r: &StructField) -> bool {
+    l.is_placeholder == r.is_placeholder
+        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
+        && eq_vis(&l.vis, &r.vis)
+        && both(&l.ident, &r.ident, |l, r| eq_id(*l, *r))
+        && eq_ty(&l.ty, &r.ty)
+}
+
+pub fn eq_fn_sig(l: &FnSig, r: &FnSig) -> bool {
+    eq_fn_decl(&l.decl, &r.decl) && eq_fn_header(&l.header, &r.header)
+}
+
+pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
+    matches!(l.unsafety, Unsafe::No) == matches!(r.unsafety, Unsafe::No)
+        && l.asyncness.is_async() == r.asyncness.is_async()
+        && matches!(l.constness, Const::No) == matches!(r.constness, Const::No)
+        && eq_ext(&l.ext, &r.ext)
+}
+
+pub fn eq_generics(l: &Generics, r: &Generics) -> bool {
+    over(&l.params, &r.params, |l, r| eq_generic_param(l, r))
+        && over(&l.where_clause.predicates, &r.where_clause.predicates, |l, r| {
+            eq_where_predicate(l, r)
+        })
+}
+
+pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool {
+    use WherePredicate::*;
+    match (l, r) {
+        (BoundPredicate(l), BoundPredicate(r)) => {
+            over(&l.bound_generic_params, &r.bound_generic_params, |l, r| {
+                eq_generic_param(l, r)
+            }) && eq_ty(&l.bounded_ty, &r.bounded_ty)
+                && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r))
+        },
+        (RegionPredicate(l), RegionPredicate(r)) => {
+            eq_id(l.lifetime.ident, r.lifetime.ident) && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r))
+        },
+        (EqPredicate(l), EqPredicate(r)) => eq_ty(&l.lhs_ty, &r.lhs_ty) && eq_ty(&l.rhs_ty, &r.rhs_ty),
+        _ => false,
+    }
+}
+
+pub fn eq_use_tree(l: &UseTree, r: &UseTree) -> bool {
+    eq_path(&l.prefix, &r.prefix) && eq_use_tree_kind(&l.kind, &r.kind)
+}
+
+pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
+    use UseTreeKind::*;
+    match (l, r) {
+        (Glob, Glob) => true,
+        (Simple(l, _, _), Simple(r, _, _)) => both(l, r, |l, r| eq_id(*l, *r)),
+        (Nested(l), Nested(r)) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)),
+        _ => false,
+    }
+}
+
+pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
+    match (l, r) {
+        (Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_)) => true,
+        _ => false,
+    }
+}
+
+pub fn eq_vis(l: &Visibility, r: &Visibility) -> bool {
+    use VisibilityKind::*;
+    match (&l.node, &r.node) {
+        (Public, Public) | (Inherited, Inherited) | (Crate(_), Crate(_)) => true,
+        (Restricted { path: l, .. }, Restricted { path: r, .. }) => eq_path(l, r),
+        _ => false,
+    }
+}
+
+pub fn eq_fn_decl(l: &FnDecl, r: &FnDecl) -> bool {
+    eq_fn_ret_ty(&l.output, &r.output)
+        && over(&l.inputs, &r.inputs, |l, r| {
+            l.is_placeholder == r.is_placeholder
+                && eq_pat(&l.pat, &r.pat)
+                && eq_ty(&l.ty, &r.ty)
+                && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
+        })
+}
+
+pub fn eq_fn_ret_ty(l: &FnRetTy, r: &FnRetTy) -> bool {
+    match (l, r) {
+        (FnRetTy::Default(_), FnRetTy::Default(_)) => true,
+        (FnRetTy::Ty(l), FnRetTy::Ty(r)) => eq_ty(l, r),
+        _ => false,
+    }
+}
+
+pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
+    use TyKind::*;
+    match (&l.kind, &r.kind) {
+        (Paren(l), _) => eq_ty(l, r),
+        (_, Paren(r)) => eq_ty(l, r),
+        (Never, Never) | (Infer, Infer) | (ImplicitSelf, ImplicitSelf) | (Err, Err) | (CVarArgs, CVarArgs) => true,
+        (Slice(l), Slice(r)) => eq_ty(l, r),
+        (Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value),
+        (Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty),
+        (Rptr(ll, l), Rptr(rl, r)) => {
+            both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
+        },
+        (BareFn(l), BareFn(r)) => {
+            l.unsafety == r.unsafety
+                && eq_ext(&l.ext, &r.ext)
+                && over(&l.generic_params, &r.generic_params, |l, r| eq_generic_param(l, r))
+                && eq_fn_decl(&l.decl, &r.decl)
+        },
+        (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
+        (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
+        (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, |l, r| eq_generic_bound(l, r)),
+        (ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, |l, r| eq_generic_bound(l, r)),
+        (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
+        (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
+        _ => false,
+    }
+}
+
+pub fn eq_ext(l: &Extern, r: &Extern) -> bool {
+    use Extern::*;
+    match (l, r) {
+        (None, None) | (Implicit, Implicit) => true,
+        (Explicit(l), Explicit(r)) => eq_str_lit(l, r),
+        _ => false,
+    }
+}
+
+pub fn eq_str_lit(l: &StrLit, r: &StrLit) -> bool {
+    l.style == r.style && l.symbol == r.symbol && l.suffix == r.suffix
+}
+
+pub fn eq_poly_ref_trait(l: &PolyTraitRef, r: &PolyTraitRef) -> bool {
+    eq_path(&l.trait_ref.path, &r.trait_ref.path)
+        && over(&l.bound_generic_params, &r.bound_generic_params, |l, r| {
+            eq_generic_param(l, r)
+        })
+}
+
+pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
+    use GenericParamKind::*;
+    l.is_placeholder == r.is_placeholder
+        && eq_id(l.ident, r.ident)
+        && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r))
+        && match (&l.kind, &r.kind) {
+            (Lifetime, Lifetime) => true,
+            (Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)),
+            (Const { ty: l }, Const { ty: r }) => eq_ty(l, r),
+            _ => false,
+        }
+        && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
+}
+
+pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
+    use GenericBound::*;
+    match (l, r) {
+        (Trait(ptr1, tbm1), Trait(ptr2, tbm2)) => tbm1 == tbm2 && eq_poly_ref_trait(ptr1, ptr2),
+        (Outlives(l), Outlives(r)) => eq_id(l.ident, r.ident),
+        _ => false,
+    }
+}
+
+pub fn eq_assoc_constraint(l: &AssocTyConstraint, r: &AssocTyConstraint) -> bool {
+    use AssocTyConstraintKind::*;
+    eq_id(l.ident, r.ident)
+        && match (&l.kind, &r.kind) {
+            (Equality { ty: l }, Equality { ty: r }) => eq_ty(l, r),
+            (Bound { bounds: l }, Bound { bounds: r }) => over(l, r, |l, r| eq_generic_bound(l, r)),
+            _ => false,
+        }
+}
+
+pub fn eq_mac_call(l: &MacCall, r: &MacCall) -> bool {
+    eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args)
+}
+
+pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool {
+    use AttrKind::*;
+    l.style == r.style
+        && match (&l.kind, &r.kind) {
+            (DocComment(l), DocComment(r)) => l == r,
+            (Normal(l), Normal(r)) => eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args),
+            _ => false,
+        }
+}
+
+pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool {
+    use MacArgs::*;
+    match (l, r) {
+        (Empty, Empty) => true,
+        (Delimited(_, ld, lts), Delimited(_, rd, rts)) => ld == rd && lts.eq_unspanned(rts),
+        (Eq(_, lts), Eq(_, rts)) => lts.eq_unspanned(rts),
+        _ => false,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
index 92c27e79452..f8d197c15e8 100644
--- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs
@@ -332,19 +332,13 @@ fn swap_binop<'a>(
 
 /// Checks if the two `Option`s are both `None` or some equal values as per
 /// `eq_fn`.
-fn both<X, F>(l: &Option<X>, r: &Option<X>, mut eq_fn: F) -> bool
-where
-    F: FnMut(&X, &X) -> bool,
-{
+pub fn both<X>(l: &Option<X>, r: &Option<X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
     l.as_ref()
         .map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y)))
 }
 
 /// Checks if two slices are equal as per `eq_fn`.
-fn over<X, F>(left: &[X], right: &[X], mut eq_fn: F) -> bool
-where
-    F: FnMut(&X, &X) -> bool,
-{
+pub fn over<X>(left: &[X], right: &[X], mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
     left.len() == right.len() && left.iter().zip(right).all(|(x, y)| eq_fn(x, y))
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 6dd8fef7e82..7b59917c2bb 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -1,6 +1,8 @@
 #[macro_use]
 pub mod sym;
 
+#[allow(clippy::module_name_repetitions)]
+pub mod ast_utils;
 pub mod attrs;
 pub mod author;
 pub mod camel_case;
@@ -19,7 +21,7 @@ pub mod sugg;
 pub mod usage;
 pub use self::attrs::*;
 pub use self::diagnostics::*;
-pub use self::hir_utils::{SpanlessEq, SpanlessHash};
+pub use self::hir_utils::{both, over, SpanlessEq, SpanlessHash};
 
 use std::borrow::Cow;
 use std::mem;
@@ -40,7 +42,7 @@ use rustc_hir::{
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::map::Map;
-use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Binder, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Ty, TyCtxt, TypeFoldable};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::symbol::{self, kw, Symbol};
@@ -72,7 +74,7 @@ pub fn in_constant(cx: &LateContext<'_, '_>, id: HirId) -> bool {
     let parent_id = cx.tcx.hir().get_parent_item(id);
     match cx.tcx.hir().get(parent_id) {
         Node::Item(&Item {
-            kind: ItemKind::Const(..),
+            kind: ItemKind::Const(..) | ItemKind::Static(..),
             ..
         })
         | Node::TraitItem(&TraitItem {
@@ -83,11 +85,7 @@ pub fn in_constant(cx: &LateContext<'_, '_>, id: HirId) -> bool {
             kind: ImplItemKind::Const(..),
             ..
         })
-        | Node::AnonConst(_)
-        | Node::Item(&Item {
-            kind: ItemKind::Static(..),
-            ..
-        }) => true,
+        | Node::AnonConst(_) => true,
         Node::Item(&Item {
             kind: ItemKind::Fn(ref sig, ..),
             ..
@@ -165,8 +163,8 @@ pub fn match_trait_method(cx: &LateContext<'_, '_>, expr: &Expr<'_>, path: &[&st
 /// Checks if an expression references a variable of the given name.
 pub fn match_var(expr: &Expr<'_>, var: Name) -> bool {
     if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
-        if path.segments.len() == 1 && path.segments[0].ident.name == var {
-            return true;
+        if let [p] = path.segments {
+            return p.ident.name == var;
         }
     }
     false
@@ -181,8 +179,7 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
 
 pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
     match *path {
-        QPath::Resolved(_, ref path) if path.segments.len() == 1 => Some(&path.segments[0]),
-        QPath::Resolved(..) => None,
+        QPath::Resolved(_, ref path) => path.segments.get(0),
         QPath::TypeRelative(_, ref seg) => Some(seg),
     }
 }
@@ -201,9 +198,12 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
         QPath::Resolved(_, ref path) => match_path(path, segments),
         QPath::TypeRelative(ref ty, ref segment) => match ty.kind {
             TyKind::Path(ref inner_path) => {
-                !segments.is_empty()
-                    && match_qpath(inner_path, &segments[..(segments.len() - 1)])
-                    && segment.ident.name.as_str() == segments[segments.len() - 1]
+                if let [prefix @ .., end] = segments {
+                    if match_qpath(inner_path, prefix) {
+                        return segment.ident.name.as_str() == *end;
+                    }
+                }
+                false
             },
             _ => false,
         },
@@ -398,7 +398,7 @@ pub fn method_calls<'tcx>(
 /// Matches an `Expr` against a chain of methods, and return the matched `Expr`s.
 ///
 /// For example, if `expr` represents the `.baz()` in `foo.bar().baz()`,
-/// `matched_method_chain(expr, &["bar", "baz"])` will return a `Vec`
+/// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec`
 /// containing the `Expr`s for
 /// `.bar()` and `.baz()`
 pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec<&'a [Expr<'a>]>> {
@@ -882,20 +882,6 @@ pub fn return_ty<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, fn_item: hir::HirId) -> T
     cx.tcx.erase_late_bound_regions(&ret_ty)
 }
 
-/// Checks if two types are the same.
-///
-/// This discards any lifetime annotations, too.
-//
-// FIXME: this works correctly for lifetimes bounds (`for <'a> Foo<'a>` ==
-// `for <'b> Foo<'b>`, but not for type parameters).
-pub fn same_tys<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
-    let a = cx.tcx.erase_late_bound_regions(&Binder::bind(a));
-    let b = cx.tcx.erase_late_bound_regions(&Binder::bind(b));
-    cx.tcx
-        .infer_ctxt()
-        .enter(|infcx| infcx.can_eq(cx.param_env, a, b).is_ok())
-}
-
 /// Returns `true` if the given type is an `unsafe` function.
 pub fn type_is_unsafe_function<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.kind {
@@ -1408,6 +1394,24 @@ pub fn run_lints(cx: &LateContext<'_, '_>, lints: &[&'static Lint], id: HirId) -
     })
 }
 
+#[macro_export]
+macro_rules! unwrap_cargo_metadata {
+    ($cx: ident, $lint: ident, $deps: expr) => {{
+        let mut command = cargo_metadata::MetadataCommand::new();
+        if !$deps {
+            command.no_deps();
+        }
+
+        match command.exec() {
+            Ok(metadata) => metadata,
+            Err(err) => {
+                span_lint($cx, $lint, DUMMY_SP, &format!("could not read cargo metadata: {}", err));
+                return;
+            },
+        }
+    }};
+}
+
 #[cfg(test)]
 mod test {
     use super::{trim_multiline, without_block_comments};
diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs
index 779da7e6bf2..3b7e9739211 100644
--- a/src/tools/clippy/clippy_lints/src/utils/paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs
@@ -138,5 +138,6 @@ pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
 pub const VEC_DEQUE: [&str; 4] = ["alloc", "collections", "vec_deque", "VecDeque"];
 pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
 pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
+pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
 pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
 pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 1174f421577..a8d4c7620b1 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -17,8 +17,14 @@ declare_clippy_lint! {
     /// **Known problems:** None.
     ///
     /// **Example:**
-    /// ```rust,ignore
-    /// foo(&vec![1, 2])
+    /// ```rust
+    /// # fn foo(my_vec: &[u8]) {}
+    ///
+    /// // Bad
+    /// foo(&vec![1, 2]);
+    ///
+    /// // Good
+    /// foo(&[1, 2]);
     /// ```
     pub USELESS_VEC,
     perf,
diff --git a/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
new file mode 100644
index 00000000000..86cbfa8203d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/vec_resize_to_zero.rs
@@ -0,0 +1,59 @@
+use crate::utils::span_lint_and_then;
+use if_chain::if_chain;
+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_span::source_map::Spanned;
+
+use crate::utils::{match_def_path, paths};
+use rustc_ast::ast::LitKind;
+use rustc_hir as hir;
+
+declare_clippy_lint! {
+    /// **What it does:** Finds occurences of `Vec::resize(0, an_int)`
+    ///
+    /// **Why is this bad?** This is probably an argument inversion mistake.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// vec!(1, 2, 3, 4, 5).resize(0, 5)
+    /// ```
+    pub VEC_RESIZE_TO_ZERO,
+    correctness,
+    "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake"
+}
+
+declare_lint_pass!(VecResizeToZero => [VEC_RESIZE_TO_ZERO]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VecResizeToZero {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
+        if_chain! {
+            if let hir::ExprKind::MethodCall(path_segment, _, ref args) = expr.kind;
+            if let Some(method_def_id) = cx.tables.type_dependent_def_id(expr.hir_id);
+            if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3;
+            if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind;
+            if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = args[2].kind;
+            then {
+                let method_call_span = expr.span.with_lo(path_segment.ident.span.lo());
+                span_lint_and_then(
+                    cx,
+                    VEC_RESIZE_TO_ZERO,
+                    expr.span,
+                    "emptying a vector with `resize`",
+                    |db| {
+                        db.help("the arguments may be inverted...");
+                        db.span_suggestion(
+                            method_call_span,
+                            "...or you can empty the vector with",
+                            "clear()".to_string(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    },
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
index 4d8d4438d88..7247518e19b 100644
--- a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
+++ b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
@@ -9,6 +9,7 @@ declare_clippy_lint! {
     ///
     /// **Why is this bad?** `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values.
     /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html)
+    ///
     /// **Known problems:** None.
     ///
     /// **Example:**
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs b/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs
index d8d48eb1535..511518082be 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_dependencies.rs
@@ -34,12 +34,7 @@ impl LateLintPass<'_, '_> for WildcardDependencies {
             return;
         }
 
-        let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().no_deps().exec() {
-            metadata
-        } else {
-            span_lint(cx, WILDCARD_DEPENDENCIES, DUMMY_SP, "could not read cargo metadata");
-            return;
-        };
+        let metadata = unwrap_cargo_metadata!(cx, WILDCARD_DEPENDENCIES, false);
 
         for dep in &metadata.packages[0].dependencies {
             // VersionReq::any() does not work
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 32d9a45c37d..b637253bd02 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -19,8 +19,14 @@ declare_clippy_lint! {
     /// still around.
     ///
     /// **Example:**
-    /// ```rust
+    /// ```rust,ignore
+    /// // Bad
     /// use std::cmp::Ordering::*;
+    /// foo(Less);
+    ///
+    /// // Good
+    /// use std::cmp::Ordering;
+    /// foo(Ordering::Less)
     /// ```
     pub ENUM_GLOB_USE,
     pedantic,
@@ -60,15 +66,15 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     ///
-    /// Bad:
     /// ```rust,ignore
+    /// // Bad
     /// use crate1::*;
     ///
     /// foo();
     /// ```
     ///
-    /// Good:
     /// ```rust,ignore
+    /// // Good
     /// use crate1::foo;
     ///
     /// foo();
diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
index fb4700d8743..0820385e01b 100644
--- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
@@ -14,7 +14,11 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust
-    /// 0.0f32 / 0.0;
+    /// // Bad
+    /// let nan = 0.0f32 / 0.0;
+    ///
+    /// // Good
+    /// let nan = f32::NAN;
     /// ```
     pub ZERO_DIVIDED_BY_ZERO,
     complexity,
diff --git a/src/tools/clippy/doc/changelog_update.md b/src/tools/clippy/doc/changelog_update.md
index 0b80cce6d23..49726464957 100644
--- a/src/tools/clippy/doc/changelog_update.md
+++ b/src/tools/clippy/doc/changelog_update.md
@@ -18,7 +18,7 @@ been very rare that Clippy changes were included in a patch release.
 
 ### 1. Finding the relevant Clippy commits
 
-Each Rust release ships with its own version of Clippy. The Clippy submodule can
+Each Rust release ships with its own version of Clippy. The Clippy subtree can
 be found in the `tools` directory of the Rust repository.
 
 Depending on the current time and what exactly you want to update, the following
@@ -32,8 +32,10 @@ bullet points might be helpful:
   need to select the Rust release tag from the dropdown and then check the
   commit of the Clippy directory:
 
-  ![Explanation of how to find the commit hash](https://user-images.githubusercontent.com/2042399/62846160-1f8b0480-bcce-11e9-9da8-7964ca034e7a.png)
-
+To find the commit hash, issue the following command when in a `rust-lang/rust` checkout:
+```
+git log --oneline -- src/tools/clippy/ | grep -o "Merge commit '[a-f0-9]*' into .*" | head -1 | sed -e "s/Merge commit '\([a-f0-9]*\)' into .*/\1/g"
+```
 
 ### 2. Fetching the PRs between those commits
 
@@ -74,5 +76,5 @@ relevant commit ranges.
 
 [changelog]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md
 [forge]: https://forge.rust-lang.org/
-[rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools
-[rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools
+[rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy
+[rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy
diff --git a/src/tools/clippy/doc/common_tools_writing_lints.md b/src/tools/clippy/doc/common_tools_writing_lints.md
index ed33b37c6bd..dbc43450594 100644
--- a/src/tools/clippy/doc/common_tools_writing_lints.md
+++ b/src/tools/clippy/doc/common_tools_writing_lints.md
@@ -4,7 +4,9 @@ You may need following tooltips to catch up with common operations.
 
 - [Common tools for writing lints](#common-tools-for-writing-lints)
   - [Retrieving the type of an expression](#retrieving-the-type-of-an-expression)
+  - [Checking if an expression is calling a specific method](#checking-if-an-expr-is-calling-a-specific-method)
   - [Checking if a type implements a specific trait](#checking-if-a-type-implements-a-specific-trait)
+  - [Checking if a type defines a method](#checking-if-a-type-defines-a-method)
   - [Dealing with macros](#dealing-with-macros)
 
 Useful Rustc dev guide links:
@@ -49,6 +51,26 @@ Two noticeable items here:
 - `tables` is [`TypeckTables`][TypeckTables] and is created by type checking step, 
   it includes useful information such as types of expressions, ways to resolve methods and so on.
 
+# Checking if an expr is calling a specific method
+
+Starting with an `expr`, you can check whether it is calling a specific method `some_method`:
+
+```rust
+impl LateLintPass<'_, '_> for MyStructLint {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr<'_>) {
+        if_chain! {
+            // Check our expr is calling a method
+            if let hir::ExprKind::MethodCall(path, _, _args) = &expr.kind;
+            // Check the name of this method is `some_method`
+            if path.ident.name == sym!(some_method);
+            then {
+                // ...
+            }
+        }
+    }
+}
+```
+
 # Checking if a type implements a specific trait
 
 There are two ways to do this, depending if the target trait is part of lang items.
@@ -83,6 +105,32 @@ A list of defined paths for Clippy can be found in [paths.rs][paths]
 
 We access lang items through the type context `tcx`. `tcx` is of type [`TyCtxt`][TyCtxt] and is defined in the `rustc_middle` crate.
 
+# Checking if a type defines a specific method
+
+To check if our type defines a method called `some_method`:
+
+```rust
+use crate::utils::{is_type_diagnostic_item, return_ty};
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MyTypeImpl {
+    fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, impl_item: &'tcx ImplItem<'_>) {
+        if_chain! {
+            // Check if item is a method/function
+            if let ImplItemKind::Fn(ref signature, _) = impl_item.kind;
+            // Check the method is named `some_method`
+            if impl_item.ident.name == sym!(some_method);
+            // We can also check it has a parameter `self`
+            if signature.decl.implicit_self.has_implicit_self();
+            // We can go further and even check if its return type is `String`
+            if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(string_type));
+            then {
+                // ...
+            }
+        }
+    }
+}
+```
+
 # Dealing with macros
 
 There are several helpers in Clippy's utils to deal with macros:
diff --git a/src/tools/clippy/doc/release.md b/src/tools/clippy/doc/release.md
index 9d69fa8a7f6..391952ea6b1 100644
--- a/src/tools/clippy/doc/release.md
+++ b/src/tools/clippy/doc/release.md
@@ -7,11 +7,11 @@ Clippy is released together with stable Rust releases. The dates for these
 releases can be found at the [Rust Forge]. This document explains the necessary
 steps to create a Clippy release.
 
-1. [Find the Clippy commit](#find-the-clippy-commit)
-2. [Tag the stable commit](#tag-the-stable-commit)
-3. [Update `CHANGELOG.md`](#update-changelogmd)
-4. [Remerge the `beta` branch](#remerge-the-beta-branch)
-5. [Update the `beta` branch](#update-the-beta-branch)
+1. [Remerge the `beta` branch](#remerge-the-beta-branch)
+2. [Update the `beta` branch](#update-the-beta-branch)
+3. [Find the Clippy commit](#find-the-clippy-commit)
+4. [Tag the stable commit](#tag-the-stable-commit)
+5. [Update `CHANGELOG.md`](#update-changelogmd)
 
 _NOTE: This document is for stable Rust releases, not for point releases. For
 point releases, step 1. and 2. should be enough._
@@ -19,43 +19,6 @@ point releases, step 1. and 2. should be enough._
 [Rust Forge]: https://forge.rust-lang.org/
 
 
-## Find the Clippy commit
-
-The first step is to tag the Clippy commit, that is included in the stable Rust
-release. This commit can be found in the Rust repository.
-
-```bash
-# Assuming the current directory corresponds to the Rust repository
-$ git fetch upstream    # `upstream` is the `rust-lang/rust` remote
-$ git checkout 1.XX.0   # XX should be exchanged with the corresponding version
-$ git submodule update
-$ SHA=$(git submodule status src/tools/clippy | awk '{print $1}')
-```
-
-
-## Tag the stable commit
-
-After finding the Clippy commit, it can be tagged with the release number.
-
-```bash
-# Assuming the current directory corresponds to the Clippy repository
-$ git checkout $SHA
-$ git tag rust-1.XX.0               # XX should be exchanged with the corresponding version
-$ git push upstream master --tags   # `upstream` is the `rust-lang/rust-clippy` remote
-```
-
-After this, the release should be available on the Clippy [release page].
-
-[release page]: https://github.com/rust-lang/rust-clippy/releases
-
-
-## Update `CHANGELOG.md`
-
-For this see the document on [how to update the changelog].
-
-[how to update the changelog]: https://github.com/rust-lang/rust-clippy/blob/master/doc/changelog_update.md
-
-
 ## Remerge the `beta` branch
 
 This step is only necessary, if since the last release something was backported
@@ -76,7 +39,7 @@ If this command outputs `master`, this step is **not** necessary.
 ```bash
 # Assuming `HEAD` is the current `master` branch of rust-lang/rust-clippy
 $ git checkout -b backport_remerge
-$ git merge beta
+$ git merge upstream/beta
 $ git diff  # This diff has to be empty, otherwise something with the remerge failed
 $ git push origin backport_remerge  # This can be pushed to your fork
 ```
@@ -96,8 +59,7 @@ determined.
 ```bash
 # Assuming the current directory corresponds to the Rust repository
 $ git checkout beta
-$ git submodule update
-$ BETA_SHA=$(git submodule status src/tools/clippy | awk '{print $1}')
+$ BETA_SHA=$(git log --oneline -- src/tools/clippy/ | grep -o "Merge commit '[a-f0-9]*' into .*" | head -1 | sed -e "s/Merge commit '\([a-f0-9]*\)' into .*/\1/g")
 ```
 
 After finding the Clippy commit, the `beta` branch in the Clippy repository can
@@ -109,3 +71,39 @@ $ git checkout beta
 $ git rebase $BETA_SHA
 $ git push upstream beta
 ```
+
+
+## Find the Clippy commit
+
+The first step is to tag the Clippy commit, that is included in the stable Rust
+release. This commit can be found in the Rust repository.
+
+```bash
+# Assuming the current directory corresponds to the Rust repository
+$ git fetch upstream    # `upstream` is the `rust-lang/rust` remote
+$ git checkout 1.XX.0   # XX should be exchanged with the corresponding version
+$ SHA=$(git log --oneline -- src/tools/clippy/ | grep -o "Merge commit '[a-f0-9]*' into .*" | head -1 | sed -e "s/Merge commit '\([a-f0-9]*\)' into .*/\1/g")
+```
+
+
+## Tag the stable commit
+
+After finding the Clippy commit, it can be tagged with the release number.
+
+```bash
+# Assuming the current directory corresponds to the Clippy repository
+$ git checkout $SHA
+$ git tag rust-1.XX.0               # XX should be exchanged with the corresponding version
+$ git push upstream master --tags   # `upstream` is the `rust-lang/rust-clippy` remote
+```
+
+After this, the release should be available on the Clippy [release page].
+
+[release page]: https://github.com/rust-lang/rust-clippy/releases
+
+
+## Update `CHANGELOG.md`
+
+For this see the document on [how to update the changelog].
+
+[how to update the changelog]: https://github.com/rust-lang/rust-clippy/blob/master/doc/changelog_update.md
diff --git a/src/tools/clippy/src/lintlist/mod.rs b/src/tools/clippy/src/lintlist/mod.rs
index f63301c7db0..cac3cc6bdb3 100644
--- a/src/tools/clippy/src/lintlist/mod.rs
+++ b/src/tools/clippy/src/lintlist/mod.rs
@@ -166,7 +166,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
     },
     Lint {
         name: "cast_ptr_alignment",
-        group: "correctness",
+        group: "pedantic",
         desc: "cast from a pointer to a more-strictly-aligned pointer",
         deprecation: None,
         module: "types",
@@ -935,6 +935,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "loops",
     },
     Lint {
+        name: "iter_next_slice",
+        group: "style",
+        desc: "using `.iter().next()` on a sliced array, which can be shortened to just `.get()`",
+        deprecation: None,
+        module: "methods",
+    },
+    Lint {
         name: "iter_nth",
         group: "perf",
         desc: "using `.iter().nth()` on a standard library type with O(1) element access",
@@ -1016,7 +1023,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         group: "style",
         desc: "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block",
         deprecation: None,
-        module: "returns",
+        module: "let_and_return",
     },
     Lint {
         name: "let_underscore_lock",
@@ -1735,7 +1742,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
     Lint {
         name: "pub_enum_variant_names",
         group: "pedantic",
-        desc: "enums where all variants share a prefix/postfix",
+        desc: "public enums where all variants share a prefix/postfix",
         deprecation: None,
         module: "enum_variants",
     },
@@ -2293,6 +2300,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "no_effect",
     },
     Lint {
+        name: "unnecessary_sort_by",
+        group: "complexity",
+        desc: "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer",
+        deprecation: None,
+        module: "unnecessary_sort_by",
+    },
+    Lint {
         name: "unnecessary_unwrap",
         group: "complexity",
         desc: "checks for calls of `unwrap[_err]()` that cannot fail",
@@ -2314,6 +2328,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "misc_early",
     },
     Lint {
+        name: "unnested_or_patterns",
+        group: "complexity",
+        desc: "unnested or-patterns, e.g., `Foo(Bar) | Foo(Baz) instead of `Foo(Bar | Baz)`",
+        deprecation: None,
+        module: "unnested_or_patterns",
+    },
+    Lint {
         name: "unreachable",
         group: "restriction",
         desc: "`unreachable!` should not be present in production code",
@@ -2461,6 +2482,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "types",
     },
     Lint {
+        name: "vec_resize_to_zero",
+        group: "correctness",
+        desc: "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake",
+        deprecation: None,
+        module: "vec_resize_to_zero",
+    },
+    Lint {
         name: "verbose_bit_mask",
         group: "style",
         desc: "expressions where a bit mask is less readable than the corresponding method call",
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 1c4914a470c..f28aedbf0ab 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -184,8 +184,15 @@ fn run_ui_cargo(config: &mut compiletest::Config) {
                 }
 
                 let src_path = case.path().join("src");
-                env::set_current_dir(&src_path)?;
 
+                // When switching between branches, if the previous branch had a test
+                // that the current branch does not have, the directory is not removed
+                // because an ignored Cargo.lock file exists.
+                if !src_path.exists() {
+                    continue;
+                }
+
+                env::set_current_dir(&src_path)?;
                 for file in fs::read_dir(&src_path)? {
                     let file = file?;
                     if file.file_type()?.is_dir() {
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml
index c64adcf7c01..ae0a6032996 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/Cargo.toml
@@ -2,3 +2,5 @@
 name = "cargo_common_metadata"
 version = "0.1.0"
 publish = false
+
+[workspace]
diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml
index c8233f328bb..737e84e963c 100644
--- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml
+++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/Cargo.toml
@@ -9,3 +9,5 @@ readme = "README.md"
 license = "MIT OR Apache-2.0"
 keywords = ["metadata", "lint", "clippy"]
 categories = ["development-tools::testing"]
+
+[workspace]
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml
index 72731fbc75d..278bebbbd9e 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/Cargo.toml
@@ -5,6 +5,8 @@ name = "multiple_crate_versions"
 version = "0.1.0"
 publish = false
 
+[workspace]
+
 # One of the versions of winapi is only a dev dependency: allowed
 [dependencies]
 ctrlc = "=3.1.0"
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml
index 3a94b723f3f..4f97b011334 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/Cargo.toml
@@ -3,6 +3,8 @@ name = "multiple_crate_versions"
 version = "0.1.0"
 publish = false
 
+[workspace]
+
 [dependencies]
 ctrlc = "=3.1.0"
 ansi_term = "=0.11.0"
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml
index a9b06420b33..b4b49bb369a 100644
--- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml
+++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/Cargo.toml
@@ -3,6 +3,8 @@ name = "cargo_common_metadata"
 version = "0.1.0"
 publish = false
 
+[workspace]
+
 [dependencies]
 regex = "1.3.7"
 serde = "1.0.110"
diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml
index fd2a3414856..3e1a02cbb3c 100644
--- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml
+++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/Cargo.toml
@@ -3,5 +3,7 @@ name = "wildcard_dependencies"
 version = "0.1.0"
 publish = false
 
+[workspace]
+
 [dependencies]
 regex = "*"
diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml
index 38cb139146e..f844cab09ba 100644
--- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml
+++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/Cargo.toml
@@ -3,5 +3,7 @@ name = "wildcard_dependencies"
 version = "0.1.0"
 publish = false
 
+[workspace]
+
 [dependencies]
 regex = "1"
diff --git a/src/tools/clippy/tests/ui/checked_conversions.fixed b/src/tools/clippy/tests/ui/checked_conversions.fixed
index 7febd6f3761..12290db3dcf 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.fixed
+++ b/src/tools/clippy/tests/ui/checked_conversions.fixed
@@ -1,106 +1,76 @@
 // run-rustfix
 
+#![allow(
+    clippy::cast_lossless,
+    // Int::max_value will be deprecated in the future
+    deprecated,
+)]
 #![warn(clippy::checked_conversions)]
-#![allow(clippy::cast_lossless)]
-#![allow(dead_code)]
+
 use std::convert::TryFrom;
 
 // Positive tests
 
 // Signed to unsigned
 
-fn i64_to_u32(value: i64) -> Option<u32> {
-    if u32::try_from(value).is_ok() {
-        Some(value as u32)
-    } else {
-        None
-    }
+pub fn i64_to_u32(value: i64) {
+    let _ = u32::try_from(value).is_ok();
+    let _ = u32::try_from(value).is_ok();
 }
 
-fn i64_to_u16(value: i64) -> Option<u16> {
-    if u16::try_from(value).is_ok() {
-        Some(value as u16)
-    } else {
-        None
-    }
+pub fn i64_to_u16(value: i64) {
+    let _ = u16::try_from(value).is_ok();
+    let _ = u16::try_from(value).is_ok();
 }
 
-fn isize_to_u8(value: isize) -> Option<u8> {
-    if u8::try_from(value).is_ok() {
-        Some(value as u8)
-    } else {
-        None
-    }
+pub fn isize_to_u8(value: isize) {
+    let _ = u8::try_from(value).is_ok();
+    let _ = u8::try_from(value).is_ok();
 }
 
 // Signed to signed
 
-fn i64_to_i32(value: i64) -> Option<i32> {
-    if i32::try_from(value).is_ok() {
-        Some(value as i32)
-    } else {
-        None
-    }
+pub fn i64_to_i32(value: i64) {
+    let _ = i32::try_from(value).is_ok();
+    let _ = i32::try_from(value).is_ok();
 }
 
-fn i64_to_i16(value: i64) -> Option<i16> {
-    if i16::try_from(value).is_ok() {
-        Some(value as i16)
-    } else {
-        None
-    }
+pub fn i64_to_i16(value: i64) {
+    let _ = i16::try_from(value).is_ok();
+    let _ = i16::try_from(value).is_ok();
 }
 
 // Unsigned to X
 
-fn u32_to_i32(value: u32) -> Option<i32> {
-    if i32::try_from(value).is_ok() {
-        Some(value as i32)
-    } else {
-        None
-    }
+pub fn u32_to_i32(value: u32) {
+    let _ = i32::try_from(value).is_ok();
+    let _ = i32::try_from(value).is_ok();
 }
 
-fn usize_to_isize(value: usize) -> isize {
-    if isize::try_from(value).is_ok() && value as i32 == 5 {
-        5
-    } else {
-        1
-    }
+pub fn usize_to_isize(value: usize) {
+    let _ = isize::try_from(value).is_ok() && value as i32 == 5;
+    let _ = isize::try_from(value).is_ok() && value as i32 == 5;
 }
 
-fn u32_to_u16(value: u32) -> isize {
-    if u16::try_from(value).is_ok() && value as i32 == 5 {
-        5
-    } else {
-        1
-    }
+pub fn u32_to_u16(value: u32) {
+    let _ = u16::try_from(value).is_ok() && value as i32 == 5;
+    let _ = u16::try_from(value).is_ok() && value as i32 == 5;
 }
 
 // Negative tests
 
-fn no_i64_to_i32(value: i64) -> Option<i32> {
-    if value <= (i32::max_value() as i64) && value >= 0 {
-        Some(value as i32)
-    } else {
-        None
-    }
+pub fn no_i64_to_i32(value: i64) {
+    let _ = value <= (i32::max_value() as i64) && value >= 0;
+    let _ = value <= (i32::MAX as i64) && value >= 0;
 }
 
-fn no_isize_to_u8(value: isize) -> Option<u8> {
-    if value <= (u8::max_value() as isize) && value >= (u8::min_value() as isize) {
-        Some(value as u8)
-    } else {
-        None
-    }
+pub fn no_isize_to_u8(value: isize) {
+    let _ = value <= (u8::max_value() as isize) && value >= (u8::min_value() as isize);
+    let _ = value <= (u8::MAX as isize) && value >= (u8::MIN as isize);
 }
 
-fn i8_to_u8(value: i8) -> Option<u8> {
-    if value >= 0 {
-        Some(value as u8)
-    } else {
-        None
-    }
+pub fn i8_to_u8(value: i8) {
+    let _ = value >= 0;
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/checked_conversions.rs b/src/tools/clippy/tests/ui/checked_conversions.rs
index a643354e243..895a301e821 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.rs
+++ b/src/tools/clippy/tests/ui/checked_conversions.rs
@@ -1,106 +1,76 @@
 // run-rustfix
 
+#![allow(
+    clippy::cast_lossless,
+    // Int::max_value will be deprecated in the future
+    deprecated,
+)]
 #![warn(clippy::checked_conversions)]
-#![allow(clippy::cast_lossless)]
-#![allow(dead_code)]
+
 use std::convert::TryFrom;
 
 // Positive tests
 
 // Signed to unsigned
 
-fn i64_to_u32(value: i64) -> Option<u32> {
-    if value <= (u32::max_value() as i64) && value >= 0 {
-        Some(value as u32)
-    } else {
-        None
-    }
+pub fn i64_to_u32(value: i64) {
+    let _ = value <= (u32::max_value() as i64) && value >= 0;
+    let _ = value <= (u32::MAX as i64) && value >= 0;
 }
 
-fn i64_to_u16(value: i64) -> Option<u16> {
-    if value <= i64::from(u16::max_value()) && value >= 0 {
-        Some(value as u16)
-    } else {
-        None
-    }
+pub fn i64_to_u16(value: i64) {
+    let _ = value <= i64::from(u16::max_value()) && value >= 0;
+    let _ = value <= i64::from(u16::MAX) && value >= 0;
 }
 
-fn isize_to_u8(value: isize) -> Option<u8> {
-    if value <= (u8::max_value() as isize) && value >= 0 {
-        Some(value as u8)
-    } else {
-        None
-    }
+pub fn isize_to_u8(value: isize) {
+    let _ = value <= (u8::max_value() as isize) && value >= 0;
+    let _ = value <= (u8::MAX as isize) && value >= 0;
 }
 
 // Signed to signed
 
-fn i64_to_i32(value: i64) -> Option<i32> {
-    if value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64) {
-        Some(value as i32)
-    } else {
-        None
-    }
+pub fn i64_to_i32(value: i64) {
+    let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64);
+    let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64);
 }
 
-fn i64_to_i16(value: i64) -> Option<i16> {
-    if value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()) {
-        Some(value as i16)
-    } else {
-        None
-    }
+pub fn i64_to_i16(value: i64) {
+    let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value());
+    let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN);
 }
 
 // Unsigned to X
 
-fn u32_to_i32(value: u32) -> Option<i32> {
-    if value <= i32::max_value() as u32 {
-        Some(value as i32)
-    } else {
-        None
-    }
+pub fn u32_to_i32(value: u32) {
+    let _ = value <= i32::max_value() as u32;
+    let _ = value <= i32::MAX as u32;
 }
 
-fn usize_to_isize(value: usize) -> isize {
-    if value <= isize::max_value() as usize && value as i32 == 5 {
-        5
-    } else {
-        1
-    }
+pub fn usize_to_isize(value: usize) {
+    let _ = value <= isize::max_value() as usize && value as i32 == 5;
+    let _ = value <= isize::MAX as usize && value as i32 == 5;
 }
 
-fn u32_to_u16(value: u32) -> isize {
-    if value <= u16::max_value() as u32 && value as i32 == 5 {
-        5
-    } else {
-        1
-    }
+pub fn u32_to_u16(value: u32) {
+    let _ = value <= u16::max_value() as u32 && value as i32 == 5;
+    let _ = value <= u16::MAX as u32 && value as i32 == 5;
 }
 
 // Negative tests
 
-fn no_i64_to_i32(value: i64) -> Option<i32> {
-    if value <= (i32::max_value() as i64) && value >= 0 {
-        Some(value as i32)
-    } else {
-        None
-    }
+pub fn no_i64_to_i32(value: i64) {
+    let _ = value <= (i32::max_value() as i64) && value >= 0;
+    let _ = value <= (i32::MAX as i64) && value >= 0;
 }
 
-fn no_isize_to_u8(value: isize) -> Option<u8> {
-    if value <= (u8::max_value() as isize) && value >= (u8::min_value() as isize) {
-        Some(value as u8)
-    } else {
-        None
-    }
+pub fn no_isize_to_u8(value: isize) {
+    let _ = value <= (u8::max_value() as isize) && value >= (u8::min_value() as isize);
+    let _ = value <= (u8::MAX as isize) && value >= (u8::MIN as isize);
 }
 
-fn i8_to_u8(value: i8) -> Option<u8> {
-    if value >= 0 {
-        Some(value as u8)
-    } else {
-        None
-    }
+pub fn i8_to_u8(value: i8) {
+    let _ = value >= 0;
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr
index f678f009621..648ba3ccd01 100644
--- a/src/tools/clippy/tests/ui/checked_conversions.stderr
+++ b/src/tools/clippy/tests/ui/checked_conversions.stderr
@@ -1,52 +1,100 @@
 error: Checked cast can be simplified.
-  --> $DIR/checked_conversions.rs:13:8
+  --> $DIR/checked_conversions.rs:17:13
    |
-LL |     if value <= (u32::max_value() as i64) && value >= 0 {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
+LL |     let _ = value <= (u32::max_value() as i64) && value >= 0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
    |
    = note: `-D clippy::checked-conversions` implied by `-D warnings`
 
 error: Checked cast can be simplified.
-  --> $DIR/checked_conversions.rs:21:8
+  --> $DIR/checked_conversions.rs:18:13
    |
-LL |     if value <= i64::from(u16::max_value()) && value >= 0 {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
+LL |     let _ = value <= (u32::MAX as i64) && value >= 0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u32::try_from(value).is_ok()`
 
 error: Checked cast can be simplified.
-  --> $DIR/checked_conversions.rs:29:8
+  --> $DIR/checked_conversions.rs:22:13
    |
-LL |     if value <= (u8::max_value() as isize) && value >= 0 {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
+LL |     let _ = value <= i64::from(u16::max_value()) && value >= 0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: Checked cast can be simplified.
-  --> $DIR/checked_conversions.rs:39:8
+  --> $DIR/checked_conversions.rs:23:13
    |
-LL |     if value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64) {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
+LL |     let _ = value <= i64::from(u16::MAX) && value >= 0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
 
 error: Checked cast can be simplified.
-  --> $DIR/checked_conversions.rs:47:8
+  --> $DIR/checked_conversions.rs:27:13
    |
-LL |     if value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()) {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
+LL |     let _ = value <= (u8::max_value() as isize) && value >= 0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
 
 error: Checked cast can be simplified.
-  --> $DIR/checked_conversions.rs:57:8
+  --> $DIR/checked_conversions.rs:28:13
    |
-LL |     if value <= i32::max_value() as u32 {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
+LL |     let _ = value <= (u8::MAX as isize) && value >= 0;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u8::try_from(value).is_ok()`
 
 error: Checked cast can be simplified.
-  --> $DIR/checked_conversions.rs:65:8
+  --> $DIR/checked_conversions.rs:34:13
    |
-LL |     if value <= isize::max_value() as usize && value as i32 == 5 {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
+LL |     let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
 error: Checked cast can be simplified.
-  --> $DIR/checked_conversions.rs:73:8
+  --> $DIR/checked_conversions.rs:35:13
    |
-LL |     if value <= u16::max_value() as u32 && value as i32 == 5 {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
+LL |     let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
 
-error: aborting due to 8 previous errors
+error: Checked cast can be simplified.
+  --> $DIR/checked_conversions.rs:39:13
+   |
+LL |     let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value());
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
+
+error: Checked cast can be simplified.
+  --> $DIR/checked_conversions.rs:40:13
+   |
+LL |     let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i16::try_from(value).is_ok()`
+
+error: Checked cast can be simplified.
+  --> $DIR/checked_conversions.rs:46:13
+   |
+LL |     let _ = value <= i32::max_value() as u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
+
+error: Checked cast can be simplified.
+  --> $DIR/checked_conversions.rs:47:13
+   |
+LL |     let _ = value <= i32::MAX as u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::try_from(value).is_ok()`
+
+error: Checked cast can be simplified.
+  --> $DIR/checked_conversions.rs:51:13
+   |
+LL |     let _ = value <= isize::max_value() as usize && value as i32 == 5;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
+
+error: Checked cast can be simplified.
+  --> $DIR/checked_conversions.rs:52:13
+   |
+LL |     let _ = value <= isize::MAX as usize && value as i32 == 5;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `isize::try_from(value).is_ok()`
+
+error: Checked cast can be simplified.
+  --> $DIR/checked_conversions.rs:56:13
+   |
+LL |     let _ = value <= u16::max_value() as u32 && value as i32 == 5;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
+
+error: Checked cast can be simplified.
+  --> $DIR/checked_conversions.rs:57:13
+   |
+LL |     let _ = value <= u16::MAX as u32 && value as i32 == 5;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::try_from(value).is_ok()`
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/checked_conversions.stdout b/src/tools/clippy/tests/ui/checked_conversions.stdout
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/src/tools/clippy/tests/ui/checked_conversions.stdout
+++ /dev/null
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3969.rs b/src/tools/clippy/tests/ui/crashes/ice-3969.rs
new file mode 100644
index 00000000000..4feab7910b7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-3969.rs
@@ -0,0 +1,51 @@
+// https://github.com/rust-lang/rust-clippy/issues/3969
+// used to crash: error: internal compiler error:
+// src/librustc_traits/normalize_erasing_regions.rs:43: could not fully normalize `<i32 as
+// std::iter::Iterator>::Item test from rustc ./ui/trivial-bounds/trivial-bounds-inconsistent.rs
+
+// Check that tautalogically false bounds are accepted, and are used
+// in type inference.
+#![feature(trivial_bounds)]
+#![allow(unused)]
+
+trait A {}
+
+impl A for i32 {}
+
+struct Dst<X: ?Sized> {
+    x: X,
+}
+
+struct TwoStrs(str, str)
+where
+    str: Sized;
+
+fn unsized_local()
+where
+    for<'a> Dst<A + 'a>: Sized,
+{
+    let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+}
+
+fn return_str() -> str
+where
+    str: Sized,
+{
+    *"Sized".to_string().into_boxed_str()
+}
+
+fn use_op(s: String) -> String
+where
+    String: ::std::ops::Neg<Output = String>,
+{
+    -s
+}
+
+fn use_for()
+where
+    i32: Iterator,
+{
+    for _ in 2i32 {}
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3969.stderr b/src/tools/clippy/tests/ui/crashes/ice-3969.stderr
new file mode 100644
index 00000000000..923db0664a7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-3969.stderr
@@ -0,0 +1,22 @@
+error: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/ice-3969.rs:25:17
+   |
+LL |     for<'a> Dst<A + 'a>: Sized,
+   |                 ^^^^^^ help: use `dyn`: `dyn A + 'a`
+   |
+   = note: `-D bare-trait-objects` implied by `-D warnings`
+
+error: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/ice-3969.rs:27:16
+   |
+LL |     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+   |                ^ help: use `dyn`: `dyn A`
+
+error: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/ice-3969.rs:27:57
+   |
+LL |     let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+   |                                                         ^ help: use `dyn`: `dyn A`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/regressions.rs b/src/tools/clippy/tests/ui/crashes/regressions.rs
index 623ae51f9f0..3d5063d1a3a 100644
--- a/src/tools/clippy/tests/ui/crashes/regressions.rs
+++ b/src/tools/clippy/tests/ui/crashes/regressions.rs
@@ -6,4 +6,8 @@ pub fn foo(bar: *const u8) {
     println!("{:#p}", bar);
 }
 
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/4917
+/// <foo
+struct A {}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
index c30d23de3f8..7f92d0dbdc9 100644
--- a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
@@ -40,4 +40,6 @@ fn main() {
     let _ = (&HashSet::<i32>::new()).iter(); //~ WARN equivalent to .iter()
     let _ = std::path::Path::new("12/34").iter(); //~ WARN equivalent to .iter()
     let _ = std::path::PathBuf::from("12/34").iter(); //~ ERROR equivalent to .iter()
+
+    let _ = (&[1, 2, 3]).iter().next(); //~ WARN equivalent to .iter()
 }
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.rs b/src/tools/clippy/tests/ui/into_iter_on_ref.rs
index 94bc1689619..416056d3fdb 100644
--- a/src/tools/clippy/tests/ui/into_iter_on_ref.rs
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.rs
@@ -40,4 +40,6 @@ fn main() {
     let _ = (&HashSet::<i32>::new()).into_iter(); //~ WARN equivalent to .iter()
     let _ = std::path::Path::new("12/34").into_iter(); //~ WARN equivalent to .iter()
     let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter()
+
+    let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter()
 }
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr
index 80e2d104f82..1cd6400b019 100644
--- a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr
@@ -156,5 +156,11 @@ error: this `.into_iter()` call is equivalent to `.iter()` and will not move the
 LL |     let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR equivalent to .iter()
    |                                               ^^^^^^^^^ help: call directly: `iter`
 
-error: aborting due to 26 previous errors
+error: this `.into_iter()` call is equivalent to `.iter()` and will not move the `array`
+  --> $DIR/into_iter_on_ref.rs:44:26
+   |
+LL |     let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter()
+   |                          ^^^^^^^^^ help: call directly: `iter`
+
+error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/iter_next_slice.fixed b/src/tools/clippy/tests/ui/iter_next_slice.fixed
new file mode 100644
index 00000000000..79c1db87ac3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_next_slice.fixed
@@ -0,0 +1,24 @@
+// run-rustfix
+#![warn(clippy::iter_next_slice)]
+
+fn main() {
+    // test code goes here
+    let s = [1, 2, 3];
+    let v = vec![1, 2, 3];
+
+    s.get(0);
+    // Should be replaced by s.get(0)
+
+    s.get(2);
+    // Should be replaced by s.get(2)
+
+    v.get(5);
+    // Should be replaced by v.get(5)
+
+    v.get(0);
+    // Should be replaced by v.get(0)
+
+    let o = Some(5);
+    o.iter().next();
+    // Shouldn't be linted since this is not a Slice or an Array
+}
diff --git a/src/tools/clippy/tests/ui/iter_next_slice.rs b/src/tools/clippy/tests/ui/iter_next_slice.rs
new file mode 100644
index 00000000000..ef9a55f3d99
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_next_slice.rs
@@ -0,0 +1,24 @@
+// run-rustfix
+#![warn(clippy::iter_next_slice)]
+
+fn main() {
+    // test code goes here
+    let s = [1, 2, 3];
+    let v = vec![1, 2, 3];
+
+    s.iter().next();
+    // Should be replaced by s.get(0)
+
+    s[2..].iter().next();
+    // Should be replaced by s.get(2)
+
+    v[5..].iter().next();
+    // Should be replaced by v.get(5)
+
+    v.iter().next();
+    // Should be replaced by v.get(0)
+
+    let o = Some(5);
+    o.iter().next();
+    // Shouldn't be linted since this is not a Slice or an Array
+}
diff --git a/src/tools/clippy/tests/ui/iter_next_slice.stderr b/src/tools/clippy/tests/ui/iter_next_slice.stderr
new file mode 100644
index 00000000000..bbf61df0cda
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_next_slice.stderr
@@ -0,0 +1,28 @@
+error: Using `.iter().next()` on an array
+  --> $DIR/iter_next_slice.rs:9:5
+   |
+LL |     s.iter().next();
+   |     ^^^^^^^^^^^^^^^ help: try calling: `s.get(0)`
+   |
+   = note: `-D clippy::iter-next-slice` implied by `-D warnings`
+
+error: Using `.iter().next()` on a Slice without end index.
+  --> $DIR/iter_next_slice.rs:12:5
+   |
+LL |     s[2..].iter().next();
+   |     ^^^^^^^^^^^^^^^^^^^^ help: try calling: `s.get(2)`
+
+error: Using `.iter().next()` on a Slice without end index.
+  --> $DIR/iter_next_slice.rs:15:5
+   |
+LL |     v[5..].iter().next();
+   |     ^^^^^^^^^^^^^^^^^^^^ help: try calling: `v.get(5)`
+
+error: Using `.iter().next()` on an array
+  --> $DIR/iter_next_slice.rs:18:5
+   |
+LL |     v.iter().next();
+   |     ^^^^^^^^^^^^^^^ help: try calling: `v.get(0)`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/len_zero.fixed b/src/tools/clippy/tests/ui/len_zero.fixed
index 624e5ef8fcf..a29b832eb60 100644
--- a/src/tools/clippy/tests/ui/len_zero.fixed
+++ b/src/tools/clippy/tests/ui/len_zero.fixed
@@ -141,3 +141,11 @@ fn main() {
 fn test_slice(b: &[u8]) {
     if !b.is_empty() {}
 }
+
+mod issue_3807 {
+    // Avoid suggesting changes to ranges if the user did not enable `range_is_empty`.
+    // See https://github.com/rust-lang/rust/issues/48111#issuecomment-445132965
+    fn no_suggestion() {
+        let _ = (0..42).len() == 0;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/len_zero.rs b/src/tools/clippy/tests/ui/len_zero.rs
index 7fba971cfd8..8fd0093f4fd 100644
--- a/src/tools/clippy/tests/ui/len_zero.rs
+++ b/src/tools/clippy/tests/ui/len_zero.rs
@@ -141,3 +141,11 @@ fn main() {
 fn test_slice(b: &[u8]) {
     if b.len() != 0 {}
 }
+
+mod issue_3807 {
+    // Avoid suggesting changes to ranges if the user did not enable `range_is_empty`.
+    // See https://github.com/rust-lang/rust/issues/48111#issuecomment-445132965
+    fn no_suggestion() {
+        let _ = (0..42).len() == 0;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.fixed b/src/tools/clippy/tests/ui/len_zero_ranges.fixed
new file mode 100644
index 00000000000..7da26f8ff4d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/len_zero_ranges.fixed
@@ -0,0 +1,14 @@
+// run-rustfix
+
+#![feature(range_is_empty)]
+#![warn(clippy::len_zero)]
+#![allow(unused)]
+
+mod issue_3807 {
+    // With the feature enabled, `is_empty` should be suggested
+    fn suggestion_is_fine() {
+        let _ = (0..42).is_empty();
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.rs b/src/tools/clippy/tests/ui/len_zero_ranges.rs
new file mode 100644
index 00000000000..be7b4244bc0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/len_zero_ranges.rs
@@ -0,0 +1,14 @@
+// run-rustfix
+
+#![feature(range_is_empty)]
+#![warn(clippy::len_zero)]
+#![allow(unused)]
+
+mod issue_3807 {
+    // With the feature enabled, `is_empty` should be suggested
+    fn suggestion_is_fine() {
+        let _ = (0..42).len() == 0;
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.stderr b/src/tools/clippy/tests/ui/len_zero_ranges.stderr
new file mode 100644
index 00000000000..6e5fa41fb08
--- /dev/null
+++ b/src/tools/clippy/tests/ui/len_zero_ranges.stderr
@@ -0,0 +1,10 @@
+error: length comparison to zero
+  --> $DIR/len_zero_ranges.rs:10:17
+   |
+LL |         let _ = (0..42).len() == 0;
+   |                 ^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(0..42).is_empty()`
+   |
+   = note: `-D clippy::len-zero` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/let_and_return.rs b/src/tools/clippy/tests/ui/let_and_return.rs
new file mode 100644
index 00000000000..09614b8c1ad
--- /dev/null
+++ b/src/tools/clippy/tests/ui/let_and_return.rs
@@ -0,0 +1,138 @@
+#![allow(unused)]
+#![warn(clippy::let_and_return)]
+
+fn test() -> i32 {
+    let _y = 0; // no warning
+    let x = 5;
+    x
+}
+
+fn test_inner() -> i32 {
+    if true {
+        let x = 5;
+        x
+    } else {
+        0
+    }
+}
+
+fn test_nowarn_1() -> i32 {
+    let mut x = 5;
+    x += 1;
+    x
+}
+
+fn test_nowarn_2() -> i32 {
+    let x = 5;
+    x + 1
+}
+
+fn test_nowarn_3() -> (i32, i32) {
+    // this should technically warn, but we do not compare complex patterns
+    let (x, y) = (5, 9);
+    (x, y)
+}
+
+fn test_nowarn_4() -> i32 {
+    // this should technically warn, but not b/c of clippy::let_and_return, but b/c of useless type
+    let x: i32 = 5;
+    x
+}
+
+fn test_nowarn_5(x: i16) -> u16 {
+    #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
+    let x = x as u16;
+    x
+}
+
+// False positive example
+trait Decode {
+    fn decode<D: std::io::Read>(d: D) -> Result<Self, ()>
+    where
+        Self: Sized;
+}
+
+macro_rules! tuple_encode {
+    ($($x:ident),*) => (
+        impl<$($x: Decode),*> Decode for ($($x),*) {
+            #[inline]
+            #[allow(non_snake_case)]
+            fn decode<D: std::io::Read>(mut d: D) -> Result<Self, ()> {
+                // Shouldn't trigger lint
+                Ok(($({let $x = Decode::decode(&mut d)?; $x }),*))
+            }
+        }
+    );
+}
+
+tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7);
+
+mod no_lint_if_stmt_borrows {
+    mod issue_3792 {
+        use std::io::{self, BufRead, Stdin};
+
+        fn read_line() -> String {
+            let stdin = io::stdin();
+            let line = stdin.lock().lines().next().unwrap().unwrap();
+            line
+        }
+    }
+
+    mod issue_3324 {
+        use std::cell::RefCell;
+        use std::rc::{Rc, Weak};
+
+        fn test(value: Weak<RefCell<Bar>>) -> u32 {
+            let value = value.upgrade().unwrap();
+            let ret = value.borrow().baz();
+            ret
+        }
+
+        struct Bar {}
+
+        impl Bar {
+            fn new() -> Self {
+                Bar {}
+            }
+            fn baz(&self) -> u32 {
+                0
+            }
+        }
+
+        fn main() {
+            let a = Rc::new(RefCell::new(Bar::new()));
+            let b = Rc::downgrade(&a);
+            test(b);
+        }
+    }
+
+    mod free_function {
+        struct Inner;
+
+        struct Foo<'a> {
+            inner: &'a Inner,
+        }
+
+        impl Drop for Foo<'_> {
+            fn drop(&mut self) {}
+        }
+
+        impl Foo<'_> {
+            fn value(&self) -> i32 {
+                42
+            }
+        }
+
+        fn some_foo(inner: &Inner) -> Foo<'_> {
+            Foo { inner }
+        }
+
+        fn test() -> i32 {
+            let x = Inner {};
+            let value = some_foo(&x).value();
+            value
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/let_return.stderr b/src/tools/clippy/tests/ui/let_and_return.stderr
index 128a22c86e3..eacf948b392 100644
--- a/src/tools/clippy/tests/ui/let_return.stderr
+++ b/src/tools/clippy/tests/ui/let_and_return.stderr
@@ -1,5 +1,5 @@
 error: returning the result of a `let` binding from a block
-  --> $DIR/let_return.rs:7:5
+  --> $DIR/let_and_return.rs:7:5
    |
 LL |     let x = 5;
    |     ---------- unnecessary `let` binding
@@ -14,7 +14,7 @@ LL |     5
    |
 
 error: returning the result of a `let` binding from a block
-  --> $DIR/let_return.rs:13:9
+  --> $DIR/let_and_return.rs:13:9
    |
 LL |         let x = 5;
    |         ---------- unnecessary `let` binding
diff --git a/src/tools/clippy/tests/ui/let_return.rs b/src/tools/clippy/tests/ui/let_return.rs
deleted file mode 100644
index 23645d48fe7..00000000000
--- a/src/tools/clippy/tests/ui/let_return.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-#![allow(unused)]
-#![warn(clippy::let_and_return)]
-
-fn test() -> i32 {
-    let _y = 0; // no warning
-    let x = 5;
-    x
-}
-
-fn test_inner() -> i32 {
-    if true {
-        let x = 5;
-        x
-    } else {
-        0
-    }
-}
-
-fn test_nowarn_1() -> i32 {
-    let mut x = 5;
-    x += 1;
-    x
-}
-
-fn test_nowarn_2() -> i32 {
-    let x = 5;
-    x + 1
-}
-
-fn test_nowarn_3() -> (i32, i32) {
-    // this should technically warn, but we do not compare complex patterns
-    let (x, y) = (5, 9);
-    (x, y)
-}
-
-fn test_nowarn_4() -> i32 {
-    // this should technically warn, but not b/c of clippy::let_and_return, but b/c of useless type
-    let x: i32 = 5;
-    x
-}
-
-fn test_nowarn_5(x: i16) -> u16 {
-    #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
-    let x = x as u16;
-    x
-}
-
-// False positive example
-trait Decode {
-    fn decode<D: std::io::Read>(d: D) -> Result<Self, ()>
-    where
-        Self: Sized;
-}
-
-macro_rules! tuple_encode {
-    ($($x:ident),*) => (
-        impl<$($x: Decode),*> Decode for ($($x),*) {
-            #[inline]
-            #[allow(non_snake_case)]
-            fn decode<D: std::io::Read>(mut d: D) -> Result<Self, ()> {
-                // Shouldn't trigger lint
-                Ok(($({let $x = Decode::decode(&mut d)?; $x }),*))
-            }
-        }
-    );
-}
-
-tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7);
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed
index b4227eaf2f8..be37dc16b9a 100644
--- a/src/tools/clippy/tests/ui/needless_collect.fixed
+++ b/src/tools/clippy/tests/ui/needless_collect.fixed
@@ -9,7 +9,7 @@ use std::collections::{BTreeSet, HashMap, HashSet};
 fn main() {
     let sample = [1; 5];
     let len = sample.iter().count();
-    if sample.iter().next().is_none() {
+    if sample.get(0).is_none() {
         // Empty
     }
     sample.iter().cloned().any(|x| x == 1);
diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr
index 8884c8e1612..9113aad90dd 100644
--- a/src/tools/clippy/tests/ui/needless_collect.stderr
+++ b/src/tools/clippy/tests/ui/needless_collect.stderr
@@ -1,28 +1,28 @@
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect.rs:11:28
+  --> $DIR/needless_collect.rs:11:29
    |
 LL |     let len = sample.iter().collect::<Vec<_>>().len();
-   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()`
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()`
    |
    = note: `-D clippy::needless-collect` implied by `-D warnings`
 
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect.rs:12:21
+  --> $DIR/needless_collect.rs:12:15
    |
 LL |     if sample.iter().collect::<Vec<_>>().is_empty() {
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.next().is_none()`
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get(0).is_none()`
 
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect.rs:15:27
+  --> $DIR/needless_collect.rs:15:28
    |
 LL |     sample.iter().cloned().collect::<Vec<_>>().contains(&1);
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.any(|x| x == 1)`
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)`
 
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect.rs:16:34
+  --> $DIR/needless_collect.rs:16:35
    |
 LL |     sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len();
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `.count()`
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs
index 856a430ba2b..ca70e3b7148 100644
--- a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs
+++ b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs
@@ -4,6 +4,7 @@
 
 use std::cmp::Ordering;
 
+#[allow(clippy::unnested_or_patterns)]
 #[warn(clippy::neg_cmp_op_on_partial_ord)]
 fn main() {
     let a_value = 1.0;
diff --git a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr
index d05fd34ce33..8c5d548222e 100644
--- a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr
+++ b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr
@@ -1,5 +1,5 @@
 error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable.
-  --> $DIR/neg_cmp_op_on_partial_ord.rs:15:21
+  --> $DIR/neg_cmp_op_on_partial_ord.rs:16:21
    |
 LL |     let _not_less = !(a_value < another_value);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,19 +7,19 @@ LL |     let _not_less = !(a_value < another_value);
    = note: `-D clippy::neg-cmp-op-on-partial-ord` implied by `-D warnings`
 
 error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable.
-  --> $DIR/neg_cmp_op_on_partial_ord.rs:18:30
+  --> $DIR/neg_cmp_op_on_partial_ord.rs:19:30
    |
 LL |     let _not_less_or_equal = !(a_value <= another_value);
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable.
-  --> $DIR/neg_cmp_op_on_partial_ord.rs:21:24
+  --> $DIR/neg_cmp_op_on_partial_ord.rs:22:24
    |
 LL |     let _not_greater = !(a_value > another_value);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: The use of negated comparison operators on partially ordered types produces code that is hard to read and refactor. Please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable.
-  --> $DIR/neg_cmp_op_on_partial_ord.rs:24:33
+  --> $DIR/neg_cmp_op_on_partial_ord.rs:25:33
    |
 LL |     let _not_greater_or_equal = !(a_value >= another_value);
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 7bb08797ef3..2045ffdb5f0 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -29,7 +29,7 @@ fn or_fun_call() {
     with_enum.unwrap_or(Enum::A(5));
 
     let with_const_fn = Some(Duration::from_secs(1));
-    with_const_fn.unwrap_or(Duration::from_secs(5));
+    with_const_fn.unwrap_or_else(|| Duration::from_secs(5));
 
     let with_constructor = Some(vec![1]);
     with_constructor.unwrap_or_else(make);
@@ -94,7 +94,7 @@ fn test_or_with_ctors() {
 
     let b = "b".to_string();
     let _ = Some(Bar("a".to_string(), Duration::from_secs(1)))
-        .or(Some(Bar(b, Duration::from_secs(2))));
+        .or_else(|| Some(Bar(b, Duration::from_secs(2))));
 
     let vec = vec!["foo"];
     let _ = opt.ok_or(vec.len());
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 96d55771e6c..bc5978b538f 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -1,10 +1,16 @@
 error: use of `unwrap_or` followed by a function call
+  --> $DIR/or_fun_call.rs:32:19
+   |
+LL |     with_const_fn.unwrap_or(Duration::from_secs(5));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Duration::from_secs(5))`
+   |
+   = note: `-D clippy::or-fun-call` implied by `-D warnings`
+
+error: use of `unwrap_or` followed by a function call
   --> $DIR/or_fun_call.rs:35:22
    |
 LL |     with_constructor.unwrap_or(make());
    |                      ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)`
-   |
-   = note: `-D clippy::or-fun-call` implied by `-D warnings`
 
 error: use of `unwrap_or` followed by a call to `new`
   --> $DIR/or_fun_call.rs:38:5
@@ -78,5 +84,11 @@ error: use of `or` followed by a function call
 LL |     let _ = Some("a".to_string()).or(Some("b".to_string()));
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
 
-error: aborting due to 13 previous errors
+error: use of `or` followed by a function call
+  --> $DIR/or_fun_call.rs:97:10
+   |
+LL |         .or(Some(Bar(b, Duration::from_secs(2))));
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))`
+
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed
index 332c0427ef6..79e482eec30 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed
@@ -4,8 +4,6 @@
 const ANSWER: i32 = 42;
 
 fn main() {
-    let arr = [1, 2, 3, 4, 5];
-
     // These should be linted:
 
     (21..=42).rev().for_each(|x| println!("{}", x));
@@ -14,16 +12,18 @@ fn main() {
     for _ in (-42..=-21).rev() {}
     for _ in (21u32..42u32).rev() {}
 
-    let _ = &[] as &[i32];
-
     // These should be ignored as they are not empty ranges:
 
     (21..=42).for_each(|x| println!("{}", x));
     (21..42).for_each(|x| println!("{}", x));
 
+    let arr = [1, 2, 3, 4, 5];
     let _ = &arr[1..=3];
     let _ = &arr[1..3];
 
     for _ in 21..=42 {}
     for _ in 21..42 {}
+
+    // This range is empty but should be ignored, see issue #5689
+    let _ = &arr[0..0];
 }
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs
index 901ec8bcc09..b2e8bf33771 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs
@@ -4,8 +4,6 @@
 const ANSWER: i32 = 42;
 
 fn main() {
-    let arr = [1, 2, 3, 4, 5];
-
     // These should be linted:
 
     (42..=21).for_each(|x| println!("{}", x));
@@ -14,16 +12,18 @@ fn main() {
     for _ in -21..=-42 {}
     for _ in 42u32..21u32 {}
 
-    let _ = &arr[3..3];
-
     // These should be ignored as they are not empty ranges:
 
     (21..=42).for_each(|x| println!("{}", x));
     (21..42).for_each(|x| println!("{}", x));
 
+    let arr = [1, 2, 3, 4, 5];
     let _ = &arr[1..=3];
     let _ = &arr[1..3];
 
     for _ in 21..=42 {}
     for _ in 21..42 {}
+
+    // This range is empty but should be ignored, see issue #5689
+    let _ = &arr[0..0];
 }
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr
index 9a646fd9939..de83c4f3d63 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr
@@ -1,5 +1,5 @@
 error: this range is empty so it will yield no values
-  --> $DIR/reversed_empty_ranges_fixable.rs:11:5
+  --> $DIR/reversed_empty_ranges_fixable.rs:9:5
    |
 LL |     (42..=21).for_each(|x| println!("{}", x));
    |     ^^^^^^^^^
@@ -11,7 +11,7 @@ LL |     (21..=42).rev().for_each(|x| println!("{}", x));
    |     ^^^^^^^^^^^^^^^
 
 error: this range is empty so it will yield no values
-  --> $DIR/reversed_empty_ranges_fixable.rs:12:13
+  --> $DIR/reversed_empty_ranges_fixable.rs:10:13
    |
 LL |     let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
    |             ^^^^^^^^^^^^
@@ -22,7 +22,7 @@ LL |     let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::<Ve
    |             ^^^^^^^^^^^^^^^^^^
 
 error: this range is empty so it will yield no values
-  --> $DIR/reversed_empty_ranges_fixable.rs:14:14
+  --> $DIR/reversed_empty_ranges_fixable.rs:12:14
    |
 LL |     for _ in -21..=-42 {}
    |              ^^^^^^^^^
@@ -33,7 +33,7 @@ LL |     for _ in (-42..=-21).rev() {}
    |              ^^^^^^^^^^^^^^^^^
 
 error: this range is empty so it will yield no values
-  --> $DIR/reversed_empty_ranges_fixable.rs:15:14
+  --> $DIR/reversed_empty_ranges_fixable.rs:13:14
    |
 LL |     for _ in 42u32..21u32 {}
    |              ^^^^^^^^^^^^
@@ -43,11 +43,5 @@ help: consider using the following if you are attempting to iterate over this ra
 LL |     for _ in (21u32..42u32).rev() {}
    |              ^^^^^^^^^^^^^^^^^^^^
 
-error: this range is empty and using it to index a slice will always yield an empty slice
-  --> $DIR/reversed_empty_ranges_fixable.rs:17:18
-   |
-LL |     let _ = &arr[3..3];
-   |              ----^^^^- help: if you want an empty slice, use: `[] as &[i32]`
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs
index 561a35625f0..264d3d1e95a 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs
@@ -4,11 +4,12 @@ const ANSWER: i32 = 42;
 const SOME_NUM: usize = 3;
 
 fn main() {
-    let _ = (42 + 10..42 + 10).map(|x| x / 2).find(|&x| x == 21);
-
     let arr = [1, 2, 3, 4, 5];
     let _ = &arr[3usize..=1usize];
     let _ = &arr[SOME_NUM..1];
 
     for _ in ANSWER..ANSWER {}
+
+    // Should not be linted, see issue #5689
+    let _ = (42 + 10..42 + 10).map(|x| x / 2).find(|&x| x == 21);
 }
diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr
index 240188cbb46..f23d4eb0f9c 100644
--- a/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.stderr
@@ -1,28 +1,22 @@
-error: this range is empty so it will yield no values
-  --> $DIR/reversed_empty_ranges_unfixable.rs:7:13
-   |
-LL |     let _ = (42 + 10..42 + 10).map(|x| x / 2).find(|&x| x == 21);
-   |             ^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings`
-
 error: this range is reversed and using it to index a slice will panic at run-time
-  --> $DIR/reversed_empty_ranges_unfixable.rs:10:18
+  --> $DIR/reversed_empty_ranges_unfixable.rs:8:18
    |
 LL |     let _ = &arr[3usize..=1usize];
    |                  ^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::reversed-empty-ranges` implied by `-D warnings`
 
 error: this range is reversed and using it to index a slice will panic at run-time
-  --> $DIR/reversed_empty_ranges_unfixable.rs:11:18
+  --> $DIR/reversed_empty_ranges_unfixable.rs:9:18
    |
 LL |     let _ = &arr[SOME_NUM..1];
    |                  ^^^^^^^^^^^
 
 error: this range is empty so it will yield no values
-  --> $DIR/reversed_empty_ranges_unfixable.rs:13:14
+  --> $DIR/reversed_empty_ranges_unfixable.rs:11:14
    |
 LL |     for _ in ANSWER..ANSWER {}
    |              ^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
index 7ad272ade5f..ccf8f61c4a9 100644
--- a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed
@@ -14,6 +14,8 @@ fn str_lit_as_bytes() {
 
     let strify = stringify!(foobar).as_bytes();
 
+    let current_version = env!("CARGO_PKG_VERSION").as_bytes();
+
     let includestr = include_bytes!("entry_unfixable.rs");
 
     let _ = b"string with newline\t\n";
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
index 1bf4538b7c9..178df08e249 100644
--- a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs
@@ -14,6 +14,8 @@ fn str_lit_as_bytes() {
 
     let strify = stringify!(foobar).as_bytes();
 
+    let current_version = env!("CARGO_PKG_VERSION").as_bytes();
+
     let includestr = include_str!("entry_unfixable.rs").as_bytes();
 
     let _ = "string with newline\t\n".as_bytes();
diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr
index ff6e3346dfc..99c512354d5 100644
--- a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr
+++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr
@@ -13,13 +13,13 @@ LL |     let bs = r###"raw string with 3# plus " ""###.as_bytes();
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with 3# plus " ""###`
 
 error: calling `as_bytes()` on `include_str!(..)`
-  --> $DIR/string_lit_as_bytes.rs:17:22
+  --> $DIR/string_lit_as_bytes.rs:19:22
    |
 LL |     let includestr = include_str!("entry_unfixable.rs").as_bytes();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("entry_unfixable.rs")`
 
 error: calling `as_bytes()` on a string literal
-  --> $DIR/string_lit_as_bytes.rs:19:13
+  --> $DIR/string_lit_as_bytes.rs:21:13
    |
 LL |     let _ = "string with newline/t/n".as_bytes();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline/t/n"`
diff --git a/src/tools/clippy/tests/ui/unit_arg.fixed b/src/tools/clippy/tests/ui/unit_arg.fixed
deleted file mode 100644
index a739cf7ad81..00000000000
--- a/src/tools/clippy/tests/ui/unit_arg.fixed
+++ /dev/null
@@ -1,64 +0,0 @@
-// run-rustfix
-#![warn(clippy::unit_arg)]
-#![allow(unused_braces, clippy::no_effect, unused_must_use)]
-
-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);
-}
-
-struct Bar;
-
-impl Bar {
-    fn bar<T: Debug>(&self, t: T) {
-        println!("{:?}", t);
-    }
-}
-
-fn bad() {
-    foo(());
-    foo(());
-    foo(());
-    foo(());
-    foo3((), 2, 2);
-    let b = Bar;
-    b.bar(());
-}
-
-fn ok() {
-    foo(());
-    foo(1);
-    foo({ 1 });
-    foo3("a", 3, vec![3]);
-    let b = Bar;
-    b.bar({ 1 });
-    b.bar(());
-    question_mark();
-}
-
-fn question_mark() -> Result<(), ()> {
-    Ok(Ok(())?)?;
-    Ok(Ok(()))??;
-    Ok(())
-}
-
-#[allow(dead_code)]
-mod issue_2945 {
-    fn unit_fn() -> Result<(), i32> {
-        Ok(())
-    }
-
-    fn fallible() -> Result<(), i32> {
-        Ok(unit_fn()?)
-    }
-}
-
-fn main() {
-    bad();
-    ok();
-}
diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs
index d90c49f79de..2992abae775 100644
--- a/src/tools/clippy/tests/ui/unit_arg.rs
+++ b/src/tools/clippy/tests/ui/unit_arg.rs
@@ -1,6 +1,5 @@
-// run-rustfix
 #![warn(clippy::unit_arg)]
-#![allow(unused_braces, clippy::no_effect, unused_must_use)]
+#![allow(clippy::no_effect, unused_must_use, unused_variables)]
 
 use std::fmt::Debug;
 
@@ -21,7 +20,6 @@ impl Bar {
 }
 
 fn bad() {
-    foo({});
     foo({
         1;
     });
@@ -30,11 +28,25 @@ fn bad() {
         foo(1);
         foo(2);
     });
-    foo3({}, 2, 2);
     let b = Bar;
     b.bar({
         1;
     });
+    taking_multiple_units(foo(0), foo(1));
+    taking_multiple_units(foo(0), {
+        foo(1);
+        foo(2);
+    });
+    taking_multiple_units(
+        {
+            foo(0);
+            foo(1);
+        },
+        {
+            foo(2);
+            foo(3);
+        },
+    );
 }
 
 fn ok() {
@@ -65,6 +77,13 @@ mod issue_2945 {
     }
 }
 
+#[allow(dead_code)]
+fn returning_expr() -> Option<()> {
+    Some(foo(1))
+}
+
+fn taking_multiple_units(a: (), b: ()) {}
+
 fn main() {
     bad();
     ok();
diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr
index 21ccc684ea9..56f6a855dfa 100644
--- a/src/tools/clippy/tests/ui/unit_arg.stderr
+++ b/src/tools/clippy/tests/ui/unit_arg.stderr
@@ -1,79 +1,181 @@
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:24:9
+  --> $DIR/unit_arg.rs:23:5
    |
-LL |     foo({});
-   |         ^^
+LL | /     foo({
+LL | |         1;
+LL | |     });
+   | |______^
    |
    = note: `-D clippy::unit-arg` implied by `-D warnings`
-help: if you intended to pass a unit value, use a unit literal instead
+help: remove the semicolon from the last statement in the block
    |
-LL |     foo(());
-   |         ^^
-
-error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:25:9
+LL |         1
    |
-LL |       foo({
-   |  _________^
-LL | |         1;
-LL | |     });
-   | |_____^
+help: or move the expression in front of the call...
    |
-help: if you intended to pass a unit value, use a unit literal instead
+LL |     {
+LL |         1;
+LL |     };
+   |
+help: ...and use a unit literal instead
    |
 LL |     foo(());
    |         ^^
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:28:9
+  --> $DIR/unit_arg.rs:26:5
    |
 LL |     foo(foo(1));
-   |         ^^^^^^
+   |     ^^^^^^^^^^^
+   |
+help: move the expression in front of the call...
    |
-help: if you intended to pass a unit value, use a unit literal instead
+LL |     foo(1);
+   |
+help: ...and use a unit literal instead
    |
 LL |     foo(());
    |         ^^
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:29:9
+  --> $DIR/unit_arg.rs:27:5
    |
-LL |       foo({
-   |  _________^
+LL | /     foo({
 LL | |         foo(1);
 LL | |         foo(2);
 LL | |     });
-   | |_____^
+   | |______^
+   |
+help: remove the semicolon from the last statement in the block
+   |
+LL |         foo(2)
    |
-help: if you intended to pass a unit value, use a unit literal instead
+help: or move the expression in front of the call...
+   |
+LL |     {
+LL |         foo(1);
+LL |         foo(2);
+LL |     };
+   |
+help: ...and use a unit literal instead
    |
 LL |     foo(());
    |         ^^
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:33:10
+  --> $DIR/unit_arg.rs:32:5
    |
-LL |     foo3({}, 2, 2);
-   |          ^^
+LL | /     b.bar({
+LL | |         1;
+LL | |     });
+   | |______^
    |
-help: if you intended to pass a unit value, use a unit literal instead
+help: remove the semicolon from the last statement in the block
    |
-LL |     foo3((), 2, 2);
-   |          ^^
+LL |         1
+   |
+help: or move the expression in front of the call...
+   |
+LL |     {
+LL |         1;
+LL |     };
+   |
+help: ...and use a unit literal instead
+   |
+LL |     b.bar(());
+   |           ^^
 
-error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:35:11
+error: passing unit values to a function
+  --> $DIR/unit_arg.rs:35:5
    |
-LL |       b.bar({
-   |  ___________^
-LL | |         1;
+LL |     taking_multiple_units(foo(0), foo(1));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: move the expressions in front of the call...
+   |
+LL |     foo(0);
+LL |     foo(1);
+   |
+help: ...and use unit literals instead
+   |
+LL |     taking_multiple_units((), ());
+   |                           ^^  ^^
+
+error: passing unit values to a function
+  --> $DIR/unit_arg.rs:36:5
+   |
+LL | /     taking_multiple_units(foo(0), {
+LL | |         foo(1);
+LL | |         foo(2);
 LL | |     });
+   | |______^
+   |
+help: remove the semicolon from the last statement in the block
+   |
+LL |         foo(2)
+   |
+help: or move the expressions in front of the call...
+   |
+LL |     foo(0);
+LL |     {
+LL |         foo(1);
+LL |         foo(2);
+LL |     };
+   |
+help: ...and use unit literals instead
+   |
+LL |     taking_multiple_units((), ());
+   |                           ^^  ^^
+
+error: passing unit values to a function
+  --> $DIR/unit_arg.rs:40:5
+   |
+LL | /     taking_multiple_units(
+LL | |         {
+LL | |             foo(0);
+LL | |             foo(1);
+...  |
+LL | |         },
+LL | |     );
    | |_____^
    |
-help: if you intended to pass a unit value, use a unit literal instead
+help: remove the semicolon from the last statement in the block
    |
-LL |     b.bar(());
-   |           ^^
+LL |             foo(1)
+   |
+help: remove the semicolon from the last statement in the block
+   |
+LL |             foo(3)
+   |
+help: or move the expressions in front of the call...
+   |
+LL |     {
+LL |         foo(0);
+LL |         foo(1);
+LL |     };
+LL |     {
+LL |         foo(2);
+ ...
+help: ...and use unit literals instead
+   |
+LL |         (),
+LL |         (),
+   |
+
+error: passing a unit value to a function
+  --> $DIR/unit_arg.rs:82:5
+   |
+LL |     Some(foo(1))
+   |     ^^^^^^^^^^^^
+   |
+help: move the expression in front of the call...
+   |
+LL |     foo(1);
+   |
+help: ...and use a unit literal instead
+   |
+LL |     Some(())
+   |          ^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs
new file mode 100644
index 00000000000..18a31eb3dee
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs
@@ -0,0 +1,26 @@
+#![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);
+    taking_two_units({}, foo(0));
+    taking_three_units({}, foo(0), foo(1));
+}
+
+fn taking_two_units(a: (), b: ()) {}
+fn taking_three_units(a: (), b: (), c: ()) {}
+
+fn main() {
+    bad();
+}
diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr
new file mode 100644
index 00000000000..bb58483584b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr
@@ -0,0 +1,51 @@
+error: passing a unit value to a function
+  --> $DIR/unit_arg_empty_blocks.rs:15:5
+   |
+LL |     foo({});
+   |     ^^^^--^
+   |         |
+   |         help: use a unit literal instead: `()`
+   |
+   = 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
+   |
+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
+   |
+LL |     taking_two_units({}, foo(0));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: move the expression in front of the call...
+   |
+LL |     foo(0);
+   |
+help: ...and use unit literals instead
+   |
+LL |     taking_two_units((), ());
+   |                      ^^  ^^
+
+error: passing unit values to a function
+  --> $DIR/unit_arg_empty_blocks.rs:18:5
+   |
+LL |     taking_three_units({}, foo(0), foo(1));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: move the expressions in front of the call...
+   |
+LL |     foo(0);
+LL |     foo(1);
+   |
+help: ...and use unit literals instead
+   |
+LL |     taking_three_units((), (), ());
+   |                        ^^  ^^  ^^
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
new file mode 100644
index 00000000000..779fd57707a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
@@ -0,0 +1,26 @@
+// run-rustfix
+
+use std::cmp::Reverse;
+
+fn id(x: isize) -> isize {
+    x
+}
+
+fn main() {
+    let mut vec: Vec<isize> = vec![3, 6, 1, 2, 5];
+    // Forward examples
+    vec.sort();
+    vec.sort_unstable();
+    vec.sort_by_key(|&a| (a + 5).abs());
+    vec.sort_unstable_by_key(|&a| id(-a));
+    // Reverse examples
+    vec.sort_by_key(|&b| Reverse(b));
+    vec.sort_by_key(|&b| Reverse((b + 5).abs()));
+    vec.sort_unstable_by_key(|&b| Reverse(id(-b)));
+    // Negative examples (shouldn't be changed)
+    let c = &7;
+    vec.sort_by(|a, b| (b - a).cmp(&(a - b)));
+    vec.sort_by(|_, b| b.cmp(&5));
+    vec.sort_by(|_, b| b.cmp(c));
+    vec.sort_unstable_by(|a, _| a.cmp(c));
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs
new file mode 100644
index 00000000000..0485a5630af
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs
@@ -0,0 +1,26 @@
+// run-rustfix
+
+use std::cmp::Reverse;
+
+fn id(x: isize) -> isize {
+    x
+}
+
+fn main() {
+    let mut vec: Vec<isize> = vec![3, 6, 1, 2, 5];
+    // Forward examples
+    vec.sort_by(|a, b| a.cmp(b));
+    vec.sort_unstable_by(|a, b| a.cmp(b));
+    vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs()));
+    vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b)));
+    // Reverse examples
+    vec.sort_by(|a, b| b.cmp(a));
+    vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
+    vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a)));
+    // Negative examples (shouldn't be changed)
+    let c = &7;
+    vec.sort_by(|a, b| (b - a).cmp(&(a - b)));
+    vec.sort_by(|_, b| b.cmp(&5));
+    vec.sort_by(|_, b| b.cmp(c));
+    vec.sort_unstable_by(|a, _| a.cmp(c));
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr
new file mode 100644
index 00000000000..903b6e5099c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr
@@ -0,0 +1,46 @@
+error: use Vec::sort here instead
+  --> $DIR/unnecessary_sort_by.rs:12:5
+   |
+LL |     vec.sort_by(|a, b| a.cmp(b));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort()`
+   |
+   = note: `-D clippy::unnecessary-sort-by` implied by `-D warnings`
+
+error: use Vec::sort here instead
+  --> $DIR/unnecessary_sort_by.rs:13:5
+   |
+LL |     vec.sort_unstable_by(|a, b| a.cmp(b));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:14:5
+   |
+LL |     vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| (a + 5).abs())`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:15:5
+   |
+LL |     vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b)));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&a| id(-a))`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:17:5
+   |
+LL |     vec.sort_by(|a, b| b.cmp(a));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(b))`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:18:5
+   |
+LL |     vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:19:5
+   |
+LL |     vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a)));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&b| Reverse(id(-b)))`
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
new file mode 100644
index 00000000000..b39e891094f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
@@ -0,0 +1,33 @@
+// run-rustfix
+
+#![feature(or_patterns)]
+#![feature(box_patterns)]
+#![warn(clippy::unnested_or_patterns)]
+#![allow(clippy::cognitive_complexity, clippy::match_ref_pats)]
+#![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)]
+
+fn main() {
+    if let box (0 | 2) = Box::new(0) {}
+    if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {}
+    const C0: &u8 = &1;
+    if let &(0 | 2) | C0 = &0 {}
+    if let &mut (0 | 2) = &mut 0 {}
+    if let x @ (0 | 2) = 0 {}
+    if let (0, 1 | 2 | 3) = (0, 0) {}
+    if let (1 | 2 | 3, 0) = (0, 0) {}
+    if let (x, ..) | (x, 1 | 2) = (0, 1) {}
+    if let [0 | 1] = [0] {}
+    if let [x, 0 | 1] = [0, 1] {}
+    if let [x, 0 | 1 | 2] = [0, 1] {}
+    if let [x, ..] | [x, 1 | 2] = [0, 1] {}
+    struct TS(u8, u8);
+    if let TS(0 | 1, x) = TS(0, 0) {}
+    if let TS(1 | 2 | 3, 0) = TS(0, 0) {}
+    if let TS(x, ..) | TS(x, 1 | 2) = TS(0, 0) {}
+    struct S {
+        x: u8,
+        y: u8,
+    }
+    if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {}
+    if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.rs b/src/tools/clippy/tests/ui/unnested_or_patterns.rs
new file mode 100644
index 00000000000..096f5a71150
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.rs
@@ -0,0 +1,33 @@
+// run-rustfix
+
+#![feature(or_patterns)]
+#![feature(box_patterns)]
+#![warn(clippy::unnested_or_patterns)]
+#![allow(clippy::cognitive_complexity, clippy::match_ref_pats)]
+#![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)]
+
+fn main() {
+    if let box 0 | box 2 = Box::new(0) {}
+    if let box ((0 | 1)) | box (2 | 3) | box 4 = Box::new(0) {}
+    const C0: &u8 = &1;
+    if let &0 | C0 | &2 = &0 {}
+    if let &mut 0 | &mut 2 = &mut 0 {}
+    if let x @ 0 | x @ 2 = 0 {}
+    if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {}
+    if let (1, 0) | (2, 0) | (3, 0) = (0, 0) {}
+    if let (x, ..) | (x, 1) | (x, 2) = (0, 1) {}
+    if let [0] | [1] = [0] {}
+    if let [x, 0] | [x, 1] = [0, 1] {}
+    if let [x, 0] | [x, 1] | [x, 2] = [0, 1] {}
+    if let [x, ..] | [x, 1] | [x, 2] = [0, 1] {}
+    struct TS(u8, u8);
+    if let TS(0, x) | TS(1, x) = TS(0, 0) {}
+    if let TS(1, 0) | TS(2, 0) | TS(3, 0) = TS(0, 0) {}
+    if let TS(x, ..) | TS(x, 1) | TS(x, 2) = TS(0, 0) {}
+    struct S {
+        x: u8,
+        y: u8,
+    }
+    if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
+    if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
new file mode 100644
index 00000000000..1899dc657df
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
@@ -0,0 +1,179 @@
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:10:12
+   |
+LL |     if let box 0 | box 2 = Box::new(0) {}
+   |            ^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unnested-or-patterns` implied by `-D warnings`
+help: nest the patterns
+   |
+LL |     if let box (0 | 2) = Box::new(0) {}
+   |            ^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:11:12
+   |
+LL |     if let box ((0 | 1)) | box (2 | 3) | box 4 = Box::new(0) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:13:12
+   |
+LL |     if let &0 | C0 | &2 = &0 {}
+   |            ^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let &(0 | 2) | C0 = &0 {}
+   |            ^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:14:12
+   |
+LL |     if let &mut 0 | &mut 2 = &mut 0 {}
+   |            ^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let &mut (0 | 2) = &mut 0 {}
+   |            ^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:15:12
+   |
+LL |     if let x @ 0 | x @ 2 = 0 {}
+   |            ^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let x @ (0 | 2) = 0 {}
+   |            ^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:16:12
+   |
+LL |     if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let (0, 1 | 2 | 3) = (0, 0) {}
+   |            ^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:17:12
+   |
+LL |     if let (1, 0) | (2, 0) | (3, 0) = (0, 0) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let (1 | 2 | 3, 0) = (0, 0) {}
+   |            ^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:18:12
+   |
+LL |     if let (x, ..) | (x, 1) | (x, 2) = (0, 1) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let (x, ..) | (x, 1 | 2) = (0, 1) {}
+   |            ^^^^^^^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:19:12
+   |
+LL |     if let [0] | [1] = [0] {}
+   |            ^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let [0 | 1] = [0] {}
+   |            ^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:20:12
+   |
+LL |     if let [x, 0] | [x, 1] = [0, 1] {}
+   |            ^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let [x, 0 | 1] = [0, 1] {}
+   |            ^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:21:12
+   |
+LL |     if let [x, 0] | [x, 1] | [x, 2] = [0, 1] {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let [x, 0 | 1 | 2] = [0, 1] {}
+   |            ^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:22:12
+   |
+LL |     if let [x, ..] | [x, 1] | [x, 2] = [0, 1] {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let [x, ..] | [x, 1 | 2] = [0, 1] {}
+   |            ^^^^^^^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:24:12
+   |
+LL |     if let TS(0, x) | TS(1, x) = TS(0, 0) {}
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let TS(0 | 1, x) = TS(0, 0) {}
+   |            ^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:25:12
+   |
+LL |     if let TS(1, 0) | TS(2, 0) | TS(3, 0) = TS(0, 0) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let TS(1 | 2 | 3, 0) = TS(0, 0) {}
+   |            ^^^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:26:12
+   |
+LL |     if let TS(x, ..) | TS(x, 1) | TS(x, 2) = TS(0, 0) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let TS(x, ..) | TS(x, 1 | 2) = TS(0, 0) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns.rs:31:12
+   |
+LL |     if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {}
+   |            ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 16 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed
new file mode 100644
index 00000000000..02a129c55a3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#![feature(or_patterns)]
+#![feature(box_patterns)]
+#![warn(clippy::unnested_or_patterns)]
+#![allow(clippy::cognitive_complexity, clippy::match_ref_pats)]
+#![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)]
+
+fn main() {
+    if let Some(Some(0 | 1)) = None {}
+    if let Some(Some(0 | 1 | 2)) = None {}
+    if let Some(Some(0 | 1 | 2 | 3 | 4)) = None {}
+    if let Some(Some(0 | 1 | 2)) = None {}
+    if let ((0 | 1 | 2,),) = ((0,),) {}
+    if let 0 | 1 | 2 = 0 {}
+    if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {}
+    if let box box (0 | 2 | 4) = Box::new(Box::new(0)) {}
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.rs b/src/tools/clippy/tests/ui/unnested_or_patterns2.rs
new file mode 100644
index 00000000000..acf3158989d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#![feature(or_patterns)]
+#![feature(box_patterns)]
+#![warn(clippy::unnested_or_patterns)]
+#![allow(clippy::cognitive_complexity, clippy::match_ref_pats)]
+#![allow(unreachable_patterns, irrefutable_let_patterns, unused_variables)]
+
+fn main() {
+    if let Some(Some(0)) | Some(Some(1)) = None {}
+    if let Some(Some(0)) | Some(Some(1) | Some(2)) = None {}
+    if let Some(Some(0 | 1) | Some(2)) | Some(Some(3) | Some(4)) = None {}
+    if let Some(Some(0) | Some(1 | 2)) = None {}
+    if let ((0,),) | ((1,) | (2,),) = ((0,),) {}
+    if let 0 | (1 | 2) = 0 {}
+    if let box (0 | 1) | (box 2 | box (3 | 4)) = Box::new(0) {}
+    if let box box 0 | box (box 2 | box 4) = Box::new(Box::new(0)) {}
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr
new file mode 100644
index 00000000000..1847fd8e098
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr
@@ -0,0 +1,91 @@
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns2.rs:10:12
+   |
+LL |     if let Some(Some(0)) | Some(Some(1)) = None {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unnested-or-patterns` implied by `-D warnings`
+help: nest the patterns
+   |
+LL |     if let Some(Some(0 | 1)) = None {}
+   |            ^^^^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns2.rs:11:12
+   |
+LL |     if let Some(Some(0)) | Some(Some(1) | Some(2)) = None {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let Some(Some(0 | 1 | 2)) = None {}
+   |            ^^^^^^^^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns2.rs:12:12
+   |
+LL |     if let Some(Some(0 | 1) | Some(2)) | Some(Some(3) | Some(4)) = None {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let Some(Some(0 | 1 | 2 | 3 | 4)) = None {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns2.rs:13:12
+   |
+LL |     if let Some(Some(0) | Some(1 | 2)) = None {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let Some(Some(0 | 1 | 2)) = None {}
+   |            ^^^^^^^^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns2.rs:14:12
+   |
+LL |     if let ((0,),) | ((1,) | (2,),) = ((0,),) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let ((0 | 1 | 2,),) = ((0,),) {}
+   |            ^^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns2.rs:15:12
+   |
+LL |     if let 0 | (1 | 2) = 0 {}
+   |            ^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let 0 | 1 | 2 = 0 {}
+   |            ^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns2.rs:16:12
+   |
+LL |     if let box (0 | 1) | (box 2 | box (3 | 4)) = Box::new(0) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unnested or-patterns
+  --> $DIR/unnested_or_patterns2.rs:17:12
+   |
+LL |     if let box box 0 | box (box 2 | box 4) = Box::new(Box::new(0)) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: nest the patterns
+   |
+LL |     if let box box (0 | 2 | 4) = Box::new(Box::new(0)) {}
+   |            ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/vec_resize_to_zero.rs b/src/tools/clippy/tests/ui/vec_resize_to_zero.rs
new file mode 100644
index 00000000000..0263e2f5f20
--- /dev/null
+++ b/src/tools/clippy/tests/ui/vec_resize_to_zero.rs
@@ -0,0 +1,15 @@
+#![warn(clippy::vec_resize_to_zero)]
+
+fn main() {
+    // applicable here
+    vec![1, 2, 3, 4, 5].resize(0, 5);
+
+    // not applicable
+    vec![1, 2, 3, 4, 5].resize(2, 5);
+
+    // applicable here, but only implemented for integer litterals for now
+    vec!["foo", "bar", "baz"].resize(0, "bar");
+
+    // not applicable
+    vec!["foo", "bar", "baz"].resize(2, "bar")
+}
diff --git a/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr b/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr
new file mode 100644
index 00000000000..feb846298c6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/vec_resize_to_zero.stderr
@@ -0,0 +1,13 @@
+error: emptying a vector with `resize`
+  --> $DIR/vec_resize_to_zero.rs:5:5
+   |
+LL |     vec![1, 2, 3, 4, 5].resize(0, 5);
+   |     ^^^^^^^^^^^^^^^^^^^^------------
+   |                         |
+   |                         help: ...or you can empty the vector with: `clear()`
+   |
+   = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings`
+   = help: the arguments may be inverted...
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
index 2aa24ea1156..4f8754a9301 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
@@ -6,7 +6,8 @@
     unused_variables,
     dead_code,
     clippy::single_match,
-    clippy::wildcard_in_or_patterns
+    clippy::wildcard_in_or_patterns,
+    clippy::unnested_or_patterns
 )]
 
 use std::io::ErrorKind;
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
index 07c93feaf28..5e66644ceca 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs
@@ -6,7 +6,8 @@
     unused_variables,
     dead_code,
     clippy::single_match,
-    clippy::wildcard_in_or_patterns
+    clippy::wildcard_in_or_patterns,
+    clippy::unnested_or_patterns
 )]
 
 use std::io::ErrorKind;
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
index 7151a5c5770..e03b3be43ed 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
@@ -1,5 +1,5 @@
 error: wildcard match will miss any future added variants
-  --> $DIR/wildcard_enum_match_arm.rs:37:9
+  --> $DIR/wildcard_enum_match_arm.rs:38:9
    |
 LL |         _ => eprintln!("Not red"),
    |         ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
@@ -11,25 +11,25 @@ LL | #![deny(clippy::wildcard_enum_match_arm)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: wildcard match will miss any future added variants
-  --> $DIR/wildcard_enum_match_arm.rs:41:9
+  --> $DIR/wildcard_enum_match_arm.rs:42:9
    |
 LL |         _not_red => eprintln!("Not red"),
    |         ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan`
 
 error: wildcard match will miss any future added variants
-  --> $DIR/wildcard_enum_match_arm.rs:45:9
+  --> $DIR/wildcard_enum_match_arm.rs:46:9
    |
 LL |         not_red => format!("{:?}", not_red),
    |         ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan`
 
 error: wildcard match will miss any future added variants
-  --> $DIR/wildcard_enum_match_arm.rs:61:9
+  --> $DIR/wildcard_enum_match_arm.rs:62:9
    |
 LL |         _ => "No red",
    |         ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
 
 error: match on non-exhaustive enum doesn't explicitly match all known variants
-  --> $DIR/wildcard_enum_match_arm.rs:78:9
+  --> $DIR/wildcard_enum_match_arm.rs:79:9
    |
 LL |         _ => {},
    |         ^ help: try this: `std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::ConnectionRefused | std::io::ErrorKind::ConnectionReset | std::io::ErrorKind::ConnectionAborted | std::io::ErrorKind::NotConnected | std::io::ErrorKind::AddrInUse | std::io::ErrorKind::AddrNotAvailable | std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::AlreadyExists | std::io::ErrorKind::WouldBlock | std::io::ErrorKind::InvalidInput | std::io::ErrorKind::InvalidData | std::io::ErrorKind::TimedOut | std::io::ErrorKind::WriteZero | std::io::ErrorKind::Interrupted | std::io::ErrorKind::Other | std::io::ErrorKind::UnexpectedEof | _`